如何在ForEach循环中向PowerShell对象属性追加成员而非覆盖?
解决Azure PowerShell中合并多cmdlet输出并追加属性值的问题
我明白你现在的困扰:在循环里给对象添加同名属性时,要么报错要么被覆盖,而你想要的是把所有相关的角色名收集到同一个属性里。下面分两部分给你优化方案:
一、简化RBAC角色的对象构建
首先看你最初的RBAC角色代码,其实可以更简洁高效。因为Get-AzRoleAssignment返回的是一个结果集合,直接提取roleDefinitionName和scope会自动得到数组,不需要逐个调用Add-Member:
$rbacroles = Get-AzRoleAssignment -ObjectId $user.id $obj = [PSCustomObject]@{ AzureRoles = $rbacroles.roleDefinitionName Scope = $rbacroles.scope }
用[PSCustomObject]创建对象比New-Object加Add-Member更直观,而且直接就能把多个角色的名称和作用域以数组形式存入对应属性。
二、实现AAD角色的追加(而非覆盖)
你遇到的核心问题是循环中重复添加同名属性会覆盖内容,解决思路是先收集所有角色名到数组,再一次性添加到对象,或者动态往已存在的属性数组里追加元素:
方案1:先收集所有AAD角色名,再赋值给对象
这种方式最稳妥,避免循环中操作对象属性的覆盖问题:
# 初始化空数组用于存储AAD角色名 $aadRoleNames = @() foreach ($aadrole in $aadroles) { $id = $aadrole.roleDefinitionId $uri = "https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions/$id" $roledef = Invoke-RestMethod -Headers $Headers -Uri $uri # 将当前角色名追加到数组 $aadRoleNames += $roledef.displayName } # 一次性将数组添加到对象 $obj | Add-Member -MemberType NoteProperty -Name AzureADRoles -Value $aadRoleNames
方案2:循环中动态追加到已存在的属性
如果需要在循环中逐步添加(比如场景更复杂的情况),可以先判断属性是否存在,不存在就创建数组,存在则往数组里加元素:
foreach ($aadrole in $aadroles) { $id = $aadrole.roleDefinitionId $uri = "https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions/$id" $roledef = Invoke-RestMethod -Headers $Headers -Uri $uri # 检查对象是否已有AzureADRoles属性 if (-not $obj.PSObject.Properties['AzureADRoles']) { # 不存在则创建数组属性 $obj | Add-Member -MemberType NoteProperty -Name AzureADRoles -Value @($roledef.displayName) } else { # 存在则追加元素到数组 $obj.AzureADRoles += $roledef.displayName } }
这里用PSObject.Properties检查属性是否存在,避免直接访问不存在的属性报错,同时用@()确保初始值是数组,防止后续追加变成字符串拼接。
额外优化建议
- 调用Graph API时,推荐使用
Microsoft.Graph模块的cmdlet(比如Get-MgRoleManagementDirectoryRoleDefinition)代替直接Invoke-RestMethod,更符合PowerShell的使用习惯,还能自动处理认证和API版本问题。 - 如果
$aadroles是Get-AzADRoleAssignment的结果,可以直接提取RoleDefinitionId集合,用批量请求或管道处理来提升执行效率。
内容的提问来源于stack exchange,提问作者Ryvik
相关产品推荐
相关产品推荐

