如何保留对象格式同时筛选Get-ADUser的属性子集?
我完全懂你的痛点——处理数十万AD用户时,性能和对象兼容性简直是两难。问题的核心在于:Select-Object会把原生的ADUser对象转换成自定义的PSObject,而Get-ADPrincipalGroupMembership这类AD cmdlet只认原生AD主体对象(比如ADUser、ADGroup)或者能解析为主体标识符的字符串(比如SamAccountName)。
给你两个最实用的解决方案,既能保留所需属性,又能维持对象兼容性,还能保证性能:
方案1:从源头控制Get-ADUser返回的属性(最优解)
这是最根本的解决办法——直接让Get-ADUser只返回你需要的属性,而不是先拉取全量属性再用Select-Object筛选。这样返回的仍然是原生的ADUser对象,完全兼容所有AD相关cmdlet,同时因为从AD服务器拉取的数据更少,性能会比你之前的方法还要好。
示例代码:
# 只获取你需要的属性(比如SamAccountName、DisplayName、EmailAddress) # 注意:SamAccountName是默认返回的属性,也可以省略,但写出来更清晰 $users = Get-ADUser -Filter * -Properties SamAccountName, DisplayName, EmailAddress # 直接遍历原生ADUser对象,完美兼容Get-ADPrincipalGroupMembership $users | ForEach-Object { Write-Host "正在处理用户: $($_.DisplayName)" # 直接传入$_(ADUser对象)即可,无需额外提取属性 $userGroups = Get-ADPrincipalGroupMembership $_ # 其他需要用到多属性的操作也能直接用 Write-Host "$($_.SamAccountName) 的邮箱是: $($_.EmailAddress)" }
这个方法的优势:
- 原生
ADUser对象,支持所有AD cmdlet的直接调用 - 从AD服务器拉取的数据量最小,内存占用更低,性能最优
- 无需额外转换对象格式,代码更简洁
方案2:如果必须用Select-Object(特殊场景)
如果你因为某些原因必须用Select-Object筛选(比如从其他非AD来源获取的对象),可以给自定义对象添加AD主体类型标识,让AD cmdlet能识别它:
# 先获取全量或部分属性,再用Select-Object保留所需属性,同时指定类型名称 $users = Get-ADUser -Filter * | Select-Object SamAccountName, DisplayName, EmailAddress -TypeName Microsoft.ActiveDirectory.Management.ADUser # 此时传入Get-ADPrincipalGroupMembership即可正常工作 $users | ForEach-Object { $groups = Get-ADPrincipalGroupMembership $_ }
不过这个方法不如方案1可靠,因为自定义对象的方法和原生ADUser对象可能存在差异,建议优先用方案1。
为什么ExpandProperty不行?
-ExpandProperty SamAccountName会把属性值提取成纯字符串数组,丢失了所有其他属性和对象结构,只能用于只需要SamAccountName的场景,完全不符合你需要多属性+对象格式的需求。
关键提醒
你提到$users要用于多个命令,那保持原生ADUser类型是重中之重——所有AD cmdlet都是围绕这个类型设计的,用原生对象能避免后续所有兼容性问题,同时性能拉满,不用再频繁调用Get-ADUser重新获取数据。
内容的提问来源于stack exchange,提问作者James T

