All scripts
Microsoft 365 634

SharePoint Modern Pages Inventory Report

Lists every modern page across a set of SharePoint sites using PnP.PowerShell, with author, publish status, and last modified date, exported to CSV so you can find stale or orphaned pages.

Get-SharePointModernPagesInventory.ps1
<#
.SYNOPSIS
    Lists modern pages across one or more SharePoint sites and exports the results to CSV.

.DESCRIPTION
    Connects to each site with PnP.PowerShell, reads the Site Pages library, and pulls
    the title, author, created date, last modified date, and publish status for every
    modern page. Useful for finding pages nobody has touched in years, or for checking
    who actually owns a given page before you go and edit or delete it.

.AUTHOR
    Shehryar Hassan

.EXAMPLE
    .\Get-SharePointModernPagesInventory.ps1 -SiteUrls "https://contoso.sharepoint.com/sites/Intranet","https://contoso.sharepoint.com/sites/HR" -OutputPath "C:\Reports\ModernPages.csv"
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)]
    [string[]]$SiteUrls,

    [Parameter(Mandatory = $false)]
    [string]$OutputPath = ".\SharePointModernPages_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
)

if (-not (Get-Module -ListAvailable -Name PnP.PowerShell)) {
    Write-Error "PnP.PowerShell module is not installed. Run: Install-Module PnP.PowerShell -Scope CurrentUser"
    return
}

Import-Module PnP.PowerShell -ErrorAction Stop

$results = New-Object System.Collections.Generic.List[Object]

foreach ($siteUrl in $SiteUrls) {
    Write-Host "Connecting to $siteUrl ..." -ForegroundColor Cyan

    try {
        Connect-PnPOnline -Url $siteUrl -Interactive -ErrorAction Stop
    }
    catch {
        Write-Warning "Could not connect to $siteUrl, skipping. $($_.Exception.Message)"
        continue
    }

    try {
        $pages = Get-PnPListItem -List "Site Pages" -PageSize 500 -ErrorAction Stop
    }
    catch {
        Write-Warning "Could not read Site Pages library for $siteUrl, skipping. $($_.Exception.Message)"
        continue
    }

    foreach ($page in $pages) {
        $fieldValues = $page.FieldValues

        $publishStatus = if ($fieldValues["_ModerationStatus"] -eq 0) { "Published" } else { "Not published" }

        $results.Add([PSCustomObject]@{
            SiteUrl       = $siteUrl
            PageName      = $fieldValues["FileLeafRef"]
            Title         = $fieldValues["Title"]
            Author        = $fieldValues["Author"].LookupValue
            Editor        = $fieldValues["Editor"].LookupValue
            Created       = $fieldValues["Created"]
            Modified      = $fieldValues["Modified"]
            PublishStatus = $publishStatus
        })
    }

    Disconnect-PnPOnline
}

if ($results.Count -eq 0) {
    Write-Warning "No pages found across the sites provided."
    return
}

$results | Sort-Object SiteUrl, Modified | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8

Write-Host "Exported $($results.Count) pages to $OutputPath" -ForegroundColor Green

Read it before you run it, and test in a safe tenant first.