locked
Invalid Enumeration Context using powershell script to check computer accounts RRS feed

  • Question

  • Hello,

    I am using a powershell script downloaded from technet gallery (http://gallery.technet.microsoft.com/PowerShell-Organize-d37c2a29#content) to automatically move the computers to OUs based on IP subnets in active directory. But after a while the script is failing with an error 'Invalid Enumeration Context'  on the line

    Get-ADComputer -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows XP*" } -Properties PasswordLastSet | ForEach-Object {

    I tried to fix the error by including diffrent Page Size values 10, 1 and 0 as shown below but thats only helped to run the script a little longer before failing with the same error. I also incrased the MaxPageSize value to 10000 in ladp policies using ntdsutil in active directory but had no effect.

    Get-ADComputer -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows XP*" } -Properties PasswordLastSet -ResultPageSize 1 | ForEach-Object {

    Can you please help me with this issue?

    Thanks veru much in advance!

    Jashy

    Wednesday, January 30, 2013 3:24 PM

Answers

  • The blog post Bill linked suggests the problem is worsened if you query based on an attribute that is not indexed. The operatingSystem (and also the operatingSystemVersion) attribute is not indexed. Assuming you have a large number of computer objects in your domain, and you frequently query based on OS, it perhaps makes sense to make operatingSystem indexed. This is controlled by the searchFlags attribute of the attribute (of the attribute object in the cn=Schema container). This is a flag attribute, similar to userAccountControl, where each bit of the integer corresponds to a different setting. In this case, the bit mask for IS_INDEXED is 1. In my domain, the searchFlags attribute of the operatingSystem attribute has no value. If this is also true in your domain, you could simply assign the value 1 to make operatingSystem indexed.

    In ADSI Edit, navigate to the container cn=Schema,cn=Configuration,dc=MyDomain,dc=com, find the attribute with name "Operating-System" (the Common Name is "Operating-System", but the LDAPDisplayName is "operatingSystem"), right click and select "Properties", find the searchFlags attribute, click "Edit" and enter the value 1. Then save. I assume it takes awhile for the attribute to be indexed.

    My guess is that the Get-ADComputer cmdlet is prone to this problem because it retrieves a default set of properties, whether you need them or not. Some of these properties require code to convert into friendly formats, like objectGUID and SID. You only add one additional property, but it also requires code to convert into a friendly format. This makes the recordset larger than necessary, and requires more work on the DC. So, another workaround might be to use DirectorySearcher instead of Get-ADComputer. If this approach is of interest, I have a PowerShell V1 script linked on this page:

    http://www.rlmueller.net/PwdLastChanged.htm

    which documents the datetime the password was last changed for all users in the domain. This could be modified for all computers with the specified OS's by replacing the LDAP syntax filter with this:

    $Searcher.Filter = "(&(objectcategory=computer)(|(operatingSystem=Windows 7*)(operatingSystem=Windows XP*)))"

    -----

    You would add your code to compare pwdLastSet to your critical values and move the appropriate objects. Come to think of it, I also have a PowerShell V1 script that moves old computers (based on pwdLastSet) linked on this page:

    http://www.rlmueller.net/MoveOldComputers.htm

    In this case the filter includes a clause to only consider enabled computer accounts (testing the flag attribute userAccountControl). You can add the clauses for operatingSystem (use the OR operator "|" to filter on either W7 orXP), and you can remove the clause with userAccountControl if you also want to consider disabled accounts.

    In my experience, these PowerShell V1 scripts are faster than ones using Get-ADComputer in PowerShell V2. This may not be true in PowerShell V3, which supposedly has greatly improved the efficiency of the AD cmdlets. In fact, another workaround for you might be PowerShell V3.


    Richard Mueller - MVP Directory Services

    • Marked as answer by Abu Ameen Sunday, February 3, 2013 2:06 PM
    Wednesday, January 30, 2013 6:03 PM

All replies

  • Hi,

    Did you try searching before asking? I used the search terms

    get-adcomputer invalid enumeration context

    in a search engine. This blog posting was in the first few results:

    Ask the Directory Services Team - Saturday Mail Sack: Because it turns out, Friday night was alright for fighting edition

    In that blog posting, there is this link:

    The mystery of Windows PowerShell's "invalid enumeration context"

    Bill

    Wednesday, January 30, 2013 3:31 PM
  • As long as paging is enabled, the PageSize used in a query only affects performance (how many recordsets needed to retrieve the information and how much work is required in the remote database for each recordset). In fact, the optimal page size is often much less than people expect. It is rarely as large as 1000. The only way a poor page size setting could raise an error is if it causes a timeout, which would be a different error.

    I would recomment that you restore the default of 1000. A very large page size could adversely affect query performance. The default for Get-ADComputer is 256, which sounds good to me.


    Richard Mueller - MVP Directory Services

    Wednesday, January 30, 2013 4:06 PM
  • Hi Bill,

    I have seen that blog. My DC is not a busy one and also have more hardware resources than a normal domain controller. The post also suggest 'you could also increase the indexes' but I don't know how to do that!

    Thanks very much!

    Jashy

    Wednesday, January 30, 2013 4:23 PM
  • Thanks Richard. I have changed the value to the default 1000. But I get the same error though..I don't know whats going wrong.

    Jashy

    Wednesday, January 30, 2013 4:25 PM
  • Hi,

    Since your get-adcomputer enumeration contexts are expiring, I would suggest using a different solution than get-adcomputer.

    Bill

    Wednesday, January 30, 2013 4:55 PM
  • You do not show all of the code or all of the error message.

    Try changing this:

    Get-ADComputer -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows XP*" } -Properties PasswordLastSet -ResultPageSize 1

    to:

    Get-ADComputer -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows XP*" } -Properties PasswordLastSet  } | Out-Null

    Eun just that line to see if it still causes an error.


    ¯\_(ツ)_/¯

    Wednesday, January 30, 2013 5:51 PM
  • The blog post Bill linked suggests the problem is worsened if you query based on an attribute that is not indexed. The operatingSystem (and also the operatingSystemVersion) attribute is not indexed. Assuming you have a large number of computer objects in your domain, and you frequently query based on OS, it perhaps makes sense to make operatingSystem indexed. This is controlled by the searchFlags attribute of the attribute (of the attribute object in the cn=Schema container). This is a flag attribute, similar to userAccountControl, where each bit of the integer corresponds to a different setting. In this case, the bit mask for IS_INDEXED is 1. In my domain, the searchFlags attribute of the operatingSystem attribute has no value. If this is also true in your domain, you could simply assign the value 1 to make operatingSystem indexed.

    In ADSI Edit, navigate to the container cn=Schema,cn=Configuration,dc=MyDomain,dc=com, find the attribute with name "Operating-System" (the Common Name is "Operating-System", but the LDAPDisplayName is "operatingSystem"), right click and select "Properties", find the searchFlags attribute, click "Edit" and enter the value 1. Then save. I assume it takes awhile for the attribute to be indexed.

    My guess is that the Get-ADComputer cmdlet is prone to this problem because it retrieves a default set of properties, whether you need them or not. Some of these properties require code to convert into friendly formats, like objectGUID and SID. You only add one additional property, but it also requires code to convert into a friendly format. This makes the recordset larger than necessary, and requires more work on the DC. So, another workaround might be to use DirectorySearcher instead of Get-ADComputer. If this approach is of interest, I have a PowerShell V1 script linked on this page:

    http://www.rlmueller.net/PwdLastChanged.htm

    which documents the datetime the password was last changed for all users in the domain. This could be modified for all computers with the specified OS's by replacing the LDAP syntax filter with this:

    $Searcher.Filter = "(&(objectcategory=computer)(|(operatingSystem=Windows 7*)(operatingSystem=Windows XP*)))"

    -----

    You would add your code to compare pwdLastSet to your critical values and move the appropriate objects. Come to think of it, I also have a PowerShell V1 script that moves old computers (based on pwdLastSet) linked on this page:

    http://www.rlmueller.net/MoveOldComputers.htm

    In this case the filter includes a clause to only consider enabled computer accounts (testing the flag attribute userAccountControl). You can add the clauses for operatingSystem (use the OR operator "|" to filter on either W7 orXP), and you can remove the clause with userAccountControl if you also want to consider disabled accounts.

    In my experience, these PowerShell V1 scripts are faster than ones using Get-ADComputer in PowerShell V2. This may not be true in PowerShell V3, which supposedly has greatly improved the efficiency of the AD cmdlets. In fact, another workaround for you might be PowerShell V3.


    Richard Mueller - MVP Directory Services

    • Marked as answer by Abu Ameen Sunday, February 3, 2013 2:06 PM
    Wednesday, January 30, 2013 6:03 PM
  • Hello,

    Thanks very much for your response. Code is exactly the same available in the technet gallery http://gallery.technet.microsoft.com/PowerShell-Organize-d37c2a29#content

    Error is below

    get-adcomputer <<<< -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows XP*" } -Properties PasswordLastSet -ResultPageSize 1 | foreach-object {
    • CategoryInfo : NotSpecified: (:) [Get-ADComputer], ADException
    • FullyQualifiedErrorId : The server has returned the following error: invalid enumeration context.,Microsoft.ActiveDirectory.Management.Commands.GetADComputer

    I will try your suggestion and update the result.

    Jashy

    Wednesday, January 30, 2013 6:03 PM
  • Hi Richard,

    Thanks very much for your detailed reply.   I indexed the operating system attribute in AD today and waited for few hours but had the same error when ran the script. I also tried to use the DirectorySearcher but that failed with an error 'you cannot call method using a null valued expression'. I am not good in scripting so using a different method and matching with the old one will take some time for me as I was bit busy today at work. I will work on the script again after the week end and will update you the result.  I am yet to try Powershell V3..

    Your response and links to the scripts were very helpful, I couldn't have asked for a better response, much appreciated.

    Best Regards,


    Thursday, January 31, 2013 3:42 PM
  • Hello Richard,

    I could fix the script today using DirectorySearcher method and finished my task successfully!

    Thanks very much again for your help!!

    Best Regards,

    Sunday, February 3, 2013 2:06 PM
  • I was able to get it to work by using get-qaduser instead of get-aduser and before running it I set the default result size to something much greater than the number of users in my domain.

    Bonnie

    Sunday, May 4, 2014 12:22 AM
  • I know this is a bit old, but try this - it is probably what is in the Foreach is what is taking the longest.

    Assign the set to a variable, then pipe the variable.

    $machines = Get-ADComputer -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows XP*" } -Properties PasswordLastSet -ResultPageSize 1

    $machines | ForEach-Object {...}

    or 

    $machines | %{....}

    or 

    foreach ($mc in $machines){...}


    I used to be an adventurer too, until I took an arrow to the knee.

    • Proposed as answer by lashunnarah Wednesday, February 28, 2018 7:19 PM
    Wednesday, January 6, 2016 9:02 PM
  • I know this is a bit old, but try this - it is probably what is in the Foreach is what is taking the longest.

    Assign the set to a variable, then pipe the variable.

    $machines = Get-ADComputer -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows XP*" } -Properties PasswordLastSet -ResultPageSize 1

    $machines | ForEach-Object {...}

    or 

    $machines | %{....}

    or 

    foreach ($mc in $machines){...}


    I used to be an adventurer too, until I took an arrow to the knee.

    That is no different that what the OP put in the question. 


    - Chris Ream -

    **Remember, if you find a post that is helpful, or is the answer, please mark it appropriately.**

    Thursday, January 7, 2016 10:30 PM
  • Hello Richard,

    I could fix the script today using DirectorySearcher method and finished my task successfully!

    Thanks very much again for your help!!

    Best Regards,


    Hi, may you please share with me how did you fix it exactly, I fa  e the same issue now.
    Wednesday, June 15, 2016 11:24 AM
  • I had the exact same problem.  M. Emerson Bruce is correct.  For further explanation of why his is correct see: https://social.technet.microsoft.com/wiki/contents/articles/32418.active-directory-troubleshooting-server-has-returned-the-following-error-invalid-enumeration-context.aspx

    Thursday, April 13, 2017 2:28 PM
  • No, it never assigns the set to a variable in the question.

    This frequently happens if you do not assign a set to a variable, and instead get the set and pipe directly.

    $myset | do some stuff

    vs.

    get-adcomputer -filter * | do some stuff


    I used to be an adventurer too, until I took an arrow to the knee.



    Thursday, April 13, 2017 5:50 PM
  • I'm a few years late with an optional answer but MaxEnumContextExpiration times out after 30 minutes by default so improve your query by making it faster (pull only those properties needed) and/or pull the data to a local variable and then pipe the variable array to your next function in the pipeline. 
    Monday, July 10, 2017 2:43 PM
  • I know this is a bit old, but try this - it is probably what is in the Foreach is what is taking the longest.

    Assign the set to a variable, then pipe the variable.

    $machines = Get-ADComputer -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows XP*" } -Properties PasswordLastSet -ResultPageSize 1

    $machines | ForEach-Object {...}

    or 

    $machines | %{....}

    or 

    foreach ($mc in $machines){...}


    I used to be an adventurer too, until I took an arrow to the knee.

    Using this method resolved my issue.  This is a much simpler solution than the one marked as the answer IMO.  Also as Squirrel678 remarked, the https://social.technet.microsoft.com/wiki/contents/articles/32418.active-directory-troubleshooting-server-has-returned-the-following-error-invalid-enumeration-context.aspx explains why this works in great detail.

    In my case the code ended up looking like this:

    $ADComp = Get-ADComputer -Filter { OperatingSystem -like "Windows 7*" -or OperatingSystem -like "Windows 10*" } -Properties PasswordLastSet
    $ADComp | ForEach-Object {the rest of the script}

    Thanks!

    Wednesday, February 28, 2018 7:19 PM