PowerShell中AD查询后Foreach-Object管道变量对比无输出问题
问题分析与解决方案
你猜的没错!问题确实出在管道变量$_的作用域冲突上,这也是PowerShell管道里很容易踩的坑。
为什么最后一行没输出?
看你最后一段代码:
ForEach-Object{get-aduser -filter * -Properties mail | Where-Object {$_.samaccountname -eq $_.User}}
在ForEach-Object的脚本块里,当你调用get-aduser -filter *时,后续Where-Object里的$_已经变成了get-aduser返回的每个AD用户对象,而不是前面管道传过来的、包含User和Abteilung属性的对象。这就导致你在做$_.samaccountname -eq $_.User的时候,其实是拿当前AD用户的samaccountname和它自己的User属性(这个属性根本不存在)做对比,自然匹配不上,所以没有输出。
两种解决思路
思路1:一次性获取所有需要的属性(推荐,更高效)
既然你一开始就查询AD用户,不如直接在首次Get-ADUser时就把mail属性一起拉取,这样不需要后续二次查询AD,既节省资源又避免变量冲突:
Get-ADUser -Filter * -Property Distinguishedname, mail | # 筛选Verkauf OU下的用户 Where-Object {($_.Distinguishedname.split(',')[2]).TrimStart("OU=") -like 'Verkauf'} | # 构造需要的属性列 Select-Object @{name='User'; Expression={$_.samaccountname}}, @{Name='Abteilung'; Expression={($_.Distinguishedname.split(',')[1]).TrimStart("OU=")}}, mail | # 筛选部门为z的用户 Where-Object {$_.Abteilung -eq "z"} | # 按部门和用户名排序 Sort-Object Abteilung, User
这样运行后,直接就能得到包含用户名、部门和邮箱的结果列表。
思路2:避免变量覆盖(适合必须二次查询的场景)
如果因为某些原因必须分两次查询AD,那你需要把ForEach-Object里的当前对象存到一个独立变量里,避免被内部管道的$_覆盖:
# 前面的管道部分保持不变,直到ForEach-Object Get-ADUser -filter * -property Distinguishedname | Where-Object {($_.Distinguishedname.split(',')[2]).trimstart("OU=") -like 'Verkauf'} | Select-Object @{name='User'; expression={$_.samaccountname}}, @{Name='Abteilung' ;Expression={($_.Distinguishedname.split(',')[1]).trimstart("OU=")}} | Sort-Object Abteilung, user | Where-Object {$_.Abteilung -eq "z"} | ForEach-Object { # 把当前管道对象存到独立变量里 $targetUser = $_ # 直接用Filter查询指定用户,比查所有再过滤高效得多 Get-ADUser -Filter "samaccountname -eq '$($targetUser.User)'" -Properties mail | # 补充部门属性,保持结果格式一致 Select-Object @{Name='User'; Expression={$_.samaccountname}}, @{Name='Abteilung'; Expression={"z"}}, mail }
这里额外提一句:用Get-ADUser -Filter直接定位用户,比Get-ADUser -Filter *再过滤要高效太多,尤其是AD用户数量多的时候,一定要优先用这种方式。
内容的提问来源于stack exchange,提问作者SSIO
相关产品推荐
相关产品推荐

