Automate Azure setup with PowerShell (how-to)
Prefer code over portal clicks? This how-to lets you build the Azure RM integration in no time.
Result: vScope app registration with Microsoft Graph + Defender for Endpoint application permissions, admin consent granted, and (optionally) Azure RBAC Reader on your chosen scope.
What the script does
Section titled “What the script does”- Creates an app registration + service principal for vScope.
- Grants required Microsoft Graph and Defender for Endpoint application permissions.
- Grants admin consent.
- Optionally assigns Azure RBAC Reader at a scope you provide.
Requirements (and what you change)
Section titled “Requirements (and what you change)”- PowerShell 7+
- Role: Global Admin, Privileged Role Admin, or Cloud App Admin (plus rights to assign RBAC if using
-RbacScope). - Modules:
Install-Module Microsoft.Graph -Scope CurrentUserInstall-Module Az.Accounts,Az.Resources -Scope CurrentUser(only when using-RbacScope)
- The script creates a tenant-wide app registration + service principal, grants admin consent to the listed Graph and Defender application permissions, and (optionally) assigns Azure RBAC at the scope you pass.
Quick start
Section titled “Quick start”Save the script below as script.ps1 in your working directory, then run:
.\script.ps1 -DisplayName "vScope App Registration" -GenerateClientSecret -RbacScope "/subscriptions/<subscription-id>"- Omit
-RbacScopeif you will assign Reader manually in the portal. - Keep the printed ClientSecret safe; it is shown once.
Script
Section titled “Script”param( [Parameter(Mandatory=$true)] [string]$DisplayName,
[switch]$GenerateClientSecret,
[string]$RbacScope = $null,
[string]$AzRoleDefinitionName = "Reader")
# --------------------------------------------------------# Step 1: Define Required Permission Sets# --------------------------------------------------------
$GraphAppPermissions = @( "AuditLog.Read.All", "DeviceManagementConfiguration.Read.All", "DeviceManagementManagedDevices.Read.All", "Directory.Read.All", "Group.Read.All", "Reports.Read.All", "Sites.Read.All", "Policy.Read.All", "Team.ReadBasic.All", "DeviceManagementApps.Read.All")
$DefenderAppPermissions = @( "AdvancedQuery.Read.All", "Machine.Read.All")
# --------------------------------------------------------# Step 2: Connect to Microsoft Graph# --------------------------------------------------------
Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Cyan$scopes = @( "Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All")Connect-MgGraph -Scopes $scopes | Out-Null
# --------------------------------------------------------# Step 3: Create the Application and Service Principal# --------------------------------------------------------
Write-Host "Creating application '$DisplayName'..." -ForegroundColor Cyan$app = New-MgApplication -DisplayName $DisplayName$sp = New-MgServicePrincipal -AppId $app.AppIdWrite-Host "App created. AppId: $($app.AppId)" -ForegroundColor Green
# --------------------------------------------------------# Step 4: Optionally Create a Client Secret# --------------------------------------------------------
$secretValue = $nullif ($GenerateClientSecret.IsPresent) { Write-Host "Creating client secret (shown once)..." -ForegroundColor Yellow $pwd = Add-MgApplicationPassword -ApplicationId $app.Id -PasswordCredential @{ displayName = "ApplicationSecret" } $secretValue = $pwd.SecretText}
# --------------------------------------------------------# Step 5: Resolve Resource Service Principals# --------------------------------------------------------
function Get-ResourceSp { param([string]$WellKnownAppId, [string]$FallbackDisplayName) $spn = $null if ($WellKnownAppId) { $spn = Get-MgServicePrincipal -Filter "appId eq '$WellKnownAppId'" } if (-not $spn -and $FallbackDisplayName) { $spn = Get-MgServicePrincipal -Filter "displayName eq '$FallbackDisplayName'" } return $spn}
$graphSp = Get-ResourceSp -WellKnownAppId "00000003-0000-0000-c000-000000000000" -FallbackDisplayName "Microsoft Graph"if (-not $graphSp) { throw "Could not find Microsoft Graph service principal in this tenant." }
$defenderSp = Get-ResourceSp -WellKnownAppId $null -FallbackDisplayName "WindowsDefenderATP"if (-not $defenderSp) { Write-Warning "WindowsDefenderATP service principal not found. The Defender permissions step will be skipped."; $DefenderAppPermissions = @() }
# --------------------------------------------------------# Step 6: Grant Application Permissions# --------------------------------------------------------
function Grant-AppRole { param( [Microsoft.Graph.PowerShell.Models.MicrosoftGraphServicePrincipal]$ResourceSp, [string]$RoleValue ) $role = $ResourceSp.AppRoles | Where-Object { $_.Value -eq $RoleValue -and $_.AllowedMemberTypes -contains "Application" -and $_.IsEnabled } if (-not $role) { throw "App role '$RoleValue' not found on resource '$($ResourceSp.DisplayName)'." } New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $sp.Id -BodyParameter @{ principalId = $sp.Id resourceId = $ResourceSp.Id appRoleId = $role.Id } | Out-Null Write-Host "Granted application permission '$RoleValue' on '$($ResourceSp.DisplayName)'." -ForegroundColor Green}
Write-Host "Granting Microsoft Graph application permissions..." -ForegroundColor Cyanforeach ($perm in $GraphAppPermissions) { Grant-AppRole -ResourceSp $graphSp -RoleValue $perm }
if ($DefenderAppPermissions.Count -gt 0) { Write-Host "Granting Defender for Endpoint application permissions..." -ForegroundColor Cyan foreach ($perm in $DefenderAppPermissions) { Grant-AppRole -ResourceSp $defenderSp -RoleValue $perm }}
# --------------------------------------------------------# Step 7: Optional Azure RBAC Assignment# --------------------------------------------------------
if ($RbacScope) { Write-Host "Assigning Azure RBAC role '$AzRoleDefinitionName' at scope $RbacScope ..." -ForegroundColor Cyan try { try { Get-AzContext | Out-Null } catch { Connect-AzAccount | Out-Null } New-AzRoleAssignment -ObjectId $sp.Id -RoleDefinitionName $AzRoleDefinitionName -Scope $RbacScope | Out-Null Write-Host "Azure RBAC role assigned." -ForegroundColor Green } catch { Write-Warning "Failed to assign Azure RBAC role. Assign later in Portal > Access control (IAM). Error: $($_.Exception.Message)" }}
# --------------------------------------------------------# Step 8: Output Configuration Summary# --------------------------------------------------------
$summary = [pscustomobject]@{ TenantId = (Get-MgContext).TenantId ApplicationName = $app.DisplayName ApplicationId = $app.AppId ServicePrincipalId = $sp.Id ClientSecret = $secretValue NextSteps = "Use TenantId, ApplicationId (ClientId) and ClientSecret (or cert) in vScope's Azure RM credential."}$summary | Format-ListAfter running
Section titled “After running”- You should see:
AppId,ServicePrincipalId, and, when requested, aClientSecret(shown once). Keep the secret secure. - Verify creation:
Get-MgServicePrincipal -AppId <AppId> - Verify optional RBAC:
Get-AzRoleAssignment -ObjectId <ServicePrincipalId> -Scope <scope> - Copy ApplicationId (ClientId) and ClientSecret into the Azure RM credential in vScope, then run Test Credential.
- If you skipped
-RbacScope, assign Reader manually in the portal and retest. - Common issue: missing Graph consent scopes or not being logged into the right Azure context will block RBAC; re-run
Connect-AzAccountin that case.