All About Site Permissions
In the first installment of this series, we explored the benefits of using PnP PowerShell to manage your SharePoint Online environment. In this article, we dive deeper into working SharePoint Online through PnP PowerShell, with practical examples of managing site permissions.
Note: The code from all examples is available on GitHub for quick reference.
Reporting Site Permissions
Managing permissions is an important part of the role of a tenant administrator. Permissions management in SharePoint Online is at the forefront of many organizations who are considering deploying (or have already deployed) Copilot for Microsoft 365. Poor permissions management means that Copilot can make sensitive data more visible to users who have permissions where they shouldn’t.
Using PnP PowerShell to assess and update permissions within SharePoint Online is a great way to manage permissions at scale. For example, the following script returns the role assignments for the currently connected SharePoint site:
##Connect to site Connect-PnPOnline -Interactive -ClientId "<ClientID>" -Url "https://<TenantDomain>.sharepoint.com/sites/<SiteName>" ##Get Site Role Assignments #Get all the role assignments for the site $RoleAssignments = (Get-PnPWeb -Includes RoleAssignments).RoleAssignments #Loop through each role assignment foreach($RoleAssignment in $RoleAssignments) { #Get the role definition bindings $RoleDefinitionBindings = Get-PnPProperty -ClientObject $RoleAssignment -Property RoleDefinitionBindings #Get the member details $Member = Get-PnPProperty -ClientObject $RoleAssignment -Property member #Output the role assignment and role definition Write-Host "$($member.GetType().name): $($Member.Title) - Role: $($RoleDefinitionBindings.Name)" }
The steps taken in the script are:
- Get all role assignments for the current site.
- Loop through each role assignment and return the role name and the role member details.
- Format the output to write to the screen the member type, member name, and role (Shown in Figure 1).
SharePoint sites are provisioned with three built-in role groups (Owners, Members, and Visitors). In the result in Figure 1 these three roles are shown. The Get-PnPGroup cmdlet returns these built-in groups without returning all groups as shown below:
##Get Owner Group Get-PnPGroup -AssociatedOwnerGroup ##Get Member Group Get-PnPGroup -AssociatedMemberGroup ##Get Visitor Group Get-PnPGroup -AssociatedVisitorGroup
To expand the members of any groups in the site, use the Get-PnPGroupMember cmdlet. For example, to return all members of the owners group on the site, use the following cmdlet:
<em>Get-PnPGroup -AssociatedOwnerGroup | Get-PnPGroupMember</em>
A complication arises when retrieving group members for Microsoft 365 Group-connected sites. In these sites, the Owners and Members groups in SharePoint include the Owners and Members of the corresponding Microsoft 365 Group.
The Get-PnPEntraIDGroupMember and Get-PnPEntraIDGroupOwner cmdlets return the members and owners of any non-SharePoint groups (Groups provisioned in Entra including security groups and Microsoft 365 Groups). In the below example, the code expands any object with the PrincipalType set to SecurityGroup, this includes both security groups and Microsoft 365 Groups:
##Get Member group members and expand any nested groups $Group = Get-PnPGroup -AssociatedMemberGroup $GroupMembers = Get-PnPGroupMember -Identity $Group.Id foreach($GroupMember in $GroupMembers) { if($GroupMember.PrincipalType -eq "SecurityGroup") { $NestedGroupMembers = Get-PnPEntraIDGroupMember -Identity $GroupMember.LoginName.Split('|')[-1] foreach($NestedGroupMember in $NestedGroupMembers) { Write-Host "Nested Group Member: $($NestedGroupMember.displayName) is a member of $($GroupMember.Title)" } } Write-Host "Owner Group Member: $($GroupMember.Title)" }
Note: If you aren’t seeing the values you expect, make sure to check you have the appropriate permissions on the App Registration you created. Get-PnPEntraIDGroup requires Group.Read Delegated permissions on the Microsoft Graph. Check out the previous article for more information on registering the required app in Microsoft Entra.
Updating Site Permissions
Reporting on existing SharePoint permissions is useful, but updating permissions using PnP PowerShell (in my opinion) saves a tremendous amount of time and effort that is used when navigating the web interface of SharePoint Online.
Something to keep in mind when using PnP PowerShell with Delegated permissions is that you need to have permissions to any site you’re modifying. The easiest way to do this when using delegated permissions is to add your account as an Owner on a site before you connect to it. In production adding yourself as an owner of each site may cause some concern among users and security administrators. For production environments, it is often better to use Application permissions which I will detail in the next part of this series.
For the purposes of this example, the below code gets the current signed-in user and adds them as an owner to the Demo-Finance site:
$currentUser = (Get-PnPProperty -ClientObject (Get-PnPWeb) -Property CurrentUser).LoginName Set-PnPTenantSite -Url "https://<TenantDomain>.sharepoint.com/sites/demo-finance" -Owners $currentUser
In the previous examples reporting on permissions we looked at the Get-PnPGroup cmdlet, this cmdlet is also very useful when adding users to one of the built-in permission groups. In the below example, we add Dale Cooper to the visitors group of the site:
$VisitorsGroup = Get-PnPGroup -AssociatedVisitorGroup Add-PnPGroupMember -LoginName "dale.cooper@contoso.com" -Group $VisitorsGroup.LoginName
The New-PnPSiteGroup cmdlet is used to create new site groups and define the permission levels for these groups. This is useful when you want a specific permission level that’s not covered by the three built in role groups. The below cmdlet adds a new group to the site with the Contributor permission:
<em>New-PnPSiteGroup -Name "Contributors Group" -PermissionLevels "Contribute"</em>
The default permission levels (outlined here) cover the majority of requirements for standard SharePoint permissions, at times though, custom permission levels are useful. For example, you can use custom permission levels if you want to give a user “Read” level permissions to a site but also allow them to update list items. The list of permissions available for use in SharePoint is available here. The below script creates the new permission level by cloning the default “Read” permission level and assigning it to a user.
Add-PnPRoleDefinition -RoleName "List Updater" -Clone "Read" -Include EditListItems Set-PnPWebPermission -User "laura.palmer@contoso.com" -AddRole "List Updater"
Removing permissions follows much of the same logic as adding permissions. The Remove-PnPGroupMember cmdlet removes a specific member from a group, as shown below:
<em>Remove-PnPGroupMember -Group (Get-PnPGroup -AssociatedVisitorGroup).id -LoginName dale.cooper@contoso.com</em>
Taking this a step further, the below script returns all members of the associated member’s site group and removes each of them:
$MembersGroup = Get-PnPGroup -AssociatedMemberGroup $Members = Get-PnPGroupMember -Identity $MembersGroup.Id foreach ($Member in $Members) { Remove-PnPGroupMember -Group $MembersGroup.Title -LoginName $Member.LoginName }
Using Connections
We’ve seen so far that when we are working with sites in PnP PowerShell, we connect first to the site we want to interact with, and then perform the tasks we need. Connecting to one site at a time is fine when working on a specific site’s permissions or design, but can limit the flexibility of your scripts.
That’s where the -ReturnConnection parameter of the Connect-PnPOnline cmdlet comes in. When connecting to a SharePoint site, adding the -ReturnConnection parameter will return the connection that is established which can be saved as a variable as shown in the below example:
<em>$AdministrationConnection = Connect-PnPOnline -Interactive -ClientId "<ClientID>" -Url "https://<TenantDomain>.sharepoint.com/sites/demo-Administration" -ReturnConnection</em>
The returned connection is then used with the -Connection parameter when running other cmdlets to work across multiple sites at once as shown in Figure 2.
A practical example of where using connections becomes very useful is when we need to compare sites. In the below script, we connect to the Administration and Finance sites and copy the Members from one to the other without needing to change connections:
##Create Connections $AdministrationConnection = Connect-PnPOnline -Interactive -ClientId "<ClientID>" -Url "https://<TenantDomain>.sharepoint.com/sites/demo-Administration" -ReturnConnection $FinanceConnection = Connect-PnPOnline -Interactive -ClientId "<ClientID>" -Url "https://<TenantDomain>.sharepoint.com/sites/demo-Finance" -ReturnConnection ##Get Members from the source site $SourceMemberGroup = Get-PnPGroup -AssociatedMemberGroup -Connection $AdministrationConnection $SourceMembers = Get-PnPGroupMember -Group $SourceMemberGroup -Connection $AdministrationConnection ##Get the target site member group $TargetMemberGroup = Get-PnPGroup -AssociatedMemberGroup -Connection $FinanceConnection ##Add the members to the target site foreach ($SourceMember in $SourceMembers) { Add-PnPGroupMember -LoginName $SourceMember.LoginName -Group $TargetMemberGroup.LoginName -Connection $FinanceConnection }
Permissions are Key
In this article, we looked at some core tasks that tenant administrators can use PnP PowerShell to help with. Permissions are central to SharePoint Online and it’s important to be able to manage site permissions effectively.
There’s still a lot more in PnP PowerShell that we haven’t even touched on so keep an eye out for the next article in the series!