functions/Invoke-SPPermissionScan.ps1

function Invoke-SPPermissionScan {
    <#
    .SYNOPSIS
        Executes a managed and logged sharepoint permission scan.
     
    .DESCRIPTION
        Executes a managed and logged sharepoint permission scan.
        This scan then matches the result against specified users, resolving the effective access rights of a user.
 
        This includes simplified logging options (for more options, see https://psframework.org).
        It can also at stages export data to csv as it comes in.
 
        This command is designed to be able to handle any Sharepoint site scale.
        More sites means longer runtimes, but should not affect quality of result.
 
        Connect via Connect-Sharepoint before running this command.
     
    .PARAMETER UserIdentity
        IDs or UserPrincipalName of users to match against the Sharepoint permissions.
        Group memberships are taken into account recursively.
     
    .PARAMETER SiteUrl
        Sharepoint sites to scan.
        If this parameter is not specified, all Sharepoint sites in the tenant will be scanned.
     
    .PARAMETER LogPath
        The path to the file into which the command should log actions.
        The output will be in a CSV format and include detailed information on what information was retrieved against what site.
     
    .PARAMETER ExportPathRaw
        Path to which raw Sharepoint permission results should be written as CSV.
        Specify this path if you want an export of all permissions in their raw state without matching it against users.
     
    .PARAMETER ExportPathResult
        Path to which processed permission results should be written as CSV.
        This content is equal to the output objects of this command.
     
    .PARAMETER RawExclude
        Whether the raw export should exclude specific permissions.
        By default, Sharepoint internal permissions are excluded.
 
    .PARAMETER LogLevel
        How detailed a log should be written.
     
    .EXAMPLE
        PS C:\> Invoke-SPPermissionScan -UserIdentity (Get-Content .\users.txt)
 
        Scan all sharepoint sites for their permissions and match them against the users stored in the "users.txt" text file.
    #>

    [CmdletBinding()]
    param (
        [string[]]
        $UserIdentity,

        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string[]]
        $SiteUrl,

        [string]
        $LogPath,

        [PsfValidateScript('PSFramework.Validate.FSPath.FileOrParent', ErrorString = 'PSFramework.Validate.FSPath.FileOrParent')]
        [string]
        $ExportPathRaw,

        [PsfValidateScript('PSFramework.Validate.FSPath.FileOrParent', ErrorString = 'PSFramework.Validate.FSPath.FileOrParent')]
        [string]
        $ExportPathResult,

        [ValidateSet('None', 'System', 'SPRole', 'SPUser', 'AAD', 'AADRole', 'Unknown')]
        [string[]]
        $RawExclude = @('System', 'SPRole', 'SPUser'),

        [LogLevel]
        $LogLevel = 'Medium'
    )

    begin {
        if (-not $script:adminUrl) {
            throw "Not connected yet, call 'Connect-Sharepoint' to connect!"
        }
    
        Connect-Sharepoint -TenantID $script:TenantID -ClientID $script:ClientID -Thumbprint $script:Thumbprint -AdminUrl $script:adminUrl
    
        if ($LogPath) {
            Set-PSFLoggingProvider -Name logfile -InstanceName SPPermissionScan -FilePath $LogPath -Enabled $true
        }
        else {
            $LogLevel = 'None'
        }
    
        $userData = Resolve-SPGraphUser -Identity $UserIdentity -LogLevel $LogLevel
        Write-PSFMessage -Level Host -Message 'Starting Sharepoint Permission Scan' -Tag progress
    }
    process {
        if ($SiteUrl) {
            $SiteUrl | Get-SPSitePermission -Exclude $RawExclude -LogLevel $LogLevel | Export-CsvData -Path $ExportPathRaw | ConvertTo-UserSitePermission -UserData $userData -LogLevel $LogLevel | Export-CsvData -Path $ExportPathResult
        }
        else {
            $urlCache = Join-Path -Path (Get-PSFPath -Name Temp) -ChildPath "ssp-$(Get-Random).txt"
            try {
                # Get-PnPTenantSite keeps all sites in memory before returning them
                # Writing them to file and then reading from file minimizes memory impact
                Get-PnPTenantSite | ForEach-Object Url | Set-Content -Path $urlCache
                Get-Content -Path $urlCache | Get-SPSitePermission -Exclude $RawExclude -LogLevel $LogLevel | Export-CsvData -Path $ExportPathRaw | ConvertTo-UserSitePermission -UserData $userData -LogLevel $LogLevel | Export-CsvData -Path $ExportPathResult
            }
            finally {
                Remove-Item -Path $urlCache -Force -ErrorAction Ignore
            }
        }
    }
    end {
        Write-PSFMessage -Level Host -Message 'Sharepoint Permission Scan Concluded' -Tag progress
        if ($LogPath) {
            Wait-PSFMessage
            Set-PSFLoggingProvider -Name logfile -InstanceName SPPermissionScan -Enabled $false
        }
        Connect-Sharepoint -TenantID $script:TenantID -ClientID $script:ClientID -Thumbprint $script:Thumbprint -AdminUrl $script:adminUrl
    }
}