This article provides a PowerShell script to help you verify where BindTuning products, including both Design (themes) and Build (web part) features, are installed across your SharePoint Online tenant. This script automates the process of checking each site collection, saving you time and effort.
Before you begin
Before running the PowerShell script, ensure you meet the following prerequisites:
Windows PowerShell v4.0 (or above)
SharePoint PnP PowerShell cmdlets
Windows Management Framework
Note: If these prerequisites are not met, the provided script is designed to prompt you for the necessary module installations or version upgrades.
Additionally, to ensure the script can access your SharePoint Administration Center, it must be run using a SharePoint (Tenant) Admin account.
Running the Script
Follow these steps to execute the PowerShell script:
Save the Script: Copy the entire PowerShell script provided below and paste it into a new file. Save this file with an
.ps1
extension (e.g.,GetBindTuningInstallations.ps1
).Execute the Script: Open PowerShell and navigate to the directory where you saved your
.ps1
file. Run the script.Provide Tenant Name: When prompted, enter your SharePoint tenant name. For example, if your tenant URL is
https://myTenant.sharepoint.com
, you should inputmyTenant
.
β
The script will then run automatically, listing all present site collections in your tenant and the corresponding number of BindTuning applications installed on each.
The PowerShell Script
clspushd (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