WIP wrapper module for PnP PowerShell SharePoint permissions

This commit is contained in:
Corbin 2026-04-18 08:37:01 -04:00
parent ab2740394a
commit 030730448d

View File

@ -0,0 +1,234 @@
#region Private Helpers
<#
.SYNOPSIS
Tests if a PnP Group exists.
.DESCRIPTION
This function tests if a PnP Group exists in the current SharePoint site.
.PARAMETER Identity
The identity of the group to test.
.EXAMPLE
Test-PnPGroup -Identity "MyGroup"
#>
function Test-PnPGroup {
param(
[string]$Identity
)
try {
Get-PnPGroup -Identity $Identity -ErrorAction Stop | Out-Null
return $true
} catch {
return $false
}
}
<#
.SYNOPSIS
Tests if an Entra ID Group exists and PnP can resolve it.
.DESCRIPTION
This function tests if a Entra ID Group exists and can be resolved by PnP.
.PARAMETER Identity
The identity of the group to test.
.EXAMPLE
Test-EntraIdGroup -Identity "MyGroup"
#>
function Test-EntraIdGroup {
param(
[string]$Identity
)
try {
Get-PnPEntraIdGroup -Identity $Identity -ErrorAction Stop | Out-Null
return $true
} catch {
return $false
}
}
#endregion
#region Public Functions
<#
.SYNOPSIS
Sets permissions on a folder in a SharePoint document library.
.DESCRIPTION
This script breaks permission inheritance on a specified folder in a SharePoint document library and assigns permissions to a specified owner group and additional groups defined in the ACL parameter.
.PARAMETER Name
The name of the folder to set permissions on.
.PARAMETER List
The name of the document library containing the folder. Default is 'Shared Documents'.
.PARAMETER Owner
The name of the SharePoint group to assign as the owner of the folder with 'Full Control' permissions.
.PARAMETER Acl
An array of objects defining additional groups and their permissions to assign to the folder. Each object should have a 'DisplayName' property for the group name and a 'Role' property for the permission level (e.g., 'Read', 'Edit').
.EXAMPLE
$Acl = @(
@{ DisplayName = "SG-ADMIN-AdvocateFloats-Dynamic"; Role = "Edit" },
@{ DisplayName = "SG-ADMIN-AdvocateManagers-Dynamic"; Role = "Edit" }
)
.\Set-PnPFolderAcl.ps1 -Name "ProjectX" -List "Shared Documents" -Owner "Project Owners" -Acl $Acl
#>
function Set-PnPFolderAcl {
[CmdletBinding(
SupportsShouldProcess = $true,
ConfirmImpact = 'High'
)]
param(
[Parameter(
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName
)]
[string]$FolderName,
[Parameter()]
[string]$List = 'Shared Documents',
[Parameter(Mandatory)]
[string]$Owner,
[Parameter(Mandatory)]
[pscustomobject[]]$Acl
)
begin {
if (-not (Get-PnPContext)) {
Throw "Not connected to a SharePoint site. Run Connect-PnPOnline first."
}
if (-not (Get-PnPList -Identity $List -ErrorAction SilentlyContinue)) {
Throw "The specified list '$List' does not exist."
}
if (-not (Test-PnPGroup -Identity $Owner)) {
Throw "The specified owner group '$Owner' does not exist."
}
$ValidRoles = Get-PnPRoleDefinition | Select-Object -ExpandProperty Name
if (-not $ValidRoles) {
throw "Unable to retrieve SharePoint role definitions."
}
foreach ($entry in $Acl) {
if (-not ($entry.PSObject.Properties.Name -contains 'Group' -and
$entry.PSObject.Properties.Name -contains 'Role')) {
Throw "Each ACL entry must contain 'Group' and 'Role' properties."
}
if (-not (Test-PnPGroup -Identity $entry.Group) -and
-not (Test-EntraIdGroup -Identity $entry.Group)) {
Throw "The specified group '$($entry.Group)' does not exist as a PnP Group or Entra ID Group."
}
if ($entry.Role -notin $ValidRoles) {
Throw "Invalid role '$($entry.Role)' specified for group '$($entry.Group)'. Valid roles are: $($ValidRoles -join ', ')."
}
}
}
process {
$FolderPath = "$List/$FolderName"
# Retrieve folder and current permissions
$FolderItem = Get-PnPFolder -Url $FolderPath -ErrorAction Stop
$ListItem = Get-PnPListItem -List $List -Id $FolderItem.ListItemAllFields.Id
# Break inheritance ONLY IF the folder doesn't already have unique permissions
if (-not $ListItem.HasUniqueRoleAssignments) {
if ($PSCmdlet.ShouldProcess(
$FolderPath,
"Break inheritance and grant Full Control to '$Owner' on '$FolderPath'."
)) {
Write-Verbose "Breaking inheritance for '$FolderPath'."
Write-Verbose "Granting 'Full Control' to '$Owner' on '$FolderPath'."
Set-PnPFolderPermission `
-List $List `
-Identity $FolderPath `
-Group $Owner `
-AddRole 'Full Control' `
-ClearExisting
}
}
# Get existing role assignments
$RoleAssignments = Get-PnPProperty -ClientObject $ListItem -Property RoleAssignments
$CurrentAcl = foreach ($ra in $RoleAssignments) {
$principal = Get-PnPProperty -ClientObject $ra -Property Member
$bindings = Get-PnPProperty -ClientObject $ra -Property RoleDefinitionBindings
foreach ($binding in $bindings) {
[pscustomobject]@{
Principal = $principal.Title
Role = $binding.Name
}
}
}
# foreach ($entry in $CurrentAcl) {
# if ($entry.Principal -eq $Owner) {
# continue
# }
# if
# }
foreach ($entry in $Acl) {
$GroupName = $entry.Group
$Role = $entry.Role
$AlreadyAssigned = $ResolvedRoles | Where-Object {
$_.Principal -eq $GroupName -and
$_.Role -eq $Role
}
if ($AlreadyAssigned) {
Write-Verbose "Permission '$Role' already assigned to '$GroupName' on '$FolderPath'. Skipping."
continue
}
if (Test-PnPGroup $GroupName) {
if ($PSCmdlet.ShouldProcess(
$FolderPath,
"Grant '$Role' to SharePoint group '$GroupName' on '$FolderPath'."
)) {
Write-Verbose "Granting '$Role' to SharePoint group '$GroupName' on '$FolderPath'."
Set-PnPFolderPermission `
-List $List `
-Identity $FolderPath `
-Group $GroupName `
-AddRole $Role
}
} elseif (Test-EntraIdGroup $GroupName) {
if ($PSCmdlet.ShouldProcess(
$FolderPath,
"Grant '$Role' to Entra ID group '$GroupName' on '$FolderPath'."
)) {
Write-Verbose "Granting '$Role' to Entra ID group '$GroupName' on '$FolderPath'."
Set-PnPFolderPermission `
-List $List `
-Identity $FolderPath `
-Group $GroupName `
-AddRole $Role
}
}
}
}
}
#endregion
Export-ModuleMember -Function Set-PnPFolderAcl