powershell 为什么我不能将对象存储在Parallel ForEach-Object循环中的变量中?

luaexgnf  于 2023-10-18  发布在  Shell
关注(0)|答案(1)|浏览(121)

我正在尝试从每个域控制器中为每个用户检索AD属性LastLogon。由于这将花费大量的时间,我尝试使用PowerShell 7的Parallel功能

示例

$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)
    }
}

错误

Get-ADUser: 
Line |
   7 |  …        $lastLogonAD = Get-ADUser -Identity $_ -Properties LastLogon -Server  …
     |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The server has returned the following error: invalid enumeration context.

我发现,如果我删除-Server参数,它就可以工作,或者如果我没有将属性存储到变量中,它也可以工作。

删除server参数

foreach ($DC in $DCs) {
        $lastLogonAD = Get-ADUser -Identity $_ -Properties LastLogon -ErrorAction Stop | Select-Object -ExpandProperty LastLogon

        $lastLogonConverted = [datetime]::FromFileTimeUTC($lastLogonAD)
    }

不存储变量

foreach ($DC in $DCs) {
        Get-ADUser -Identity $_ -Properties LastLogon -Server $DC -ErrorAction Stop | Select-Object -ExpandProperty LastLogon

        $lastLogonConverted = [datetime]::FromFileTimeUTC($lastLogonAD)
    }
htrmnn0y

htrmnn0y1#

错误“服务器返回了以下错误:无效的枚举上下文。”主要是因为您的代码非常低效,此错误发生在运行超过30分钟的查询上。请参阅TechNet文章Active Directory Troubleshooting: server has returned the following error - invalid enumeration context
您的并行循环应该按每个域控制器而不是按每个用户运行。并行调用应该处理每个运行空间的所有用户。
下面的代码做什么:
1.获取将被并行处理的DistinguishedName的列表。
1.启动每个域控制器的并行调用,并将DistinguishedName的列表传递给每个并行调用的进程。
1.然后按DistinguishedName对所有结果进行分组,按LastLogon对每个组进行排序,并使用最新的LastLogon在每个组中选择用户。
1.最后,使用构造的“友好”属性LastLogonDate投影对象。

$sites = # needs to be defined here...

# only need the users `DistinguishedName` here
$users = (Get-ADUser -Filter '[filter]').DistinguishedName

# parallel loop per DC instead of per user
Get-ADDomainController -Filter * |
    Where-Object { $_.Site -in $sites } |
    ForEach-Object -Parallel {
        $using:users | Get-ADUser -Properties LastLogon -Server $_
    } |
    Group-Object DistinguishedName |
    ForEach-Object {
        $_.Group | Sort-Object LastLogon -Descending -Top 1 |
            Select-Object *, @{ N='LastLogonDate'; E={ [datetime]::FromFileTimeUtc($_.LastLogon) }}
    }

如果你真的需要每个用户都有一个Source DC的引用,那么解决的方法是在并行循环中用一个新的SourceDC属性重新创建对象,例如:

# No code changes before this
    ForEach-Object -Parallel {
        $sourceDC = $_
        $using:users | Get-ADUser -Properties LastLogon -Server $_ |
            Select-Object *, @{ N='SourceDC'; E={ $sourceDC.Name }}
    }
    # No code changes after this

如果在此更改后您仍然面临相同的问题,则需要减少查询的用户数量。或者,您可以尝试使用一个精心设计的LDAP过滤器对DC进行单个调用:

# create one big ldap filter
$filter = -join @(
    '(|'
    (Get-ADUser -Filter '[filter]').DistinguishedName |
        ForEach-Object { "(distinguishedName=$_)" }
    ')'
)

Get-ADDomainController -Filter * |
    Where-Object { $_.Site -in $sites } |
    ForEach-Object -Parallel {
        # then using this filter we can make a single call per DC
        Get-ADUser -LDAPFilter $using:filter -Properties LastLogon -Server $_
    } |
    # rest of the code stays the same here...

相关问题