PnP PowerShell Compatibility Guide¶
Last Updated: 2026-04-16 Cesivi Server Version: v281.0+ Document Status: Official Guidance Current Module: CesiviPnP 3.29 (fork of PnP.PowerShell 3.29)
Overview¶
Cesivi Server supports PnP PowerShell via CesiviPnP — a fork of PnP.PowerShell 3.29 that uses Cesivi.Client instead of Microsoft.SharePoint.Client. This approach eliminates the closed-source CSOM client-side limitations that caused ~30 test skips in earlier versions.
Quick Answer:
- ✅ CesiviPnP (recommended): Fork of PnP.PowerShell 3.29, net481, 427P/0F/4S
- ⚠️ PnP.PowerShell 3.x (upstream): May work via -AccessToken, not officially tested
- ⚠️ PnP PowerShell 1.x/2.x (legacy): Partially compatible, not recommended
CesiviPnP — Recommended Module¶
What Is CesiviPnP?¶
CesiviPnP is a fork of PnP.PowerShell 3.29 maintained alongside Cesivi Server. Key differences:
- Uses Cesivi.Client instead of
Microsoft.SharePoint.Client(eliminates CSOM client bugs) - Targets net481 (same as the rest of the PnP/CSOM test suite)
- Runs in isolated AppDomain to prevent static state accumulation between test classes
- Zero failures — 427P/0F/4S across 39 test classes
Test Coverage (v281.0)¶
| Metric | Value |
|---|---|
| Tests Passing | 427 |
| Tests Failing | 0 |
| Tests Skipped | 4 (1 auto-paging design, 3 Forms-folder/multi-request gaps — tracked) |
| Test Classes | 39 |
| Cmdlet Coverage | 224/224 cmdlets (100% of applicable) |
Installation¶
CesiviPnP is built as part of the Cesivi solution:
# Build CesiviPnP module
dotnet build Cesivi.PnP/Cesivi.PnP.csproj
# Module output: bin/Debug/net481/CesiviPnP.psd1
Connection Example¶
# Import CesiviPnP module
Import-Module "path/to/CesiviPnP.psd1"
# Obtain access token from Cesivi Azure AD mock
$tokenResponse = Invoke-RestMethod -Method Post `
-Uri "http://localhost:5000/oauth2/v2.0/token" `
-Body @{
grant_type = "client_credentials"
client_id = "12345678-1234-1234-1234-123456789012"
client_secret = "mock-secret"
scope = "http://localhost:5000/.default"
}
# Connect with access token
$accessToken = ConvertTo-SecureString $tokenResponse.access_token -AsPlainText -Force
Connect-PnPOnline -Url "http://localhost:5000" -AccessToken $accessToken
# Use cmdlets normally
Get-PnPWeb
Get-PnPList
Get-PnPListItem -List "Documents"
Helper Function¶
function Connect-CesiviPnP {
param(
[string]$Url = "http://localhost:5000",
[string]$ClientId = "12345678-1234-1234-1234-123456789012",
[string]$ClientSecret = "mock-secret"
)
$tokenResponse = Invoke-RestMethod -Method Post `
-Uri "$Url/oauth2/v2.0/token" `
-Body @{
grant_type = "client_credentials"
client_id = $ClientId
client_secret = $ClientSecret
scope = "$Url/.default"
}
$accessToken = ConvertTo-SecureString $tokenResponse.access_token -AsPlainText -Force
Connect-PnPOnline -Url $Url -AccessToken $accessToken
Write-Host "Connected to $Url via CesiviPnP" -ForegroundColor Green
}
Connect-CesiviPnP
$web = Get-PnPWeb
Write-Host "Web Title: $($web.Title)"
Supported Authentication¶
- ✅ Access Token (
-AccessToken) — Via Cesivi OAuth2 mock (recommended) - ✅ OAuth 2.0 Client Credentials — Service-to-service authentication
- ✅ Username/Password (
-Credentials) — NTLM/Basic fallback
Running CesiviPnP Tests¶
Batch Runner (Recommended)¶
# Run all 33+ PnP test classes with process isolation
bash Scripts/run-pnp-test-batch.sh
# Expected result: 427P/0F/4S — 33+ classes
Individual Test Classes¶
bash Scripts/test-watchdog.sh 180 Cesivi.Tests.PnP/Cesivi.Tests.PnP.csproj
Filter by Category¶
dotnet test --filter "FullyQualifiedName~PnpListTests"
dotnet test --filter "FullyQualifiedName~PnpWebTests"
dotnet test --filter "FullyQualifiedName~PnpUserGroupTests"
Cmdlet Coverage Matrix¶
Fully Supported Categories (100%)¶
| Category | Cmdlets | Status |
|---|---|---|
| Web | Get/Set-PnPWeb, Get/Add/Remove-PnPSubWeb | ✅ Full |
| Lists | Get/New/Remove-PnPList, Set-PnPList | ✅ Full |
| List Items | Get/Add/Set/Remove-PnPListItem | ✅ Full |
| Files | Get/Add/Remove-PnPFile, Copy/Move-PnPFile | ✅ Full |
| Folders | Get/Add/Remove-PnPFolder | ✅ Full |
| Fields | Get/Add/Remove-PnPField, Set-PnPField | ✅ Full |
| Content Types | Get/Add/Remove-PnPContentType, Set-PnPContentType | ✅ Full |
| User/Groups | Get/New/Remove-PnPGroup, Get/Add/Remove-PnPGroupMember | ✅ Full |
| Permissions | Get/Set/Remove-PnPListPermission, Get/Set-PnPUser | ✅ Full |
| Views | Get/Add/Remove-PnPView, Set-PnPView | ✅ Full |
| Features | Enable/Disable/Get-PnPFeature | ✅ Full |
| Property Bags | Get/Set/Remove-PnPPropertyBagValue | ✅ Full |
| Navigation | Get/Add/Remove-PnPNavigationNode | ✅ Full |
| Provisioning | Get/Apply-PnPProvisioningTemplate | ✅ Full |
| Search | Submit-PnPSearchQuery, Invoke-PnPSearchIndexing | ✅ Full |
| Taxonomy | Get/New/Remove-PnPTermGroup, Get/New/Remove-PnPTermSet | ✅ Full |
| Recycle Bin | Get/Restore/Remove-PnPRecycleBinItem | ✅ Full |
| Alerts | Get/Add/Remove-PnPAlert | ✅ Full |
| Webhooks | Get/Add/Remove-PnPWebhookSubscription | ✅ Full |
| Role Definitions | Get/Add/Remove-PnPRoleDefinition | ✅ Full |
| Publishing | Get/Add-PnPPublishingPage, Enable-PnPFeature (publishing) | ✅ Full |
| Site Policies | Get/Set-PnPSitePolicy | ✅ Full |
Partially Supported¶
| Category | Status | Notes |
|---|---|---|
| Workflow | ⚠️ Basic | Start/stop workflow, not full workflow manager |
| Managed Metadata | ⚠️ Basic | Term store operations, not full enterprise MMS |
| User Profiles | ⚠️ Basic | Get/Set profile properties |
| Site Templates | ⚠️ Partial | Save/Apply-PnPProvisioningTemplate with common templates |
Not Supported¶
| Category | Notes |
|---|---|
| SharePoint Online-only cmdlets | SPO-specific admin operations |
| Modern sites (Teams/Communication) | Cesivi targets classic SharePoint |
| Power Platform integration | No Power Apps/Flow connectors |
| Microsoft Graph cmdlets | Not implemented |
Known Limitations¶
Auto-Paging Behavior (1 test SKIPPED — By Design)¶
Cmdlet: Get-PnPListItem -PageSize N
Behavior: PnP auto-fetches ALL pages regardless of -PageSize. This is PnP library design, not a bug.
Workaround: Filter client-side after retrieval.
Folder PropertyBag with ServerRelativeUrl¶
Cmdlets: Set-PnPPropertyBagValue -Folder, Get-PnPPropertyBagValue -Folder
Root Cause: GetFolderByServerRelativePath() doesn't add ObjectIdentityQuery — CSOM protocol limitation.
Workaround: Use web-level PropertyBag operations instead.
Disable-PnPFeature After Enable in Same Session¶
Root Cause: CSOM-cached feature collection doesn't reflect REST-activated features in same session. Workaround: Create a new PnP connection between Enable and Disable operations.
Frequently Asked Questions¶
Q: What happened to PnP PowerShell 1.x/2.x support?¶
CesiviPnP supersedes both. CesiviPnP is based on PnP.PowerShell 3.29 (the current upstream), with Cesivi.Client as the CSOM backend. Earlier attempts to support 1.x/2.x had significant limitations (low coverage, client bugs, Azure AD dependency). CesiviPnP achieves 427P/0F/4S — far better than any earlier attempt.
Q: Can I use upstream PnP.PowerShell 3.x directly?¶
You may be able to connect using -AccessToken (Cesivi provides OAuth2 mock endpoints). However, the upstream module uses Microsoft.SharePoint.Client which has known static state bugs. Results will vary. CesiviPnP is the supported path.
Q: What OAuth2 endpoints does Cesivi provide?¶
POST {url}/oauth2/v2.0/token— Client credentials flowGET {url}/.well-known/openid-configuration— OpenID metadataGET {url}/oauth2/v2.0/keys— JWKS endpoint
Q: How does CesiviPnP handle authentication?¶
CesiviPnP uses the same OAuth2 mock that all Cesivi tests use. Pass -AccessToken to Connect-PnPOnline. The token is obtained via client credentials flow against {url}/oauth2/v2.0/token.
Q: What about CSOM directly (without PnP)?¶
CSOM via Cesivi.Client achieves 100% (580P/0F/7S). Use CSOM for operations not covered by PnP cmdlets. See CSOM Details.
Q: What if I need specific cmdlets not yet implemented?¶
Options:
1. Use CSOM directly — PnP cmdlets are wrappers around CSOM
2. Use REST API — most operations available via /_api/
3. Check _docs/features/PNP_POWERSHELL.md for detailed cmdlet list
Resources¶
- CesiviPnP Test Suite:
Cesivi.Tests.PnP/— 39 test classes - Batch Runner:
Scripts/run-pnp-test-batch.sh - PnP Area Guide:
_project/areas/pnp/INDEX.md - Cmdlet Matrix:
_docs/features/PNP_CMDLET_MATRIX.md(if exists) - Known Limitations:
_docs/KNOWN_LIMITATIONS.md - Upstream PnP: https://github.com/pnp/powershell
Document Version: 282.0 Last Updated: 2026-04-16 (PLAN-1036 - MASTERPLAN v282.0) Author: Cesivi Server Team