Set up Enterprise App to use App-Only Sites.Selected permissions and wite to SharePoint with PnP Powershell

I wanted to run unattended scripts against SharePoint for various governance and content cleanup jobs and found the guidance for this to be a little confusing.   I think it's a good idea to limit the access of any script, so I prefer to set up an App per script and use the Sites.Selected permission to limit the sites to which my app has access.   Here's the process I used to get it to work:

You can register an app in the Azure portal UI, but there's a few steps that must be performed with PowerShell, so I figured just doing it all in Powershell made it consistent.  

Step 0:  Get the right version of PnP.Powershell

I also had to use the PnP.PowerShell 2.2.81 nightly build because there was a bug introduced in 2.2.0.  If you need to get a specific version you can run Install-Module, but I prefer to use Save-Module with specific version so I can keep different version of PnP.PowerShell around to avoid having my old scripts affected by new modules and potential regression issues.  

Once you have the right version, run the following line (or include in your script file):

Import-Module D:\psbin\PnP.PowerShell\2.2.81\PnP.PowerShell.psd1

Step 1: Register the App

In this step we'll do the one time app registration with a certificate, then we'll give the App Sites.Selected WRITE permission (your only choice when doing the initial grant is READ|WRITE).  Immediately after, we update the permissions with FullControl, as this is required to upload files.

Permissions Needed: Global Administrator/Azure AD Admin

In my Dev tenant this is no problem since I have this right.  In prod environments I don't typically have this right so I would plan to hand this script or the steps off to one of my admins.

Generate Certificate

You'll need to use a certificate to authenticate with your app.  In this example I am testing against my developer tenant.  I'm using a self-signed cert, but you can be more secure and use one created by a trusted CA.   If you go the trusted CA route, you can skip to the registration

$pw = "USEAGOODPASSWORD" #this is not a good password....

$commonName = 'EAUpload'

$certificateName = "EASharePointSiteUpload_TEST"

$certFile = "$certificateName.cer"

$certPfx = "$certificateName.pfx"

$certPass = (ConvertTo-SecureString -String $pw -AsPlainText -Force)

New-PnPAzureCertificate -CommonName $commonName -OutPfx "$certPfx" -OutCert "$certFile" -CertificatePassword $certPass

Register the App with a Certificate

Make sure to update the script to replace YOURTENANT then run

# SETUP

$hostUrl = "https://YOURTENANT.sharepoint.com"

$hostRelativeUrl = "/sites/EAUploadTest" #change to whatever site you want the app to work with

$siteUrl = "$hostUrl$hostRelativeUrl"

$appName = "EAUploadTestApp_TEST"

$tenant = "YOURTENANT.onmicrosoft.com"

# END SETUP

Write-Host "Registering App on $siteUrl"

Connect-PnPOnline $siteUrl -Interactive

$reg = Register-PnPAzureADApp -ApplicationName $appName `

                        -Tenant $tenant `

                        -CertificatePath $certPfx `

                        -CertificatePassword $certPass `

                        -GraphApplicationPermissions "User.Read.All" `

                        -SharePointApplicationPermissions  "Sites.Selected" `

                        -Interactive

Write-Host "Granting WRITE permissions to app on: $siteUrl"

$grant = Grant-PnPAzureADAppSitePermission -Permissions Write -Site $siteUrl -AppId "PUTAPPIDHERE" -DisplayName "MYAPP_SITESSELECTED_FULL"

$reset = Set-PnPAzureADAppSitePermission -PermissionId $grant.Id -Permissions FullControl

Disconnect-PnPOnline

Step 2:  Allow NoScript on the SP Site

I couldn't figure out any way around this, seems that a site has to have NoScript disabled in order to allow api uploads.

Permissions Needed:   SP Admin

Connect-PnPOnline $siteUrl -Interactive

Write-Host "Setting NoScript to FALSE (so we can do file uploads)"

Set-PnPSite -NoScriptSite $false

Write-Host "Disconnecting from Admin (User) Credentials"

Disconnect-PnPOnline


Step 3: Test with App-Only Credentials

Here we connect with only App credentials (not user credentials).

Write-Host "Connecting with App Credentials"

Connect-PnPOnline -Url $siteUrl -ClientId $reg.'AzureAppId/ClientId' -Tenant $tenant -CertificatePath $certPfx -CertificatePassword $certPass #-ThumbPrint $reg.'Certificate Thumbprint' 

Write-Host "--Saving File"

$testFile = 'testFile.txt' 

Add-PnPFile -Path $testFile -Folder "$hostRelativeUrl/Shared Documents/"

Write-Host "--Disconnecting from App Credentials"

Disconnect-PnPOnline

Comments

Popular posts from this blog

Programmatically Update Page Layouts

Microsoft Virtualilzation Headaches

ERROR: Failed to create feature receiver...