Tuesday, April 24, 2018

How to run AzureAD PowerShell commandlets in Azure

I have a PowerShell script which today uses AzureAD commandlets to perform some write operations in Azure AD. This script is to be run on a schedule, and where better to run this than in Azure. It could be as a web job or as an Azure Function.

When running in an app service we cannot use interactive login, but have to use the connect signature below which takes an ADAL app id and a certificate:

Connect-AzureAD –TenantId <tenantId> –ApplicationId <appid> –CertificateThumbprint <thumbprint>

This means we have to create and ADAL app which accepts a certificate, as well as make sure we can access the certificate from the app service.

For this tutorial I’ll go with an Azure Function, but the steps are pretty much the same.

Pre-requisite

Install the AzureAD or AzureADPreview command lets on your local machine.

Steps covered

  • Create a self-signed certificate
  • Create an ADAL app
  • Grant the ADAL app access to write to AAD
  • Create an Azure Function
  • Load Azure AD PowerShell in an Azure Function
  • Connect to AzureAD using an ADAL app and a certificate

Create a self-signed certificate

You can create and export a certificate using the steps at https://docs.microsoft.com/en-us/powershell/azure/active-directory/signing-in-service-principal?view=azureadps-2.0. Make sure you open PowerShell as an admin account.

$pwd = "mikael"
$currentDate = Get-Date
$endDate = $currentDate.AddYears(10) #10 years is nice and long
$thumb = (New-SelfSignedCertificate -DnsName "techmikael.com" -CertStoreLocation "cert:\LocalMachine\My"  -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $endDate).Thumbprint
$pwd = ConvertTo-SecureString -String $pwd -Force -AsPlainText
Export-PfxCertificate -cert "cert:\localmachine\my\$thumb" -FilePath .\techmikael.pfx -Password $pwd
$path = (Get-Item -Path ".\").FullName
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("$path\techmikael.pfx", $pwd)
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())

Create ADAL application and test connection

Next up is creating the application registration and service principal which we will need when connection to Azure AD.

# Connect to Azure AD as an admin account
Connect-AzureAD

# Create Azure Active Directory Application (ADAL App)
$application = New-AzureADApplication -DisplayName "AzureADPosh" -IdentifierUris "https://techmikael.com/AzureADPosh"
New-AzureADApplicationKeyCredential -ObjectId $application.ObjectId -CustomKeyIdentifier "AzureADPosh" -Type AsymmetricX509Cert -Usage Verify -Value $keyValue -StartDate $currentDate -EndDate $endDate

# Create the Service Principal and connect it to the Application
$sp=New-AzureADServicePrincipal -AppId $application.AppId 

# Give the application read/write permissions to AAD
Add-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | where-object {$_.DisplayName -eq "Directory Writers"}).Objectid -RefObjectId $sp.ObjectId

# Test to login using the app
$tenant = Get-AzureADTenantDetail
$appId = $application.AppId
Connect-AzureAD -TenantId $tenant.ObjectId -ApplicationId  $Application.AppId -CertificateThumbprint $thumb

You should now be able to run any AzureAD command in the context of the service principal for the ADAL app you just created.

Make sure to copy out:

  • Tenant id
  • Application id
  • Thumbprint

as you will need this later in the Azure function.

Create and configure a Function App in Azure

Log in to the Azure Portal (portal.azure.com) and create a new Function App.

image

Next navigate to Application settings for the Function App and click SSL, in order to upload the self-signed certificate.

image

Point to the exported pfx file and use the password you selected.

image

Next navigate to Application settings where you should set the platform to 64bit, which works best for PowerShell, as well as add an application setting named WEBSITE_LOAD_CERTIFICATES which has the thumbprint of the certificate to ensure your certificate is available to the function.

image

By opening KUDU PowerShell for the Function App you can see the certificate being available.

image

Uploading the AzureAD module to the Azure Function

You might have seen tutorials where you create a folder named modules below the PowerShell function, where these modules will then be auto loaded for your use. This will not work as there are some warnings/errors which you want to ignore when loading the module. Instead upload it to a separate folder, and load it manually.

The easiest way to upload the module is to open Kudu, found on the Application settings page.

image

In Kudu navigate to D:\home\site and create a folder named PoshModules and navigate to inside the folder. Open a Windows Explorer window on your local machine and find your installation of AzureAD. On my machine they are located at C:\Program Files\WindowsPowerShell\Modules\AzureADPreview\2.0.1.2.

Then drag and drop all the files over to the PoshModules folder.

image

Create a function and test it

Create a new custom function of type PowerShell. You need to enable experimental support for PowerShell to be available.

image

Copy in this sample function where you replace appId, tenantId and thumb variables with your own.

$ProgressPreference = "SilentlyContinue"
$WarningPreference = "SilentlyContinue"
# Import AzureAD and suppress errors
Import-Module "d:\home\site\PoshModules\AzureADPreview.psd1" -ErrorAction SilentlyContinue

# POST method: $req
$requestBody = Get-Content $req -Raw | ConvertFrom-Json

$appId = "<appid>"
$thumb = "<thumb>"
$tenantId = "<tenantid>"
Connect-AzureAD -TenantId $tenantId -ApplicationId  $appId -CertificateThumbprint $thumb
$user = (Get-AzureADUser)[0]

Out-File -Encoding Ascii -FilePath $res -inputObject "User:$($user.DisplayName)"

image ..and that’s all there is to it :)

Summary

If you have scripts set up using for example Azure AD PowerShell commandlets, you can indeed move them to Azure, running using a service principal. There are some hoops to jump though, but it’s not impossible.