Skip to content

Instantly share code, notes, and snippets.

@tyconsulting
Created October 15, 2017 06:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tyconsulting/ec73a46113f53c2ad3b59ccaaa7502ce to your computer and use it in GitHub Desktop.
Save tyconsulting/ec73a46113f53c2ad3b59ccaaa7502ce to your computer and use it in GitHub Desktop.
Create a key-based Azure AD Service Principal
#Requires -Version 5.0
#Requires -Modules AzureRM.Resources, AzureRM.Profile
<#
============================================================================
AUTHOR: Tao Yang
DATE: 09/10/2017
Version: 1.0
Comment: Create Azure AD Application and key phrase based Service Principal
============================================================================
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true)][PSCredential]$AzureCredential,
[Parameter(Mandatory = $true)]
[ValidateScript({
try {
[System.Guid]::Parse($_) | Out-Null
$true
} catch {
$false
}
})]
[String]$SubscriptionId,
[Parameter(Mandatory = $false)][ValidateNotNullOrEmpty()][String]$AADAppName = 'Automation_' + $([GUID]::NewGuid().Tostring()) -replace('-', ''),
[Parameter(Mandatory = $false)][ValidateNotNullOrEmpty()][string]$Role = 'Contributor',
[Parameter(Mandatory = $false)][int]$PasswordLength = 44
)
#region functions
Function New-Password
{
param(
[UInt32][ValidateScript({$_ -ge 8 -and $_ -le 128})] $Length=10,
[Switch] $LowerCase=$TRUE,
[Switch] $UpperCase=$FALSE,
[Switch] $Numbers=$FALSE,
[Switch] $Symbols=$FALSE
)
if (-not ($LowerCase -or $UpperCase -or $Numbers -or $Symbols)) {
throw "You must specify one of: -LowerCase -UpperCase -Numbers -Symbols"
return $null
}
# Specifies bitmap values for character sets selected.
$CHARSET_LOWER = 1
$CHARSET_UPPER = 2
$CHARSET_NUMBER = 4
$CHARSET_SYMBOL = 8
# Creates character arrays for the different character classes,
# based on ASCII character values.
$charsLower = 97..122 | foreach-object { [Char] $_ }
$charsUpper = 65..90 | foreach-object { [Char] $_ }
$charsNumber = 48..57 | foreach-object { [Char] $_ }
$charsSymbol = 35,36,42,43,44,45,46,47,58,59,61,63,64,
91,92,93,95,123,125,126 | foreach-object { [Char] $_ }
# Contains the array of characters to use.
$charList = @()
# Contains bitmap of the character sets selected.
$charSets = 0
if ($LowerCase) {
$charList += $charsLower
$charSets = $charSets -bor $CHARSET_LOWER
}
if ($UpperCase) {
$charList += $charsUpper
$charSets = $charSets -bor $CHARSET_UPPER
}
if ($Numbers) {
$charList += $charsNumber
$charSets = $charSets -bor $CHARSET_NUMBER
}
if ($Symbols) {
$charList += $charsSymbol
$charSets = $charSets -bor $CHARSET_SYMBOL
}
# Returns True if the string contains at least one character
# from the array, or False otherwise.
# Loops until the string contains at least
# one character from each character class.
do {
# No character classes matched yet.
$flags = 0
$output = ""
# Create output string containing random characters.
1..$Length | foreach-object {
$output += $charList[(get-random -maximum $charList.Length)]
}
# Check if character classes match.
if ($LowerCase) {
foreach ($char in $output.ToCharArray()) {If ($charsLower -contains $char) {$flags = $flags -bor $CHARSET_LOWER; break }}
}
if ($UpperCase) {
foreach ($char in $output.ToCharArray()) {If ($charsUpper -contains $char) {$flags = $flags -bor $CHARSET_UPPER; break }}
}
if ($Numbers) {
foreach ($char in $output.ToCharArray()) {If ($charsNumber -contains $char) {$flags = $flags -bor $CHARSET_NUMBER; break }}
}
if ($Symbols) {
foreach ($char in $output.ToCharArray()) {If ($charsSymbol -contains $char) {$flags = $flags -bor $CHARSET_SYMBOL; break }}
}
}
until ($flags -eq $charSets)
# Output the string.
$output
}
#endregion
#Login to Azure
$null = Add-AzureRmAccount -Credential $AzureCredential -SubscriptionId $SubscriptionId
$Context = Get-AzureRmContext
$CurrentAccount = $Context.Account.Id
$TenantDomainName = $Context.Tenant.Directory
$TenantId = $Context.Tenant.Id
#Validating role
Write-Output '', "Validating AAD role '$Role'..."
If (Get-AzureRMRoleDefinition $Role)
{
Write-Output " - AAD role '$Role' validated."
} else {
Write-Error "Azure AD role '$Role' not found. Unable to continue."
Exit -1
}
#Create AAD App and service principal
$ApplicationPassword = New-Password -Length $PasswordLength -LowerCase -UpperCase -Numbers
Write-output '', 'Creating Azure AD application...'
Write-Output " - Azure AD Application name: '$AADAppName'"
$Application = New-AzureRmADApplication -DisplayName $AADAppName -HomePage ("http://$TenantDomainName/$AADAppName") -IdentifierUris ("http://$TenantDomainName/$AADAppName") -Password $ApplicationPassword
Write-Output '', 'Creating Azure AD Application Service Principal.'
$ApplicationServicePrincipal = New-AzureRmADServicePrincipal -ApplicationId $Application.ApplicationId
Write-output " - Assigning the '$Role' role to the application Service Principal. Please wait..."
$NewRole = $null
$Retries = 0
While ($NewRole -eq $null -and $Retries -le 5)
{
# Sleep here for a few seconds to allow the service principal application to become active (should only take a couple of seconds normally)
Start-Sleep -Seconds 10
$RoleAssignment = New-AzureRmRoleAssignment -RoleDefinitionName $Role -ServicePrincipalName $Application.ApplicationId -ErrorAction SilentlyContinue
Start-Sleep -Seconds 10
$NewRole = Get-AzureRmRoleAssignment -ServicePrincipalName $Application.ApplicationId -ErrorAction SilentlyContinue
$Retries++
}
Write-Output '', "The Azure AD Application and service principal is created:"
Write-Output " - Azure AD Tenant Domain: '$TenantDomainName'"
Write-Output " - Azure AD Tenant Id: '$TenantId'"
Write-Output " - Application name: '$AADAppName'"
Write-Output " - Application Id: '$($Application.ApplicationId)'"
Write-Output " - Application password: '$ApplicationPassword'"
Write-Output " - Azure Subscription Id: '$SubscriptionId'"
Write-Output " - Azure AD Role: '$Role'"
Write-Output '', "Done!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment