Introduction
Migrating permissions, site groups, and settings from a SharePoint Hub Site to an associated site is a common task, especially in large organizations. While available migration tools can make this easy, they often come at a cost.
What This Script Does
- Connects to both Hub Site and Associated Site
- Copies custom permission levels
- Copies site groups with users
- Applies appropriate role assignments
- Updates sharing capabilities
- Streamlines migration process for SharePoint Online environments
Script Parameters
Param ( [string] $ClientId = $(Throw "Please provide ClientId"), [string] $HubSiteURL = $(Throw "Please provide HubSiteURL"), [string] $AdminSiteURL = $(Throw "Please provide AdminSiteURL"), [string] $ClientSecret = $(Throw "Please provide ClientSecret"), [string] $AssociatedSiteURL = $(Throw "Please provide Associated Site URL") )
You’ll need to register an Azure AD App with appropriate SharePoint API permissions and provide its ClientId and ClientSecret. This ensures secure authentication without using stored credentials.
Authentication and Setup
$HubSiteConnection = Connect-PnPOnline -Url $HubSiteURL -ClientId $ClientId -ClientSecret $ClientSecret -ReturnConnection
$AssociatedSiteConnection = Connect-PnPOnline -Url $AssociatedSiteURL -ClientId $ClientId -ClientSecret $ClientSecret -ReturnConnection
This part of the script connects to both the Hub Site and the Associated Site using PnP PowerShell, returning secure connections for use in the following functions.
Updating Sharing Capability
function Update-ExternalSharing {
param (
[string] $AssociatedSiteURL,
[string] $AdminSiteURL
)
Connect-PnPOnline -Url $AdminSiteURL -ClientId $ClientId -ClientSecret $ClientSecret
Set-PnPTenantSite -Url $AssociatedSiteURL -SharingCapability ExternalUserSharingOnly
}
This function sets the sharing capability of the associated site to allow external users to access the site — but only if they are authenticated. This is done by updating the SharingCapability property of the site to ExternalUserSharingOnly. Copying Permission Levels
function Copy-PermissionLevels {
param (
$HubSiteConnection,
$AssociatedSiteConnection
)
$AllPermissionLevels = Get-PnPRoleDefinition -Connection $HubSiteConnection
foreach ($PermissionLevel in $AllPermissionLevels) {
if (-not $PermissionLevel.Hidden) {
$ExistingPermission = Get-PnPRoleDefinition -Identity $PermissionLevel.Name -Connection $AssociatedSiteConnection -ErrorAction SilentlyContinue
if (!$ExistingPermission) {
$selectedPermissions = New-Object Microsoft.SharePoint.Client.BasePermissions
[Enum]::GetValues([Microsoft.SharePoint.Client.PermissionKind]) | ForEach-Object {
if ($PermissionLevel.BasePermissions.Has($_)) {
$selectedPermissions.Set($_)
}
}
$newRole = Add-PnPRoleDefinition -RoleName $PermissionLevel.Name -Description $PermissionLevel.Description -Connection $AssociatedSiteConnection
$newRole.BasePermissions = $selectedPermissions
$newRole.Update()
Invoke-PnPQuery -Connection $AssociatedSiteConnection
}
}
}
}
This function copies non-hidden permission levels from the hub site to the associated site. It checks if the permission already exists to avoid duplication and applies the same Base Permissions.
Copying Groups and Users function Copy-HubSiteGroups {
param (
$HubSiteName,
$AssociatedSiteName,
$HubSiteConnection,
$AssociatedSiteConnection
)
$GroupMappings = @(
@{ Source = "$HubSiteName Owners"; Destination = "$AssociatedSiteName Owners" },
@{ Source = "$HubSiteName Members"; Destination = "$AssociatedSiteName Members" },
@{ Source = "$HubSiteName Visitors"; Destination = "$AssociatedSiteName Visitors" }
)
foreach ($Mapping in $GroupMappings) {
$SourceGroup = Get-PnPGroup -Identity $Mapping.Source -Connection $HubSiteConnection
$DestinationGroup = Get-PnPGroup -Identity $Mapping.Destination -Connection $AssociatedSiteConnection -ErrorAction SilentlyContinue
if (-not $DestinationGroup) {
New-PnPGroup -Title $Mapping.Destination -Connection $AssociatedSiteConnection
}
$SourceGroup.Users | ForEach-Object {
$LoginName = if ($_ -like "*#ext#*") { $_.Email } else { $_.LoginName }
Add-PnPGroupMember -Group $Mapping.Destination -LoginName $LoginName -Connection $AssociatedSiteConnection
}
}
}
This function replicates SharePoint default groups (Owners, Members, Visitors) from the hub to the associated site. It handles both internal and external users and ensures group membership is preserved.
Main Function
To simplify script execution, we can wrap all functional calls inside a Main
function:
function Main {
# Connect to the Hub Site and Associated Site using PnP PowerShell
$HubSiteConnection = Connect-PnPOnline -Url $HubSiteURL -ClientId $ClientId -ClientSecret $ClientSecret -ReturnConnection
$AssociatedSiteConnection = Connect-PnPOnline -Url $AssociatedSiteURL -ClientId $ClientId -ClientSecret $ClientSecret -ReturnConnection
# Update external sharing settings before proceeding
Update-ExternalSharing -AdminSiteURL $AdminSiteURL -AssociatedSiteURL $AssociatedSiteURL
# Copy custom permission levels from Hub Site to Associated Site
Copy-PermissionLevels -HubSiteConnection $HubSiteConnection -AssociatedSiteConnection $AssociatedSiteConnection
# Extract names of sites to match default group names
$HubSiteName = ($HubSiteURL -split "/")[-1]
$AssociatedSiteName = ($AssociatedSiteURL -split "/")[-1]
# Copy site groups and their users
Copy-HubSiteGroups -HubSiteName $HubSiteName -AssociatedSiteName $AssociatedSiteName -HubSiteConnection $HubSiteConnection -AssociatedSiteConnection $AssociatedSiteConnection
}
Main
Running the Script
To run this PowerShell script, first make sure you’ve saved it with a .ps1 extension — for example, name it CopyGroupsAndPermissions.ps1. Once saved, navigate to the directory where the script is stored using PowerShell and run the following command (make sure to replace the placeholder values with your actual credentials and URLs):
./CopyGroupsAndPermissions.ps1 `
-ClientId "xxxx-xxxx-xxxx-xxxx" `
-HubSiteURL "https://yourtenant.sharepoint.com/sites/hubsite" `
-ClientSecret "your-client-secret" `
-AdminSiteURL "https://yourtenant-admin.sharepoint.com" `
-AssociatedSiteURL "https://yourtenant.sharepoint.com/sites/associatedsite"
Final Thoughts
This script is ideal for scenarios where:
- You need to replicate security and structure across multiple sites
- You want to avoid third-party tools like ShareGate
If you're working on managing large SharePoint environments with many associated sites, this can save time and reduce manual effort.
No comments:
Post a Comment