Slow PowerShell script performance optimalisation - Stack Overflow

I try to loop into all SharePoint sites, libraries, folders and documents and check which one are share

I try to loop into all SharePoint sites, libraries, folders and documents and check which one are shared with more as 50 members. This script is very slow at this moment. Does someone have some PowerShell performance optimalisation tips?

The bigest problem is I think the part where I need to loop into all folders and documents. Some sites have thousands of documents.

function LogEntry($logentry) {
    $moment = get-date -f "yyyy-MM-dd HH:mm"
    Write-Host "$moment $logentry"
    "$moment $logentry" | out-file -append $transcriptLogFileFullPath
}

function countInheritedPermissionFiles {
        param (
            [Microsoft.SharePoint.Client.ClientObject]$folder,
            [string]$listName
        )
    
        $folderItems = Get-PnPFolderItem -Identity $folder
    
        foreach($folderItem in $folderItems) {
            if($folderItem.TypedObject.ToString() -eq "Microsoft.SharePoint.Client.Folder") {
                $folderByPnP = Get-PnPFolder -Url $folderItem.ServerRelativeUrl -Includes ListItemAllFields.HasUniqueRoleAssignments, Folders
     
                if(!$folderByPnP.ListItemAllFields.HasUniqueRoleAssignments) {
                    countInheritedPermissionFiles $folderByPnP $listName
                }
            } else {
                $item = Get-PnPListItem -List $listName -UniqueId  $folderItem.UniqueId
    
                $HasUniquePermissions = Get-PnPProperty -ClientObject $item[0] -Property "HasUniqueRoleAssignments"
    
                if(!$HasUniquePermissions) {
                    $global:inheritedPermissionsFileCount ++
                }
            }
        }
    }
    
    function getPermissions($_object) {
    
        # make arrays empty
        $global:permissionUsers = @()
        $global:permissionType = @()
        $global:permissionLevels = @()
    
        $roleAssignments = Get-PnPProperty -ClientObject $_object -Property RoleAssignments
      
        #Loop through each permission assigned and extract details   
        Foreach($roleAssignment in $_object.RoleAssignments)
        {
            #Get the Permission Levels assigned and Member
            Get-PnPProperty -ClientObject $roleAssignment -Property RoleDefinitionBindings, Member
    
            if($roleAssignment.Member.LoginName -notlike "*Limited Access*" -and $roleAssignment.RoleDefinitionBindings[0].Name -notlike "*Beperkte toegang*" -and $roleAssignment.RoleDefinitionBindings[0].Name -notlike "*Limited Access*") {
                #Get the Permission Levels assigned, Remove Limited Access
                foreach($roleDefinitionBinding in $roleAssignment.RoleDefinitionBindings) {
                    if(!$global:permissionLevels.Contains($roleDefinitionBinding.Name)) {
                        $global:permissionLevels += $roleDefinitionBinding.Name
                    }
                }
    
                #Check if the Principal is SharePoint group
                If($roleAssignment.Member.PrincipalType -eq "SharePointGroup")
                {
                    if(!$global:permissionType.Contains("SharePointGroup")) {
                        $global:permissionType += "SharePointGroup"
                    }
    
                    #Get Group Members
                    $GroupMembers = Get-PnPGroupMember -Identity $roleAssignment.Member.LoginName
    
                    foreach($groupMember in $GroupMembers) {
                        if(!$global:permissionUsers.Contains($groupMember.Email) -and $groupMember.LoginName -notlike "*c:0o.c|federateddirectoryclaimprovider|*" -and $groupMember.Email -ne "") {
                            $global:permissionUsers += $groupMember.Email
                        }   
                    }
                }
                Else #User
                {
                    if(!$global:permissionType.Contains("DirectUser")) {
                        $global:permissionType += "DirectUser"
                    }
    
                    if(!$global:permissionUsers.Contains($roleAssignment.Member.Email)) {
                        $global:permissionUsers += $roleAssignment.Member.Email
                    }
                }
            }
        }
    }
    
    #Parameters
    $dateTime = (Get-Date).toString("dd-MM-yyyy-hh-mm-ss")
    $invocation = (Get-Variable MyInvocation).Value
    $directorypath = Split-Path $invocation.MyCommand.Path
    $fileName = "M365OversharingReport.csv"
    $reportOutput = $directorypath + "\Report\"+ $fileName
    $traceLoggingFolderPath = $directorypath + "\Logs\"
    $traceLoggingFilename = "transcript-${datetime}.log"
    $transcriptLogFileFullPath = Join-Path -Path $traceLoggingFolderPath -ChildPath $traceLoggingFilename
    $global:permissionUsers = @()
    $global:permissionType = @()
    $global:permissionLevels = @()
    $global:inheritedPermissionsFileCount = 0
    $recordsCount = 0
    $minUsersCount = 50
    $adminSiteURL = ";
    $tenant =  "myCompany.onmicrosoft"
    $spSiteDomain = ";
    $certThumbprint = "something"
    $appId = "someGuid"
    
    LogEntry("START")
    
    Connect-PnPOnline -Url $adminSiteURL -ClientId $appId -Thumbprint $certThumbprint -Tenant $tenant
    
    $excludedSites = @(";, "/", "/", ";, ";)
    $excludedLists = @("Access Requests", "App Packages", "appdata", "appfiles", "Apps in Testing", "Cache Profiles", "Composed Looks", "Content and Structure Reports", "Content type publishing error log", "Converted Forms",
        "Device Channels", "Form Templates", "fpdatasources", "Get started with Apps for Office and SharePoint", "List Template Gallery", "Long Running Operation Status", "Maintenance Log Library", "Images", "site collection images"
        , "Master Docs", "Master Page Gallery", "MicroFeed", "NintexFormXml", "Quick Deploy Items", "Relationships List", "Reusable Content", "Reporting Metadata", "Reporting Templates", "Search Config List", "Site Assets", "Preservation Hold Library",
        "Site Pages", "Solution Gallery", "Style Library", "Suggested Content Browser Locations", "Theme Gallery", "TaxonomyHiddenList", "User Information List", "Web Part Gallery", "wfpub", "wfsvc", "Workflow History", "Workflow Tasks", "Pages")
    
    # Haal alle sitecollecties op
    LogEntry("Get all SharePoint sites")
    $sitesCollection = Get-PnPTenantSite
    
    LogEntry("Found '$($sitesCollection.Count)' SharePoint sites")
    
    # Read CSV and to skip the processed sites
    $processedSites = @()
    if (Test-Path $reportOutput) {
        
        $processedSites = Import-Csv $reportOutput | Where-Object { $_.Status -eq "ProcessedOversharing" -or $_.Status -eq "ProcessedExcludedSite" -or $_.Status -eq "ProcessedNoOversharing"  } | Select-Object -ExpandProperty SiteUrl
        LogEntry("Found '$($processedSites.Count)' SharePoint sites already analysed in CSV file")
    }
    
    $siteCounter = 0
    
    # Loop into all sitecollection
    ForEach($site in $sitesCollection) {
        $siteCounter++
        LogEntry("Site $siteCounter / $($sitesCollection.Count)")
        
        # Check if this site is already processed
        if ($processedSites -contains $site.Url) {
            LogEntry("Site $($site.Url) is already processed, skip it and do nothing...")
            continue
        }
    
        if(!$excludedSites.Contains($site.Url) -and !$site.Url.Contains(($spSiteDomain + "/portals"))) {
            Connect-PnPOnline -Url $site.Url -ClientId $appId -Thumbprint $certThumbprint -Tenant $tenant
            $skipped = $true
            $owners = ""
            If($Site.Template -like 'GROUP*') {
                # Get M365 Group owner
                try {
                    $owners = (Get-PnPMicrosoft365GroupOwners -Identity ($Site.GroupId)  | Select-Object -ExpandProperty Email) -join "; "
                }
                Catch [Exception] {}
            } Else {
                # Get site owner
                try {                
                    $ownergroup = Get-PnPGroup -AssociatedOwnerGroup
                    $owners = ($ownergroup.Users | Where-Object { $_.Email -ne $null } | Select-Object -ExpandProperty Email) -join "; "
                }
                Catch [Exception] {}
            }
    
            try {
                $web = Get-PnPWeb
                $libraries = Get-PnPList -Includes BaseType, Hidden, Title, HasUniqueRoleAssignments, RootFolder | Where-Object {$_.Hidden -eq $False -and $_.Title -notin $excludedLists -and $_.BaseType -eq "DocumentLibrary" }
    
                $siteListItemsCount = 0
                LogEntry("Process '$($libraries.Count)' libraries")
                
                foreach($library in $libraries) {
                    $siteListItemsCount += $library.ItemCount
    
                    if($library.HasUniqueRoleAssignments) {
                        getPermissions $library
    
                        if($global:permissionUsers.Count -gt $minUsersCount) {
                            $recordsCount++
    
                            LogEntry("Site $siteCounter / $($sitesCollection.Count), save record $recordsCount (library) '$($site.Url)$($library.RootFolder.ServerRelativeUrl)'")
                            
                            $libraryAccessItem = New-Object PSObject
                            $libraryAccessItem | Add-Member -NotePropertyName "SharePointObjectType" -NotePropertyValue "Library"
                            $libraryAccessItem | Add-Member -NotePropertyName "UsersCount" -NotePropertyValue $global:permissionUsers.Count
                            $libraryAccessItem | Add-Member -NotePropertyName "ItemsCount" -NotePropertyValue $library.ItemCount
                            $libraryAccessItem | Add-Member -NotePropertyName "PermissionInheritedItemsCount" -NotePropertyValue $library.ItemCount
                            $libraryAccessItem | Add-Member -NotePropertyName "SiteUrl" -NotePropertyValue $site.Url
                            $libraryAccessItem | Add-Member -NotePropertyName "ListUrl" -NotePropertyValue $library.RootFolder.ServerRelativeUrl
                            $libraryAccessItem | Add-Member -NotePropertyName "ServerRelativeUrl" -NotePropertyValue $library.RootFolder.ServerRelativeUrl
                            $libraryAccessItem | Add-Member -NotePropertyName "LinkType" -NotePropertyValue ($global:permissionLevels -join '|')
                            $libraryAccessItem | Add-Member -NotePropertyName "SharedLinkOrDirectAccess" -NotePropertyValue "DirectAccess"
                            $libraryAccessItem | Add-Member -NotePropertyName "DirectPermissionType" -NotePropertyValue ($global:permissionType -join '|')
                            $libraryAccessItem | Add-Member -NotePropertyName "Users" -NotePropertyValue ($global:permissionUsers -join '|')
                            $libraryAccessItem | Add-Member -NotePropertyName "Owners" -NotePropertyValue $Owners
                            $libraryAccessItem | Add-Member -NotePropertyName "SiteTemplate" -NotePropertyValue $site.Template
                            $libraryAccessItem | Add-Member -NotePropertyName "Status" -NotePropertyValue "ProcessedOversharing"
                            $libraryAccessItem | Add-Member -NotePropertyName "ErrorMessage" -NotePropertyValue ""
    
                            # Save row to CSV
                            $libraryAccessItem | Export-CSV $reportOutput -Append -NoTypeInformation
                            $skipped = $false
                        }
                    } 
    
                    # Get documents from library
                    $listItems = Get-PnPListItem -List $library -PageSize 2000 # TODO, Check if I get more as 2000 results
                    LogEntry("Process '$($listItems.Count)' documents from library '$($library.Title)'")
    
                    ForEach($item in $listItems) {
                        # Check if this document has unique permissions
                        $hasUniquePermissions = Get-PnPProperty -ClientObject $Item -Property "HasUniqueRoleAssignments"
                        If($hasUniquePermissions) {
                            getPermissions $item
    
                            if($global:permissionUsers.Count -gt $minUsersCount) {
                                $recordsCount++
                                
                                LogEntry("Site $siteCounter / $($sitesCollection.Count), save record $recordsCount (document) '$($site.Url)$($item.FieldValues["FileRef"])'")
                                
                                $directAccessItem = New-Object PSObject
                                if ($item.FileSystemObjectType -eq "Folder") {
                                    # Get documents and folders
                                    $folderRelativePath = $item.FieldValues["FileRef"].Replace($web.ServerRelativeUrl,"")
                                    $items = Get-PnPFolderItem -FolderSiteRelativeUrl $folderRelativePath -Recursive -ItemType File
                                    $directAccessItem | Add-Member -NotePropertyName "SharePointObjectType" -NotePropertyValue "Folder"
                                    $directAccessItem | Add-Member -NotePropertyName "UsersCount" -NotePropertyValue $global:permissionUsers.Count
                                    $directAccessItem | Add-Member -NotePropertyName "ItemsCount" -NotePropertyValue $items.Count
                                    
                                    # Initialiseer bestandstelling
                                    $global:inheritedPermissionsFileCount = 0
    
                                    $folder = Get-PnPFolder -Url $item.FieldValues["FileRef"] -Includes Files, Folders
    
                                    # Count documents from this subfolder
                                    countInheritedPermissionFiles $folder $library.Title
    
                                    $directAccessItem | Add-Member -NotePropertyName "PermissionInheritedItemsCount" -NotePropertyValue $global:inheritedPermissionsFileCount
                                } else {
                                    $directAccessItem | Add-Member -NotePropertyName "SharePointObjectType" -NotePropertyValue "File"
                                    $directAccessItem | Add-Member -NotePropertyName "UsersCount" -NotePropertyValue $global:permissionUsers.Count
                                    $directAccessItem | Add-Member -NotePropertyName "ItemsCount" -NotePropertyValue "N/A"
                                    $directAccessItem | Add-Member -NotePropertyName "PermissionInheritedItemsCount" -NotePropertyValue "N/A"        
                                }
    
                                $directAccessItem | Add-Member -NotePropertyName "SiteUrl" -NotePropertyValue $site.Url
                                $directAccessItem | Add-Member -NotePropertyName "ListUrl" -NotePropertyValue $library.RootFolder.ServerRelativeUrl
                                $directAccessItem | Add-Member -NotePropertyName "ServerRelativeUrl" -NotePropertyValue $item.FieldValues["FileRef"]
                                $directAccessItem | Add-Member -NotePropertyName "RoleList" -NotePropertyValue "TODO"
                                $directAccessItem | Add-Member -NotePropertyName "LinkScope" -NotePropertyValue "TODO"
                                $directAccessItem | Add-Member -NotePropertyName "LinkType" -NotePropertyValue ($global:permissionLevels -join '|')
    
                                $SharingLinks = if ($item.FileSystemObjectType -eq "File") {
                                    Get-PnPFileSharingLink -Identity $item.FieldValues["FileRef"]
                                } elseif ($item.FileSystemObjectType -eq "Folder") {
                                    Get-PnPFolderSharingLink -Folder $item.FieldValues["FileRef"]
                                }
    
                                if($SharingLinks) {
                                    $directAccessItem | Add-Member -NotePropertyName "SharedLinkOrDirectAccess" -NotePropertyValue "DirectAccess/SharedLinks"
                                } else {
                                    $directAccessItem | Add-Member -NotePropertyName "SharedLinkOrDirectAccess" -NotePropertyValue "DirectAccess"
                                }
    
                                $directAccessItem | Add-Member -NotePropertyName "DirectPermissionType" -NotePropertyValue ($global:permissionType -join '|')
                                $directAccessItem | Add-Member -NotePropertyName "Users" -NotePropertyValue ($global:permissionUsers -join '|')
                                $directAccessItem | Add-Member -NotePropertyName "Owners" -NotePropertyValue $Owners                          
                                $directAccessItem | Add-Member -NotePropertyName "SiteTemplate" -NotePropertyValue $site.Template
                                $directAccessItem | Add-Member -NotePropertyName "Status" -NotePropertyValue "ProcessedOversharing"
                                $directAccessItem | Add-Member -NotePropertyName "ErrorMessage" -NotePropertyValue ""
    
                                # Save row to CSV
                                $directAccessItem | Export-CSV $reportOutput -Append -NoTypeInformation
                                $skipped = $false
                            }
                        }
                    }
                }
    
                getPermissions $web
                if($global:permissionUsers.Count -gt $minUsersCount) {
                    $recordsCount++
    
                    LogEntry("Site $siteCounter / $($sitesCollection.Count), save record $recordsCount (site) '$($site.Url)'")
    
                    $siteAccessItem = New-Object PSObject
                    $siteAccessItem | Add-Member -NotePropertyName "SharePointObjectType" -NotePropertyValue "Site"
                    $siteAccessItem | Add-Member -NotePropertyName "UsersCount" -NotePropertyValue $global:permissionUsers.Count
                    $siteAccessItem | Add-Member -NotePropertyName "ItemsCount" -NotePropertyValue $siteListItemsCount
                    $siteAccessItem | Add-Member -NotePropertyName "PermissionInheritedItemsCount" -NotePropertyValue $siteListItemsCount
                    $siteAccessItem | Add-Member -NotePropertyName "SiteUrl" -NotePropertyValue $site.Url
                    $siteAccessItem | Add-Member -NotePropertyName "ListUrl" -NotePropertyValue "N/A"
                    $siteAccessItem | Add-Member -NotePropertyName "ServerRelativeUrl" -NotePropertyValue $web.ServerRelativeUrl
                    $siteAccessItem | Add-Member -NotePropertyName "LinkType" -NotePropertyValue ($global:permissionLevels -join '|')
                    $siteAccessItem | Add-Member -NotePropertyName "SharedLinkOrDirectAccess" -NotePropertyValue "DirectAccess"
                    $siteAccessItem | Add-Member -NotePropertyName "DirectPermissionType" -NotePropertyValue ($global:permissionType -join '|')
                    $siteAccessItem | Add-Member -NotePropertyName "Users" -NotePropertyValue ($global:permissionUsers -join '|')
                    $siteAccessItem | Add-Member -NotePropertyName "Owners" -NotePropertyValue $Owners
                    $siteAccessItem | Add-Member -NotePropertyName "SiteTemplate" -NotePropertyValue $site.Template
                    $siteAccessItem | Add-Member -NotePropertyName "Status" -NotePropertyValue "ProcessedOversharing"
                    $siteAccessItem | Add-Member -NotePropertyName "ErrorMessage" -NotePropertyValue ""
    
                    # Save row to CSV
                    $siteAccessItem | Export-CSV $reportOutput -Append -NoTypeInformation
                    $skipped = $false
                }
            }
            catch [Exception] {
                LogEntry("Catch error: " + $_.Exception.Message)
            }
    
            if($skipped) {
                $libraryAccessItem = New-Object PSObject
                $libraryAccessItem | Add-Member -NotePropertyName "SharePointObjectType" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "UsersCount" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "ItemsCount" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "PermissionInheritedItemsCount" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "SiteUrl" -NotePropertyValue $site.Url
                $libraryAccessItem | Add-Member -NotePropertyName "ListUrl" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "ServerRelativeUrl" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "LinkType" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "SharedLinkOrDirectAccess" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "DirectPermissionType" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "Users" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "Owners" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "SiteTemplate" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "Status" -NotePropertyValue "ProcessedNoOversharing"
                $libraryAccessItem | Add-Member -NotePropertyName "ErrorMessage" -NotePropertyValue ""
    
                # Save row to CSV
                $libraryAccessItem | Export-CSV $reportOutput -Append -NoTypeInformation
            }
    
        } else {
            $libraryAccessItem = New-Object PSObject
            $libraryAccessItem | Add-Member -NotePropertyName "SharePointObjectType" -NotePropertyValue "Site"
            $libraryAccessItem | Add-Member -NotePropertyName "UsersCount" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "ItemsCount" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "PermissionInheritedItemsCount" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "SiteUrl" -NotePropertyValue $site.Url
            $libraryAccessItem | Add-Member -NotePropertyName "ListUrl" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "ServerRelativeUrl" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "LinkType" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "SharedLinkOrDirectAccess" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "DirectPermissionType" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "Users" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "Owners" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "SiteTemplate" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "Status" -NotePropertyValue "ProcessedExcludedSite"
            $libraryAccessItem | Add-Member -NotePropertyName "ErrorMessage" -NotePropertyValue ""
    
            # save row in CSV
            $libraryAccessItem | Export-CSV $reportOutput -Append -NoTypeInformation
        }
    } else {
        break
    }
    
    LogEntry("Sharing Links Report Generated Successfully $reportOutput")
    LogEntry("FINISHED")

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745569233a4633580.html

相关推荐

  • Slow PowerShell script performance optimalisation - Stack Overflow

    I try to loop into all SharePoint sites, libraries, folders and documents and check which one are share

    20小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信