Private/PartnerActions/Set-SAMConsent.ps1
function Set-SAMConsent { [CmdletBinding()] param ( [Parameter(Mandatory)] [String] $CustomerTenantId, [Parameter()] [bool]$Retry ) # Get SAM tokens if not already available begin { if (!$SAMTokens) { $SAMTokens = Get-SAMTokens } } process { # Get the access token needed for subsequent requests $AccessToken = New-CustomPartnerAccessToken -Scopes "https://api.partnercenter.microsoft.com/user_impersonation" -TenantId $PartnerTenantId $AuthHeader = @{ Authorization = "Bearer $($AccessToken.access_token)" Accept = 'application/json' } try { # Get the relevant customer $Customers = (Invoke-RestMethod -Uri "https://api.partnercenter.microsoft.com/v1/customers?size=9999" -Headers $AuthHeader).items $Customer = $Customers | Where-Object { $_.companyProfile.tenantId -eq $CustomerTenantId } } catch { throw "Failed to find customer with ID $($CustomerTenantId): $_" } $ConsentBody = @{ ApplicationId = $($SAMTokens.ApplicationId) ApplicationGrants = @( @{ EnterpriseApplicationId = '00000003-0000-0000-c000-000000000000' Scope = @( 'DelegatedPermissionGrant.ReadWrite.All', 'Directory.ReadWrite.All', 'AppRoleAssignment.ReadWrite.All' ) -Join ',' } ) } | ConvertTo-Json $AppCreationResponse = Invoke-RestMethod -Uri "https://api.partnercenter.microsoft.com/v1/customers/$CustomerTenantId/applicationconsents" -Method POST -ContentType 'application/json' -Body $ConsentBody -Headers $AuthHeader -SkipHttpErrorCheck -StatusCodeVariable StatusCode switch($StatusCode) { {$_ -eq "200" -or $_ -eq "201"} { Write-Host "Successfully created consent for $($Customer.companyProfile.companyName)" -ForegroundColor Green Write-Host "Waiting 60 seconds for consent to propogate fully..." -foregroundcolor yellow Start-Sleep -Seconds 5 } 409 { Write-Host "Consent already exists for $($Customer.companyProfile.companyName)" -ForegroundColor Yellow if(!$Retry) { Write-Host "Trying to delete and recreate, in case customer has gotten new licenses (e.g. Teams, Exchange Online)..." -ForegroundColor Yellow $ConsentUri = "https://api.partnercenter.microsoft.com/v1/customers/$CustomerTenantId/applicationconsents/$($SAMTokens.ApplicationId)" Invoke-Restmethod -Uri $ConsentUri -Method DELETE -ContentType 'application/json' -Headers $AuthHeader -SkipHttpErrorCheck | Out-Null Set-SAMConsent -CustomerTenantId $CustomerTenantId -Retry:$true } } 400 { # This just means, that one of the applications we are trying to get consent for, does not exist in the tenant. # Microsoft still creates the consent for the applications that do exist, so we can ignore this error. if($AppCreationResponse.message -like "*doesnt exist in customer tenant*") { Write-Host "Successfully created consent for $($Customer.companyProfile.companyName)" -ForegroundColor Green Write-Host "Waiting 60 seconds for consent to propogate fully..." -foregroundcolor yellow Start-Sleep -Seconds 5 } else { throw "Failed to create consent for $($Customer.companyProfile.companyName): $($_)" } } default { throw "Failed to create consent for $($Customer.companyProfile.companyName): $AppCreationResponse" } } Disconnect-Mggraph -ErrorAction SilentlyContinue | Out-Null $Global:GraphToken = $null Connect-CustomerGraph -CustomerTenantId $CustomerTenantId -AsApp:$false # Now that our application has consent to create new delegated permissions and app role assignments, we can do this. $ServicePrincipalList = Get-MgServicePrincipal -All $ServicePrincipal = $ServicePrincipalList | Where-Object { $_.AppId -eq $SAMTokens.ApplicationId } $SPSearchCount = 1 while(!$ServicePrincipal -and $SPSearchCount -lt 20) { Write-Host "Service principal not found yet, waiting 10 seconds for it to be created... [$($SPSearchCount)/20]" -ForegroundColor Yellow Start-Sleep -Seconds 10 $ServicePrincipalList = Get-MgServicePrincipal -All $ServicePrincipal = $ServicePrincipalList | Where-Object { $_.AppId -eq $SAMTokens.ApplicationId } $SPSearchCount++ } if(!$ServicePrincipal) { throw "Failed to find service principal for our SAM APP: $($SAMTokens.ApplicationId), stopping here.." } $CurrentRoles = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ServicePrincipal.Id $CurrentDelegatedScopes = Get-MgServicePrincipalOauth2PermissionGrant -ServicePrincipalId $ServicePrincipal.Id $RequiredResourceAccess = (Get-Content "$PSScriptRoot\SAMManifest.json" | ConvertFrom-Json).requiredResourceAccess $Grants = foreach ($App in $RequiredResourceAccess) { $svcPrincipalId = $ServicePrincipalList | Where-Object -Property AppId -EQ $App.resourceAppId if (!$svcPrincipalId) { #Write-Host "Creating service principal for $($App.resourceAppId)" -ForegroundColor Yellow $svcPrincipalId = New-MgServicePrincipal -AppId $App.resourceAppId -ErrorAction SilentlyContinue } foreach ($SingleResource in $App.ResourceAccess | Where-Object -Property Type -EQ 'Role') { if ($SingleResource.id -In $CurrentRoles.appRoleId) { continue } [pscustomobject]@{ principalId = $($ServicePrincipal.id) resourceId = $($svcPrincipalId.id) appRoleId = "$($SingleResource.Id)" } } } $counter = 0 foreach ($Grant in $Grants) { try { #Write-Host "New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $($ServicePrincipal.id) -AppRoleId $($Grant.appRoleId) -PrincipalId $($Grant.principalId) -ResourceId $($Grant.resourceId)" -ForegroundColor Green if($Grant.resourceId -eq $null -or $Grant.principalId -eq $null) { #Write-Host "Skipping grant of $($Grant.appRoleId) to $($Grant.principalId) because the customer doesn't have licenses for this API." -ForegroundColor Yellow continue } Write-Host "Adding $($Grant.appRoleId) to $($Grant.resourceId)" -ForegroundColor Yellow $SettingsRequest = New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $ServicePrincipal.id -AppRoleId $Grant.appRoleId -PrincipalId $Grant.principalId -ResourceId $Grant.resourceId $counter++ } catch { Write-Host "Failed to grant $($Grant.appRoleId) to $($Grant.resourceId)" -ForegroundColor Yellow } } #Write-Host "Added $counter Application permissions to $($ServicePrincipal.displayName)" # Add delegated permissions $Translator = Get-Content "$PSScriptRoot\PermissionsTranslator.json" | ConvertFrom-Json foreach ($App in $RequiredResourceAccess) { $svcPrincipalId = $ServicePrincipalList | Where-Object -Property appId -EQ $App.resourceAppId if (!$svcPrincipalId) { try { $Body = @{ appId = $App.resourceAppId } | ConvertTo-Json -Compress #Write-Host "Attempting to create service principal for $($App.resourceAppId)" -ForegroundColor Yellow $svcPrincipalId = New-MgServicePrincipal -AppId $App.resourceAppId -ErrorAction SilentlyContinue } catch { Write-Host "Failed to create service principal for $($App.resourceAppId)" -ForegroundColor Yellow continue } } $DelegatedScopes = $App.resourceAccess | Where-Object -Property type -EQ 'Scope' if ($AdditionalScopes) { $NewScope = (@(($Translator | Where-Object { $_.id -in $DelegatedScopes.id }).value) -join ' ') } else { if ($NoTranslateRequired) { $NewScope = @($DelegatedScopes | ForEach-Object { $_.id } | Sort-Object -Unique) -join ' ' } else { $NewScope = @(($Translator | Where-Object { $_.id -in $DelegatedScopes.id }).value | Sort-Object -Unique) -join ' ' } } $OldScope = ($CurrentDelegatedScopes | Where-Object -Property Resourceid -EQ $svcPrincipalId.id) if(!$svcPrincipalId) { Write-Host "Skipping grant of $NewScope because the customer doesn't have licenses for this API." -ForegroundColor Yellow continue } if (!$OldScope) { #Write-Host "clientId: $($ServicePrincipal.id) resourceId: $($svcPrincipalId.id) scope: $NewScope" -ForegroundColor Yellow $CreateRequest = New-MgOauth2PermissionGrant -ClientId $ServicePrincipal.id -ResourceId $svcPrincipalId.id -Scope $NewScope -ConsentType 'AllPrincipals' -ErrorAction SilentlyContinue Write-Host "Added delegated permissions for $($svcPrincipalId.displayName)" -ForegroundColor Green } else { $compare = Compare-Object -ReferenceObject $OldScope.scope.Split(' ') -DifferenceObject $NewScope.Split(' ') if (!$compare) { Write-Host "All delegated permissions exist for $($svcPrincipalId.displayName)" -ForegroundColor Green continue } $null = Update-MgOauth2PermissionGrant -OAuth2PermissionGrantId $OldScope.id -Scope $NewScope -ErrorAction SilentlyContinue # Added permissions #$Added = ($Compare | Where-Object { $_.SideIndicator -eq '=>' }).InputObject -join ' ' #$Removed = ($Compare | Where-Object { $_.SideIndicator -eq '<=' }).InputObject -join ' ' Write-Host "Successfully updated permissions for $($svcPrincipalId.displayName)" -ForegroundColor Green #Write-Host "Added: $Added" -ForegroundColor Green #Write-Host "Removed: $Removed" -ForegroundColor Yellow } } } } |