Public/Export-M365SharingReport.ps1
|
function Export-M365SharingReport { <# .SYNOPSIS Generates an HTML report of SharePoint sites and their external sharing setting. .DESCRIPTION Lists SharePoint Online sites with their SharingCapability (external sharing posture) and storage usage. Read-only. Requires a SharePoint Online connection (Connect-SPOService); if missing, the report is created empty with a note. .PARAMETER Path Target path of the HTML file. Default: .\Sharing-Report.html .EXAMPLE Export-M365SharingReport -BrandName 'CloudNest365' #> [CmdletBinding()] [OutputType([pscustomobject])] param( [string]$Path = (Join-Path (Get-Location) 'Sharing-Report.html'), [string]$BrandName = 'TenantToolbox', [string]$BrandTagline = 'M365 Tenant Administration', [switch]$Csv, [switch]$Excel, [string]$DataPath, [switch]$NoHtml, [switch]$PassThru, [switch]$NoOpen ) $data = @(); $spoOk = $true try { Assert-TTSpo } catch { $spoOk = $false; Write-Warning $_ } $capLabel = @{ Disabled = @{ t = 'Internal only'; c = 'b-ok' } ExistingExternalUserSharingOnly = @{ t = 'Existing guests'; c = 'b-info' } ExternalUserSharingOnly = @{ t = 'New guests'; c = 'b-warn' } ExternalUserAndGuestSharing = @{ t = 'Anyone (anonymous)'; c = 'b-bad' } } if ($spoOk) { Write-TTLog -Level INFO -Message "Reading SharePoint sites (SPO) ..." $sites = Get-SPOSite -Limit All -ErrorAction Stop $data = foreach ($s in $sites) { [pscustomobject]@{ Title = $s.Title; Url = $s.Url; Sharing = [string]$s.SharingCapability; StorageMB = [int]$s.StorageUsageCurrent } } $data = @($data) } $total = $data.Count $anon = @($data | Where-Object { $_.Sharing -eq 'ExternalUserAndGuestSharing' }).Count $external = @($data | Where-Object { $_.Sharing -in 'ExternalUserSharingOnly', 'ExternalUserAndGuestSharing', 'ExistingExternalUserSharingOnly' }).Count $genAt = Get-Date -Format 'yyyy-MM-dd HH:mm'; $tenant = try { (Get-MgContext).TenantId } catch { '' } $rows = foreach ($s in ($data | Sort-Object @{E = { switch ($_.Sharing) { 'ExternalUserAndGuestSharing' { 0 } 'ExternalUserSharingOnly' { 1 } 'ExistingExternalUserSharingOnly' { 2 } default { 3 } } } }, Title)) { $cap = if ($capLabel.ContainsKey($s.Sharing)) { $capLabel[$s.Sharing] } else { @{ t = $s.Sharing; c = 'b-info' } } $fAnon = if ($s.Sharing -eq 'ExternalUserAndGuestSharing') { '1' } else { '0' } $fExt = if ($s.Sharing -in 'ExternalUserSharingOnly', 'ExternalUserAndGuestSharing', 'ExistingExternalUserSharingOnly') { '1' } else { '0' } $stor = if ($s.StorageMB -ge 1024) { "$([math]::Round($s.StorageMB/1024,1)) GB" } else { "$($s.StorageMB) MB" } $searchAttr = TTEnc ("$($s.Title) $($s.Url)".ToLower()); $nameAttr = TTEnc ([string]$s.Title).ToLower() @" <tr class="item" data-f-anon="$fAnon" data-f-external="$fExt" data-name="$nameAttr" data-search="$searchAttr"> <td><div class="u"><b>$(TTEnc $s.Title)</b><span class="upn">$(TTEnc $s.Url)</span></div></td> <td><span class="b $($cap.c)">$(TTEnc $cap.t)</span></td><td>$stor</td> </tr> "@ } $kpiHtml = New-TTKpis @( @{ n = $total; l = 'Sites'; filter = 'all' } @{ n = $external; l = 'External sharing'; kind = 'warn'; filter = 'external' } @{ n = $anon; l = 'Anonymous links'; kind = 'bad'; filter = 'anon' } ) $toolbar = New-TTToolbar -SearchPlaceholder 'Search site ...' -Filters @( @{ label = 'All'; key = 'all' }, @{ label = 'External'; key = 'external' }, @{ label = 'Anonymous'; key = 'anon' } ) $note = if (-not $spoOk) { '<p class="muted" style="padding:0 0 12px">Not connected to SharePoint Online. Run Connect-SPOService -Url https://<tenant>-admin.sharepoint.com, then re-run this report.</p>' } else { '' } $body = @" $note <div class="panel"><table class="tbl"><thead><tr><th data-sort="name">Site</th><th>External sharing</th><th>Storage</th></tr></thead> <tbody> $($rows -join "`n") </tbody></table><div class="empty" id="empty">No site matches the filters.</div></div> "@ $html = New-TTHtmlPage -Title 'SharePoint Sharing' -Heading 'SharePoint External Sharing' -Sub "Tenant $tenant · generated $genAt · $total sites" ` -BrandName $BrandName -BrandTagline $BrandTagline -KpiHtml $kpiHtml -ToolbarHtml $toolbar -BodyHtml $body Write-TTLog -Level INFO -Message "Sharing report created: $Path ($total sites, $anon anonymous)." $flat = $data | Select-Object Title, Url, Sharing, StorageMB Complete-TTReport -Html $html -Path $Path -Data $flat -Csv:$Csv -Excel:$Excel -DataPath $DataPath -NoHtml:$NoHtml -NoOpen:$NoOpen -Kind 'Sharing-Report' if ($PassThru) { $data } } |