SharePoint Online: PoweShell script to reassign Full permission to any subsite and lists into

Steel Contributor

When you are managing SharePoint Online content or migration site from On Premise to the cloud, the "Site Collection Administrator" permission set has to not be given to any site owner, but only place them into the original "Site Onwer" group which has the "Full Control" permission set.

 

The question appears when a site owner is playing withe the permission set and remove his group from the object (list or site). The same question is existing when you are loading the content from an On Premise SharePoint farm (in which the site collection admin could be given to the site owner) to SharePoint Online, and you need to reset the Permission set for that Site Owner group.

 

This PowerShell script is using CSOM Object to loop into all the site collection (in all the subsites) and apply the Full Control permission into any list and Subsite (it's not going deeper in the List content level).

In the same script, the Site Access request is configured with the given email address to delegate the permission management to the defined Site Onwer.

 

[string]$username = "LoginAccount@tenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\\SECUREDPWD\ExportedPWD-$($username).txt"

[string]$SPOSiteCollectionURLToSet = “https://tenant.sharepoint.com/sites/MySiteCollection”
[string]$RootSiteOwnerGroupToSet = "MySiteCollection Owners"
[string]$SiteOwnerEmailAdress = "SiteOnwerEmail@mycompany.com"
[boolean]$ChangeRequestAccessEmail = $false
[string]$RoleTypeToApply = "Administrator"

function Load-DLLandAssemblies
{
    [string]$defaultDLLPath = ""

    # Load assemblies to PowerShell session 

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
}

Function Invoke-LoadMethod() {
param(
   [Microsoft.SharePoint.Client.ClientObject]$Object = $(throw "Please provide a Client Object"),
   [string]$PropertyName
) 
   $ctx = $Object.Context
   $load = [Microsoft.SharePoint.Client.ClientContext].GetMethod("Load") 
   $type = $Object.GetType()
   $clientLoad = $load.MakeGenericMethod($type) 


   $Parameter = [System.Linq.Expressions.Expression]::Parameter(($type), $type.Name)
   $Expression = [System.Linq.Expressions.Expression]::Lambda(
            [System.Linq.Expressions.Expression]::Convert(
                [System.Linq.Expressions.Expression]::PropertyOrField($Parameter,$PropertyName),
                [System.Object]
            ),
            $($Parameter)
   )
   $ExpressionArray = [System.Array]::CreateInstance($Expression.GetType(), 1)
   $ExpressionArray.SetValue($Expression, 0)
   $clientLoad.Invoke($ctx,@($Object,$ExpressionArray))
}

Function Add-Group-As-FullPermission-InSPWeb()
{
    Param( 
        [Microsoft.SharePoint.Client.ClientContext]$Context,
        [string]$SPGroupName,
        [Microsoft.SharePoint.Client.Web]$SPWeb,
        [string]$RoleType
    ) 
    Write-Host " ---------------------------------------------------------"

    # get group/principal
    $Mygroups = $SPWeb.SiteGroups
    $MyRootWeb = $Context.Site.RootWeb
    $context.Load($MyRootWeb)
    $Context.Load($Mygroups)
    $Context.ExecuteQuery()
<#
    foreach($MyTempGroup in $Mygroups)
    { Write-Host "        --->>> Group In Group List: ", $MyTempGroup.Title }
#>
    $Mygroup = $Mygroups | where {$_.Title -eq $SPGroupName}    
    #$MyRoleType = [Microsoft.SharePoint.Client.RoleType]$Roletype
    
    $roleDefs = $SPWeb.RoleDefinitions
    $Context.Load($roleDefs)
    $Context.ExecuteQuery()
    $roleDef = $roleDefs | where {$_.RoleTypeKind -eq $Roletype}    
    Write-Host "        --- Role Definition: ", $roleDef.Name 
    Write-Host "        --- Group Name: ", $Mygroup.Title, " - Original Name:", $SPGroupName
    
    try{
        $collRdb = new-object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($Context)
        $collRdb.Add($roleDef)
        $collRoleAssign = $SPWeb.RoleAssignments
        $rollAssign = $collRoleAssign.Add($Mygroup, $collRdb)
        $Context.ExecuteQuery()
        Write-Host "       >>>>> Permissions assigned successfully." -ForegroundColor Green
    }
    catch{
        write-host "       !!!!!!! info: $($_.Exception.Message)" -foregroundcolor red
    }

    Write-Host " ---------------------------------------------------------"
}

Function Add-Group-As-FullPermission-InSPList()
{
    Param( 
        [Microsoft.SharePoint.Client.ClientContext]$Context,
        [string]$SPGroupName,
        [Microsoft.SharePoint.Client.Web]$SPWeb,
        [Microsoft.SharePoint.Client.List]$SPList,
        [string]$RoleType
    ) 
    Write-Host "         ---------------------------------------------------------"

    # get group/principal
    $Mygroups = $SPWeb.SiteGroups
    $MyRootWeb = $Context.Site.RootWeb
    $context.Load($MyRootWeb)
    $Context.Load($Mygroups)
    $context.Load($SPList)
    $Context.ExecuteQuery()

<#
    foreach($MyTempGroup in $Mygroups)
    { Write-Host "        --->>> Group In Group List: ", $MyTempGroup.Title }
#>
    $Mygroup = $Mygroups | where {$_.Title -eq $SPGroupName}    
    #$MyRoleType = [Microsoft.SharePoint.Client.RoleType]$Roletype
    
    # get role definition
    $roleDefs = $SPWeb.RoleDefinitions
    $Context.Load($roleDefs)
    $Context.ExecuteQuery()
    $roleDef = $roleDefs | where {$_.RoleTypeKind -eq $Roletype}    
    Write-Host "        --- Role Definition: ", $roleDef.Name 
    Write-Host "        --- Group Name: ", $Mygroup.Title, " - Original Name:", $SPGroupName
    
    try{
        $collRdb = new-object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($Context)
        $collRdb.Add($roleDef)
        $collRoleAssign = $SPList.RoleAssignments
        $rollAssign = $collRoleAssign.Add($Mygroup, $collRdb)
        $Context.ExecuteQuery()
        Write-Host "       >>>>> Permissions assigned successfully." -ForegroundColor Green
    }
    catch{
        write-host "       !!!!!!! info: $($_.Exception.Message)" -foregroundcolor red
    }

    Write-Host "         ---------------------------------------------------------"
}

function Check-Permission-InLists
{
    Param( 
        [Microsoft.SharePoint.Client.ClientContext]$Context, 
        [Microsoft.SharePoint.Client.Web]$SPWeb 
    ) 

    $Mylists = $SPWeb.Lists;
    $Context.Load($Mylists)
    #you can use one execute per multiple loads
    $Context.ExecuteQuery();
    Write-host " ---- CHECK IN LISTS --- "
    foreach($myList in $MyLists)
    {
        Write-host "    ==== List Name:", $mylist.Title
        if($mylist.hidden -eq $false)
        {
            Write-host "        ====> List Name not hidden:", $mylist.Title   -ForegroundColor Yellow
            Invoke-LoadMethod -Object $myList -PropertyName "HasUniqueRoleAssignments"
            $context.ExecuteQuery()
            if($myList.HasUniqueRoleAssignments)
            {
                Write-Host "           -->> List in the SPWeb:", $myList.Title  -ForegroundColor Yellow
                Write-Host "           -->> Has Unique Permissions:", $myList.HasUniqueRoleAssignments

                Add-Group-As-FullPermission-InSPList -Context $Context -SPGroupName $RootSiteOwnerGroupToSet -SPWeb $SPWeb -SPList $myList -RoleType $RoleTypeToApply

            }
        }
    }
}

function Get-SPOSubWebs
{
    Param( 
        [Microsoft.SharePoint.Client.ClientContext]$Context, 
        [Microsoft.SharePoint.Client.Web]$RootWeb 
    ) 
    
    $Webs = $RootWeb.Webs
    $Context.Load($Webs)
    $Context.ExecuteQuery()
    ForEach ($sWeb in $Webs)
    {
        Write-host " -------------------------------------------------------- "
        Write-host "   -->> SubSite:", $sWeb.URL -ForegroundColor green
        Invoke-LoadMethod -Object $sWeb -PropertyName "HasUniqueRoleAssignments"
        $context.ExecuteQuery()
        Write-Host "       -->> Has Unique Permissions:", $sWeb.HasUniqueRoleAssignments

        if($sWeb.HasUniqueRoleAssignments)
        {
            Invoke-LoadMethod -Object $sWeb -PropertyName "RequestAccessEmail"
            $context.ExecuteQuery()
            Write-Host "       -->> Request Access Email Before change:", $sWeb.RequestAccessEmail
            if(($ChangeRequestAccessEmail) -and ($sWeb.RequestAccessEmail -ne $SiteOwnerEmailAdress))
            {
                Write-Host "      ===->> Request Access Email to change"
                $sWeb.RequestAccessEmail = $SiteOwnerEmailAdress
                $sWeb.Update()
                $context.ExecuteQuery()
                Invoke-LoadMethod -Object $sWeb -PropertyName "RequestAccessEmail"
                $context.ExecuteQuery()
                Write-Host "   -->> Request Access Email After change:", $sWeb.RequestAccessEmail
            }

            Add-Group-As-FullPermission-InSPWeb -Context $Context -SPGroupName $RootSiteOwnerGroupToSet -SPWeb $sWeb -RoleType $RoleTypeToApply
        }

        Check-Permission-InLists -Context $Myctx -SPWeb $sWeb
        Get-SPOSubWebs -Context $Context -RootWeb $sWeb
    } 
}

function Reset-Group-OwnerShip
{
    Param( 
        [Microsoft.SharePoint.Client.ClientContext]$Context, 
       # [Microsoft.SharePoint.Client.Web]$SPWeb,
        [string]$GroupOwnerName
    ) 
    $MyRootWeb = $Context.Site.RootWeb
    $Mygroups = $MyRootWeb.SiteGroups
    $context.Load($MyRootWeb)
    $Context.Load($Mygroups)
    $Context.ExecuteQuery()

    foreach($MyTempGroup in $Mygroups)
    {
        Write-Host "        --->>> Group Name: ", $MyTempGroup.Title
        $ThegroupOwner = $Context.Web.SiteGroups.GetByName($GroupOwnerName); 
        $MyTempGroup.Owner = $ThegroupOwner
        $MyTempGroup.Update()
        $Context.ExecuteQuery()    
    }
}

function SetGroupAsFullOwner([string]$MyRootWebURL)
{
    [bool]$CreateSGSDocLibList = $false
    
    $Myctx = New-Object Microsoft.SharePoint.Client.ClientContext($MyRootWebURL)
    $secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
    $creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd
    $Myctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($creds.UserName,$creds.Password)
    $Myctx.RequestTimeout = 1000000 # milliseconds
    $MyspoRootweb = $Myctx.Web
    $Myctx.Load($MyspoRootweb)
    $Myctx.ExecuteQuery()

Write-Host " "
Write-Host " ---------------------------------------------------------"
Write-Host "  >>>> # Server Version:" $Myctx.ServerVersion " # <<<<<<" -ForegroundColor Green 
Write-Host " ---------------------------------------------------------"
Write-Host " "

    Write-host " -------------------------------------------------------- "
    Write-host "   -->> RootSite:", $MyspoRootweb.URL -ForegroundColor green

    Reset-Group-OwnerShip -Context $Myctx -GroupOwnerName $RootSiteOwnerGroupToSet
    Invoke-LoadMethod -Object $MyspoRootweb -PropertyName "RequestAccessEmail"
    $Myctx.ExecuteQuery()
    Write-Host "   -->> Request Access Email Before change:", $MyspoRootweb.RequestAccessEmail
    
    if($MyspoRootweb.RequestAccessEmail -ne $SiteOwnerEmailAdress)
    {
        Write-Host "   ===->> Request Access Email to change"
        $MyspoRootweb.RequestAccessEmail = $SiteOwnerEmailAdress
        $MyspoRootweb.Update()
        $Myctx.ExecuteQuery()
        Invoke-LoadMethod -Object $MyspoRootweb -PropertyName "RequestAccessEmail"
        $Myctx.ExecuteQuery()
        Write-Host "   -->> Request Access Email After change:", $MyspoRootweb.RequestAccessEmail
    }

    Check-Permission-InLists -Context $Myctx -SPWeb $MyspoRootweb
    
    Get-SPOSubWebs -Context $Myctx -RootWeb $MyspoRootweb
}

cls
Load-DLLandAssemblies

SetGroupAsFullOwner $SPOSiteCollectionURLToSet

I'm using that script since many months to reapply the permission set after site content migration from SharePoint 2007 to SharePoint Online, the maximum test validation was done with one site collection having more than 2900 Subsites.

 

 

Original Post message:

 

Fabrice Romelard [MBA Risk Management]

 

Sites Sources:

0 Replies