PnP PowerShell Changes Its Entra ID App
Critical Need to Update Scripts Using PnP PowerShell Before September 9 2024
On August 21, 2024, the Pattern and Practices (PnP) team announced a major change for the PnP PowerShell module. To improve security by encouraging the use apps configured with only the permissions needed to process data within the tenant, the PnP PowerShell module is moving away from the multi-tenant Entra app (the PnP Management Shell, application identifier 31359c7f-bd7e-475c-86db-fdb8c937548e) used up to this point to require tenants to register a unique tenant-specific app for PnP.
Reading between the lines, the fear is that attackers will target the current PnP multi-tenant app and attempt to use it to compromise tenants. The multi-tenant app holds many Graph API permissions (Figure 1) together with a mixture of permissions for Entra ID, SharePoint Online, and the Office 365 service management API. Being able to gain control over such an app would be a rich prize for an attacker.
Swapping out one type of Entra app for another might sound innocuous, but it means that the sign-in command for PnP in every script must be updated. The PnP team will remove the current multi-tenant app on September 9, 2024, so any script that isn’t updated will promptly fail because it cannot authenticate. That’s quite a change.
The Usefulness of PnP PowerShell
I don’t use PnP PowerShell very often because I prefer to use Graph APIs or the Microsoft Graph PowerShell SDK whenever possible. However, sometimes PnP just works better or can perform a task that isn’t possible with the Graph. For instance, creating and populating Microsoft Lists is possible with the Graph, but it’s easier with PnP. SharePoint’s support for Graph APIs is weak and PnP is generally a better option for SharePoint Online automation, such as updating site property bags with custom properties (required to allow adaptive scopes to identify SharePoint Online sites). Finally, I use PnP to create files in SharePoint Online document libraries generated as the output from Azure Automation runbooks.
Creating a PnP Tenant Application
The first thing to do is to download the latest version of the PnP PowerShell module (which only runs on PowerShell 7) from the PowerShell Gallery. The maintainers update the module regularly. I used version 2.9.0 for this article.
The easiest way to create a tenant-specific application for PnP PowerShell is to run the Register-PnPEntraIDApp cmdlet:
Register-PnPEntraIDApp -ApplicationName “PnP PowerShell App” -Tenant office365itpros.onmicrosoft.com -Interactive
The cmdlet creates an Entra ID app and populates the app with some default properties, including a default set of Graph API permissions and a self-signed certificate for authentication. It doesn’t matter what name you give the app because authentication will use the unique application identifier (client id) Entra ID creates for the new app. The user who runs the cmdlet must be able to consent for the permissions requested for the app (Figure 2).
The Graph permissions allow read-write access to users, groups, and sites. Other permissions will be necessary to use PnP PowerShell with other workloads, such as Teams. Consent for these permissions is granted in the same way as for any other Entra ID app. Don’t rush to grant consent for other permissions until the need is evident and justified.
Using the Tenant App to Connect to PnP PowerShell
PnP PowerShell supports several ways to authenticate, including in Azure Automation runbooks. Most of the examples found on the internet show how to connect using the multi-tenant application. To make sure that scripts continue to work after September 9, every script that uses PnP PowerShell must be reviewed to ensure that its code works with the tenant-specific application. For instance, a simple interactive connection looks like this:
Connect-PnPOnline -Url https://office365itpros.sharepoint.com -ClientId cb5f363f-fbc0-46cb-bcfd-0933584a8c57 -Interactive
The value passed in the ClientId parameter is the application identifier for the PnP PowerShell application.
Azure Automation requires a little finesse. In many situations, it’s sufficient to use a managed identity. However, if a runbook needs to add content to a SharePoint site, like uploading a document, an account belonging to a site member must be used for authentication. This example uses credentials stored as a resource in the automation account executing the runbook.
$SiteURL = “https://office365itpros.sharepoint.com/sites/Office365Adoption”
# Insert the credential you want to use here… it should be the username and password for a site member
$SiteMemberCredential = Get-AutomationPSCredential -Name “ChannelMemberCredential”
$SiteMemberCredential
# Connect to the SharePoint Online site with PnP
$PnpConnection = Connect-PnPOnline $SiteURL -Credentials $SiteMemberCredential -ReturnConnection -ClientId cb5f363f-fbc0-46cb-bcfd-0933584a8c57
[array]$DocumentLibraries = Get-PnPList -Connection $PnpConnection | Where-Object {$_.BaseType -eq “DocumentLibrary”}
# Display the name, Default URL and Number of Items for each library
$DocumentLibraries | Select Title, DefaultViewURL, ItemCount
Ready, Steady, Go…
September 9 is not too far away, so the work to review, update, and test PnP PowerShell scripts needs to start very soon (if not yesterday). Announcing a change like this 19 days before it happens seems odd and isn’t in line with the general practice where Microsoft gives at least a month’s notice for a major change. I imagine that some folks coming back from their vacations have an unpleasant surprise lurking in their inboxes…