PnP PowerShell を使用して選択したクラシック ページを変換する

Microsoft 365 アセスメント ツールはクラシック ページのインベントリを作成しますが、変更は行いません。 評価出力を使用してページ ウェーブを承認し、PnP PowerShell ConvertTo-PnPPage を使用してモダン ページを作成します。

注:

PnP PowerShell はオープン ソース ソリューションであり、アクティブなコミュニティでサポートが提供されています。 Microsoft からのオープン ソース ツールのサポート SLA はありません。

ページ変換ワークフロー

  1. 完了した評価範囲から代表的なページ ウェーブを選択します。
  2. ブロックの Web パーツを解決し、インプレース ターゲットまたはクロスサイト ターゲットを選択します。
  3. テナント所有の PnP PowerShell アプリケーションと必要なアクセス許可を準備します。
  4. ソース保持の既定値とログ記録を使用して代表的なウェーブを変換します。
  5. ウェーブを展開する前に、生成されたすべてのページを検証します。

開始する前に

次の前提条件を完了します。

  1. クラシック ページの評価を実行して解釈します。
  2. 成功したスキャン範囲から代表的なウェーブを選択します。
  3. PowerShell 7.4.0 以降と、現在の安定した PnP PowerShell リリースをインストールします。
  4. 対話型 PnP PowerShell 用にテナント所有の Microsoft Entra アプリケーションを登録します。
  5. サインインしたユーザーがソース Web とターゲット Web のページを編集できることを確認します。

2024 年 9 月 9 日以降、対話型 PnP PowerShell 認証には、独自のアプリケーション登録とクライアント ID が必要です。

アプリケーションを登録するアカウントは、アプリ登録の作成を許可されている必要があります。 テナントの同意ポリシーは、管理者が同意を付与する必要があるかどうかを決定します。

アクセス許可

読み取り専用のアセスメント アプリケーションとは別の委任されたアプリケーションを使用します。

変換要件 委任された SharePoint スコープ
ソースを読み取り、モダン ページを作成、保存、公開する AllSites.Manage
アイテム レベルの一意のアクセス許可もコピーします AllSites.FullControl

サインインしているユーザーのサイト権限も適用されます。 アプリケーションの委任されたスコープでは、他の方法ではアクセスできなかったサイトへのアクセスがユーザーには許可されません。

AllSites.Manage では、生成されたページがライブラリからアクセス許可を継承するように -SkipItemLevelPermissionCopyToClientSidePage を追加します。 AllSites.FullControl は、ページの固有のアクセス許可を保持する必要がある場合にのみ使用してください。

PnP PowerShell をインストールまたは更新する

PnP PowerShell を使用するには、PowerShell 7.4.0 以降が必要です。

$PSVersionTable.PSVersion
Install-Module PnP.PowerShell -Scope CurrentUser

PnP PowerShell が既にインストールされている場合は、PowerShell 7.4.0 以降から Update-Module PnP.PowerShell を実行します。

PnP PowerShell のインストール」を参照してください。

対話型変換アプリケーションを登録する

次のコマンドは、対話型サインイン用のパブリック クライアント アプリケーションを作成します。

Register-PnPEntraIDAppForInteractiveLogin `
  -ApplicationName "Classic Page Transformation" `
  -Tenant "<tenant>.onmicrosoft.com" `
  -SharePointDelegatePermissions AllSites.Manage `
  -SignInAudience AzureADMyOrg

返されたアプリケーション ID をコピーします。 テナントの同意ポリシーによっては、管理者が最初の接続の前に同意を与える必要がある場合があります。

このパブリック クライアント登録は、代理対話型またはデバイス ログイン用です。 無人認証に必要なアプリケーションのアクセス許可や証明書は提供されません。

手動登録およびその他の認証方法については、「PnP PowerShell 用に Entra ID アプリケーションを登録する」を参照してください。

21Vianet が運用する GCC High、DoD、または Microsoft 365 の場合、アプリケーションを登録して接続するときに、一致する -AzureEnvironment 値を指定します。 Register-PnPEntraIDAppForInteractiveLogin および Connect-PnPOnline コマンドレット リファレンスを参照してください。

PnP PowerShell に評価行をマップする

評価フィールド PnP PowerShell での使用
SiteUrl + WebUrl Connect-PnPOnline のソース URL。
ListUrl, ListId, PageUrl 正確な SitePages ライブラリとソース ファイルの ID。
PageType このワークフローに対して WikiPage または WebPartPage である必要があります。
Layout 代表的なパターンのグループ化と検証。

第 1 ウェーブ ページを変換する前に、次のものが必要です。

  • 成功したサイトと Web カバレッジ。
  • PageType WikiPage または WebPartPage に等しい。
  • 未解決のマップされていない Web パーツはありません。
  • WebPartCount 0 より大きい。 手動レビュー後に、この自動例以外のゼロ部分のページを処理します。
  • ライブラリからアクセス許可を継承するソース ページ。
  • 記録されたコンテンツとレイアウトのベースラインを検証用に記録します。

代表的なページ グループを構築する

次のスクリプトは、候補インベントリを作成します。 ページは変換されません。

ページの種類、レイアウト、順序付けされた Web パーツの署名別に、適格な Wiki ページと Web パーツ ページをグループ化します。 署名には、Web パーツの種類、マッピング結果、非表示状態、閉じた状態が含まれます。

$pages = Import-Csv .\classicpages.csv
$webParts = Import-Csv .\classicpagewebparts.csv
$partsByPage = @{}

function Get-PageKey {
  param($Row)

  '{0}|{1}|{2}|{3}' -f $Row.ScanId, $Row.SiteUrl, $Row.WebUrl, $Row.PageUrl
}

foreach ($part in $webParts) {
  $key = Get-PageKey $part
  if (-not $partsByPage.ContainsKey($key)) {
    $partsByPage[$key] = [Collections.Generic.List[object]]::new()
  }

  $partsByPage[$key].Add($part)
}

$candidates = foreach ($page in $pages) {
  $fileName = [IO.Path]::GetFileName($page.PageUrl)

  if ($page.PageType -notin @('WikiPage', 'WebPartPage') -or
      $page.HomePage -eq 'True' -or
      -not $page.ListUrl.EndsWith('/SitePages', [StringComparison]::OrdinalIgnoreCase) -or
      $page.WebPartCount -eq '0' -or
      $page.MappingPercentage -ne '100' -or
      -not [string]::IsNullOrWhiteSpace($page.UnmappedWebParts) -or
      $fileName.StartsWith('Migrated_', [StringComparison]::OrdinalIgnoreCase) -or
      $fileName.StartsWith('Previous_', [StringComparison]::OrdinalIgnoreCase)) {
    continue
  }

  $key = Get-PageKey $page
  if (-not $partsByPage.ContainsKey($key)) {
    throw "Web Part rows are missing for $($page.PageUrl)."
  }

  $signature = (
    $partsByPage[$key] |
      Sort-Object { [int]$_.WebPartIndex } |
      ForEach-Object {
        '{0}|Mappable={1}|Hidden={2}|Closed={3}' -f
          $_.WebPartTypeShort, $_.IsMappable, $_.Hidden, $_.IsClosed
      }
  ) -join ';'

  [pscustomobject]@{
    PatternKey = '{0}|{1}|{2}' -f $page.PageType, $page.Layout, $signature
    ScanId = $page.ScanId
    SiteUrl = $page.SiteUrl
    WebUrl = $page.WebUrl
    PageUrl = $page.PageUrl
    PageType = $page.PageType
    ListUrl = $page.ListUrl
    ListId = $page.ListId
    AssessmentTimeZoneId = [TimeZoneInfo]::Local.Id
    Layout = $page.Layout
    HomePage = $page.HomePage
    WebPartCount = [int]$page.WebPartCount
    MappingPercentage = $page.MappingPercentage
    UnmappedWebParts = $page.UnmappedWebParts
    ModifiedAt = $page.ModifiedAt
    WebPartSignature = $signature
    IncludePattern = 'True'
    Selected = 'False'
    ExpectedVisibleContent = ''
    ValidationOwner = ''
  }
}

$groups = $candidates | Group-Object PatternKey -AsHashTable -AsString

$candidateInventory = foreach ($candidate in $candidates) {
  $candidate | Select-Object *,
    @{ Name = 'PatternPageCount'; Expression = { $groups[$candidate.PatternKey].Count } }
}

$candidateInventory |
  Sort-Object PatternKey, PageUrl |
  Export-Csv .\representative-page-groups.csv -NoTypeInformation

representative-page-groups.csvを確認し、移行ウェーブに含まれるすべてのPatternKeyから少なくとも 1 つのページを選択します。 Web パーツのプロパティ、リンクされたコンテンツ、またはビジネス動作がパターン内で大きく異なる場合は、追加のページを選択する。

計画されている移行外のパターンの IncludePattern=False を設定します。 選択したページごとに、 Selected=True と塗りつぶしの ExpectedVisibleContentValidationOwnerを設定します。

評価 CSV を生成した同じコンピューターでグループ化手順を実行します。 AssessmentTimeZoneId オフセットのない ModifiedAt 値を解釈するために使用されるタイムゾーンを記録します。

ゼロパート ページ、ホーム ページ、発行ページ、未解決のマッピングを含むページを別々のレビュー キューに保持します。 既定の SitePages ライブラリ外のページも、個別にレビューされる 1 ページ パスに残ります。

ソース保持の既定値について

注意

-TakeSourcePageName クラシック ソース ページの名前を変更し、 -Overwrite 既存のターゲット ページを置き換えます。 生成されたページが承認され、ロールバック計画が確立されるまで、どちらのオプションも使用しないでください。

オプション 第 1 波のガイダンス
既定の名前付け ソース名を保持し、 Migrated_<source-page>.aspxを作成します。
-TakeSourcePageName 最初は使用しないでください。 クラシック ソースの名前が Previous_ プレフィックスに変更されます。
-Overwrite 最初は使用しないでください。 既存のターゲットを自動的に置き換えるのではなく、そのターゲットを確認します。
-ReplaceHomePageWithDefault 代表的なウェーブでは使用しないでください。
-DontPublish 生成されたページが検証中に下書きのままになるように、最初のウェーブに使用します。
-SkipItemLevelPermissionCopyToClientSidePage 固有のアクセス許可をコピーする必要がない限り、 AllSites.Manage アプリケーションで使用してください。

第 1 波のドラフトをロールバックする

バッチ ワークフローは、クラシック ソース ページの名前を変更または上書きしません。 生成された下書きが検証に失敗した場合:

  1. クラシック ソース ページはサービス中のままにします。
  2. 保持 TransformationStatus=CreatedValidationStatus=Failedを設定し、 ValidationNotesValidatedByValidatedAt を塗りつぶします。
  3. 失敗した検証証拠を使用して TargetPageUrlLogPath を保持します。
  4. 生成されたMigrated_の下書きは、調査に不要になり、organizationのアイテム保持ポリシーで削除が許可されている場合は、サイト ページ ライブラリからリサイクルされます。
  5. 候補ルールまたは修復を修正し、ウェーブを再開する前に 1 つの代表ページを再試行します。

-Overwrite -TakeSourcePageNameはバッチ ワークフローの外にあります。 別の手順でいずれかのオプションを使用する前に、ページのバージョンと URL を保持し、現在のホーム ページの設定を記録し、非実稼働サイトで逆の名前変更または復元プロセスをテストし、明示的な承認を取得してください。

選択した Wiki ページまたは Web パーツ ページの 1 つを変換する

1 行が Selected=True とマークされた代表ページ スクリプトを使用します。 これにより、1 ページのテストで、より大きなウェーブと同じ検証、認証、結果コントラクトが維持されます。

バッチ スクリプトは、既定の SitePages ライブラリの Wiki ページと Web パーツ ページをサポートします。 ホーム ページ、ゼロ パート ページ、固有のアクセス許可を持つページ、評価後に変更されたページは除外されます。 これらのページは、個別にレビューされたパスを介して処理します。

すべての代表的なページを変換する

ページ ウェーブ スクリプト参照から 3 つの埋め込みファイルを同じフォルダーに保存します。

representative-page-groups.csv:

  1. 計画されている移行の各変換パターンの IncludePattern=True を設定します。
  2. 含まれるすべてのパターンの少なくとも 1 ページに Selected=True を設定します。
  3. 選択したすべてのページの ExpectedVisibleContentValidationOwner を入力します。

SharePoint ページの認証または書き込みを行わずに、完全なウェーブをプレビューします。

.\Convert-RepresentativePages.ps1 `
  -ManifestPath .\representative-page-groups.csv `
  -ClientId "<application-id>" `
  -AuthenticationMode Interactive `
  -WhatIf `
  -Force

プレビューの CSV には、 PlannedActionPlannedTargetPageUrlが記録されます。 -WhatIf認証しないため、TargetExistsNotCheckedです。

認証された読み取り専用のプリフライトを実行して、現在のソース、ホーム ページ、アクセス許可、タイムスタンプ、ターゲットが存在しないことを確認します。

.\Convert-RepresentativePages.ps1 `
  -ManifestPath .\representative-page-groups.csv `
  -ClientId "<application-id>" `
  -AuthenticationMode Interactive `
  -PreflightOnly `
  -Confirm:$false `
  -Force

すべての行は、ライブ コンバージョンの前に TransformationStatus=PreflightPassed を報告する必要があります。

対話形式で実行 影響大 確認:

.\Convert-RepresentativePages.ps1 `
  -ManifestPath .\representative-page-groups.csv `
  -ClientId "<application-id>" `
  -AuthenticationMode Interactive `
  -Confirm

スクリプトは各結果をすぐに representative-page-results.csv に書き込みます。 生成されたページは下書きのままであり、作成された各行は ValidationStatus=Pending で始まります。

次の手順に従って変換 されたクラシック ページを検証しますValidationStatus=PassedValidationNotesValidatedByValidatedAt は、ページがすべての承認基準を満たした後にのみ設定します。

ユーザーが指定したすべてのページに展開

元のrepresentative-page-groups.csvからユーザーが承認した追加の含まれる行をコピーして、approved-pages.csvを作成します。 生成されたすべてのフィールドを保持し、 ExpectedVisibleContentValidationOwnerを入力します。

選択したページのスクリプトを最初に -PreflightOnly -Confirm:$false -Force で実行します。 すべての行に PreflightPassedレポートが必要です。

拡張スクリプトを実行します。

.\Convert-SelectedPages.ps1 `
  -PagesPath .\approved-pages.csv `
  -RepresentativeManifestPath .\representative-page-groups.csv `
  -RepresentativeResultsPath .\representative-page-results.csv `
  -ClientId "<application-id>" `
  -AuthenticationMode Interactive `
  -Confirm

次の場合、スクリプトは展開を拒否します。

  • 代表的なマニフェストと結果が一致しません。
  • 代表的なページは、 CreatedPassedではありません。
  • 検証ノート、バリデーター、または検証タイムスタンプがありません。
  • PnP PowerShell のバージョンまたは 3 つのスクリプト ファイルのいずれかが、代表的な実行とは異なります。
  • 承認済みページは、元のマニフェストから変更されていないインクルード行ではありません。
  • 承認されたページは、合格した代表者がいないパターンに属します。

展開されたウェーブでは、下書きページと書き込みも作成 selected-page-results.csv。 発行する前に、これらのページを検証してください。

明示的なレビューが必要なオプション

完全なパラメーター コントラクトには、生成された ConvertTo-PnPPage コマンドレット リファレンス を使用します。

バッチ スクリプトでは、カスタム Web パーツ マッピング、発行ページ、またはクロスサイト ターゲットはサポートされていません。 これらのシナリオは、個別にレビューされた単一ページまたは高度な手順を通して処理します。

次のオプションは、バッチ ワークフロー外でのみ確認してください。

  • -CopyPageMetadata および -CopyPageMetadata
  • -UrlMappingFile-UserMappingFile-TermMappingFile
  • -Overwrite 承認とロールバック計画の後に -TakeSourcePageName されます。

モダン ページ機能のトラブルシューティング

ページ ウェーブ スクリプトでは SharePoint 機能は有効になりません。 このトラブルシューティング パスは、サポートされているクラシック チーム サイトにのみ適用されます。 従来の発行ポータルではこの機能を有効にしないでください。ページを個別のクロスサイト公開バックログとモデルにルーティングします。 モダン ページでサポートされているカスタマイズを参照してください。

Web の管理を承認されたアカウントで接続し、アクティブ化された Web 機能を一覧表示します。

$source = Connect-PnPOnline `
  -Url "https://<tenant>.sharepoint.com/sites/<site>" `
  -Interactive `
  -ClientId "<application-id>" `
  -ReturnConnection

$modernPageFeatureId = [guid]'B6917CB1-93A0-4B97-A84D-7CF49975D4EC'
$modernPageFeature = Get-PnPFeature `
  -Scope Web `
  -Connection $source |
  Where-Object DefinitionId -eq $modernPageFeatureId

if ($modernPageFeature) {
  Write-Host "Modern pages feature is active."
}
else {
  Write-Host "Modern pages feature is not active."
}

バッチ スクリプトで使用される委任された AllSites.Manage アプリケーションでは、Web 機能をアクティブ化するには十分ではありません。 サポートされているクラシック チーム サイトで機能がアクティブでない場合は、サイト所有者の承認を得て、次に接続します。

  • SharePoint AllSites.FullControl を使用する別の委任されたアプリケーション。
  • Web でフル コントロールを持つサインイン済みアカウント。
$adminConnection = Connect-PnPOnline `
  -Url "https://<tenant>.sharepoint.com/sites/<site>" `
  -Interactive `
  -ClientId "<full-control-application-id>" `
  -ReturnConnection

Enable-PnPFeature `
  -Identity $modernPageFeatureId `
  -Scope Web `
  -Connection $adminConnection

機能を有効にした後、認証済みのプリフライトを再実行します。

無人認証およびその他のページ タイプ

前に作成した委任されたパブリック クライアント アプリケーションは、アプリのみのアクセス用に個別に構成されていない限り、証明書のアプリのみの認証に再利用することはできません。

無人実行前:

  1. アプリのみのアクセス用に Entra ID アプリケーションを登録する」に従って、別のアプリのみの登録と証明書を作成します。
  2. すべてのソース サイトの SharePoint アプリケーションのアクセス許可またはサイトの割り当てを構成するには、「必要な PnP PowerShell アクセス許可を決定する」
  3. 必要な管理者の同意を与えます。
  4. -PreflightOnly -Confirm:$false および証明書認証モードでバッチ スクリプトを実行します。
  5. 認証されたプリフライトがテスト テナントに合格した後にのみ、 -PreflightOnly を削除します。

重要

証明書パラメーターのパスは Pester テストされていますが、ステージ 2 のライブ テナントは検証済みの代理対話型認証を実行します。 無人書き込みを行う前に、選択したアプリのみのアクセス許可プロファイルをテナントで検証します。

発行ページ、ブログ ページ、 SitePages外のページ、ホーム ページ、カスタム Web パーツ マッピング、および SharePoint Server ソースは、バッチ スクリプトではサポートされていません。 次の高度な参照を使用します。

次の手順

  1. 変換された各ページを検証します
  2. すべての代表ページが検証に合格した後にのみ Convert-SelectedPages.ps1 を実行します。

リファレンス