Install PnP PowerShell and Connect to SharePoint Online

In this post, I am going to show you how to install PnP PowerShell and connect to SharePoint Online, and how to check the connection actually worked before you start running anything against it.

Everything below was run on PowerShell 7.5.8 with PnP.PowerShell 2.12.0. The output is what my machine printed, not what the documentation says it should print.

Install the module

Install-Module PnP.PowerShell -Scope CurrentUser

-Scope CurrentUser installs it under your profile so you do not need to run PowerShell as administrator.

If you have had PnP installed for a while you may get this instead of an install:

WARNING: Version '2.12.0' of module 'PnP.PowerShell' is already installed at
'C:\Program Files\WindowsPowerShell\Modules\PnP.PowerShell\2.12.0'. To install
version '3.3.0', run Install-Module and add the -Force parameter.

That is not an error. It found an older copy installed for all users and stopped rather than silently putting a second one next to it. Add -Force if you do want the newer version side by side.

Check what you have with:

Get-Module PnP.PowerShell -ListAvailable | Select-Object Name, Version, ModuleBase
Name           Version ModuleBase
----           ------- ----------
PnP.PowerShell 2.12.0  C:\Program Files\WindowsPowerShell\Modules\PnP.PowerShell

Worth doing before anything else, because the syntax of several cmdlets changed between 2.x and 3.x and half the guides you will find online do not say which one they were written for.

You need an app registration first

This is the part that catches everyone coming back to an old script. You cannot just connect any more:

Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/Demo" -Interactive
WARNING: Connecting with -Interactive used the PnP Management Shell multi-tenant
App Id for authentication. As of September 9th, 2024 this option is not available
anymore.

Specified method is not supported.

The red line is the one everybody pastes into Google. The answer is in the yellow warning just above it, which most people scroll straight past.

Register your own app once per tenant:

Register-PnPEntraIDAppForInteractiveLogin `
    -ApplicationName "PnP.PowerShell" `
    -Tenant contoso.onmicrosoft.com `
    -Interactive

On 2.x you must include -Interactive or you get an unhelpful “Parameter set cannot be resolved”. I wrote that up separately in Connect-PnPOnline: Specified method is not supported.

Copy the Client ID it gives you at the end. You need it every single time from now on.

Connect

Connect-PnPOnline `
    -Url "https://contoso.sharepoint.com/sites/Demo" `
    -ClientId "b1539324-4fa0-4bf0-8c45-949d49fbe112" `
    -Interactive

Your browser opens, you sign in, and the command finishes with no output at all. That is normal – PnP tells you nothing when it works.

Check it actually connected

Because it says nothing on success, get into the habit of confirming:

Get-PnPWeb | Select-Object Title, Url, Id
Title : PowerShell Demo
Url   : https://contoso.sharepoint.com/sites/Demo
Id    : cfa3cc52-ce17-4c52-a7b8-89ae0c4f66e6

And if you want to see what you are connected as:

Get-PnPConnection | Select-Object Url, ConnectionType, ClientId
Url            : https://contoso.sharepoint.com/sites/demo
ConnectionType : O365
ClientId       : a0748433-4fa0-4bf0-8c45-949d49fbe112

The first thing everyone runs, and the first surprise

Get-PnPList | Select-Object Title, ItemCount, Hidden

On a site where I had made exactly four lists, that returned nineteen:

Title                 ItemCount Hidden
-----                 --------- ------
appdata                       0   True
Composed Looks               18   True
Departments                   4  False
Documents                     0  False
Master Page Gallery         175   True
Project Documents             9  False
Projects                     25  False
Site Pages                    1  False
Style Library                 0  False
TaxonomyHiddenList            0   True
Theme Gallery                41   True
User Information List         9   True
Web Part Gallery              6   True

Most of those are system lists SharePoint creates for itself. You almost always want:

Get-PnPList | Where-Object { -not $_.Hidden } | Select-Object Title, ItemCount

The same thing happens with folders. Listing a document library gives you a Forms folder you did not create:

Name      Type
----      ----
Archive   Folder
Contracts Folder
Forms     Folder
Reports   Folder

Forms holds the library’s form pages and is in every library on every site. If you are looping through folders to do something, filter it out or your script will try to process it.

Disconnect when you are done

Disconnect-PnPOnline

Not strictly required, but if you are switching between tenants in one session it saves you a confusing half hour wondering why your commands are hitting the wrong site ?