Skip to content

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.

  • 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.
  • 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 CurrentUser
    • Install-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.

Save the script below as script.ps1 in your working directory, then run:

Terminal window
.\script.ps1 -DisplayName "vScope App Registration" -GenerateClientSecret -RbacScope "/subscriptions/<subscription-id>"
  • Omit -RbacScope if you will assign Reader manually in the portal.
  • Keep the printed ClientSecret safe; it is shown once.
Terminal window
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.AppId
Write-Host "App created. AppId: $($app.AppId)" -ForegroundColor Green
# --------------------------------------------------------
# Step 4: Optionally Create a Client Secret
# --------------------------------------------------------
$secretValue = $null
if ($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 Cyan
foreach ($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-List
  • You should see: AppId, ServicePrincipalId, and, when requested, a ClientSecret (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-AzAccount in that case.