Skip to content

PnP PowerShell Support

HomeDocumentationFeatures → PnP PowerShell


Overview

Cesivi Server provides limited support for PnP PowerShell cmdlets. Since PnP PowerShell is a wrapper around CSOM (Client-Side Object Model), its compatibility is inherently limited by the underlying CSOM implementation constraints.

PnP Coverage: 21.4% (51/238 tests passing) Status: ⚠️ CSOM-Dependent - 85% of failures inherited from CSOM limitations Best For: Simple PowerShell automation and basic CRUD operations


Understanding PnP PowerShell Limitations

The Dependency Chain

PnP Cmdlet (PowerShell)
    ↓ (wraps)
CSOM Operation (ClientContext, Load/Query)
    ↓ (uses)
CSOM Binary Protocol (proprietary JSON format)
    ↓ (communicates with)
Mock Server Response

Key Insight: Every PnP cmdlet ultimately uses CSOM. If CSOM can't deserialize the response or initialize properties correctly, PnP cmdlets fail too.

Why Coverage is Low (21.4%)

PnP PowerShell's 21.4% pass rate directly reflects CSOM's 70.3% pass rate:

Failure Breakdown (187 failing tests): - 155-165 tests (85%): CSOM-dependent failures - 136 tests (73%): PropertyNotInitializedException from CSOM Load() lambda limitation - 20-29 tests (27%): Binary JSON serialization errors from CSOM protocol - 15-25 tests (10-15%): PnP-specific failures - Parameter binding issues - Missing cmdlet implementations - PowerShell wrapper edge cases

Conclusion: Fixing PnP requires fixing CSOM first. The 21.4% pass rate is the architectural ceiling for CSOM-dependent operations.


What Works

Connection Management (✅ Reliable)

# Connect to mock server
Connect-PnPOnline -Url "http://localhost:5000" -UseWebLogin

# With credentials
Connect-PnPOnline -Url "http://localhost:5000" -Credentials (Get-Credential)

# Generic authentication (when AcceptAllCredentials: true)
$creds = New-Object PSCredential("testuser", (ConvertTo-SecureString "password" -AsPlainText -Force))
Connect-PnPOnline -Url "http://localhost:5000" -Credentials $creds

# Verify connection
Get-PnPConnection

# Disconnect
Disconnect-PnPOnline

Web Operations (✅ 90%+ Reliable)

# Get web properties (WORKS)
$web = Get-PnPWeb
Write-Host "Web Title: $($web.Title)"
Write-Host "Web URL: $($web.Url)"

# Get all webs (WORKS)
$webs = Get-PnPSubWebs
foreach ($web in $webs) {
    Write-Host "Subweb: $($web.Title)"
}

# Create subweb (WORKS with limitations)
New-PnPWeb -Title "My Subweb" -Url "mysubweb" -Template "STS#0"

# Remove web (WORKS)
Remove-PnPWeb -Url "mysubweb" -Force

List Operations (✅ 85%+ Reliable for Basic)

# Get a list (WORKS)
$list = Get-PnPList -Identity "Documents"
Write-Host "List Title: $($list.Title)"
Write-Host "Item Count: $($list.ItemCount)"

# Get all lists (WORKS)
$lists = Get-PnPList
foreach ($list in $lists) {
    Write-Host "List: $($list.Title)"
}

# Create a list (WORKS)
New-PnPList -Title "MyList" -Template GenericList

# Remove a list (WORKS)
Remove-PnPList -Identity "MyList" -Force

File Operations (✅ 85%+ Reliable)

# Upload a file (WORKS)
Add-PnPFile -Path "C:\temp\document.pdf" -Folder "Shared Documents"

# Download a file (WORKS)
Get-PnPFile -Url "/sites/site/Shared Documents/document.pdf" -Path "C:\temp\downloaded.pdf" -AsFile

# Get file metadata (WORKS)
$file = Get-PnPFile -Url "/sites/site/Shared Documents/document.pdf"
Write-Host "File Size: $($file.Length)"

# Remove a file (WORKS)
Remove-PnPFile -ServerRelativeUrl "/sites/site/Shared Documents/document.pdf" -Force

Folder Operations (✅ 80%+ Reliable)

# Create a folder (WORKS)
New-PnPFolder -Name "MyFolder" -Folder "Shared Documents"

# Get folder (WORKS with limitations)
$folder = Get-PnPFolder -Url "/sites/site/Shared Documents/MyFolder"

# Remove folder (WORKS)
Remove-PnPFolder -Name "MyFolder" -Folder "Shared Documents" -Force

What Doesn't Work (or Has Limitations)

List Item Operations (⚠️ 50% Reliable)

Problem: PnP cmdlets use selective loading internally, triggering CSOM PropertyNotInitializedException.

# ❌ PROBLEMATIC - May throw PropertyNotInitializedException
$items = Get-PnPListItem -List "Documents" -Fields "Title", "Created"
$title = $items[0]["Title"]  # May fail

# ✅ WORKAROUND - Use REST API instead
$items = Invoke-PnPSPRestMethod -Url "/_api/web/lists/getbytitle('Documents')/items?`$select=Title,Created"
foreach ($item in $items.value) {
    Write-Host "Title: $($item.Title), Created: $($item.Created)"
}

Field and Content Type Operations (❌ <30% Reliable)

Problem: Field/ContentType cmdlets depend heavily on CSOM selective loading and site column persistence.

# ❌ OFTEN FAILS - CSOM limitations
Get-PnPField -Identity "Title"  # May fail with PropertyNotInitializedException
New-PnPField -DisplayName "MyField" -InternalName "MyField" -Type Text  # May not persist
Set-PnPField -Identity "MyField" -Values @{Description="New description"}  # May not persist

# ✅ WORKAROUND - Use REST API
Invoke-PnPSPRestMethod -Url "/_api/web/fields/getbyinternalname('Title')"

View Operations (❌ <20% Reliable)

Problem: View updates don't persist (CSOM persistence limitation).

# ❌ OFTEN FAILS
Get-PnPView -List "Documents"  # May fail
Set-PnPView -List "Documents" -Identity "All Documents" -Values @{RowLimit=100}  # Doesn't persist

# ✅ WORKAROUND - Use REST API
Invoke-PnPSPRestMethod -Url "/_api/web/lists/getbytitle('Documents')/views"

Cmdlet Compatibility Matrix

Legend

  • Fully Compatible - Works reliably (>85% success rate)
  • ⚠️ Partially Compatible - Works with limitations (60-85% success rate)
  • Not Compatible - Fails consistently (<60% success rate)

Connection & Web Management

Cmdlet Status Notes Alternative
Connect-PnPOnline ✅ 95%+ Works reliably N/A
Disconnect-PnPOnline ✅ 95%+ Works reliably N/A
Get-PnPContext ✅ 95%+ Works reliably N/A
Get-PnPWeb ✅ 90%+ Some properties may be null REST API
New-PnPWeb ⚠️ 70%+ Site creation limited REST API
Remove-PnPWeb ✅ 85%+ Works reliably N/A

List & List Item Operations

Cmdlet Status Notes Alternative
Get-PnPList ✅ 90%+ Basic scenarios work REST API
New-PnPList ✅ 85%+ Basic list creation REST API
Remove-PnPList ✅ 90%+ Reliable deletion N/A
Get-PnPListItem ⚠️ 50%+ Fails with -Fields parameter REST API
Add-PnPListItem ⚠️ 60%+ Creation works, updates may fail REST API
Set-PnPListItem ❌ <20% CSOM serialization errors REST API
Remove-PnPListItem ✅ 85%+ Item deletion reliable N/A

File & Folder Operations

Cmdlet Status Notes Alternative
Get-PnPFile ✅ 90%+ File metadata retrieval works REST API
Add-PnPFile ✅ 85%+ File upload reliable REST API
Remove-PnPFile ✅ 85%+ File deletion reliable REST API
Get-PnPFolder ⚠️ 70%+ Folder metadata partial REST API
New-PnPFolder ✅ 80%+ Folder creation works REST API
Remove-PnPFolder ✅ 80%+ Folder deletion works REST API
Copy-PnPFile ⚠️ 40%+ File copy unreliable REST API
Move-PnPFile ⚠️ 40%+ File move unreliable REST API

Field & Content Type Operations

Cmdlet Status Notes Alternative
Get-PnPField ⚠️ 60%+ Selective field loading may fail REST API
New-PnPField ❌ <30% Field creation not persisting REST API
Set-PnPField ❌ <20% Field updates not persisting REST API
Get-PnPContentType ⚠️ 50%+ Collection loading may fail REST API
New-PnPContentType ❌ <20% ContentType creation fails REST API

Permission & User Operations

Cmdlet Status Notes Alternative
Get-PnPUser ✅ 85%+ User lookup works REST API
New-PnPUser ⚠️ 70%+ User addition works REST API
Get-PnPGroup ✅ 85%+ Group enumeration works REST API
New-PnPGroup ⚠️ 70%+ Group creation works REST API
Grant-PnPSiteDesignRights ⚠️ 50%+ Permission assignment partial REST API

Start with PnP for Simple Operations

# ✅ This works well
Connect-PnPOnline -Url "http://localhost:5000" -UseWebLogin

# ✅ Simple metadata retrieval
$web = Get-PnPWeb
$list = Get-PnPList "Documents"
Write-Host "List has $($list.ItemCount) items"

# ✅ File operations
Add-PnPFile -Path "C:\temp\file.pdf" -Folder "Shared Documents"

Switch to REST for Complex Operations

# ❌ This may fail with PnP
$items = Get-PnPListItem -List "Documents" -Fields "Title", "Created"

# ✅ Use REST API instead
$items = Invoke-PnPSPRestMethod -Url "/_api/web/lists/getbytitle('Documents')/items?`$select=Title,Created"
foreach ($item in $items.value) {
    Write-Host "Title: $($item.Title)"
}

# ✅ Field operations via REST
$fields = Invoke-PnPSPRestMethod -Url "/_api/web/fields"
foreach ($field in $fields.value) {
    Write-Host "Field: $($field.Title)"
}

Use CSOM Directly for Advanced Scenarios

# ✅ Direct CSOM access for full control
$ctx = Get-PnPContext
$list = $ctx.Web.Lists.GetByTitle("Documents")
$ctx.Load($list.Items)  # No lambda expression
$ctx.ExecuteQuery()

foreach ($item in $list.Items) {
    Write-Host "Item: $($item['Title'])"
}

Common Errors and Solutions

Error: PropertyNotInitializedException

Symptom:

The property or field 'FieldValuesAsText' has not been initialized

Cause: PnP cmdlet uses selective loading internally, triggering CSOM limitation.

Solution:

# ❌ Fails with PropertyNotInitializedException
$items = Get-PnPListItem -List "Documents" -Fields "Title"

# ✅ Use REST API instead
$items = Invoke-PnPSPRestMethod -Url "/_api/web/lists/getbytitle('Documents')/items?`$select=Title"

Error: Cannot contact site

Symptom:

Cannot contact site at the specified URL http://localhost:5000

Solutions: 1. Wait 5-10 seconds after starting server 2. Verify server health: Invoke-WebRequest http://localhost:5000/health 3. Check credentials 4. Use -RetryCount and -RetryWait parameters

Connect-PnPOnline -Url "http://localhost:5000" -UseWebLogin -RetryCount 3 -RetryWait 2

Error: List does not exist

Symptom:

List 'Documents' does not exist at site with URL 'http://localhost:5000'

Solutions: 1. Verify list name (case-sensitive) 2. Check if list was created 3. Use REST to verify list existence

# Verify list exists
$lists = Invoke-PnPSPRestMethod -Url "/_api/web/lists?`$filter=Title eq 'Documents'"
if ($lists.value.Count -eq 0) {
    Write-Host "List 'Documents' does not exist"
    New-PnPList -Title "Documents" -Template DocumentLibrary
}

Performance Characteristics

Operation Type Avg Response Time Reliability Notes
Connection 100-200ms High Initial connection
Simple Cmdlets 50-150ms High Get-PnPWeb, Get-PnPList
File Operations 200-500ms High Upload/download
Complex Cmdlets 100-300ms Medium May fail with CSOM errors
REST API Calls 20-50ms High Invoke-PnPSPRestMethod

Recommendation: Use REST API via Invoke-PnPSPRestMethod for best performance and reliability.


Example Scripts

Complete CRUD Script (Using Workarounds)

# Connect
Connect-PnPOnline -Url "http://localhost:5000" -UseWebLogin

# Create a list (✅ Works)
New-PnPList -Title "MyList" -Template GenericList

# Add items (⚠️ Use REST for reliability)
$itemData = @{
    __metadata = @{ type = "SP.Data.MyListListItem" }
    Title = "Item 1"
}
Invoke-PnPSPRestMethod -Method POST `
    -Url "/_api/web/lists/getbytitle('MyList')/items" `
    -Content $itemData

# Get items with specific fields (✅ Use REST)
$items = Invoke-PnPSPRestMethod -Url "/_api/web/lists/getbytitle('MyList')/items?`$select=Title,Created"
foreach ($item in $items.value) {
    Write-Host "Title: $($item.Title), Created: $($item.Created)"
}

# Update item (✅ Use REST)
$updateData = @{
    __metadata = @{ type = "SP.Data.MyListListItem" }
    Title = "Updated Title"
}
Invoke-PnPSPRestMethod -Method POST `
    -Url "/_api/web/lists/getbytitle('MyList')/items(1)" `
    -Content $updateData `
    -XHTTPMethod "MERGE"

# Delete item (✅ Use REST or PnP)
Remove-PnPListItem -List "MyList" -Identity 1 -Force

# Delete list (✅ Works)
Remove-PnPList -Identity "MyList" -Force

# Disconnect
Disconnect-PnPOnline

Bulk File Upload Script

# Connect
Connect-PnPOnline -Url "http://localhost:5000" -UseWebLogin

# Upload all files from a folder (✅ Works reliably)
$files = Get-ChildItem "C:\temp\documents" -File
foreach ($file in $files) {
    Write-Host "Uploading $($file.Name)..."
    Add-PnPFile -Path $file.FullName -Folder "Shared Documents"
}

Write-Host "Upload complete: $($files.Count) files"

# Disconnect
Disconnect-PnPOnline

When to Use What

Scenario Recommended Reason
Simple metadata retrieval PnP PowerShell Easy, works well
Get list items with specific fields REST API Avoids CSOM selective loading
Bulk item updates REST API Better reliability
Create/delete lists PnP PowerShell Simple, reliable
File operations PnP PowerShell Upload/download work well
Field/ContentType operations REST API PnP has low success rate
Complex permission operations REST API or CSOM direct More control

Features

  • CSOM - Underlying CSOM implementation and limitations
  • REST API - Recommended alternative for complex operations
  • Authentication - Auth methods and configuration
  • Permissions - Permission system guide

Reference

Troubleshooting


Last Updated: November 15, 2025 Version: 1.0.0

Navigation: Home | Documentation | Features | PnP PowerShell