Windows PowerShell  

SharePoint Detailed Permission Report using PnP PowerShell

Introduction

Microsoft 365 does not provide a built-in report to extract complete permission details across SharePoint (site, libraries, folders, files, and items) in a single view.

To achieve this, a custom PnP PowerShell script is used to generate a detailed permission report.

Purpose

This solution helps to:

  • Identify who has access to what

  • Detect unique permissions (broken inheritance)

  • Expand SharePoint group members into individual users

  • Support security audits and access reviews

When This is Required

Use this approach when:

  • Performing security or audit reviews

  • Investigating unauthorized access

  • Validating data access across files/folders

  • Preparing compliance reports

What the Report Includes

  • Site, Library, Folder, File, and Item-level permissions

  • User details (Name, UPN, Email)

  • Permission levels (Read, Contribute, Full Control)

  • Direct vs Group-based access

Prerequisites

1. Required PowerShell Modules

Install the PnP PowerShell module:

Install-Module -Name PnP.PowerShell -Scope CurrentUser

Verify installation:

Get-Module PnP.PowerShell -ListAvailable

2. Required Permissions (Very Important)

To successfully extract full permission details, the account must have:

Recommended

  • Site Collection Administrator (Best option)

Minimum Required

  • Full Control on the target SharePoint site

Ability to:

  • Read permissions

  • Access all lists and libraries

  • View items (including restricted content)

3. Admin Role Requirements

Depending on scope:

For Single Site Reports

  • Site Collection Admin is sufficient

For Multiple Sites / Tenant-Level Execution

  • SharePoint Administrator role required

4. Authentication Method

Use modern authentication:

Connect-PnPOnline -Url “<SiteURL>” -Interactive

5. Environment Requirements

  • Windows machine or server

  • PowerShell 5.1 or PowerShell 7+

  • Internet access to Microsoft 365

6. Access Considerations

  • Script will only return data based on access level

If permissions are missing:

  • Some users/groups may not appear

  • Some items may be skipped

PowerShell Script

Update the $SiteURL before running

# Create Output Folder

New-Item -ItemType Directory -Force -Path “C:\Temp”

# Site URL

$SiteURL = “https://yourtenant.sharepoint.com/sites/yoursite”

# Output File

$ReportOutput = “C:\Temp\SharePoint_Permission_Report.csv”

# Connect to SharePoint

Connect-PnPOnline -Url $SiteURL -Interactive

# Report Array

$PermissionData = New-Object System.Collections.ArrayList

Function Get-PermissionDetails {

    param ($Object, $ObjectType, $ObjectTitle, $ObjectURL)

    Get-PnPProperty -ClientObject $Object -Property HasUniqueRoleAssignments, RoleAssignments

    if (-not $Object.HasUniqueRoleAssignments) { return }

    foreach ($RoleAssignment in $Object.RoleAssignments) {

        Get-PnPProperty -ClientObject $RoleAssignment -Property RoleDefinitionBindings, Member

        $PermissionLevels = (

            $RoleAssignment.RoleDefinitionBindings |

            Select-Object -ExpandProperty Name |

            Where-Object { $_ -ne “Limited Access” }

        ) -join “, “

        if ([string]::IsNullOrEmpty($PermissionLevels)) { continue }

        $Member = $RoleAssignment.Member

        if ($Member.PrincipalType -eq “SharePointGroup”) {

            $Users = Get-PnPGroupMembers -Identity $Member.Title

            foreach ($User in $Users) {

                if ($User.Title -eq “System Account”) { continue }

                $PermissionData.Add([PSCustomObject]@{

                    ObjectType  = $ObjectType

                    ObjectTitle = $ObjectTitle

                    ObjectURL   = $ObjectURL

                    GroupName   = $Member.Title

                    UserName    = $User.Title

                    UserUPN     = $User.LoginName

                    Email       = $User.Email

                    Permissions = $PermissionLevels

                }) | Out-Null

            }

        }

        else {

            if ($Member.Title -ne “System Account”) {

                $PermissionData.Add([PSCustomObject]@{

                    ObjectType  = $ObjectType

                    ObjectTitle = $ObjectTitle

                    ObjectURL   = $ObjectURL

                    GroupName   = “Direct”

                    UserName    = $Member.Title

                    UserUPN     = $Member.LoginName

                    Email       = $Member.Email

                    Permissions = $PermissionLevels

                }) | Out-Null

            }

        }

    }

}

$Web = Get-PnPWeb

# Site Level

Get-PermissionDetails $Web “Site” $Web.Title $Web.Url

# Lists & Libraries

$Lists = Get-PnPList | Where-Object { $_.Hidden -eq $false }

foreach ($List in $Lists) {

    Get-PermissionDetails $List “Library” $List.Title $List.RootFolder.ServerRelativeUrl

    $Items = Get-PnPListItem -List $List.Title -PageSize 500

    foreach ($Item in $Items) {

        if ($Item.FileSystemObjectType -eq “File”) {

            Get-PermissionDetails $Item “File” $Item.FieldValues.FileLeafRef $Item.FieldValues.FileRef

        }

        elseif ($Item.FileSystemObjectType -eq “Folder”) {

            Get-PermissionDetails $Item “Folder” $Item.FieldValues.FileLeafRef $Item.FieldValues.FileRef

        }

    }

}

# Export Report

$PermissionData |

Sort-Object ObjectURL, UserUPN -Unique |

Export-Csv -Path $ReportOutput -NoTypeInformation -Encoding UTF8

Write-Host “Report Generated: $ReportOutput”

Output

  • CSV file with full permission breakdown

  • Can be used for audit, investigation, or review

Summary

This script provides a complete permission visibility solution for SharePoint, which is not available natively in Microsoft 365, enabling better security, governance, and compliance control.