Skip to content

Commit

Permalink
Merge pull request #679 from reshmee011/uninstallSPFx
Browse files Browse the repository at this point in the history
Update to deploy Spfx sample and new sample to remove spfx package
  • Loading branch information
pkbullock authored Mar 24, 2024
2 parents 103d2c3 + 135b3b5 commit 9ac12e1
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@ At the time of submitting this script sample there is no concept of a hub site a

### Prerequisites

- The user account that runs the script must have SharePoint Online tenant administrator access.
- The user account that runs the script must have Global tenant administrator access. If running the script as SharePoint administrator the cmdlet "Approve-PnPTenantServicePrincipalPermissionRequest" will fail.

- Before running the script, edit the script and update the variable values in the Config Variables section, such as Admin Center URL, Hub Site URL, the CSV output file path and alternatively the sppkg packages Folder.
- Before running the script, edit the script and update the variable values in the Config Variables section, such as Admin Center URL, Hub Site URL, the CSV output file path and alternatively the sppkg packages Folder.

This script snippet automates the deployment and potential upgrades of SPFx packages across associated sites of a hub site, leveraging the tenant-level app catalog. It navigates through each associated site, checks for existing packages, installs or upgrades them as needed, and records the deployment details for reporting purposes.
This approach offers flexibility and control over SPFx solutions, ensuring targeted deployment and version management across your SharePoint environment.

The script does not cover admin consent to app permissions. A global administrator will have to grant admin consent if required by the SPFx solutions.

# [PnP PowerShell](#tab/pnpps)

Expand All @@ -34,86 +31,96 @@ $fileName = "\Log_Tenant-" + $dateTime + ".csv"
$OutPutView = $directorypath + $fileName
$sppkgFolder = "./packages"
$sppkgFolder = "./packages"
cd $PSScriptRoot
$packageFiles = Get-ChildItem $sppkgFolder
Connect-PnPOnline $tenantAppCatalogUrl -Interactive
$appCatConnection = Get-PnPConnection
$appCatConnection = Get-PnPConnection
Connect-PnPOnline $AdminCenterURL -Interactive
$adminConnection = Get-PnPConnection
$adminConnection = Get-PnPConnection
$SiteAppUpdateCollection = @()
$HubSiteID = (Get-PnPTenantSite -Identity $hubSiteUrl -Connection $adminConnection ).HubSiteId
#Get associated sites with hub
$associatedSites = Get-PnPTenantSite -Detailed -Connection $adminConnection| Where-Object { $_.HubSiteId -eq $HubSiteID }
foreach($package in $packageFiles)
{
$packageName = $package.PSChildName
Write-Host ("Installing {0}..." -f $packageName) -ForegroundColor Yellow
Start-Sleep -Seconds 10
#deploy sppkg assuming app catalog is already configured
Add-pnpapp -Path ("{0}/{1}" -f $sppkgFolder , $package.PSChildName) -Scope Tenant -Overwrite -Publish
$associatedSites = Get-PnPHubSiteChild -Identity $hubSiteUrl -Connection $adminConnection
foreach ($package in $packageFiles) {
$packageName = $package.PSChildName
Write-Host ("Installing {0}..." -f $packageName) -ForegroundColor Yellow
# deploy sppkg assuming app catalog is already configured
Add-pnpapp -Path ("{0}/{1}" -f $sppkgFolder, $package.PSChildName) -Scope Tenant -Overwrite -Publish
}
#Get all site collections associated with the hub site
#TO Test with updated changes
$associatedSites | select url | ForEach-Object {
$Site = Get-PnPTenantSite $_.url -Connection $adminConnection
Connect-PnPOnline -Url $Site.url -Interactive
$siteConnection = Get-PnPConnection
Write-Host ("Deploying packages to {0}..." -f $Site.url) -ForegroundColor Yellow
foreach($package in $packageFiles)
{
$ExportVw = New-Object PSObject
$ExportVw | Add-Member -MemberType NoteProperty -name "Site URL" -value $Site.url
$packageName = $package.PSChildName
$ExportVw | Add-Member -MemberType NoteProperty -name "Package Name" -value $packageName
#Find Name of app from installed package
$RestMethodUrl = '/_api/web/lists/getbytitle(''Apps%20for%20SharePoint'')/items?$select=Title,LinkFilename'
$apps = (Invoke-PnPSPRestMethod -Url $RestMethodUrl -Method Get -Connection $appCatConnection).Value
$appTitle = ($apps | where-object {$_.LinkFilename -eq $packageName} | select Title).Title
#Install App to the Site if not already installed
$associatedSites += $hubSiteUrl # Add the hub site to the list of associated sites
# Get all site collections associated with the hub site
$associatedSites | ForEach-Object {
$Site = Get-PnPTenantSite $_ -Connection $adminConnection
Connect-PnPOnline -Url $Site.url -Interactive
$siteConnection = Get-PnPConnection
foreach ($package in $packageFiles) {
$ExportVw = New-Object PSObject
$ExportVw | Add-Member -MemberType NoteProperty -name "Site URL" -value $Site.url
$packageName = $package.PSChildName
Write-Host "Deploying packages $packageName to $($Site.url)" -ForegroundColor Yellow
$ExportVw | Add-Member -MemberType NoteProperty -name "Package Name" -value $packageName
# Find Name of app from installed package
$RestMethodUrl = '/_api/web/lists/getbytitle(''Apps%20for%20SharePoint'')/items?$select=Title,LinkFilename'
$apps = (Invoke-PnPSPRestMethod -Url $RestMethodUrl -Method Get -Connection $appCatConnection).Value
$appTitle = ($apps | where-object { $_.LinkFilename -eq $packageName } | select Title).Title
$currentPackage = Get-PnPApp -Identity $appTitle -scope Tenant
# Install App to the Site if not already installed
$web = Get-PnPWeb -Includes AppTiles -Connection $siteConnection
$app = $web.AppTiles | where-object {$_.Title -eq $currentPackage.Title }
if(!$app)
{
$app = $web.AppTiles | where-object { $_.Title -eq $currentPackage.Title }
if (!$app) {
Install-PnPApp -Identity $currentPackage.Id -Connection $siteConnection
Start-Sleep -Seconds 5
} else {
$currentPackage = Get-PnPApp -Identity $appTitle -Connection $siteConnection
Write-Host "Current package version on site $($site.Url): $($currentPackage.InstalledVersion)"
Write-Host "Latest package version: $($currentPackage.AppCatalogVersion)"
# Update the package to the latest version
if ($currentPackage.InstalledVersion -ne $currentPackage.AppCatalogVersion) {
Write-Host "Upgrading package on site $($site.Url) to latest version..."
Update-PnPApp -Identity $currentPackage.Id
$currentPackage = Get-PnPApp -Identity $appTitle -Connection $siteConnection
$ExportVw | Add-Member -MemberType NoteProperty -name "Package Version" -value $currentPackage.AppCatalogVersion
} else {
Write-Host "Package already up-to-date on site $($site.Url)."
}
}
# Get the current version of the SPFx package
$currentPackage = Get-PnPApp -Identity $appTitle -Connection $siteConnection
Write-Host "Current package version on site $($site.Url): $($currentPackage.InstalledVersion)"
Write-Host "Latest package version: $($currentPackage.AppCatalogVersion)"
# Update the package to the latest version
if ($currentPackage.InstalledVersion -ne $currentPackage.AppCatalogVersion) {
Write-Host "Upgrading package on site $($site.Url) to latest version..."
Update-PnPApp -Identity $currentPackage.Id
$currentPackage = Get-PnPApp -Identity $appTitle -Connection $siteConnection
$ExportVw | Add-Member -MemberType NoteProperty -name "Package Version" -value $currentPackage.AppCatalogVersion
$SiteAppUpdateCollection += $ExportVw
} else {
Write-Host "Package already up-to-date on site $($site.Url)."
}
}
$SiteAppUpdateCollection += $ExportVw
}
#Export the result Array to CSV file
# Export the result Array to CSV file
$SiteAppUpdateCollection | Export-CSV $OutPutView -Force -NoTypeInformation
Disconnect-PnPOnline
start-sleep -Seconds 30
foreach ($package in $packageFiles) {
$packageName = $package.PSChildName
Write-Host ("Approving {0}..." -f $packageName) -ForegroundColor Yellow
$RestMethodUrl = '/_api/web/lists/getbytitle(''Apps%20for%20SharePoint'')/items?$select=Title,LinkFilename'
$apps = (Invoke-PnPSPRestMethod -Url $RestMethodUrl -Method Get -Connection $appCatConnection).Value
$appTitle = ($apps | where-object { $_.LinkFilename -eq $packageName } | select Title).Title
# deploy sppkg assuming app catalog is already configured
$permRequests = Get-PnPTenantServicePrincipalPermissionRequests | where-object { $_.PackageName -eq $appTitle }
$permRequests | ForEach-Object {
Write-Host "Approving permission request for $($_.Resource) at scope $($_.Scope) and package $appTitle..."
Approve-PnPTenantServicePrincipalPermissionRequest -RequestId $_.Id.Guid -Force -ErrorAction Ignore
}
}
```

> [!Note]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
"Deploys and Installs SharePoint Framework (SPFx) solutions to Hub Site and Associated Sites using the tenant app catalog."
],
"creationDateTime": "2024-01-08",
"updateDateTime": "2024-01-08",
"updateDateTime": "2024-03-20",
"products": [
"SharePoint"
],
"metadata": [
{
"key": "PNP-POWERSHELL",
"value": "2.2.0"
"value": "2.4.0"
}
],
"categories": [
Expand All @@ -35,11 +35,12 @@
"Get-PnPApp",
"Install-PnPApp",
"Update-PnPApp",
"Get-PnPHubSite",
"Get-PnPSite",
"Get-PnPTenant",
"Get-PnPHubSiteChild",
"Get-PnPWeb",
"Invoke-PnPSPRestMethod"
"Invoke-PnPSPRestMethod",
"Get-PnPTenantServicePrincipalPermissionRequests",
"Approve-PnPTenantServicePrincipalPermissionRequest"

],
"thumbnails": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
plugin: add-to-gallery
---

# Retracting SPFx Solutions from Hub Site and associated sites

## Summary

At the time of submitting this script sample there is no concept of a hub site app catalog. However you may want to install or upgrade or uninstall a SPFx solution to all sites within a hub for example all sites linked to the intranet hub. There is a script that covers deploying SPFx across all sites in a hub using the tenant app catalog. [Deploys and Installs SharePoint Framework (SPFx) solutions to Hub Site and Associated Sites using the tenant app catalog](../spo-deploy-install-update-spfx-hubsiteassociatedsites-tenantappcatalog/README.md). This sample covers how to uninstall SPFx package across hub site and associated sites from the tenant app catalogue.

![Example Screenshot](assets/example.png)

### Prerequisites

- The user account that runs the script must have SharePoint Online tenant administrator access.

- Before running the script, edit the script and update the variable values in the Config Variables section, such as Admin Center URL, Hub Site URL, the CSV output file path and alternatively the sppkg packages Folder.

This script snippet automates the removal of SPFx packages across associated sites of a hub site, leveraging the tenant-level app catalog. It navigates through each associated site, checks for existing packages and uninstalls them.

# [PnP PowerShell](#tab/pnpps)

```powershell
$AdminCenterURL="https://contoso-admin.sharepoint.com"
$tenantAppCatalogUrl = "https://contoso.sharepoint.com/sites/apps"
$hubSiteUrl = "https://contoso.sharepoint.com/sites/Contosoinc-intranet"
$dateTime = (Get-Date).toString("dd-MM-yyyy")
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
$fileName = "\Log_Tenant_Removing_Solution" + $dateTime + ".csv"
$OutPutView = $directorypath + $fileName
$sppkgFolder = "./packages"
cd $PSScriptRoot
$packageFiles = Get-ChildItem $sppkgFolder
Connect-PnPOnline $tenantAppCatalogUrl -Interactive
$appCatConnection = Get-PnPConnection
Connect-PnPOnline $AdminCenterURL -Interactive
$adminConnection = Get-PnPConnection
$SiteAppUpdateCollection = @()
$associatedSites = Get-PnPHubSiteChild -Identity $hubSiteUrl -Connection $adminConnection
$associatedSites += $hubSiteUrl #Add the hub site to the list of associated sites
#Get all site collections associated with the hub site
$associatedSites | ForEach-Object {
$Site = Get-PnPTenantSite $_ -Connection $adminConnection
Connect-PnPOnline -Url $Site.url -Interactive
$siteConnection = Get-PnPConnection
foreach($package in $packageFiles)
{
$packageName = $package.PSChildName
#Find Name of app from installed package
$RestMethodUrl = '/_api/web/lists/getbytitle(''Apps%20for%20SharePoint'')/items?$select=Title,LinkFilename'
$apps = (Invoke-PnPSPRestMethod -Url $RestMethodUrl -Method Get -Connection $appCatConnection).Value
$appTitle = ($apps | where-object {$_.LinkFilename -eq $packageName} | Select-Object Title).Title
$currentPackage = Get-PnPApp -Identity $appTitle -scope Tenant
#check is app is installed on site
$web = Get-PnPWeb -Includes AppTiles -Connection $siteConnection
$app = $web.AppTiles | where-object {$_.Title -eq $currentPackage.Title }
if($app)
{
Write-Host "Removing packages $packageName from $($Site.url)" -ForegroundColor Yellow
Uninstall-PnPApp -Identity $currentPackage.Id -Connection $siteConnection
$ExportVw = New-Object PSObject
$ExportVw | Add-Member -MemberType NoteProperty -name "Site URL" -value $Site.url
$ExportVw | Add-Member -MemberType NoteProperty -name "Package Name" -value $packageName
}
$SiteAppUpdateCollection += $ExportVw
}
}
foreach($package in $packageFiles)
{
$packageName = $package.PSChildName
Write-Host "Removing $packageName from tenant" -ForegroundColor Yellow
$RestMethodUrl = '/_api/web/lists/getbytitle(''Apps%20for%20SharePoint'')/items?$select=Title,LinkFilename'
$apps = (Invoke-PnPSPRestMethod -Url $RestMethodUrl -Method Get -Connection $appCatConnection).Value
$appTitle = ($apps | where-object {$_.LinkFilename -eq $packageName} | select Title).Title
Remove-PnPApp -Identity $appTitle -Scope Tenant
}
#Export the result Array to CSV file
$SiteAppUpdateCollection | Export-CSV $OutPutView -Force -NoTypeInformation
Disconnect-PnPOnline
```

> [!Note]
> SharePoint admin rights are required to run the script
[!INCLUDE [More about PnP PowerShell](../../docfx/includes/MORE-PNPPS.md)]

***

## Source Credit

Sample first appeared on [Retracting SPFx Solutions from Tenant Sites using PnP PowerShell](https://reshmeeauckloo.com/posts/powershell-retract-spfx-from-sites-tenant/)

## Contributors

| Author(s) |
|-----------|
| [Reshmee Auckloo](https://github.com/reshmee011) |


[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/spo-uninstall-spfx-hubsiteassociatedsites-tenantappcatalog" aria-hidden="true" />
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[
{
"name": "spo-uninstall-spfx-hubsiteassociatedsites-tenantappcatalog",
"source": "pnp",
"title": "Retracting SPFx Solutions from Hub Site and associated sites",
"shortDescription": "Retracting SPFx Solutions from Hub Site and associated sites ",
"url": "https://pnp.github.io/script-samples/spo-uninstall-spfx-hubsiteassociatedsites-tenantappcatalog/README.html",
"longDescription": [
"Uninstalls and removes SharePoint Framework (SPFx) solutions from Hub Site and Associated Sites from the tenant app catalog."
],
"creationDateTime": "2024-03-20",
"updateDateTime": "2024-03-20",
"products": [
"SharePoint"
],
"metadata": [
{
"key": "PNP-POWERSHELL",
"value": "2.4.0"
}
],
"categories": [
"Modernize",
"Deploy",
"Remove",
"SPFx",
"Hub Site"
],
"tags": [
"modern",
"Connect-PnPOnline",
"Disconnect-PnPOnline",
"Get-PnPHubSiteChild",
"Invoke-PnPSPRestMethod",
"Get-PnPApp",
"Uninstall-PnPApp",
"Remove-PnPApp",
"Get-PnPWeb",
"Get-PnPTenantSite",
"Invoke-PnPSPRestMethod"
],
"thumbnails": [
{
"type": "image",
"order": 100,
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/spo-uninstall-spfx-hubsiteassociatedsites-tenantappcatalog/assets/preview.png",
"alt": ""
}
],
"authors": [
{
"gitHubAccount": "reshmee011",
"company": "",
"pictureUrl": "https://avatars.githubusercontent.com/u/7693852?v=4",
"name": "Reshmee Auckloo"
}
],
"references": [
{
"name": "Want to learn more about PnP PowerShell and the cmdlets",
"description": "Check out the PnP PowerShell site to get started and for the reference to the cmdlets.",
"url": "https://aka.ms/pnp/powershell"
}
]
}
]

0 comments on commit 9ac12e1

Please sign in to comment.