/New-AADServicePrincipal.ps1 Secret
Created
September 7, 2019 10:52
Star
You must be signed in to star a gist
Create Azure AD service principals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Modules 'AzureAD' | |
#Requires -RunAsAdministrator | |
<# | |
============================================ | |
AUTHOR: Tao Yang | |
DATE: 01/03/2019 | |
Version: 1.0 | |
Comment: Create Azure AD service principals | |
============================================ | |
#> | |
<# | |
.SYNOPSIS | |
New Azure AD Application for an Automation Account | |
.DESCRIPTION | |
Creates an Azure AD Application as well as a Service Principal | |
.PARAMETER AADAppName | |
A string containing the name of the Application that will be registerd in Azure AD e.g. my-aad-app | |
.PARAMETER KeyType | |
Service Principal key type. Possible values are: 'cert', 'secret' and 'both'. Default value is 'key' | |
.EXAMPLE | |
.\New-AADServicePrinciple.ps1 -AADAppName my-aad-app | |
#> | |
[CmdLetBinding()] | |
Param ( | |
[Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$AADAppName, | |
[Parameter(Mandatory = $false)][ValidateSet('secret','cert', 'both')][String]$KeyType='key' | |
) | |
#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 | |
} | |
Function Process-AzureADSignOn | |
{ | |
Write-output '', "Sign in to Azure AD with your Global Administrator account." | |
$script:AADConnection = Connect-AzureAD | |
} | |
#endregion | |
#region Sign-in to Azure AD | |
Try { | |
$CurrentAADSession = Get-AzureADCurrentSessionInfo -ErrorAction SilentlyContinue | |
$TenantId = $CurrentAADSession.Tenant.Id.Tostring() | |
Write-output "You are currently signed to to tenant '$($CurrentAADSession.tenant.Domain)' using account '$($CurrentAADSession.Account.Id).'" | |
Write-Output '', "Press any key to continue using current sign-in session or Esc to login using another user account." | |
$KeyPress = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | |
If ($KeyPress.virtualKeyCode -eq 27) | |
{ | |
Process-AzureADSignOn | |
$TenantId = $Script:AADConnection.TenantId.Tostring() | |
} | |
} Catch { | |
Process-AzureADSignOn | |
$TenantId = $Script:AADConnection.TenantId.Tostring() | |
} | |
#endregion | |
#region common variables | |
$AADAppCertValidMonth = 12 | |
#endregion | |
# region main code | |
Write-Verbose "Checking for pre-existing Azure AD application" | |
$testApp = Get-AzureADApplication -SearchString $AADAppName -ErrorAction SilentlyContinue | |
if (!$testApp) | |
{ | |
$Guid = [GUID]::NewGuid().Tostring() | |
$ApplicationName = "$($AADAppName)_$($Guid)" | |
try | |
{ | |
# Create Azure AD application | |
Write-Output '', "Creating Azure AD Application" | |
$AADApp = new-AzureADApplication -DisplayName $ApplicationName -Homepage "Http://$AADAppName" -IdentifierUris "Http://$AADAppName" | |
# Create Azure AD Service Principal | |
Write-Output '', "Creating Azure AD Service Principal" | |
$sp = New-AzureADServicePrincipal -AppId $AADApp.AppId -DisplayName $ApplicationName | |
$StartDate = ([Datetime]::Now).AddHours(-25) | |
$EndDate = $StartDate.AddMonths($AADAppCertValidMonth) | |
$SPKeyEndDate = $EndDate.AddDays(-1) | |
If ($KeyType -ieq 'cert' -or $KeyType -ieq 'both') | |
{ | |
Write-Output '', 'Creating certificate based key for the Service Principal' | |
$CertPath = Join-Path -Path $env:TEMP -ChildPath ($ApplicationName + '.pfx') | |
$Cert = New-SelfSignedCertificate -DnsName $ApplicationName -CertStoreLocation cert:\LocalMachine\My -KeyExportPolicy Exportable -Provider 'Microsoft Enhanced RSA and AES Cryptographic Provider' -NotAfter $EndDate -NotBefore $StartDate | |
$CertThumbprint = $Cert.Thumbprint | |
$CertPlainPassword = New-Password -Length 12 -LowerCase -UpperCase -Numbers -Symbols | |
$CertPassword = ConvertTo-SecureString -String $CertPlainPassword -AsPlainText -Force | |
Export-PfxCertificate -Cert ('Cert:\localmachine\my\' + $CertThumbprint) -FilePath $CertPath -Password $CertPassword -Force | out-null | |
#Creating AAD application key credential | |
Write-Output " - Self signed certificated created. It is temporarily located at '$CertPath'." | |
$PFXCert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList @($CertPath, $CertPlainPassword) | |
$KeyValue = [System.Convert]::ToBase64String($PFXCert.GetRawCertData()) | |
$SpKeyCred = New-AzureADApplicationKeyCredential -ObjectId $AADApp.ObjectId -Type AsymmetricX509Cert -Usage Verify -Value $KeyValue -StartDate $cert.GetEffectiveDateString() -EndDate $SPKeyEndDate | |
$DeleteCert = Remove-Item (Join-Path Cert:\LocalMachine\My $CertThumbprint) -Force | |
} | |
if ($KeyType -ieq 'secret' -or $KeyType -ieq 'both') { | |
Write-Output '', 'Creating secret based key for the Service Principal' | |
$AppPassword = New-Password -Length 44 -LowerCase -UpperCase -Numbers -Symbols | |
$SPPasswordCred = New-AzureADApplicationPasswordCredential -ObjectId $AADApp.objectId -StartDate $StartDate -EndDate $SPKeyEndDate -Value $AppPassword | |
} | |
} catch { | |
throw $_.exception | |
} | |
} else | |
{ | |
Write-output "" | |
Write-Error "ApplicationID '$($testApp.DisplayName)' already exists. No need to create it again." | |
Exit | |
} | |
if ($Application.ApplicationId.guid) | |
{ | |
$ApplicationId = $Application.ApplicationId.guid | |
} else | |
{ | |
$ApplicationId = $Application.ApplicationId | |
} | |
# Outputs | |
Write-Output '', "The Azure AD Application and Service Principal has been created:" | |
Write-Output " - Azure AD Tenant Id: '$($TenantId)'" | |
Write-Output " - Application name: '$($AADApp.DisplayName)'" | |
Write-Output " - Application Id: '$($AADApp.AppId)'" | |
If ($KeyType -ieq 'cert' -or $KeyType -ieq 'both') | |
{ | |
Write-output " - Cert File: $CertPath" | |
Write-output " - Cert Thumbprint: $CertThumbprint" | |
Write-output " - Cert Password: $CertPlainPassword" | |
} | |
if ($KeyType -ieq 'secret' -or $KeyType -ieq 'both') { | |
Write-Output " - Client Secret: $AppPassword" | |
} | |
Write-output " - Credential Start date: $($StartDate.tostring())" | |
Write-output " - Credential Expiry date: $($SPKeyEndDate.tostring())" | |
Write-Output '', "Done!" | |
# endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment