How to Prevent M365 Users from Executing SharePoint Online and PnP PowerShell
While SharePoint Online and PnP PowerShell can be useful for legitimate purposes, they can also be misused by unauthorized or malicious users to perform actions that are not compliant with the SharePoint Online policies or the organization’s governance rules. For example, a user could use SharePoint Online or PnP PowerShell to:
- Create or delete sites without approval or oversight
- Change site settings or features that affect the site’s functionality or security
- Grant or revoke permissions or sharing access to other users or external parties
- Copy, move, or delete site content or metadata without authorization or auditing
- Inject malicious code or scripts into SharePoint Online pages or web parts
These actions could compromise the security, integrity, or availability of SharePoint Online and other M365 resources, and expose the organization to data breaches, compliance violations, or legal liabilities. Therefore, it is important to prevent M365 users from executing SharePoint Online and PnP PowerShell commands, unless they have a valid business need and the proper authorization to do so.
Recently I had the opportunity to work on a project where the client wanted to apply some policies to their Microsoft 365 environment. One of the requirements was restrict the access to SharePoint Online and PnP PowerShell commands for all M365 users, except for SharePoint and IT Admins. I searched the web for possible solutions and came across an article by Tony Redmond that explained how to do this for Exchange Online PowerShell. I made a small change on his PowerShell commands to suit the client’s needs and managed to achieve the desired outcome.
Following is the modified PowerShell commands.
Block SharePoint Online PowerShell:
# Connect to the Graph
Connect-MgGraph -Scopes Directory.ReadWrite.All, Group.ReadWrite.All, Application.ReadWrite.All
# Create security group to control access to SharePoint Online PowerShell
$Group = New-MgGroup -DisplayName "Allow access to SPO PowerShell" -MailEnabled:$False -SecurityEnabled:$True -MailNickName 'SPO.PowerShell'
# Create the service principal for the SharePoint Online PowerShell app
$ServicePrincipal = New-MgServicePrincipal -Appid '9bc3ab49-b65d-410a-85ad-de819febfddc'
# Check that the Service Principal exists
Get-MgServicePrincipal -ServicePrincipalId $ServicePrincipal.Id | Format-Table DisplayName, Id, AppId
DisplayName Id AppId
----------- -- -----
Microsoft SharePoint Online Management Shell c06c0183-eeab-40c4-bf19-4ea8ecb8a43a 9bc3ab49-b65d-410a-85ad-de819febfddc
# Update the Service Principal so that it requires application role assignments
Update-MgServicePrincipal -ServicePrincipalId $ServicePrincipal.Id -AppRoleAssignmentRequired:$True
# Add the security group as an assignment to the service principal
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ServicePrincipal.Id -AppRoleId ([Guid]::Empty.ToString()) -ResourceId $ServicePrincipal.Id -PrincipalId $Group.Id
Block SharePoint PnP PowerShell:
In the following commands i used the same security group name as above and i didn’t create a separate new security group to handle the exceptions for the users who need to run PnP PowerShell commands.
# Connect to the Graph
Connect-MgGraph -Scopes Directory.ReadWrite.All, Group.ReadWrite.All, Application.ReadWrite.All
# Create security group to control access to SharePoint PnP PowerShell
$Group = Get-MgGroup -Filter "DisplayName eq 'Allow access to SPO PowerShell'"
# Create the service principal for the SharePoint PnP PowerShell app
$ServicePrincipal = New-MgServicePrincipal -Appid '31359c7f-bd7e-475c-86db-fdb8c937548e'
# Check that the Service Principal exists
Get-MgServicePrincipal -ServicePrincipalId $ServicePrincipal.Id | Format-Table DisplayName, Id, AppId
# Update the Service Principal so that it requires application role assignments
Update-MgServicePrincipal -ServicePrincipalId $ServicePrincipal.Id -AppRoleAssignmentRequired:$True
# Add the security group as an assignment to the service principal
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ServicePrincipal.Id -AppRoleId ([Guid]::Empty.ToString()) -ResourceId $ServicePrincipal.Id -PrincipalId $Group.Id
The main difference between the two above is the App Identifier (Appid). If you intend to prevent users executing PowerShell for other modules like MS Teams, you need to use MS Teams App Id in your commands.
Application identifiers for other PowerShell modules are as follows:
- Exchange Online management: fb78d390-0c51-40cd-8e17-fdbfab77341b
- Microsoft Teams: 12128f48-ec9e-42f0-b203-ea49fb6af367
- Azure: 1950a258-227b-4e31-a9cf-717495945fc2
- Microsoft Graph PowerShell SDK: 14d82eec-204b-4c2f-b7e8-296a70dab67e
After running above commands, you need to be a member of this group to use the cmdlets Connect-SPOService and Connect-PnPOnline: