使用MSOnline模块扩展PowerShell用户授权信息脚本时出现执行停滞问题求助
解决MSOnline脚本获取用户组信息时的性能停滞问题
嘿,我来帮你分析下这个脚本卡住的核心原因——这绝对是性能效率问题,典型的反向遍历导致的资源浪费!
问题根源
你当前的组查询逻辑是:
- 对每个用户,先遍历租户内所有的组
- 对每个组调用
Get-MsolGroupMember远程API,检查当前用户是否是该组成员
假设你的租户有1000个组、500个授权用户,那就要执行500×1000=50万次API调用,每次远程请求都有延迟,累积起来直接让脚本卡在循环里,看起来毫无进展。虽然单条调试能出结果,但批量执行时,重复请求的开销直接拖垮了脚本运行效率。
优化解决方案
核心思路是预缓存所有组与成员的映射关系,只执行一次组和成员的拉取,之后每个用户直接从缓存中读取所属组,避免重复调用API。
修改后的完整脚本
# 第一步:一次性获取所有组及其成员,建立用户邮箱到组名的哈希表缓存(仅执行一次) $groupMemberCache = @{} Get-MsolGroup -All | ForEach-Object { $currentGroupName = $_.DisplayName # 获取当前组的所有成员 Get-MsolGroupMember -All -GroupObjectId $_.ObjectId | ForEach-Object { if ($_.EmailAddress) { # 如果缓存中没有该用户的条目,初始化一个空数组 if (-not $groupMemberCache.ContainsKey($_.EmailAddress)) { $groupMemberCache[$_.EmailAddress] = @() } # 将当前组名添加到该用户的组列表中 $groupMemberCache[$_.EmailAddress] += $currentGroupName } } } # 第二步:遍历用户并生成结果(复用缓存,无需重复查组) $result = foreach($domain in $domains){ $users = Get-MsolUser -All | Where-Object {$_.IsLicensed -eq $true -and $_.UserPrincipalName -match "$domain"} foreach ($i in $users){ $licenses = $i.Licenses $licenseArray = $licenses | ForEach-Object {$_.AccountSkuId} # 注意:你原脚本中的$licensear = Friendlyname是笔误,需补全AccountSkuId转友好名称的逻辑 $licenseString = $licenseAr -join ", " # 从缓存中快速获取当前用户的所属组 $userGroups = if ($groupMemberCache.ContainsKey($i.UserPrincipalName)) { $groupMemberCache[$i.UserPrincipalName] -join ", " } else { "无所属组" } New-Object PSObject -Property @{ Displayname = $i.Displayname Userprincipalname = $i.userprincipalname UPN = ($i.userprincipalname -Split '@')[1] Licenses = $licenseString Groups = $userGroups } } }
额外注意事项
- 原脚本中
$licensear = Friendlyname是明显的笔误,记得补全将AccountSkuId转换为友好名称的逻辑,否则Licenses字段会为空。 - 如果租户的组成员规模极大,缓存阶段可能会有短暂的等待,但这是一次性开销,后续用户处理会非常顺畅。
- 若用户没有邮箱(比如某些服务账号),缓存时会跳过这类用户,避免无效条目。
内容的提问来源于stack exchange,提问作者Matthew
相关产品推荐
相关产品推荐

