Simplify authentication with PowerShell PnP and the Windows Credential Manager
If you've ever written a PowerShell script for something SharePoint related with the PnP PowerShell module, you will have needed to authenticate to carry out your work. Regardless of the obvious fact that you will need an account that has the correct permissions to the resources you want to play with, there are a bunch of ways to do authentication. This could be:
- Credentials
- Pre-stored credentials with Windows Credential Manager
- Credentials with multi-factor authentication enabled
- Certificates
What is the Windows Credential Manager
To quote Microsoft... "Credential Manager lets you view and delete your saved credentials for signing in to websites, connected applications, and networks."
The WCM is ideal when you don't want to hardcore your password into an application of PowerShell script in this case, and need to reference it securely. This is more of an efficiency win and would probably want to look into using certificates in the long run to execute large scale logic.
How to work with saved credentials?
Luckily there is documentation on this over at the PnP.PowerShell github site, but here are the two example PowerShell commands to execute.
First you will need to add a credential which will be the username and password combination needed to authenticate. Top tip, if you save the label as the domain you want to connect to, e.g. [tenant]-admin.sharepoint.com then it will automatically search for this when attempting a connection and select it if there is a match. The same applies if you make the label specific to a site you connect to.
Add-PnPStoredCredential -Name "yourlabel" -Username youruser@domain.com
Once you have a credential added, you can connect either with just the URL if you have labelled your credential correctly, or add the extra parameter to specify the one you which to use.
Connect-PnPOnline [yourtenant]-admin.sharepoint.com -Credentials https://[yourtenant].sharepoint.com
Building in validation logic
It is important to have a redundancy when using the credential manager, allowing the users to supply a username and password if nothing was found in the Credential Manager.
# Define which credential to use
$credentialManagerCredentialToUse
$credentials = $null
$username = $null
# Check if credential exists
if (![String]::IsNullOrEmpty($credentialManagerCredentialToUse) -and $null -ne (Get-PnPStoredCredential -Name $credentialManagerCredentialToUse)) {
$username = (Get-PnPStoredCredential -Name $credentialManagerCredentialToUse).UserName
$credentials = $credentialManagerCredentialToUse
}
else {
# Prompts for credentials if not found in store
$username = Read-Host -Prompt "Please enter username (e.g. admin@contoso.onmicrosoft.com)"
$password = Read-host -AsSecureString "Please enter password"
$credentials = New-Object Management.Automation.PSCredential $username, $password
}
# Catch error for user not supplying credentials
if ($null -eq $credentials) {
Write-Host "ERROR: No credentials supplied." -ForegroundColor Red
exit
}
Other considerations
- If there are any conditional access policies blocking you from authenticating outside of a corporate network for example, you will get an error.
- If the account you are using requires MFA in some form, you will have to use interactive login to display the full UI experience. Bear this in mind if you are running headless scripts.
- You will need to update the credential if any of your details change. This is why I would recommend saving service accounts into here as a preference.