Created
December 7, 2023 18:44
-
-
Save joerodgers/2e29a650eb0dca9d1413090b44d8c3a1 to your computer and use it in GitHub Desktop.
Reports web part references on modern and classic pages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#requires -modules "PnP.PowerShell" | |
class WebPartReference | |
{ | |
[string] | |
$SiteUrl | |
[string] | |
$WebUrl | |
[string] | |
$FileName | |
[string] | |
$PageType | |
[string] | |
$Title | |
[string] | |
$WebPartId | |
[string] | |
$WebPartType | |
} | |
function Test-WebPartProperties | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$true)] | |
[string[]] | |
$PropertiesToCheck, | |
[parameter(Mandatory=$true)] | |
[System.Collections.Generic.Dictionary[string,object]] | |
$WebPartProperties | |
) | |
begin | |
{ | |
} | |
process | |
{ | |
foreach( $property in $PropertiesToCheck ) | |
{ | |
if( -not $WebPartProperties.ContainsKey( $property) ) | |
{ | |
return $false | |
} | |
} | |
return $true | |
} | |
end | |
{ | |
} | |
} | |
function Get-ModernWebPartType | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$true)] | |
[Guid] | |
$WebPartId | |
) | |
begin | |
{ | |
} | |
process | |
{ | |
$mappings = @{ | |
"c4bd7b2f-7b6e-4599-8485-16504575f590" = "Hero" | |
"8c88f208-6c77-4bdb-86a0-0c47b4316588" = "News" | |
"a5df8fdf-b508-4b66-98a6-d83bc2597f63" = "Newsreel" | |
"af8be689-990e-492a-81f7-ba3e4cd3ed9c" = "ImageGallery" | |
"c70391ea-0b10-4ee9-b2b4-006d3fcad0cd" = "QuickLinks" | |
"daf0b71c-6de8-4ef7-b511-faae7c388708" = "ContentRollup" | |
"eb95c819-ab8f-4689-bd03-0c2d65d47b1f" = "SiteActivity" | |
"20745d7d-8581-4a6c-bf26-68279bc123fc" = "Events" | |
"f6fdf4f8-4a24-437b-a127-32e66a5dd9b4" = "Twitter" | |
"275c0095-a77e-4f6d-a2a0-6a7626911518" = "Stream" | |
"cb3bfe97-a47f-47ca-bffb-bb9a5ff83d75" = "Yammer" | |
"7cba020c-5ccb-42e8-b6fc-75b3149aba7b" = "Sites" | |
"b519c4f1-5cf7-4586-a678-2f1c62cc175a" = "RecentDocuments" | |
"cbe7b0a9-3504-44dd-a3a3-0e5cacd07788" = "TitleRegion" | |
"e84a8ca2-f63c-4fb9-bc0b-d8eef5ccb22b" = "OrganizationChart" | |
"2f3b693c-1054-419c-af04-fee2782b414f" = "OfficeFeed" | |
"d0a64d22-555c-44e4-b120-aed62c263632" = "CompanyFeed" | |
"e377ea37-9047-43b9-8cdb-a761be2f8e09" = "BingMap" | |
"6410b3b6-d440-4663-8744-378976dc041e" = "LinkPreview" | |
"58fcd18b-e1af-4b0a-b23b-422c2c52d5a2" = "PowerBIReportEmbed" | |
"91a50c94-865f-4f5c-8b4e-e49659e69772" = "QuickChart" | |
"6676088b-e28e-4a90-b9cb-d0d0303cd2eb" = "GroupCalendar" | |
"f92bf067-bc19-489e-a556-7fe95f508720" = "List" | |
"7f718435-ee4d-431c-bdbf-9c4ff326f46e" = "People" | |
"71c19a43-d08c-4178-8218-4df8554c0b0e" = "CustomMessageRegion" | |
"2161a1c6-db61-4731-b97c-3cdb303f7cbb" = "Divider" | |
"b19b3b9e-8d13-4fec-a93c-401a091c0707" = "MicrosoftForms" | |
"8654b779-4886-46d4-8ffb-b5ed960ee986" = "Spacer" | |
"243166f5-4dc3-4fe2-9df2-a7971b546a0a" = "ClientWebPart" | |
"9d7e898c-f1bb-473a-9ace-8b415036578b" = "PowerApps" | |
"7b317bca-c919-4982-af2f-8399173e5a1e" = "CodeSnippet" | |
"cf91cf5d-ac23-4a7a-9dbc-cd9ea2a4e859" = "PageFields" | |
"868ac3c3-cad7-4bd6-9a1c-14dc5cc8e823" = "Weather" | |
"544dd15b-cf3c-441b-96da-004d5a8cea1d" = "YouTube" | |
"62cac389-787f-495d-beca-e11786162ef4" = "CountDown" | |
"a8cd4347-f996-48c1-bcfb-75373fed2a27" = "ListProperties" | |
"1ef5ed11-ce7b-44be-bc5e-4abd55101d16" = "MarkDown" | |
"39c4c1c2-63fa-41be-8cc2-f6c0b49b253d" = "Planner" | |
} | |
if( $mappings.ContainsKey( $WebPartId.ToString() ) ) | |
{ | |
return $mappings[$WebPartId.ToString()] | |
} | |
return $WebPartId.ToString() | |
} | |
end | |
{ | |
} | |
} | |
function Get-ClassicWebPartType | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$true)] | |
[System.Collections.Generic.Dictionary[string,object]] | |
$Properties | |
) | |
begin | |
{ | |
} | |
process | |
{ | |
# logic taken from https://github.com/pnp/pnpframework/blob/dev/src/lib/PnP.Framework/Modernization/Pages/BasePage.cs#L611 | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "ListUrl", "ListId", "Xsl", "JSLink", "ShowTimelineIfAvailable" ) | |
{ | |
return "XsltListView" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "ListViewXml", "ListName", "ListId", "ViewContentTypeId", "PageType" ) | |
{ | |
return "ListView" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "AutoPlay", "MediaSource", "Loop", "IsPreviewImageSourceOverridenForVideoSet", "PreviewImageSource" ) | |
{ | |
return "Media" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "LibraryGuid", "Layout", "Speed", "ShowToolbar", "ViewGuid" ) | |
{ | |
return "PictureLibrarySlideshow" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "ConnectionPointEnabled", "ChartXml", "DataBindingsString", "DesignerChartTheme" ) | |
{ | |
return "Chart" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "NumberLimit", "DisplayType", "MembershipGroupId", "Toolbar" ) | |
{ | |
return "Members" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "MinRuntimeVersion", "WindowlessMode", "CustomInitParameters", "Url", "ApplicationXml" ) | |
{ | |
return "Silverlight" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "FeatureId", "ProductWebId", "ProductId" ) | |
{ | |
return "Client" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "Content" ) | |
{ | |
return "ScriptEditor" | |
} | |
if( Test-WebPartProperties -WebPartProperties $Properties -PropertiesToCheck "CatalogIconImageUrl", "AllowEdit", "TitleIconImageUrl", "ExportMode" ) | |
{ | |
return "SPUserCode" | |
} | |
return "Unknown" | |
} | |
end | |
{ | |
} | |
} | |
function Get-ClassicSitePageWebPart | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$true,ValueFromPipeline=$true)] | |
[Microsoft.SharePoint.Client.ListItem] | |
$ListItem | |
) | |
begin | |
{ | |
} | |
process | |
{ | |
$webparts = Get-PnPWebPart -ServerRelativePageUrl $ListItem.FieldValues.FileRef -ErrorAction Stop | |
foreach( $webpart in $webparts ) | |
{ | |
$type = Get-ClassicWebPartType -Properties $webpart.WebPart.Properties.FieldValues | |
$wpr = [WebPartReference]::new() | |
$wpr.FileName = $ListItem.FieldValues.FileLeafRef | |
$wpr.PageType = "Classic" | |
$wpr.SiteUrl = "" | |
$wpr.Title = $webpart.WebPart.Title | |
$wpr.WebPartId = $webpart.Id | |
$wpr.WebUrl = "" | |
$wpr.WebPartType = $type | |
$wpr | |
} | |
} | |
end | |
{ | |
} | |
} | |
function Get-ModernSitePageWebPart | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$true,ValueFromPipeline=$true)] | |
[Microsoft.SharePoint.Client.ListItem] | |
$ListItem | |
) | |
begin | |
{ | |
} | |
process | |
{ | |
$webparts = Get-PnPPage -Identity $ListItem.FieldValues.FileLeafRef -ErrorAction Stop | Get-PnPPageComponent -ErrorAction Stop | |
foreach( $webpart in $webparts ) | |
{ | |
$type = Get-ModernWebPartType -WebPartId $webpart.WebPartId | |
$wpr = [WebPartReference]::new() | |
$wpr.FileName = $ListItem.FieldValues.FileLeafRef | |
$wpr.PageType = "Modern" | |
$wpr.SiteUrl = "" | |
$wpr.Title = $webpart.Title | |
$wpr.WebPartId = $webpart.WebPartId | |
$wpr.WebUrl = "" | |
$wpr.WebPartType = $type | |
$wpr | |
} | |
} | |
end | |
{ | |
} | |
} | |
function Get-SitePageWebPart | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$true,ParameterSetName="Site")] | |
[Microsoft.SharePoint.Client.Site] | |
$Site, | |
[parameter(Mandatory=$true,ParameterSetName="Web")] | |
[Microsoft.SharePoint.Client.Web] | |
$Web, | |
[parameter(Mandatory=$true,ParameterSetName="Item")] | |
[Microsoft.SharePoint.Client.ListItem] | |
$ListItem, | |
[parameter(Mandatory=$false)] | |
[switch] | |
$IncludeClassicPages | |
) | |
begin | |
{ | |
} | |
process | |
{ | |
if( $PSCmdlet.ParameterSetName -eq "Site" ) | |
{ | |
Write-Verbose "[$(Get-Date)] - Processing Site: $($Site.Url)" | |
$webs = Get-PnPSubWeb -Recurse -IncludeRootWeb | |
$webPartReferences = foreach( $web in $webs ) | |
{ | |
Get-SitePageWebPart -Web $web -IncludeClassicPages:$IncludeClassicPages.IsPresent | |
} | |
#foreach( $webPartReference in $webPartReferences ) | |
#{ | |
# $webPartReference.SiteUrl = $Site.Url | |
#} | |
return $webPartReferences | |
} | |
if( $PSCmdlet.ParameterSetName -eq "Web" ) | |
{ | |
Write-Verbose "[$(Get-Date)] - Processing Web: $($Web.Url)" | |
$connection = Get-PnPConnection | |
if( $connection.Url -ne $web.Url ) | |
{ | |
# connect to target web | |
Connect-PnPOnline ` | |
-Url $web.Url ` | |
-ClientId $connection.ClientId ` | |
-Thumbprint $connection.Certificate.Thumbprint ` | |
-Tenant $connection.Tenant ` | |
-ErrorAction Stop | |
} | |
$items = $null | |
# ran into a scenario where there was "SitePages" instead of "Site Pages" so look for both | |
if( $sitepages = Get-PnPList -Identity "Site Pages" ) | |
{ | |
$items = Get-PnPListItem -List $sitepages -PageSize 5000 | |
} | |
elseif( $sitepages = Get-PnPList -Identity "SitePages" ) | |
{ | |
$items = Get-PnPListItem -List $sitepages -PageSize 5000 | |
} | |
if( $null -ne $items ) | |
{ | |
$webPartReferences = foreach( $item in $items ) | |
{ | |
Write-Verbose "Getting parts on page: $($item.FieldValues.FileLeafRef)" | |
Get-SitePageWebPart -ListItem $item -IncludeClassicPages:$IncludeClassicPages.IsPresent | |
} | |
#foreach( $webPartReference in $webPartReferences ) | |
#{ | |
# $webPartReference.WebUrl = $Web.Url | |
#} | |
return $webPartReferences | |
} | |
return $null | |
} | |
if( $PSCmdlet.ParameterSetName -eq "Item" ) | |
{ | |
if( $ListItem.FieldValues["ClientSideApplicationId"] -eq "b6917cb1-93a0-4b97-a84d-7cf49975d4ec" ) | |
{ | |
Write-Verbose "[$(Get-Date)] - Processing modern page: $($ListItem.FieldValues.FileLeafRef)" | |
$results = Get-ModernSitePageWebPart -ListItem $ListItem | |
} | |
elseif( $IncludeClassicPages.IsPresent ) | |
{ | |
Write-Verbose "[$(Get-Date)] - Processing clasic page: $($ListItem.FieldValues.FileLeafRef)" | |
$results = Get-ClassicSitePageWebPart -ListItem $ListItem | |
} | |
$s = Get-PnPSite | |
$w = Get-PnPWeb | |
foreach( $result in $results ) | |
{ | |
$result.SiteUrl = $s.Url | |
$result.WebUrl = $w.Url | |
} | |
return $results | |
} | |
} | |
end | |
{ | |
} | |
} | |
# permissions required: SharePoint > Application > Sites.FullControl.All | |
Connect-PnPOnline ` | |
-Url "https://$env:O365_TENANT.sharepoint.com/sites/teamsite" ` | |
-ClientId $env:O365_CLIENTID ` | |
-Thumbprint $env:O365_THUMBPRINT ` | |
-Tenant $env:O365_TENANTID | |
# scan a web | |
$web = Get-PnPWeb | |
# $results = Get-SitePageWebPart -Web $web -IncludeClassicPages -Verbose | |
# scan an entire site | |
$site = Get-PnPSite | |
$results = Get-SitePageWebPart -Site $site -Verbose | |
# export results | |
$timestamp = Get-Date -Format FileDateTime | |
$results | Export-Csv -Path "WebPartInstances_$timestamp.csv" -NoTypeInformation | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment