Skip to main content
added 40 characters in body
Source Link

For you information, "Set-PnPUserSPOUser" works only if your account is already granted as site collection administrator and is not compatible with PnP contexts.

Import-Module SharePointPnPPowerShellOnline

$tenantName = "<YOUR_TENANT_NAME>"
$localeId = 2057 # UK
$timeZoneId = 2 # London


#Connect to SPO Tenant
$cnx = Connect-PnPOnline "https://$tenantName-admin.sharepoint.com" -UseWebLogin -ReturnConnection


#Get Tenant CSOM instance
$tenant = new-object Microsoft.Online.SharePoint.TenantAdministration.Tenant([Microsoft.SharePoint.Client.ClientRuntimeContext]$cnx.Context)
function Remove-PnPTenantSiteCollectionAdministrator{
    param([string]$siteUrl, [string[]]$users)
    $ctx = $tenant.Context;
    $targetSite = $tenant.GetSiteByUrl($siteUrl);
    $ctx.Load($targetSite);
    $ctx.ExecuteQuery();

    $users |%{
        $user = $targetSite.RootWeb.EnsureUser($_);
        $ctx.Load($user)
        $ctx.ExecuteQuery();
        if($user.IsSiteAdmin){
            $user.IsSiteAdmin = $false;
            $user.Update();
        }
    }
    $ctx.ExecuteQuery();
}
function Get-PnPTenantSiteAuthor{
    param([string]$siteUrl)
    $ctx = $tenant.Context;
    $targetSite = $tenant.GetSiteByUrl($siteUrl);
    $author = $targetSite.RootWeb.Author
    $ctx.Load($author);
    $ctx.ExecuteQuery()
    [pscustomobject]@{
        LoginName = $author.LoginName
        DisplayName = $author.Title
        UserPrincipalName = $author.UserPrincipalName
        Email = $author.Email
    }
}

#Get current UserName
$tenantWeb = Get-PnPWeb
$tenantWeb.Context.Load($tenantWeb.CurrentUser)
$tenantWeb.Context.ExecuteQuery()
$currentUser = $tenantWeb.CurrentUser



#Get All sites then execute
Get-PnPTenantSite | %{
    $site = $_;
    
    #Grant current user as admin if it's not already it's own
    if($site.OwnerEmail -ne $currentUser.Email){
        $site.Url | Set-PnPTenantSite -Owners $currentUser.Email |out-null
    }

    $user = Get-PnPTenantSiteAuthor $site.Url

    try{
        $ctx = $tenant.Context;

        $targetSite = $tenant.GetSiteByUrl($site.Url);
        $web = $targetSite.RootWeb;

        $timeZones = $web.RegionalSettings.TimeZones
        $ctx.Load($timeZones)
        $ctx.ExecuteQuery()

        $timeZone = $timeZones | ?{ $_.Id -eq $timeZoneId }

        $web.RegionalSettings.LocaleId = $localeId
        $web.RegionalSettings.TimeZone = $timeZone

        $web.Update()
        $ctx.ExecuteQuery()
    
    }
    finally{
    
        #Remove Current User as admin except for it's own
        if($site.OwnerEmail -ne $currentUser.Email){
            Remove-PnPTenantSiteCollectionAdministrator $site.Url $currentUser.LoginName |out-null
        }
        #ensure owner is the real owner
        if([string]::IsNullOrEmpty($site.Owner)){
            $site.Url | Set-PnPTenantSite -Owners $res$user.UserPrincipalName |out-null
        }

    }

}

For you information, "Set-PnPUser" works only if your account is already granted as site collection administrator.

Import-Module SharePointPnPPowerShellOnline

$tenantName = "<YOUR_TENANT_NAME>"
$localeId = 2057 # UK
$timeZoneId = 2 # London


#Connect to SPO Tenant
$cnx = Connect-PnPOnline "https://$tenantName-admin.sharepoint.com" -UseWebLogin -ReturnConnection


#Get Tenant CSOM instance
$tenant = new-object Microsoft.Online.SharePoint.TenantAdministration.Tenant([Microsoft.SharePoint.Client.ClientRuntimeContext]$cnx.Context)
function Remove-PnPTenantSiteCollectionAdministrator{
    param([string]$siteUrl, [string[]]$users)
    $ctx = $tenant.Context;
    $targetSite = $tenant.GetSiteByUrl($siteUrl);
    $ctx.Load($targetSite);
    $ctx.ExecuteQuery();

    $users |%{
        $user = $targetSite.RootWeb.EnsureUser($_);
        $ctx.Load($user)
        $ctx.ExecuteQuery();
        if($user.IsSiteAdmin){
            $user.IsSiteAdmin = $false;
            $user.Update();
        }
    }
    $ctx.ExecuteQuery();
}
function Get-PnPTenantSiteAuthor{
    param([string]$siteUrl)
    $ctx = $tenant.Context;
    $targetSite = $tenant.GetSiteByUrl($siteUrl);
    $author = $targetSite.RootWeb.Author
    $ctx.Load($author);
    $ctx.ExecuteQuery()
    [pscustomobject]@{
        LoginName = $author.LoginName
        DisplayName = $author.Title
        UserPrincipalName = $author.UserPrincipalName
        Email = $author.Email
    }
}

#Get current UserName
$tenantWeb = Get-PnPWeb
$tenantWeb.Context.Load($tenantWeb.CurrentUser)
$tenantWeb.Context.ExecuteQuery()
$currentUser = $tenantWeb.CurrentUser



#Get All sites then execute
Get-PnPTenantSite | %{
    $site = $_;
    
    #Grant current user as admin if it's not already it's own
    if($site.OwnerEmail -ne $currentUser.Email){
        $site.Url | Set-PnPTenantSite -Owners $currentUser.Email |out-null
    }

    $user = Get-PnPTenantSiteAuthor $site.Url

    try{
        $ctx = $tenant.Context;

        $targetSite = $tenant.GetSiteByUrl($site.Url);
        $web = $targetSite.RootWeb;

        $timeZones = $web.RegionalSettings.TimeZones
        $ctx.Load($timeZones)
        $ctx.ExecuteQuery()

        $timeZone = $timeZones | ?{ $_.Id -eq $timeZoneId }

        $web.RegionalSettings.LocaleId = $localeId
        $web.RegionalSettings.TimeZone = $timeZone

        $web.Update()
        $ctx.ExecuteQuery()
    
    }
    finally{
    
        #Remove Current User as admin except for it's own
        if($site.OwnerEmail -ne $currentUser.Email){
            Remove-PnPTenantSiteCollectionAdministrator $site.Url $currentUser.LoginName |out-null
        }
        #ensure owner is the real owner
        if([string]::IsNullOrEmpty($site.Owner)){
            $site.Url | Set-PnPTenantSite -Owners $res.UserPrincipalName |out-null
        }

    }

}

For you information, "Set-SPOUser" works only if your account is already granted as site collection administrator and is not compatible with PnP contexts.

Import-Module SharePointPnPPowerShellOnline

$tenantName = "<YOUR_TENANT_NAME>"
$localeId = 2057 # UK
$timeZoneId = 2 # London


#Connect to SPO Tenant
$cnx = Connect-PnPOnline "https://$tenantName-admin.sharepoint.com" -UseWebLogin -ReturnConnection


#Get Tenant CSOM instance
$tenant = new-object Microsoft.Online.SharePoint.TenantAdministration.Tenant([Microsoft.SharePoint.Client.ClientRuntimeContext]$cnx.Context)
function Remove-PnPTenantSiteCollectionAdministrator{
    param([string]$siteUrl, [string[]]$users)
    $ctx = $tenant.Context;
    $targetSite = $tenant.GetSiteByUrl($siteUrl);
    $ctx.Load($targetSite);
    $ctx.ExecuteQuery();

    $users |%{
        $user = $targetSite.RootWeb.EnsureUser($_);
        $ctx.Load($user)
        $ctx.ExecuteQuery();
        if($user.IsSiteAdmin){
            $user.IsSiteAdmin = $false;
            $user.Update();
        }
    }
    $ctx.ExecuteQuery();
}
function Get-PnPTenantSiteAuthor{
    param([string]$siteUrl)
    $ctx = $tenant.Context;
    $targetSite = $tenant.GetSiteByUrl($siteUrl);
    $author = $targetSite.RootWeb.Author
    $ctx.Load($author);
    $ctx.ExecuteQuery()
    [pscustomobject]@{
        LoginName = $author.LoginName
        DisplayName = $author.Title
        UserPrincipalName = $author.UserPrincipalName
        Email = $author.Email
    }
}

#Get current UserName
$tenantWeb = Get-PnPWeb
$tenantWeb.Context.Load($tenantWeb.CurrentUser)
$tenantWeb.Context.ExecuteQuery()
$currentUser = $tenantWeb.CurrentUser



#Get All sites then execute
Get-PnPTenantSite | %{
    $site = $_;
    
    #Grant current user as admin if it's not already it's own
    if($site.OwnerEmail -ne $currentUser.Email){
        $site.Url | Set-PnPTenantSite -Owners $currentUser.Email |out-null
    }

    $user = Get-PnPTenantSiteAuthor $site.Url

    try{
        $ctx = $tenant.Context;

        $targetSite = $tenant.GetSiteByUrl($site.Url);
        $web = $targetSite.RootWeb;

        $timeZones = $web.RegionalSettings.TimeZones
        $ctx.Load($timeZones)
        $ctx.ExecuteQuery()

        $timeZone = $timeZones | ?{ $_.Id -eq $timeZoneId }

        $web.RegionalSettings.LocaleId = $localeId
        $web.RegionalSettings.TimeZone = $timeZone

        $web.Update()
        $ctx.ExecuteQuery()
    
    }
    finally{
    
        #Remove Current User as admin except for it's own
        if($site.OwnerEmail -ne $currentUser.Email){
            Remove-PnPTenantSiteCollectionAdministrator $site.Url $currentUser.LoginName |out-null
        }
        #ensure owner is the real owner
        if([string]::IsNullOrEmpty($site.Owner)){
            $site.Url | Set-PnPTenantSite -Owners $user.UserPrincipalName |out-null
        }

    }

}
Source Link

The major trick is being able to grant your "SharePoint Administrator" account as site collection administrator temporarily for that operation without changing the default Site Owner.

The PnP command to help you in that case is "Set-PnPTenantSite" and some CSOM usages in an old school way to avoid PnP context mixed-up.

For you information, "Set-PnPUser" works only if your account is already granted as site collection administrator.

The PS script below would help you.

Import-Module SharePointPnPPowerShellOnline

$tenantName = "<YOUR_TENANT_NAME>"
$localeId = 2057 # UK
$timeZoneId = 2 # London


#Connect to SPO Tenant
$cnx = Connect-PnPOnline "https://$tenantName-admin.sharepoint.com" -UseWebLogin -ReturnConnection


#Get Tenant CSOM instance
$tenant = new-object Microsoft.Online.SharePoint.TenantAdministration.Tenant([Microsoft.SharePoint.Client.ClientRuntimeContext]$cnx.Context)
function Remove-PnPTenantSiteCollectionAdministrator{
    param([string]$siteUrl, [string[]]$users)
    $ctx = $tenant.Context;
    $targetSite = $tenant.GetSiteByUrl($siteUrl);
    $ctx.Load($targetSite);
    $ctx.ExecuteQuery();

    $users |%{
        $user = $targetSite.RootWeb.EnsureUser($_);
        $ctx.Load($user)
        $ctx.ExecuteQuery();
        if($user.IsSiteAdmin){
            $user.IsSiteAdmin = $false;
            $user.Update();
        }
    }
    $ctx.ExecuteQuery();
}
function Get-PnPTenantSiteAuthor{
    param([string]$siteUrl)
    $ctx = $tenant.Context;
    $targetSite = $tenant.GetSiteByUrl($siteUrl);
    $author = $targetSite.RootWeb.Author
    $ctx.Load($author);
    $ctx.ExecuteQuery()
    [pscustomobject]@{
        LoginName = $author.LoginName
        DisplayName = $author.Title
        UserPrincipalName = $author.UserPrincipalName
        Email = $author.Email
    }
}

#Get current UserName
$tenantWeb = Get-PnPWeb
$tenantWeb.Context.Load($tenantWeb.CurrentUser)
$tenantWeb.Context.ExecuteQuery()
$currentUser = $tenantWeb.CurrentUser



#Get All sites then execute
Get-PnPTenantSite | %{
    $site = $_;
    
    #Grant current user as admin if it's not already it's own
    if($site.OwnerEmail -ne $currentUser.Email){
        $site.Url | Set-PnPTenantSite -Owners $currentUser.Email |out-null
    }

    $user = Get-PnPTenantSiteAuthor $site.Url

    try{
        $ctx = $tenant.Context;

        $targetSite = $tenant.GetSiteByUrl($site.Url);
        $web = $targetSite.RootWeb;

        $timeZones = $web.RegionalSettings.TimeZones
        $ctx.Load($timeZones)
        $ctx.ExecuteQuery()

        $timeZone = $timeZones | ?{ $_.Id -eq $timeZoneId }

        $web.RegionalSettings.LocaleId = $localeId
        $web.RegionalSettings.TimeZone = $timeZone

        $web.Update()
        $ctx.ExecuteQuery()
    
    }
    finally{
    
        #Remove Current User as admin except for it's own
        if($site.OwnerEmail -ne $currentUser.Email){
            Remove-PnPTenantSiteCollectionAdministrator $site.Url $currentUser.LoginName |out-null
        }
        #ensure owner is the real owner
        if([string]::IsNullOrEmpty($site.Owner)){
            $site.Url | Set-PnPTenantSite -Owners $res.UserPrincipalName |out-null
        }

    }

}