In some instances you may want to verify where, on your tenant, you have installed any BindTuning products, comprising both the Design (themes) and Build (web part) features.
Being that accessing each site collection and verifying its correspondent associated solutions, can be a daunting process, BindTuning has devised a PowerShell script that will allow you to loop through all your pre-existing site collections automatically, listing the concrete number of BindTuning products installed on your environment.
Note: This same script was devised to work with SharePoint Online tenants.
Before we begin
Before running the PowerShell script below, note that some pre-requisites may be appliable:
- Windows PowerShell v4.0 (or above)
- SharePoint PnP cmdlets;
- Windows Management Framework.
If, however, the pre-requisites are not fulfilled, the provided script will prompt you to proceed with the corresponding modules installation and/or version upgrade.
Likewise, and considering the script to access your SharePoint Administration Center, be sure to run it utilizing a SharePoint (Tenant) Admin account.
Running the script
After all the dependencies have been sorted out, proceed to copy the PowerShell script below, pasting it on a newly created file with the .ps1 extension, so as to create a file with the following naming convention myScriptName.ps1.
cls pushd (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent) $ErrorActionPreference = "Stop" $pnpRequiredVersion = [Version]"3.25.2009.1" $PnPBinFolder = "{0}\BTResources\" -f $env:temp $today = [DateTime]::UtcNow $reportsFolder = ".\Reports"; if(!(Test-Path $reportsFolder)) { New-Item -Path ".\Reports" -ItemType Directory | Out-Null } $fileReportPath = Join-Path $reportsFolder ("TENANT APP CATALOG_{0:yyyyMMdd-HHmmss}.log" -f $today) function Main(){ try{ checkPnPCmdlets #connecto to -admin $tenantName = Read-Host ("`nPlease enter the SharePoint Tenant name (https://[TENANT].sharepoint.com") $loginUrl = ("https://{0}-admin.sharepoint.com/" -f $tenantName) connectTo $loginUrl $webInfo = Get-PnPWeb $tenantApps = Get-PnPApp -Scope Tenant if($tenantApps.Count){ "***** Tenant App Catalog *****" | Out-File -FilePath $fileReportPath -Append -NoClobber $tenantApps.ForEach({[PSCustomObject]$_}) | Format-Table -AutoSize -Property Title, AppCatalogVersion | Out-File -FilePath $fileReportPath -Append -NoClobber } [System.Collections.ArrayList]$allSitesList = Get-PnPTenantSite $allSites = New-Object System.Collections.ArrayList $allSitesList | Where-Object { $_.Url -match $tenantName } | %{ $allSites.Add($_) | Out-Null } Write-Host ("Found {0} sites" -f $allSites.Count) foreach($site in $allSites){ Write-Host ($site.Url) $fileReportPath = Join-Path $reportsFolder ("{0}_{1:yyyyMMdd-HHmmss}.log" -f ($site.Url -replace "https://","" -replace "/","_"), $today) #connect on each site connectTo $site.Url try { $siteApps = Get-PnPApp -Scope Site Write-Host (" # {0} apps found" -f $siteApps.Count) if($siteApps.Count){ "-> Modern Apps <-" | Out-File -FilePath $fileReportPath -Append -NoClobber $siteApps.ForEach({[PSCustomObject]$_}) | Format-Table -AutoSize -Property Title, AppCatalogVersion | Out-File -FilePath $fileReportPath -Append -NoClobber } } catch { #no app catalog if($_.ErrorDetails.Message -match "Attempted to perform an unauthorized operation.") { Write-Host (" # Unauthorized - The user does not have permissions to the site collection {0}" -f $site.Url) } else { Write-Host (" # No App Catalog found") } } if(!(isModern $site.Template)) { # get solutions $siteSolutions = $null $listPath = "/_catalogs/solutions/" $fieldsArr = @("FileLeafRef","SolutionId","Status","Created","Modified","SolutionTitle") try{ $siteSolutions = Get-PNPListItem -List $listPath -fields $fieldsArr Write-Host (" # {0} solutions found" -f $siteSolutions.Count) if($siteSolutions.Count){ "-> Classic Solutions <-" | Out-File -FilePath $fileReportPath -Append -NoClobber $siteSolutions.FieldValues.FileLeafRef | Format-Table -AutoSize | Out-File -FilePath $fileReportPath -Append -NoClobber } } catch { } } } } catch { errorMessage $_ closeWindow } Write-Host "`nProcess completed." closeWindow } function connectTo($loginUrl){ Write-Host ("- Connecting to: {0} ... " -f $loginUrl) -NoNewline #- Connect to site try{ $wpref = $WarningPreference $WarningPreference = 'SilentlyContinue' #check if was already connected if(isSharePointOnline $loginUrl){ Connect-PnPOnline -Url $loginUrl -NoTelemetry -useWebLogin }else{ try{ $connection = Get-PnPConnection } catch {} if($connection){ $loginUsername = $connection.PSCredential.UserName $secpasswd = $connection.PSCredential.Password $userCreds = New-Object System.Management.Automation.PSCredential ($loginUsername, $secpasswd) Connect-PnPOnline -Url $loginUrl -Credentials $userCreds -NoTelemetry } else { Connect-PnPOnline -Url $loginUrl -Credentials (Get-Credential) -NoTelemetry } } $WarningPreference = $wpref } catch { errorMessage "Unable to connect." } successMessage "Done" } function checkPnPCmdlets(){ $showPNPMenu = $false #check powershell version $PSversion = $PSVersionTable.PSVersion if(!$PSVersion){ cls errorMessage "`n* Unable to check installed PowerShell version (Requires Windows Management Framework v4.0 installed)." errorMessage ("`n* Use option 5 to download it and install.") $showPNPMenu = $true } elseif($PSVersion.Major -lt 4) { cls errorMessage ("`n* The installed PowerShell version is lower than the requirement (required: 4 or above , installed: {0})." -f $PSVersion) errorMessage ("`n* Use option 5 to download it and update.") $showPNPMenu = $true } #Check PnP Cmdlets if(!(Test-Path $PnPBinFolder)){ New-Item -Path $PnPBinFolder -Name "SharePointPnPPowerShellOnline" -ItemType "directory" | Out-Null } $PnPModule = ("{0}\SharePointPnPPowerShellOnline\{1}\SharePointPnPPowerShellOnline.psd1" -f $PnPBinFolder, $pnpRequiredVersion) if(Test-Path $PnPModule){ Import-Module -Name $PnPModule -Force -Verbose:$false -DisableNameChecking -WarningAction SilentlyContinue } $PNPCmdlets = Get-Module SharePointPnPPowerShellOnline if(!$PNPCmdlets){ cls errorMessage ("`n* SharePoint Patterns and Practices PowerShell Online (v$pnpRequiredVersion) Cmdlets not found to run this script.") errorMessage ("`n* Use option 1 to download them.") $showPNPMenu = $true } else { #check version if($PNPCmdlets[0].Version -lt $pnpRequiredVersion){ errorMessage ("`n* SharePoint Patterns and Practices (PnP) Cmdlets installed are not at the required version to run this script.") Write-Host ("`n* Latest version installed: {0}" -f ($PNPCmdlets[0].Version).ToString()) Write-Host ("* Required version: {0}" -f $pnpRequiredVersion.ToString()) [string] $option="0" if(($option = Read-Host "Proceed with the update? (Y)es or (N)o") -match 'y') { try{ Write-Host "`n* Downloading 'SharePointPnPPowerShellOnline' (v$pnpRequiredVersion) module ... " Save-Module SharePointPnPPowerShellOnline -path $PnPBinFolder -RequiredVersion $pnpRequiredVersion Menu } catch { throw $_ } } else { closeWindow } } } if($showPNPMenu){ errorMessage ("`nPlease, check the requirements before proceding with the installation.") # Menu Write-Host ("`n#--- Requirements ---#`n") Write-Host ("1 - Download SharePoint PnP PowerShell Online (v{0}) Cmdlets " -f $pnpRequiredVersion) -NoNewline Write-Host "(Required)" -BackgroundColor Yellow -ForegroundColor Black Write-Host "" Write-Host "2 - Open Windows Management Framework v4.0 download page " -NoNewline Write-Host "(Prerequisites - PowerShell version 4 or above )" -BackgroundColor Yellow -ForegroundColor Black Write-Host "" Write-Host "0 - Exit" [string] $option="0" $option = Read-Host "`nSelect option" switch($option){ "1" { Write-Host "`n* Downloading 'SharePointPnPPowerShellOnline' (v$pnpRequiredVersion) module ... " Save-Module SharePointPnPPowerShellOnline -path $PnPBinFolder -RequiredVersion $pnpRequiredVersion break } "2" { (New-Object -Com Shell.Application).Open('https://www.microsoft.com/en-us/download/details.aspx?id=40855'); checkPnPCmdlets; break } "0" { exit } default { cls } } } } function successMessage($message){ Write-Host $message -BackgroundColor Green -ForegroundColor Black } function errorMessage($message){ Write-Host $message -ForegroundColor Red } function warningMessage($message){ Write-Host $message -BackgroundColor Yellow -ForegroundColor Black } function isModern($webTemplate){ return (@("GROUP#0","SITEPAGEPUBLISHING#0","STS#3") -contains $webTemplate) } function isSharePointOnline($url){ return $url -match ".+?\.sharepoint.com" } function closeWindow(){ try{ Write-Host "Press any key to close this window." $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") } catch {} exit } & Main
While running the script, the only input necessary corresponds to your SharePoint tenant name. When prompted, provide the necessary information.
Considering a scenario where your tenant URL is similar to https://myTenant.sharepoint.com, be sure to input myTenant as the parameter.
The script will proceed to run automatically, listing all the present site collections, and their correlative number of installed BindTuning applications.
Comments