Skip to content

Instantly share code, notes, and snippets.

@hbulens
Last active May 10, 2021 17:59
Show Gist options
  • Save hbulens/ba4a5812af7ff8fd1d8fa88ff2346691 to your computer and use it in GitHub Desktop.
Save hbulens/ba4a5812af7ff8fd1d8fa88ff2346691 to your computer and use it in GitHub Desktop.
Create an Azure AD App with application permissions using PowerShell. Courtesy of https://stackoverflow.com/a/61458391/1842261
param (
[Parameter(mandatory = $false, HelpMessage = "The name of the Azure AD App.")]
[string] $appName = "dime-scheduler",
[Parameter(mandatory = $true, HelpMessage = "The id of the Azure tenant ")]
[string] $tenantId,
[Parameter(mandatory = $true, HelpMessage = "The name of the Azure tenant ")]
[string] $tenantName,
[Parameter(mandatory = $false, HelpMessage = "The permission set")]
[string[]] $applicationPermissions = @('Calendars.ReadWrite', 'MailBoxSettings.ReadWrite', 'User.Read.All')
)
If (-not(Get-InstalledModule AzureAD -ErrorAction SilentlyContinue)) {
Install-Module AzureAD -Confirm:$False -Force -AllowClobber
}
Import-Module AzureAD
$global:appId = $null;
$global:clientSecretKey = $null;
Function CreateAzureAdApp {
param (
[string] $displayName,
[string] $tenantName
)
$app = Get-AzureADApplication -SearchString $displayName
if (!$app) {
Write-Host "Azure AD App '$displayName' does not exist yet. Creating..."
$app = New-AzureADApplication -DisplayName $displayName `
-Homepage "https://localhost" `
-ReplyUrls "https://localhost" `
-IdentifierUris ('https://{0}/{1}' -f $tenantName, $displayName)
# Create SPN for App Registration
Write-Host "Creating SPN for app registration '$displayName'"
# Create a password (spn key)
$clientSecret = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId -CustomKeyIdentifier "Dime.Scheduler" -EndDate (get-date).AddYears(20)
$global:clientSecretKey = $clientSecret.Value
# Create a service principal for the app
# This is necessary to be able to grant the application the required permissions
$spForApp = New-AzureADServicePrincipal -AppId $app.AppId -PasswordCredentials @($clientSecret)
}
else {
Write-Host "Azure AD App '$displayName' already exists. No action needed."
$date = Get-Date -Format "yyyyMMdd"
$customIdentifier = "Dime.Scheduler-$date"
$clientSecret = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId -CustomKeyIdentifier $customIdentifier -EndDate (get-date).AddYears(20)
$global:clientSecretKey = $clientSecret.Value
}
$global:appId = $app.AppId
return $app
}
Function GrantApplicationPermissions {
param
(
[string] $targetServicePrincipalName,
$appPermissionsRequired,
$childApp,
$spForApp
)
$targetSp = Get-AzureADServicePrincipal -Filter "DisplayName eq '$($targetServicePrincipalName)'"
# Iterate Permissions array
Write-Host "Retrieving role assignments objects"
$roleAssignments = @()
Foreach ($appPermission in $appPermissionsRequired) {
$roleAssignment = $targetSp.AppRoles | Where-Object { $_.Value -eq $appPermission }
$roleAssignments += $roleAssignment
}
$resourceAccessObjects = New-Object 'System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess]'
foreach ($roleAssignment in $roleAssignments) {
$resourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess"
$resourceAccess.Id = $roleAssignment.Id
$resourceAccess.Type = 'Role'
$resourceAccessObjects.Add($resourceAccess)
}
$requiredResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$requiredResourceAccess.ResourceAppId = $targetSp.AppId
$requiredResourceAccess.ResourceAccess = $resourceAccessObjects
# Set the required resource access
Set-AzureADApplication -ObjectId $childApp.ObjectId -RequiredResourceAccess $requiredResourceAccess
Start-Sleep -s 1
# Grant the required resource access
foreach ($roleAssignment in $roleAssignments) {
$roleAssignmentValue = $roleAssignment.Value
Write-Host "Granting admin consent for App Role: $roleAssignmentValue"
try {
New-AzureADServiceAppRoleAssignment -ObjectId $spForApp.ObjectId -Id $roleAssignment.Id -PrincipalId $spForApp.ObjectId -ResourceId $targetSp.ObjectId
Start-Sleep -s 1
}
catch {
if ( $_.Exception.Message -like '*Permission being assigned already exists on the object*') {
Write-Host "Permission $roleAssignmentValue already exists"
}
else {
Write-Error $_.Exception.Message
}
}
}
}
Write-Output ""
Write-Output ""
Write-Output "*"
Write-Output "**"
Write-Output "***"
Write-Output "****"
Write-Output "*****"
Write-Output "******"
Write-Output "*******"
Write-Output "********"
Write-Output "*********"
Write-Output "**********"
Write-Output "***********"
Write-Output "************"
Write-Output ""
Write-Output "_____ _ _____ _ _ _"
Write-Output "| __ \(_) / ____| | | | | | |"
Write-Output "| | | |_ _ __ ___ ___ | (___ ___| |__ ___ __| |_ _| | ___ _ __"
Write-Output "| | | | | '_ ` _ \ / _ \ \___ \ / __| '_ \ / _ \/ _` | | | | |/ _ \ '__|"
Write-Output "| |__| | | | | | | | __/_ ____) | (__| | | | __/ (_| | |_| | | __/ |"
Write-Output "|_____/|_|_| |_| |_|\___(_)_____/ \___|_| |_|\___|\__,_|\__,_|_|\___|_|"
Write-Output ""
Write-Output ""
Write-Output ""
Write-Output "************"
Write-Output "***********"
Write-Output "**********"
Write-Output "*********"
Write-Output "********"
Write-Output "*******"
Write-Output "******"
Write-Output "*****"
Write-Output "****"
Write-Output "***"
Write-Output "**"
Write-Output "*"
Write-Output ""
Write-Output ""
# Connect
Connect-AzureAD -TenantId $tenantId
# Create Azure AD App
$app = CreateAzureAdApp -displayName $appName -tenantName $tenantName
# Add application permissions
$spForApp = Get-AzureADServicePrincipal -Filter ("appId eq '{0}'" -f $app.AppId)
GrantApplicationPermissions `
-targetServicePrincipalName 'Microsoft Graph' `
-appPermissionsRequired $applicationPermissions `
-childApp $app `
-spForApp $spForApp
Write-Host ""
Write-Host ""
Write-Host "******************"
Write-Host "Copy the application id to complete the installation of Dime.Scheduler"
Write-Host $global:appId
Write-Host "******************"
Write-Host "Copy the client secret to complete the installation of Dime.Scheduler"
Write-Host "WARNING: once you close this window, you won't be able to recover the client secret."
Write-Host $global:clientSecretKey
Write-Host "******************"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment