Discover where are your BindTuning products installed

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.


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(){




        #connecto to -admin

        $tenantName = Read-Host ("`nPlease enter the SharePoint Tenant name (https://[TENANT]")

        $loginUrl = ("https://{0}" -f $tenantName)        


        connectTo $loginUrl

        $webInfo = Get-PnPWeb

        $tenantApps = Get-PnPApp -Scope Tenant


            "***** Tenant App Catalog *****" | Out-File -FilePath $fileReportPath -Append -NoClobber

            $tenantApps.ForEach({[PSCustomObject]$_}) | Format-Table -AutoSize -Property Title, AppCatalogVersion | Out-File -FilePath $fileReportPath -Append -NoClobber



        $allSites = Get-PnPTenantSite

        Write-Host ("Found {0} sites" -f $allSites.Count)


        foreach($site in $allSites){

            $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)


                    "-> 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(!(isModern $site.Template)) {

                # get solutions

                $siteSolutions = $null

                $listPath = "/_catalogs/solutions/"

                $fieldsArr = @("FileLeafRef","SolutionId","Status","Created","Modified","SolutionTitle")



                    $siteSolutions = Get-PNPListItem -List $listPath -fields $fieldsArr

                    Write-Host (" # {0} solutions found" -f $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 $_



    Write-Host "`nProcess completed."



function connectTo($loginUrl){

    Write-Host ("- Connecting to: {0} ... " -f $loginUrl) -NoNewline


    #- Connect to site


        $wpref = $WarningPreference

        $WarningPreference = 'SilentlyContinue'


        #check if was already connected


        if(isSharePointOnline $loginUrl){

            Connect-PnPOnline -Url $loginUrl -NoTelemetry -useWebLogin


            try{ $connection = Get-PnPConnection } catch {}



                $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



        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) { 


        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




        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') {


                    Write-Host "`n* Downloading 'SharePointPnPPowerShellOnline' (v$pnpRequiredVersion) module ... "

                    Save-Module SharePointPnPPowerShellOnline -path $PnPBinFolder -RequiredVersion $pnpRequiredVersion


                } catch {

                    throw $_


            } else {







        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"


            "1" { 

                Write-Host "`n* Downloading 'SharePointPnPPowerShellOnline' (v$pnpRequiredVersion) module ... "

                Save-Module SharePointPnPPowerShellOnline -path $PnPBinFolder -RequiredVersion $pnpRequiredVersion



            "2" { (New-Object -Com Shell.Application).Open(''); 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 ".+?\"


function closeWindow(){


        Write-Host "Press any key to close this window."

        $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

    } catch {}



& 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, 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. 




Have more questions? Submit a request


Powered by Zendesk