前提条件
以下の準備編が完了し、VS Code上で、PnP.PowerShellのライブラリが実行可能な状態になっていること。
また、以降の全てのサンプルの前段には、下記の認証のコードが含まれていることとする。
$siteUrl = "https://xxxxxxx.sharepoint.com/sites/sub-site-name"
$clientId = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
Connect-PnPOnline -Url $siteUrl -ClientId $clientId
PnPのコマンドレットリファレンス
コマンドレットの一覧は以下のgithubから参照できる
PnP PowerShell cmdlets | PnP PowerShell ※1
ページの一括取得
全てのページを取得する (Get-PnPPage)
(公式リファレンス)
$pages = Get-PnPPage
取得結果
オブジェクトの型はMicrosoft.Online.SharePoint.TenantAdministration.SPSitePage
※ 配列の2要素目以降は省略している
[
{
"Name": "Home.aspx",
"Title": "Home",
"CreatedDateTime": "2025-10-24T15:15:53Z",
"LastModifiedDateTime": "2025-10-29T05:21:12Z",
"UniqueId": "e8fc88ec-5917-401e-b47d-xxxxxxxxxxxxx",
"TypeId": "{e883bb25-7c77-452e-8e4d-xxxxxxxxxxxxx}"
}
]
特定のページを取得する (Get-PnPPage)
(公式リファレンス)
-Identityページ名を指定することで、1ページ当たりの情報をより詳細に取得することができる。(ただしページIDでの指定はできない)
具体的には、ページ上のセクションとWebパーツ(テキストやリンクなどのGUI要素)へアクセスができる。
# 全てのページを取得する
$pages = Get-PnPPage
foreach ($p in $pages) {
# ファイル名を指定しページを取得する
$page = Get-PnPPage -Identity $p.Name
}
取得結果
オブジェクトの型はPnP.Core.Model.SharePoint.Page
全てのページを取得する場合と型が異なる。
※ プロパティが大量にあるため、重要そうなプロパティのみ抜粋
{
"PageId": "1",
"PageTitle": "Home",
"Name": "Home.aspx",
"Folder": "",
"ThumbnailUrl": "",
"LayoutType": "Home",
"Sections": [],
"Controls": {
"8c88f208-6c77-4bdb-86a0-0c47b4316588": [
{
"HtmlPropertiesData": "",
"WebPartId": "8c88f208-6c77-4bdb-86a0-0c47b4316588",
"Title": "ニュース",
"PropertiesJson": "{\"layoutId\":\"FeaturedNews\",\"dataProviderId\":\"news\",\"emptyStateHelpItemsCount\":\"1\",\"showChrome\":true,\"carouselSettings\":{\"autoplay\":false,\"autoplaySpeed\":5,\"dots\":true,\"lazyLoad\":true},\"showNewsMetadata\":{\"showSocialActions\":false,\"showAuthor\":true,\"showDate\":true,\"showSiteTitle\":true},\"isTitleEnabled\":true,\"isChromeModified\":true,\"minimumLayoutWidth\":22,\"newsDataSourceProp\":1,\"carouselHeroWrapperComponentId\":\"\",\"prefetchCount\":4,\"filters\":[{\"filterType\":1,\"value\":\"\",\"values\":[]}],\"newsSiteList\":[],\"renderItemsSliderValue\":4,\"layoutComponentId\":\"\",\"webId\":\"00621056-fc8f-4836-8fc6-d90fd6afe489\",\"siteId\":\"bd8b50ec-738d-409c-92c1-66a8882b92b0\",\"filterKQLQuery\":\"\"}",
"ControlType": "3",
"Type": {
"FullName": "PnP.Core.Model.SharePoint.PageWebPart",
"Name": "PageWebPart"
},
"InstanceId": "f7bfdec9-09c5-4fb6-bc97-xxxxxxxxxxxx"
}
]
}
}
全てのページを取得する (Get-PnPListItem)
(公式リファレンス)
$items = Get-PnPListItem -List "SitePages"
取得結果
オブジェクトの型はMicrosoft.SharePoint.Client.ListItem
※ プロパティが大量にあるため、重要そうなプロパティのみ抜粋している
※ 配列の2要素目以降は省略している
[
{
"FieldValues": {
"ID": 1,
"GUID": "128c95df-beac-43ba-90c3-xxxxxxxxxx",
"UniqueId": "e8fc88ec-5917-401e-b47d-xxxxxxxxxx",
"FileLeafRef": "Home.aspx",
"File_x0020_Type": "aspx",
"FileRef": "/sites/test-site001/SitePages/Home.aspx",
"FileDirRef": "/sites/test-site001/SitePages",
"PageLayoutType": "Home",
"File_x0020_Size": 805,
"Created": "2025/10/24 15:15:52",
"Modified": "2025/10/29 5:21:12",
"_CommentFlags": 1,
"_CommentCount": "",
"CanvasContent1": "
}
]
FieldValuesの省略
.FieldValuesは省略して記述することができる。
ListItem型は[]演算子をオーバーロードしており、内部でFieldValuesを返却しているからと思われる。
# $a と $bは等価である
$a = $item.FieldValues["FileLeafRef"]
$b = $item["FileLeafRef"]
ページ情報の取得
ページのメタデータを取得する
$items = Get-PnPListItem -List "SitePages"
foreach ($item in $items) {
# ID, ファイル名, ファイルパス, タイトル
$fileID = $item["ID"]
$fileName = $item["FileLeafRef"]
$filePath = $item["FileRef"]
$title = $item["Title"]
}
ページ全体のHTML構造を取得する
$items = Get-PnPListItem -List "SitePages"
foreach ($item in $items) {
# HTML形式のコンテンツを取得する
$html = $item["CanvasContent1"]
}}
ページ全体のHTML構造をプレーンテキストに変換
Get-PnPPageではWebパーツごとの情報しか取得できないため、Get-PnPListItemの["CanvasContent1"]へアクセスをする必要がある。
このプロパティはページ全体を表すhtml構造の情報をテキスト形式で取得することができる。
$items = Get-PnPListItem -List "SitePages"
foreach ($item in $items) {
# HTML形式のコンテンツを取得する
$html = $item["CanvasContent1"]
# タグを削除する
$tagRemovedText = $html -replace "<[^>]+>", "`r`n"
# デコードを行う
$decodedText = [System.Web.HttpUtility]::HtmlDecode($tagRemovedText)
# 連続した改行を削除
$rowText = $decodedText -replace "(`r`n){2,}", "`r`n"
}
実行結果
整形前 (非常に長いので一部のみ抜粋)
"<div><div data-sp-canvascontrol="" data-sp-canvasdataversion="1.0" data-sp-controldata="{"position":{"layoutIndex":1,"zoneIndex":1,"zoneId":"d8a599c0-f02c-49ac-b484-2bab9c442878","sectionIndex":1,"sectionFactor":0,"controlIndex":1},"id":"d073a475-6c3b-4a36-b0df-39f78a314cc7","controlType":3,"isFromSectionTemplate":false,"addedFromPersistedData":true,"webPartId":"cbe7b0a9-3504-44dd-a3a3-0e5cacd07788","reservedWidth":1268,"reservedHeight":314}">/* Your code... */
整形後 (AIを利用して整形 & プロパティは極力削除)
<div>
<div>
<div>
<h2>テストページ</h2>
</div>
<div>
<img src="/_layouts/15/images/sleektemplateimagetile.jpg">
</div>
</div>
<div>
<p>1つ目のテキストです</p>
<p><strong>太字です</strong></p>
</div>
<div>
<h2>2つ目のテキストです</h2>
<p><span>色付き文字です</span></p>
</div>
<div>
<p>3つ目のテキストです</p>
<p><span>背景が付いています</span></p>
</div>
<div>
<div>
<div>Home</div>
<div>FAQPage</div>
<div>よく寄せられる質問</div>
<a href="/sites/test-site001"></a>
<a href="/sites/test-site001/SitePages/ITHelpdeskHome.aspx"></a>
<a href="/sites/test-site001/SitePages/FAQPage.aspx"></a>
<a href="/sites/test-site001/SitePages/Frequently-asked-questions.aspx"></a>
</div>
</div>
</div>
テキスト変換
1つ目のテキストです
太字です
2つ目のテキストです
色付き文字です
3つ目のテキストです
背景が付いています
Home
FAQPage
よく寄せられる質問
利用ページのレイアウト
Webパーツの操作
テキストを取得する
$page = Get-PnPPage -Identity "テストページ.aspx"
$page.Controls[i].Text
実行結果
<p class="noSpacingAbove spacingBelow" data-text-type="withSpacing">1つ目のテキストです</p><p class="noSpacingAbove spacingBelow" data-text-type="withSpacing"><strong>太字です</strong></p>
セクション順序, 列順序, セクション内IDを取得する
各Webパーツは以下の座標情報を持っている。
- セクション順序:何番目のセクションか
- 列順序:セクション内で、左から何番目の要素か
- 順序:セクション内で、上から何番目の要素か
$page = Get-PnPPage -Identity "テストページ.aspx"
# 相対的なWebパーツを取得する
foreach ($control in $page.Controls) {
$obj = [PSCustomObject]@{
sectionOrder = $control.Section.Order
columnOrder = $control.Column.Order
order = $control.Order
text = $control.Text
}
Write-Output($obj)
}
実行結果
sectionOrder | columnOrder | order | text
-------------|-------------|-------|--------------------------------------------------------------------------------
1 | 1 | 1 |
2 | 1 | 1 | <p class="noSpacingAbove spacingBelow" data-text-type="withSpacing">1つ目のテ...
2 | 1 | 2 | <p class="noSpacingAbove spacingBelow" data-text-type="withSpacing">3つ目のテ...
2 | 2 | 1 | ■更新対象■
2 | 2 | 2 | <p class="noSpacingAbove spacingBelow" data-text-type="withSpacing">4つ目のテ...
2 | 3 | 1 | <p class="noSpacingAbove noSpacingBelow" data-text-type="noSpacing">2つ目のテ...
3 | 1 | 1 |
3 | 2 | 1 | リンクの隣にあるテキストです
利用ページのレイアウト
テキストを更新する (座標指定)
Set-PnPPageTextPartコマンドレットを利用する。(公式リファレンス)
Webパーツを更新するにはWebパーツのID(インスタンスID)を特定する必要がある
$page = Get-PnPPage -Identity "テストページ.aspx"
foreach ($control in $page.Controls) {
if ($control.Text -eq "■更新対象■") {
# テキストが「■更新対象■」であるWebパーツの1つ下のWebパーツを取得する
$target = $page.Controls | Where-Object {
$_.Section.Order -eq $control.Section.Order -and
$_.Column.Order -eq $control.Column.Order -and
$_.Order -eq ($control.Order + 1)
} | Select-Object -First 1
# Webパーツのテキストを「更新しましたよ」で更新する
Set-PnPPageTextPart `
-Page $page `
-InstanceId $target.InstanceId `
-Text "更新しましたよ"
}
}
$page.Save()
$page.Publish()
実行結果
テキストを更新する (インスタンスID指定)
ページをメンテナンスモードで開くことで、インスタンスIDを直接確認することもできる。
メンテナンスモードの実行方法
URLの末尾に「?maintenanceMode=true」を加える。
- 通常
https://{site-url}/sites/test-site001/SitePages/ページ名.aspx - メンテナンスモード
https://{site-url}/sites/test-site001/SitePages/ページ名.aspx?maintenanceMode=true
実行結果
ただし、Webパーツの種類がテキストに限っては、インスタンスIDは表示されないようだ。
よって、この方法を採用することはできない
Webパーツのテキストを追加する
Add-PnPPageTextPartコマンドレットを利用する。(公式リファレンス)
$page = Get-PnPPage -Identity "テストページ.aspx"
Add-PnPPageTextPart `
-Page $page `
-Text "<p>新しいテキストを<strong>座標指定で</strong>追加しますよ.</p>" `
-Section 2 `
-Column 2 `
-Order 1
実行結果
注意点
リファレンスを見る限り、Section,Column,Orderの座標パラメータは必須ではないが、省略すると以下のエラーが発生する。
You cannot host text controls inside a one column full width section, only an image web part or hero web part are allowed
MethodInvocationException:
レイアウトが全幅タイプ?なセクションには画像とヒーローWebパーツしか配置できませんよだそうだ。
実質、座標の指定は必須となる。
ページを保存する
$page.Save()
ページを公開する
# Get-PnPPageで取得した「PnP.Core.Model.SharePoint.Page」オブジェクトのPublishメソッドを呼び出す場合
$page.Publish()
# ファイル名を指定する場合
Set-PnPPage -Identity "ページ名.aspx" -Publish
ページ操作
ページのタイトルを変更する
Set-PnPPageコマンドレットを利用する。(公式リファレンス)
# ページのタイトルを変更する
$pageName = "テストページ.aspx"
$newTitle = "new title!"
Set-PnPPage -Identity $pageName -Title $newTitle
ページを作成する
Add-PnPPageを利用する。(公式リファレンス)
# サイトページ直下に作成する
Add-PnPPage -Name "NewPage1" -Publish
# サイトページの特定のディレクトリ内に作成する
Add-PnPPage -Name "テストフォルダ/NewPage2" -Publish
# タイトルを指定する
Add-PnPPage -Name "NewPage3" -Title "新しいタイトル" -Publish
ページをコピーする
テンプレートのページを複製するというコマンドレットはないので、実質コピーが複製に当たる。
Copy-PnPFileを利用する。(公式リファレンス)
# ページ名
$templatePage = "テストページ.aspx"
$newPage = "テストページ_copied.aspx"
# テンプレートをコピーする
Copy-PnPFile `
-SourceUrl "SitePages/$templatePage" `
-TargetUrl "SitePages/$newPage" `
-Force
# 公開する
Set-PnPPage -Identity $newPage -Publish
ファイル名を変更する
Rename-PnPFileコマンドレットを利用する。(公式リファレンス)
# 変換前と変換後のファイル名
$oldFileName = "テストページ.aspx"
$newFileName = "テストページ_updated.aspx"
# 指定のファイル名を持つページを取得する
$item = Get-PnPListItem -List "SitePages" | Where-Object {
$_["FileLeafRef"] -eq $oldFileName
}
# -SiteRelativeUrl にはサイト内の相対パスを指定する必要がある。
# 変換前:sites/{site-name}/SitePages/pageName.aspx
# 変換後:SitePages/pageName.aspx
$relativeUrl = $item["FileRef"] -replace "sites/[^/]+/", ""
# ファイル名を変更する
Rename-PnPFile `
-SiteRelativeUrl $relativeUrl `
-TargetFileName $newFileName `
-Force
フォルダを取得する
Get-PnPFolderコマンドレットを利用する。(公式リファレンス)
フォルダが存在しない場合、例外が発生する。
$RootFolderName = "SitePages"
$targetFolderName = "subFolderName"
$folder = $null
try {
$folder = Get-PnPFolder -Url ($RootFolderName + "/" + $title)
} catch [System.Management.Automation.PSInvalidOperationException]{
Write-Output "Sharepointへの接続に失敗しました"
} catch {
Write-Output "予期せぬエラーが発生しました"
} finally {
}
フォルダを作成する
Add-PnPFolderコマンドレットを利用する。(公式リファレンス)
Add-PnPFolder -Name $title -Folder $RootFolderName
フォルダが存在しない場合、作成する
Resolve-PnPFolderコマンドレットを利用する。(公式リファレンス)
$RootFolderName = "SitePages"
$targetFolderName = "subFolderName"
Resolve-PnPFolder -SiteRelativePath ($RootFolderName + "/" + $title)




