Office Apps and Services MVP,
Enterprise Architect ๐ŸŸก๐ŸŸก๐ŸŸก
thoughts on Architecture, Automation, Development and Technical Leadership
M365 Azure SPfx PowerShell DevOps keep it simple. keep it honest. keep it real.

๐Ÿ” Managed Identity rocks with PnP.PowerShell !


Managed identities provide an identity for applications to use when connecting to resources that support Azure AD authentication.

We can have 2 types of managed identities :

System-assigned User-assigned
Identity created in Azure AD and tied to the lifecycle of that service instance. If the resource is deleted, Azure automatically deletes that identity Identity created as a standalone Azure resource and assign it to one or more instances of an Azure service. The identity is managed separately from the resources that use it.

Why the heck should i care?

With managed identities, applications can get Azure AD tokens without having to manage any type of credentials, meaning that we don’t need to worry about secrets, credentials, certificates, and keys.
The platform will take care of it for you. Kind of neat, no ? ๐Ÿค 

At the time of writing this article, in this document, Microsoft state all available services that can use managed identities to access other services but there’s no documentation on M365 PowerShell modules usage with Managed Identities.

How does it work?

Whenever we have a Managed Identity enabled on a Azure Service there is an internal endpoint service , which provides the needed access token. Than, we can use the token to access other services.

How to use it?

When it comes to a service principal, we can grant API permissions to the service principal object directly in the Azure portal but, unfortunately, we do not have the same option for the Managed Identity object therefore, and at least for now, we can only achieve this through scripting .

Current examples are focused on using the Managed Identity within Azure Automation Runbooks

Azure Automation Runbooks

Goal: Test PnP.PowerShell CmdLets usage with Managed Identities

Let’s start with a simple PnP.PowerShell usage example: get all MS Teams from our tenant :

1. Enable Managed Identity

To be able to login using Managed Identity, we need to first enable the managed identity (in the example im using the System Assigned Identity) within the azure context we are using.

This can be done through the Azure Portal


2. Add Required App Permissions

To add the need permissions we can use PowerShell or any existing command lines clients. In this specific case , i do prefer to use the CLI for Microsoft 365, it already has the proper methods in-place to achieve what’s needed.

# Current managed identity object id

#login to the tenant
m365 login --authType browser

#Get current appId associated with our Managed Identity service principal
$appId= (m365 aad sp get --objectId  | ConvertFrom-Json).appId

#add required permissions for managing all SharePoint Sites
m365 aad approleassignment add --appId $appId --resource "SharePoint" --scope "Sites.FullControl.All" 
#add required permissions for getting a list of teams on the Office 365 tenant
m365 aad approleassignment add --appId $appId --resource "Microsoft Graph" --scope "Group.Read.All,User.Read.All" 
m365 logout

3. Create the RunBook and Test it

Simple PowerShell runbook to Get a Teams report …
Don’t forget to add the PnP.PowerShell module to the automation account, or else PnP Cmdlets wont work.

#Connect using Managed Identity
Connect-PnPOnline -ManagedIdentity
#Get teams
$teams= Get-PnPTeamsTeam
$teams | Select-Object DisplayName,Visibility,IsArchived    


Kinda simple … no?

Lets try to use Get-PnPWeb




According to the PnP.Documentation

“Notice that using this connection method will not allow you to access SharePoint artifacts due to limitations of token acquisition. It will however allow you to use the Teams cmdlets, Flow cmdlets, Planner cmdlets and Microsoft 365 Group cmdlets. “

I know that it is probably a question of time to have this feature implemented with the PnP.PowerShell (this is already possible within C# code).
Nevertheless and because I needed this right now, I had to improvise...

The Solution … until we have it natively on the PnP.PowerShell

We need a token (JWT) !

There is a couple environment variables you can leverage to call the identity endpoint within our container …

Variable Value
$env:header CS6Uym5hQBllslNHhdk08Tp42gIDVBr2hnRZz3XkyKw=

next we need to get our JWT making a web request to the needed Resource (where the $ResourceURL = site we want to interact with )…

$header= $env:IDENTITY_HEADER
$ResourceURL = $siteUrl
$Response = [System.Text.Encoding]::Default.GetString((Invoke-WebRequest -UseBasicParsing  -Uri "$($endpoint)?resource=$resourceURL" -Method 'GET' -Headers @{'X-IDENTITY-HEADER' = "$header"; 'Metadata' = 'True'}).RawContentStream.ToArray()) | ConvertFrom-Json
$AccessToken = $response.access_token

… use the token in Connect-PnPOnline

Connect-PnPOnline -Url $siteUrl -AccessToken $AccessToken

... et voilรก!



The same concept can also be used with Azure Functions using PowerShell

๐Ÿค  PnP.PowerShell Rocks!!!! ๐ŸŽธ

Hope it helps !

See also