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 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." } $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 "******************"