Using PowerShell To retrieve all Sites (Web Object) recursively from SharePoint Online

Introduction

When you deploy a solution for SharePoint Online (SPO), sometimes, you need to apply some post – configurations and need to iterate through all sites and sub-sites in a given Site Collection. In general talking about Office 365, there is more frequent the use of PowerShell to solve some kind of processes automation.

If you google about this topic, there are a lot of ways to achieve this, from server code doing some SPWeb.AllWebs to some JavaScript code, but in this scenario I will do using CSOM (Client Side Object Model) and PowerShell. On this way, this method could be valid to use in SharePoint Online and SharePoint 2013 OnPrem.

Code

I’d like to share a PowerShell function and script that uses “Recursion” to achieve this task:

function Log{
[CmdletBinding()]
Param
(
[string] $text,
[string] $ForegroundColor
)
$text | Out-File -FilePath $logFilePath -Append
if (!$ForegroundColor){
$ForegroundColor = (get-host).ui.rawui.ForegroundColor;
}
Write-Host $text -ForegroundColor $ForegroundColor
}
function AuthenticateUserProfile($siteUrl, $tenantAdmin, $secureAdminPassword) {
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($tenantAdmin, $secureAdminPassword)
$ctx.Credentials = $credentials
return $ctx
}
function LoadDlls ($folder){
#In this program I assume the DLLS are in a subfolder called DLLs in the same path the sript is.
Add-Type -Path "$folder\Microsoft.SharePoint.Client.dll"
Add-Type -Path "$folder\Microsoft.SharePoint.Client.Runtime.dll"
}
# Recursive function to iterate all sites and subsites in all levels
function RecursiveWebs($ctx, $web, $l){
$l++;
$start = "";
for ($i = 0 ; $i -le $l ; $i++){
$start += " ";
}
#$lText = $start + "Level: " + $l ;
#Log $lText
$counter = 1;
foreach($w in $web.Webs)
{
$url = $start + $l + "." + $counter + ": " + $w.Url;
Log $url -ForegroundColor Green;
$ctx.Load($w.Webs);
$ctx.ExecuteQuery();
if ($w.Webs.Count -gt 0){
#$text = $start + "Has " + $w.Webs.Count + " subsite/s."
#Log $text
RecursiveWebs $ctx $w $l
}
$counter++
}
}
# Configuration Parameters
$tenantAdmin = "user@domain.onmicrosoft.com"
$tenantAdminPassword = "pass"
$siteCollectionUrl = "https://domain.sharepoint.com/sites/intranet"
$secureAdminPassword = $(convertto-securestring $tenantAdminPassword -asplaintext -force)
$importFolderPath = Split-Path -parent $PSCommandPath;
$LogTime = Get-Date -Format "MM-dd-yyyy_hh"
$logFilePath = $importFolderPath + "\Output"+$LogTime+".log"
# Main
try
{
Log "Loading Dlls" -ForegroundColor Blue
$dllsPath = $importFolderPath + "\DLLs"
LoadDlls $dllsPath
Log " - Done" -ForegroundColor Green
Log "Connecting SPO" -ForegroundColor Blue
$ctx = AuthenticateUserProfile $siteCollectionUrl $tenantAdmin $secureAdminPassword;
Log " - Done" -ForegroundColor Green
$level = 1;
$web = $ctx.Web
$ctx.Load($web)
$ctx.ExecuteQuery()
#$lText = "Level: " + $level;
#Log $lText;
Log "Root Site"
$url = "1:" + $web.Url
Log $url -ForegroundColor Green
$ctx.Load($web.Webs)
$ctx.ExecuteQuery()
if ($web.Webs.Count -gt 0){
#$text = "Has " + $web.Webs.Count + " subsite/s."
#Log $text
RecursiveWebs $ctx $web $level
}
}
catch
{
Log "`n[Main] Errors found:`n$_" -ForegroundColor Red
}

One important consideration is I assumed the DLLS are in a subfolder called DLLs in the same path the PowerShell script is.

Download code

You can download the full script: PS.IterateAllWebsRecursively.zip

 

Author: José Quinto
Link: https://blog.josequinto.com/2016/03/17/using-powershell-to-retrieve-all-sites-web-object-recursively-from-sharepoint-online/
Copyright Notice: All articles in this blog are licensed under CC BY-SA 4.0 unless stating additionally.