SharePoint PnP: get all sites and subsites in tenant / web app

I wanted to use SharePoint PnP to get all the sites and subsites in a web application (on-premises).  I decided to use search, similar to how a user named Unnie solved it here with CSOM.

Script code

$creds = "MyPnPScriptConnectionCredentials"; # <-- arbitrary name
$url = "https://webappofinterest.domain.com"; # <-- SP on-prem web app of interest

$cnx = Connect-PnPOnline `
    -Credentials $creds `
    -UseAdfs `
    -Url $url `
    -ReturnConnection;

$qry = Submit-PnPSearchQuery `
    -Connection $cnx `
    -Query "Path:$url AND ((ContentClass:STS_Site) OR (ContentClass:STS_Web))" `
    -All `
    -TrimDuplicates:$false;

$sites = $qry.ResultRows | % { $_.Path } | Sort-Object;
$sites;

Setup steps

  1. Installed SharePointPnPPowerShell{2013|2016|2019} while logged in as the user account that the script runs under.  (I downloaded PnP from here.)
  2. Cached one set of credentials in Credential Manager in Windows so that I could run the script without saving sensitive info in there…  Went to Control Panel – User Accounts – Credential Manager.  Scrolled to the Generic Credentials section.  Added generic credentials as follows:
    • Internet or network address = MyPnPScriptConnectionCredentials
    • User name = DOMAIN\FarmSearchCrawlAccount
    • Password = {password for farm search crawler account}
  3. Made sure that the farm search crawler account was the default content access account in the Search Service Application, which is found on the Search Administration page under System Status in Central Admin.

Issues seen and solved

I encountered errors about “collection has not been initialized”, “it may need to be explicitly requested”, etc.  To solve this, I had to:

  1. Assign the result of the PnP commands to PowerShell variables.
  2. Use the correct PnP distribution to match the SharePoint on-premises version.  (I had thought that I could use 2019 for 2019, 2016 and 2013, for instance, but that resulted in inexplicable nonsensical errors.)

Footnote

In SharePoint Online PnP, there exists a Get-PnPSubWebs cmdlet that is part of the SharePointPnPPowerShellOnline distribution.