Saturday, January 26, 2019

Save tenant storage entity from PowerShell using app permissions in Sharepoint Online

Tenant storage entities (or tenant properties) allow to store tenant-wide properties which will be accessible from all site collections across tenant. It is often needed in installation PowerShell scripts to save some common settings to tenant storage entities. Also we may need to do that using app permissions i.e. using app id and secret instead of credentials of specific user. In this post I will show the method which may be used for that.

At first let’s try the most obvious way using PnP PowerShell cmdlets. There is overload of Connect-PnPOnline cmdlet which connects to Shrepoint Online using app id and secret instead of user credentials:

PS C:\> Connect-PnPOnline -Url https://{tenant}.sharepoint.com/sites/AppCatalog -AppId $appId -AppSecret $appSecret
PS C:\> Set-PnPStorageEntity -Key "foo" -Value "bar"

However it will give Access denied error even if app has FullControl permissions on tenant level:

Note that in this example I connected to the app catalog site for setting storage entity (below it is described why). But there will be also the same error if you will try to connect to the tenant’s root site or to tenant admin center.

Now let’s try use CSOM and OfficeDevPnP assemblies directly in PowerShell:

$csomDir = ...
$pnpCoreDir = ...
$url = "https://{tenant}.sharepoint.com/sites/test"
$appId = ...
$appSecret = ...
[System.Reflection.Assembly]::LoadFile([System.IO.Path]::Combine($csomDir, "Microsoft.SharePoint.Client.Runtime.dll"))
[System.Reflection.Assembly]::LoadFile([System.IO.Path]::Combine($csomDir, "Microsoft.SharePoint.Client.dll"))
[System.Reflection.Assembly]::LoadFile([System.IO.Path]::Combine($csomDir, "Microsoft.Online.SharePoint.Client.Tenant.dll"))
[System.Reflection.Assembly]::LoadFile([System.IO.Path]::Combine($pnpCoreDir, "OfficeDevPnP.Core.dll"))

function Get-App-Catalog-Url {
    param (
        $ctx
    )
    $tenantSettings = [Microsoft.SharePoint.Client.TenantSettings]::GetCurrent($ctx)
    Load-CSOMProperties -object $tenantSettings -propertyNames @("CorporateCatalogUrl")
    $ctx.ExecuteQuery()
    return $tenantSettings.CorporateCatalogUrl
}

$am = New-Object OfficeDevPnP.Core.AuthenticationManager
$ctx = $am.GetAppOnlyAuthenticatedContext($url, $appId, $appSecret)
$appCatalogUrl = Get-App-Catalog-Url $ctx

$appCtx = $am.GetAppOnlyAuthenticatedContext($appCatalogUrl, $appId, $appSecret)
$appCtx.Web.SetStorageEntity("foo", "bar", "", "");
$appCtx.ExecuteQuery()

At first we load CSOM and OfficeDevPnP.Core assemblies. Then we need to connect to some existing site in our tenant and get app catalog url programmatically using CSOM. After that we create ClientContext using app catalog url and call Web.SetStorageEntity method. This is the trick because if you will try to call this method with any other web site you will get the same Access denied error. Also in this example we used great Load-CSOMProperties helper method from Gary Lapointe which allows to load object with properties using CSOM in PowerShell. It can be found here: https://gist.github.com/glapointe/cc75574a1d4a225f401b.

After you will run this code it will update tenant storage entity using app permissions.


No comments:

Post a Comment