Private/Collect/Get-TcSharePointCollector.ps1
|
function Get-TcSharePointCollector { <# .SYNOPSIS Lists the SharePoint and OneDrive collectors, in the order they run. #> [CmdletBinding()] [OutputType([hashtable])] param() @( @{ Id = 'SPO-01' Workload = 'SharePoint and OneDrive' Title = 'SharePoint and OneDrive tenant settings' Service = 'Pnp' Collect = { Add-TcTable 'sharePointSettings' @(ConvertTo-TcSettingRow (Get-PnPTenant -Connection $script:TcPnpConnection -ErrorAction Stop)) Invoke-TcCollectorPart 'App catalog and home site' { $p = @([ordered]@{ 'Type' = 'App catalog' 'Name' = [string](Get-PnPTenantAppCatalogUrl -Connection $script:TcPnpConnection -ErrorAction Stop) 'Detail' = '' }) try { $h = Get-PnPHomeSite -Connection $script:TcPnpConnection -ErrorAction Stop; if ($h) { $p += [ordered]@{ 'Type' = 'Home site' 'Name' = [string]$h 'Detail' = '' } } } catch { Add-TcCollectorWarning 'Home site' $_ } Add-TcTable 'sharePointCustomizations' -Append $p } } } @{ Id = 'SPO-02' Workload = 'SharePoint and OneDrive' Title = 'SharePoint sites (all templates)' Service = 'Pnp' Collect = { $p = @{ Connection = $script:TcPnpConnection; ErrorAction = 'Stop' } if ($script:TcDepth -eq 'Complete') { $p['Detailed'] = $true } $s = @(Get-PnPTenantSite @p) Add-TcTable 'sites' @(foreach ($x in $s) { $u = [uri](Get-TcProperty $x 'Url') [ordered]@{ 'Url' = (Get-TcProperty $x 'Url') 'Path' = (Get-TcProperty $u 'AbsolutePath').TrimEnd('/').ToLowerInvariant() 'Title' = (Get-TcProperty $x 'Title') 'Template' = (Get-TcProperty $x 'Template') 'Storage MB' = [double](Get-TcSafeProperty $x 'StorageUsageCurrent' 0) 'Quota MB' = [double](Get-TcSafeProperty $x 'StorageQuota' 0) 'Last modified' = (Format-TcValue (Get-TcSafeProperty $x 'LastContentModifiedDate')) 'Days inactive' = (Get-TcDaysSince (Get-TcSafeProperty $x 'LastContentModifiedDate')) 'Sharing' = [string](Get-TcSafeProperty $x 'SharingCapability') 'Lock state' = [string](Get-TcSafeProperty $x 'LockState') 'Owner' = (Get-TcSafeProperty $x 'Owner') 'Group' = $(if ([string](Get-TcSafeProperty $x 'GroupId') -notmatch '^(00000000-|$)') { [string](Get-TcProperty $x 'GroupId') }) 'Teams' = [bool](Get-TcSafeProperty $x 'IsTeamsConnected' $false) 'Hub' = [bool](Get-TcSafeProperty $x 'IsHubSite' $false) 'Hub association' = $(if ([string](Get-TcSafeProperty $x 'HubSiteId') -notmatch '^(00000000-|$)') { [string](Get-TcProperty $x 'HubSiteId') }) 'Label' = [string](Get-TcSafeProperty $x 'SensitivityLabel') 'Custom scripts' = ([string](Get-TcSafeProperty $x 'DenyAddAndCustomizePages') -eq 'Disabled') 'Language' = (Get-TcSafeProperty $x 'LocaleId') } }) Invoke-TcCollectorPart 'Hub sites' { $sites = Get-TcTable 'sites' Add-TcTable 'hubSites' @(foreach ($h in @(Get-PnPHubSite -Connection $script:TcPnpConnection -ErrorAction Stop)) { $id = [string](Get-TcSafeProperty $h 'Id') [ordered]@{ 'Title' = (Get-TcProperty $h 'Title') 'Url' = (Get-TcProperty $h 'SiteUrl') 'Associated sites' = @($sites | Where-Object { (Get-TcProperty $_ 'Hub association') -eq $id -and (Get-TcProperty $_ 'Url') -ne (Get-TcProperty $h 'SiteUrl') }).Count } }) } } } @{ Id = 'SPO-03' Workload = 'SharePoint and OneDrive' Title = 'OneDrive accounts' Service = 'Pnp' Collect = { Add-TcTable 'oneDrive' @(foreach ($x in @(Get-PnPTenantSite -IncludeOneDriveSites -Filter "Url -like '-my.sharepoint.com/personal/'" -Connection $script:TcPnpConnection -ErrorAction Stop)) { [ordered]@{ 'Url' = (Get-TcProperty $x 'Url') 'Owner' = (Get-TcSafeProperty $x 'Owner') 'Storage MB' = [double](Get-TcSafeProperty $x 'StorageUsageCurrent' 0) 'Quota MB' = [double](Get-TcSafeProperty $x 'StorageQuota' 0) 'Last modified' = (Format-TcValue (Get-TcSafeProperty $x 'LastContentModifiedDate')) 'Days inactive' = (Get-TcDaysSince (Get-TcSafeProperty $x 'LastContentModifiedDate')) 'Lock state' = [string](Get-TcSafeProperty $x 'LockState') } }) } } @{ Id = 'SPO-04' Workload = 'SharePoint and OneDrive' Title = 'Customizations: templates, scripts, SPFx, assets' Service = 'Pnp' Collect = { $c = $script:TcPnpConnection Invoke-TcCollectorPart 'Site designs' { Add-TcTable 'sharePointCustomizations' -Append @(foreach ($d in @(Get-PnPSiteDesign -Connection $c -ErrorAction Stop)) { [ordered]@{ 'Type' = 'Site design' 'Name' = (Get-TcProperty $d 'Title') 'Detail' = [string](Get-TcProperty $d 'WebTemplate') } }) } Invoke-TcCollectorPart 'Site scripts' { Add-TcTable 'sharePointCustomizations' -Append @(foreach ($d in @(Get-PnPSiteScript -Connection $c -ErrorAction Stop)) { [ordered]@{ 'Type' = 'Site script' 'Name' = (Get-TcProperty $d 'Title') 'Detail' = '' } }) } Invoke-TcCollectorPart 'Catalog apps (SPFx)' { $apps = @() try { $apps = @(Get-PnPApp -Scope Tenant -Connection $c -ErrorAction Stop) } catch { if ((Get-TcErrorText $_) -match 'ResourceNotFound|tenantappcatalog') { Add-TcCollectorNote 'No tenant app catalog (SPFx): nothing to migrate here.' } else { throw } } Add-TcTable 'sharePointCustomizations' -Append @(foreach ($a in $apps) { [ordered]@{ 'Type' = 'SPFx app' 'Name' = (Get-TcProperty $a 'Title') 'Detail' = ('deployed {0} - version {1}' -f (Get-TcProperty $a 'Deployed'), (Get-TcProperty $a 'AppCatalogVersion')) } }) } Invoke-TcCollectorPart 'Asset libraries' { $o = Get-PnPOrgAssetsLibrary -Connection $c -ErrorAction Stop; if ($o) { Add-TcTable 'sharePointCustomizations' -Append @([ordered]@{ 'Type' = 'Asset library' 'Name' = (Format-TcValue $o) 'Detail' = '' }) } } Invoke-TcCollectorPart 'Term store' { Add-TcTable 'termStore' @(foreach ($g in @(Get-PnPTermGroup -Connection $c -ErrorAction Stop)) { $isSystem = [bool](Get-TcSafeProperty $g 'IsSystemGroup' $false) -or [bool](Get-TcSafeProperty $g 'IsSiteCollectionGroup' $false) foreach ($termSet in @(Get-PnPTermSet -TermGroup (Get-TcProperty $g 'Name') -Connection $c -ErrorAction Stop)) { $n = $null; try { $n = @(Get-PnPTerm -TermSet (Get-TcProperty $termSet 'Name') -TermGroup (Get-TcProperty $g 'Name') -Connection $c -ErrorAction Stop).Count } catch { Add-TcCollectorWarning "Terms of $(Get-TcProperty $termSet 'Name')" $_ } [ordered]@{ 'Group' = (Get-TcProperty $g 'Name') 'Term set' = (Get-TcProperty $termSet 'Name') 'Terms' = $n 'System or collection' = $isSystem } } }) } if (-not @(Get-TcTable 'sharePointCustomizations').Count) { Add-TcTable 'sharePointCustomizations' @() } } } @{ Id = 'SPO-05' Workload = 'SharePoint and OneDrive' Title = 'Site and OneDrive usage (Microsoft 365 reports)' Service = 'Graph' Collect = { Invoke-TcCollectorPart 'Site usage' { Add-TcTable 'siteUsage' @(foreach ($r in Get-TcUsageReport 'getSharePointSiteUsageDetail' | Where-Object { (Get-TcProperty $_ 'Is Deleted') -ne 'True' }) { [ordered]@{ 'Url' = (Get-TcProperty $r 'Site URL') 'Owner' = (Get-TcProperty $r 'Owner Principal Name') 'Template' = (Get-TcProperty $r 'Root Web Template') 'Files' = [long]('0' + (Get-TcProperty $r 'File Count')) 'Active files' = [long]('0' + (Get-TcProperty $r 'Active File Count')) 'Storage GB' = (ConvertTo-TcGigabyte (Get-TcProperty $r 'Storage Used (Byte)')) 'Page views' = [long]('0' + (Get-TcProperty $r 'Page View Count')) 'Last activity' = (Get-TcProperty $r 'Last Activity Date') } }) } Invoke-TcCollectorPart 'OneDrive usage' { Add-TcTable 'oneDriveUsage' @(foreach ($r in Get-TcUsageReport 'getOneDriveUsageAccountDetail' | Where-Object { (Get-TcProperty $_ 'Is Deleted') -ne 'True' }) { [ordered]@{ 'Url' = (Get-TcProperty $r 'Site URL') 'Owner' = (Get-TcProperty $r 'Owner Principal Name') 'Files' = [long]('0' + (Get-TcProperty $r 'File Count')) 'Active files' = [long]('0' + (Get-TcProperty $r 'Active File Count')) 'Storage GB' = (ConvertTo-TcGigabyte (Get-TcProperty $r 'Storage Used (Byte)')) 'Last activity' = (Get-TcProperty $r 'Last Activity Date') } }) } } } @{ Id = 'SPO-06' Workload = 'SharePoint and OneDrive' Title = 'Per-site detail: lists and libraries' Service = 'Graph' Depth = 'Complete' Requires = @('sites') Collect = { $excludedTemplates = '^(REDIRECTSITE|SRCHCEN|SPSMSITEHOST|APPCATALOG|POINTPUBLISHINGHUB|EDISC|SPSPERS|RedirectSite)' $sites = @(Limit-TcCollectorRow 'sites' @(Get-TcTable 'sites' | Where-Object { [string](Get-TcProperty $_ 'Template') -notmatch $excludedTemplates }) ([int](Get-TcCollectionSetting 'maxSiteDetails'))) if (-not $sites.Count) { Add-TcCollectorNote 'No site to detail.'; Add-TcTable 'libraries' @(); return } $denied = 0; $n = 0 Add-TcTable 'libraries' @(foreach ($s in $sites) { $n++ if ($n % 25 -eq 0) { Write-TcMessage -Message ('Sites detailed: {0}/{1}' -f $n, $sites.Count) } try { $u = [uri](Get-TcProperty $s 'Url'); $sitePath = (Get-TcProperty $u 'AbsolutePath').TrimEnd('/') $id = (Get-TcProperty (Get-TcGraphObject $(if ($sitePath) { "v1.0/sites/$(Get-TcProperty $u 'Host'):$sitePath`?`$select=id" } else { "v1.0/sites/$(Get-TcProperty $u 'Host')?`$select=id" })) 'id') $drives = @{}; foreach ($d in Get-TcGraphList "v1.0/sites/$id/drives?`$select=name,webUrl,quota") { $drives[[string](Get-TcProperty $d 'webUrl')] = $d } foreach ($l in Get-TcGraphList "v1.0/sites/$id/lists?`$select=displayName,list,lastModifiedDateTime,webUrl&`$top=200") { if ((Get-TcProperty (Get-TcProperty $l 'list') 'hidden')) { continue } $d = $drives[[string](Get-TcProperty $l 'webUrl')] [ordered]@{ 'Site' = (Get-TcProperty $s 'Url') 'List' = (Get-TcProperty $l 'displayName') 'Template' = (Get-TcProperty (Get-TcProperty $l 'list') 'template') 'Size MB' = $(if ($d) { [math]::Round([double](Get-TcProperty (Get-TcProperty $d 'quota') 'used') / 1MB, 1) }) 'Last modified' = (Format-TcValue (Get-TcProperty $l 'lastModifiedDateTime')) } } } catch { $denied++; if ($denied -le 3) { Add-TcCollectorWarning "Site detail $(Get-TcProperty $s 'Url')" $_ } } }) if ($denied) { Add-TcCollectorNote ('{0} of {1} sites could not be read with delegated access: the full detail needs the read-only application (Sites.Read.All) or site collection administrator rights.' -f $denied, $sites.Count) } } } @{ Id = 'SPO-07' Workload = 'SharePoint and OneDrive' Title = 'SharePoint and OneDrive external users' Service = 'Pnp' Collect = { $max = [int](Get-TcCollectionSetting 'maxExternalUsers'); $position = 0; $l = [System.Collections.Generic.List[object]]::new() do { try { $page = @(Get-PnPExternalUser -PageSize 50 -Position $position -Connection $script:TcPnpConnection -ErrorAction Stop) } catch { if ($position -gt 0 -and (Get-TcErrorText $_) -match 'position') { break }; throw } # The next page is empty. foreach ($u in $page) { $l.Add([ordered]@{ 'Name' = (Get-TcProperty $u 'DisplayName') 'Email' = (Get-TcProperty $u 'Email') 'Accepted as' = (Get-TcProperty $u 'AcceptedAs') 'Invited by' = (Get-TcProperty $u 'InvitedBy') 'Created' = (Format-TcValue (Get-TcProperty $u 'WhenCreated')) }) } $position += 50 } while ($page.Count -eq 50 -and $l.Count -lt $max) if ($page.Count -eq 50 -and $l.Count -ge $max) { Add-TcCollectorLimit ('only the first {0} external users were read, there may be more.' -f $l.Count) } Add-TcTable 'sharePointExternalUsers' $l } } ) } |