﻿# Get-ADObject : The server has returned the following error: invalid enumeration context. | Evotec Blog

blog

# Get-ADObject : The server has returned the following error: invalid enumeration context.

15 May 2020en

![Get-ADObject : The server has returned the following error: invalid enumeration context.](/wp-content/uploads/2020/01/PowerShellBlack.png)

Path

1. [Home](/)
2. [Blog](/blog/)
3. Get-ADObject : The server has returned the following error: invalid enumeration context.

Explore this stream

[Back to Blog](/blog/)[All categories](/categories/)[All tags](/tags/)

**Categories**

[Active Directory](/blog/?category=Active Directory)[PowerShell](/blog/?category=PowerShell)

**Tags**

[active directory](/blog/?tag=active directory)[get-adobject](/blog/?tag=get-adobject)[powershell](/blog/?tag=powershell)

**Browse**

[All categories](/categories/)[All tags](/tags/)

In the last weeks, I'm working on a **PowerShell **module that the main goal is to work on gathering and fixing **GPOs**. I've been testing my module a lot of times on my test environment, and it worked fine till the moment I run it on production, and it started to fail pretty quickly. The difference between my environment and production is **25 GPOs** vs. **5000 GPOs**. The error I was getting:

> Get-ADObject : The server has returned the following error: invalid enumeration context. At C:\Users\Administrator\Documents\WindowsPowerShell\Modules\GPOZaurr\0.0.26\GPOZaurr.psm1:1987 char:13
>
> - Get-ADObject @Splat -Properties DisplayName, Name, Create …
> - CategoryInfo : NotSpecified: (:) [Get-ADObject], ADException
> - FullyQualifiedErrorId : The server has returned the following error: invalid enumeration context.,Microsoft.ActiveDirectory.Management.Commands.GetADObject

[!\[PowerShell error showing Get-ADObject failed with invalid enumeration context while processing GPOZaurr\](/wp-content/uploads/2020/05/img_5ebe3e736d55e.png)](/wp-content/uploads/2020/05/img_5ebe3e736d55e.png)

The error doesn't tell much but I've seen the error in multiple other situations mainly when using Get-ADUser, Get-ADComputer, or Get-ADGroup, but I'm confident that it touches all AD cmdlets. The errors would be very similar:

> Get-ADUser: The server has returned the following error: invalid enumeration context. Get-ADComputer: The server has returned the following error: invalid enumeration context. Get-ADGroup: The server has returned the following error: invalid enumeration context.

### 💡 The server has returned the following error: invalid enumeration context.

The issue comes from using **ForEach-Object** on AD cmdlets. While **ForEach-Object** is excellent and allows you to execute action over the pipeline as objects are read, it causes **Get-ADObject** to timeout if actions taken during pipeline are taking a too long time. A single query has a time limit. If you start a query on **Get-ADObject** that executes multiple operations on every object from the pipeline, the time adds up and the query timeouts.

```
Get-ADObject @Splat -Properties DisplayName, Name, Created, Modified, gPCFileSysPath, gPCFunctionalityVersion, gPCWQLFilter, gPCMachineExtensionNames, Description, CanonicalName, DistinguishedName | ForEach-Object -Process {
 $DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $_.DistinguishedName -ToDomainCN
 $Output = [ordered]@{ }
 $Output['DisplayName'] = $_.DisplayName
 $Output['DomainName'] = $DomainCN
 $Output['Description'] = $_.Description
 $Output['GUID'] = $_.Name -replace '{' -replace '}'
 $Output['Path'] = $_.gPCFileSysPath
 $Output['FunctionalityVersion'] = $_.gPCFunctionalityVersion
 $Output['Created'] = $_.Created
 $Output['Modified'] = $_.Modified
 $Output['GPOCanonicalName'] = $_.CanonicalName
 $Output['GPODomainDistinguishedName'] = ConvertFrom-DistinguishedName -DistinguishedName $_.DistinguishedName -ToDC
 $Output['GPODistinguishedName'] = $_.DistinguishedName
 [PSCustomObject] $Output
}
```

So while small query like above works great, because it's just doing some small conversion of an object – using it nested to another function with another **ForEach-Object** and checking for more values makes **AD Cmdlets** timeout. My original query looks like below

```
Get-GPOZaurrAD @getGPOZaurrADSplat | ForEach-Object -Process {
 Write-Verbose "Get-GPOZaurrOwner - Processing GPO: $($_.DisplayName) from domain: $($_.DomainName)"
 $ACL = Get-ADACLOwner -ADObject $_.GPODistinguishedName -Resolve -ADAdministrativeGroups $ADAdministrativeGroups
 $Object = [ordered] @{
 DisplayName = $_.DisplayName
 DomainName = $_.DomainName
 GUID = $_.GUID
 DistinguishedName = $_.GPODistinguishedName
 Owner = $ACL.OwnerName
 OwnerSid = $ACL.OwnerSid
 OwnerType = $ACL.OwnerType
 }
 if ($IncludeSysvol) {
 $FileOwner = Get-FileOwner -JustPath -Path $_.Path -Resolve
 $Object['SysvolOwner'] = $FileOwner.OwnerName
 $Object['SysvolSid'] = $FileOwner.OwnerSid
 $Object['SysvolType'] = $FileOwner.OwnerType
 $Object['SysvolPath'] = $_.Path
 }
 [PSCUstomObject] $Object
}
```

A **Get-GPOZaurrAD** function which is a wrapper around **Get-ADObject. **It queries AD, and for each object returned, it checks the **GPO Owner** and **SysVol Owner**. This process taking about 1 second per each check, makes the connection to Active **Directory timeout**. Of course, during my tests on 25 GPOs, the timeout won't happen, but as you imagine querying **5000 AD** objects, each taking **1 second** it means a single **Get-ADObject** query would require around **83 minutes** to finish.

### 💡 Dealing with the problem

There are 2 ways to deal with this problem. The easiest ones are to simply save query first to variable and then either use ForEach-Object or foreach to gather results.

```
$Objects = Get-GPOZaurrAD @getGPOZaurrADSplat
$Objects | ForEach-Object -Process {
 Write-Verbose "Get-GPOZaurrOwner - Processing GPO: $($_.DisplayName) from domain: $($_.DomainName)"
 $ACL = Get-ADACLOwner -ADObject $_.GPODistinguishedName -Resolve -ADAdministrativeGroups $ADAdministrativeGroups
 $Object = [ordered] @{
 DisplayName = $_.DisplayName
 DomainName = $_.DomainName
 GUID = $_.GUID
 DistinguishedName = $_.GPODistinguishedName
 Owner = $ACL.OwnerName
 OwnerSid = $ACL.OwnerSid
 OwnerType = $ACL.OwnerType
 }
 if ($IncludeSysvol) {
 $FileOwner = Get-FileOwner -JustPath -Path $_.Path -Resolve
 $Object['SysvolOwner'] = $FileOwner.OwnerName
 $Object['SysvolSid'] = $FileOwner.OwnerSid
 $Object['SysvolType'] = $FileOwner.OwnerType
 $Object['SysvolPath'] = $_.Path
 }
 [PSCUstomObject] $Object
}
```

From my own testing if I am already saving data to variable I prefer the later

```
$Objects = Get-GPOZaurrAD @getGPOZaurrADSplat
foreach ($_ in $Objects) {
 Write-Verbose "Get-GPOZaurrOwner - Processing GPO: $($_.DisplayName) from domain: $($_.DomainName)"
 $ACL = Get-ADACLOwner -ADObject $_.GPODistinguishedName -Resolve -ADAdministrativeGroups $ADAdministrativeGroups
 $Object = [ordered] @{
 DisplayName = $_.DisplayName
 DomainName = $_.DomainName
 GUID = $_.GUID
 DistinguishedName = $_.GPODistinguishedName
 Owner = $ACL.OwnerName
 OwnerSid = $ACL.OwnerSid
 OwnerType = $ACL.OwnerType
 }
 if ($IncludeSysvol) {
 $FileOwner = Get-FileOwner -JustPath -Path $_.Path -Resolve
 $Object['SysvolOwner'] = $FileOwner.OwnerName
 $Object['SysvolSid'] = $FileOwner.OwnerSid
 $Object['SysvolType'] = $FileOwner.OwnerType
 $Object['SysvolPath'] = $_.Path
 }
 [PSCUstomObject] $Object
}
```

Alternatively, you can change **Active Directory Web Services** timeout to a higher value. The second option has two significant issues. One, you need to be in charge of your **Active Directory** environment, which may be hard enough in environments you would hit this issue. Also, your scripts would only work on **AD **that has higher values set, hitting errors as soon as you try to use it on similar scale environments that don't have adjusted timeout settings. Second, **Microsoft **discourages this change. You can read about it in the following article **[What's New in AD DS: Active Directory Web Services](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd391908(v=ws.10)?redirectedfrom=MSDN)**.

> Changing the default value of this parameter is strongly discouraged. Most of the search results are returned within 30 minutes.

This means that a single call for **Get-ADObject**, **Get-ADUser**, **Get-ADComputer** (and so on) has to finish in **30 minutes** or less. Using **ForEach-Object, **due to its nature, can impact the time it takes to deliver all records; therefore, you should use it with caution. Knowing this, I opted for the first approach – making sure I can use my scripts anywhere I want to.

## Related Projects

Projects that align with this post's tags, categories, and content.

[All projects](/projects/)

Matching projects...

[Back to Blog](/blog)

[Newer post: Converting Pester V4 to Pester V5 basics](/blog/converting-pester-v4-to-pester-v5-basics/)[Older post: Getting Verified badge next to your GitHub commits in VS Code](/blog/getting-verified-badge-next-to-your-github-commits-in-vs-code/)

## Related posts

- [Mastering Active Directory Hygiene: Automating Stale Computer Cleanup with CleanupMonster](/blog/mastering-active-directory-hygiene-automating-stale-computer-cleanup-with-cleanupmonster/)
- [Active Directory Replication Summary to your Email or Microsoft Teams](/blog/active-directory-replication-summary-to-your-email/)
- [Report Active Directory Accounts that are Synchronized with Azure AD](/blog/report-active-directory-accounts-that-are-synchronized-with-azure-ad/)
