使用MS Graph为SharePoint站点添加权限:Postman成功PowerShell报错
问题背景
已通过Graph Explorer和Postman,使用拥有Sites.FullControl.All权限的用户成功为SharePoint站点分配权限,但使用PowerShell基于client_credentials模式调用MS Graph API时,返回400 Bad Request错误,要求使用纯REST API完成操作(未安装Graph SDK)。
核心错误原因
PowerShell中直接将哈希表作为请求Body传递给Invoke-RestMethod时,即使设置了Content-Type: application/json,哈希表仍会默认被序列化为application/x-www-form-urlencoded格式,导致Graph API无法解析请求体,触发400错误。
解决步骤
- 序列化请求体为JSON格式:使用
ConvertTo-Json将权限配置的哈希表转换为JSON字符串,并通过-Depth参数确保嵌套结构被完整序列化(默认Depth为2,需覆盖为3以适配嵌套的身份对象结构)。 - 验证应用权限配置:确认用于client_credentials认证的Azure AD应用已被授予
Sites.FullControl.All的应用权限(非委派权限),且已完成管理员同意。 - 检查参数完整性:确保
ClientId、ClientSecret、TenantId、SiteId以及应用ID、显示名称等参数均已正确填写,无空值。
修改后的完整代码
# Define parameters $ClientId = "" $ClientSecret = "" $TenantId = "" $SiteId = "" $Scope = "https://graph.microsoft.com/.default" $TokenEndpoint = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" # Create body for token request $tokenBody = @{ grant_type = "client_credentials" client_id = $ClientId client_secret = $ClientSecret scope = $Scope } # Get access token $tokenResponse = Invoke-RestMethod -Uri $TokenEndpoint -Method POST -Body $tokenBody # Define permissions request URL $permissionsUrl = "https://graph.microsoft.com/v1.0/sites/$siteId/permissions" # Define permissions request body as hashtable $permissionsBody = @{ roles = @("write") grantedToIdentities = @( @{ application = @{ id = "" displayName = "" } } ) } # Convert hashtable to JSON with sufficient depth $jsonBody = $permissionsBody | ConvertTo-Json -Depth 3 # Define request headers $headers = @{ "Content-Type" = "application/json" "Authorization" = "Bearer $($tokenResponse.access_token)" } # Send permissions assignment request $response = Invoke-RestMethod -Uri $permissionsUrl -Method Post -Headers $headers -Body $jsonBody
额外验证建议
如果仍报错,可添加-Verbose参数到Invoke-RestMethod查看详细请求信息,或使用Invoke-WebRequest替代并检查具体错误响应内容:
try { $response = Invoke-RestMethod -Uri $permissionsUrl -Method Post -Headers $headers -Body $jsonBody } catch { $errorResponse = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($errorResponse) $reader.BaseStream.Position = 0 $reader.DiscardBufferedData() $responseBody = $reader.ReadToEnd() Write-Host "Error Response: $responseBody" }
内容的提问来源于stack exchange,提问作者Alex You
相关产品推荐
相关产品推荐

