I'm trying to retrieve the AD property LastLogon from each of our domain controllers, for each user. Due to the amount of time this will take, I'm trying to use the Parallel feature from PowerShell 7
Example
$users = Get-ADUser -Filter "[filter]"
$DCs = Get-ADDomainController -Filter * | Where-Object { $_.Site -in $using:sites }
$users | ForEach-Object -ThrottleLimit 2 -Parallel {
$serv = $using:DCs
foreach ($DC in $serv) {
$lastLogonAD = Get-ADUser -Identity $_ -Properties LastLogon -Server $DC -ErrorAction Stop | Select-Object -ExpandProperty LastLogon
$lastLogonConverted = [datetime]::FromFileTimeUTC($lastLogonAD)
}
}
Error
Get-ADUser:
Line |
7 | … $lastLogonAD = Get-ADUser -Identity $_ -Properties LastLogon -Server …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| The server has returned the following error: invalid enumeration context.
What I've found is that if I remove the -Server parameter, it works, or if I don't store the property into a variable, it works.
Removing the server parameter
foreach ($DC in $DCs) {
$lastLogonAD = Get-ADUser -Identity $_ -Properties LastLogon -ErrorAction Stop | Select-Object -ExpandProperty LastLogon
$lastLogonConverted = [datetime]::FromFileTimeUTC($lastLogonAD)
}
Not storing the variable
foreach ($DC in $DCs) {
Get-ADUser -Identity $_ -Properties LastLogon -Server $DC -ErrorAction Stop | Select-Object -ExpandProperty LastLogon
$lastLogonConverted = [datetime]::FromFileTimeUTC($lastLogonAD)
}
The error "The server has returned the following error: invalid enumeration context." is mainly because your code is very inefficient, this error occurs on queries running for more than 30 minutes. See TechNet article Active Directory Troubleshooting: server has returned the following error - invalid enumeration context.
Your parallel loop should be running per Domain Controller instead of per User. The parallel invocations should be processing all users per runspace.
What below code does:
DistinguishedNames that will be processed in parallel.DistinguishedNames to process per parallel invocation.DistinguishedName, sort each group byLastLogonand pick user on each group with the latestLastLogon.LastLogonDate.If you really need to have a reference of the Source DC per user then the way around it is to recreate the objects with a new
SourceDCproperty inside the parallel loop, for instance:If you're still facing the same issue after this change then you will need to reduce the number of users you're querying. Or perhaps you can try with a single call to the DCs using an elaborate LDAP Filter: