Transformar páginas clássicas selecionadas com o PowerShell PnP

A ferramenta de Avaliação do Microsoft 365 inventaria páginas clássicas, mas não as modifica. Use a saída de Avaliação para aprovar uma onda de páginas e use o PowerShell ConvertTo-PnPPage PnP para criar as páginas modernas.

Observação

O PnP PowerShell é uma solução de software livre com uma comunidade ativa de suporte. Não há nenhuma SLA para o suporte da ferramenta de software livre por parte da Microsoft.

Fluxo de trabalho de transformação de página

  1. Selecione uma onda de páginas representativa da cobertura de Avaliação concluída.
  2. Resolva o bloqueio de Web Parts e escolha um destino in-loco ou entre sites.
  3. Prepare um aplicativo PnP PowerShell de propriedade do locatário e as permissões necessárias.
  4. Transforme a onda representativa com padrões e registro em log que preservam a origem.
  5. Valide todas as páginas geradas antes de expandir a onda.

Antes de começar

Conclua estes pré-requisitos:

  1. Execute e interprete a avaliação de páginas clássicas.
  2. Selecione uma onda representativa da cobertura de varredura bem-sucedida.
  3. Instale o PowerShell 7.4.0 ou posterior e a versão estável atual do PowerShell PnP.
  4. Registre um aplicativo do Microsoft Entra de propriedade do locatário para o PowerShell PnP interativo.
  5. Confirme se o usuário conectado pode editar páginas nas Web de origem e de destino.

Desde 9 de setembro de 2024, a autenticação interativa do PowerShell PnP requer seu próprio registro de aplicativo e ID do cliente.

A conta que registra o aplicativo deve ter permissão para criar registros de aplicativo. A política de consentimento do locatário determina se um administrador deve conceder consentimento.

Permissões

Use um aplicativo delegado separado do aplicativo de Avaliação somente leitura.

Requisito de transformação Escopo delegado do SharePoint
Ler o código-fonte e criar, salvar e publicar a página moderna AllSites.Manage
Copiar também permissões exclusivas no nível do item AllSites.FullControl

As permissões do site do usuário conectado também se aplicam. O escopo delegado do aplicativo não concede ao usuário acesso a um site que ele não poderia acessar de outra forma.

Com AllSites.Manage, adicione -SkipItemLevelPermissionCopyToClientSidePage para que a página gerada herde permissões de sua biblioteca. Use AllSites.FullControl somente quando as permissões exclusivas da página devem ser mantidas.

Instalar ou atualizar o PnP PowerShell

O PowerShell PnP requer o PowerShell 7.4.0 ou posterior.

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

Se o PnP PowerShell já estiver instalado, execute Update-Module PnP.PowerShell a partir do PowerShell 7.4.0 ou posterior.

Consulte Instalar o PowerShell PnP.

Registrar o aplicativo de transformação interativa

O comando a seguir cria um aplicativo cliente público para entrada interativa:

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

Copie a ID do aplicativo retornada. Dependendo da política de consentimento do locatário, um administrador pode precisar conceder consentimento antes da primeira conexão.

Esse registro de cliente público é para logon interativo ou de dispositivo delegado. Ele não fornece as permissões do aplicativo ou o certificado necessário para autenticação autônoma.

Para registro manual e outros métodos de autenticação, consulte Registrar um aplicativo do Entra ID para o PowerShell PnP.

Para GCC High, DoD ou Microsoft 365 operado pela 21Vianet, especifique o valor correspondente -AzureEnvironment ao registrar o aplicativo e conectar. Consulte as referências de cmdlet Register-PnPEntraIDAppForInteractiveLogin e Connect-PnPOnline .

Mapear uma linha de Avaliação para o PnP PowerShell

Campo de avaliação Uso do PowerShell PnP
SiteUrl + WebUrl URL de origem para Connect-PnPOnline.
ListUrl, ListId, PageUrl Biblioteca exata SitePages e identidade do arquivo de origem.
PageType Deve ser WikiPage ou WebPartPage para este fluxo de trabalho.
Layout Validação e agrupamento de padrões representativos.

Antes de transformar uma página de primeira onda, exija:

  • Cobertura bem-sucedida do site e da web.
  • PageType igual a WikiPage ou WebPartPage.
  • Nenhuma Web Part não mapeada não resolvida.
  • WebPartCount maior que 0. Lidar com páginas de partes zero fora deste exemplo automatizado após revisão manual.
  • Uma página de origem que herda permissões de sua biblioteca.
  • Uma linha de base de layout e conteúdo gravado para validação.

Criar grupos de páginas representativos

O script a seguir cria um inventário de candidatos. Não transforma páginas.

Ele agrupa páginas elegíveis de Wiki e Web Part por tipo de página, layout e assinatura de Web Part ordenada. A assinatura inclui o tipo de Web Part, o resultado do mapeamento, o estado oculto e o estado fechado.

$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

Examine representative-page-groups.csv e selecione pelo menos uma página de cada PatternKey que o ciclo de migração conterá. Selecione páginas adicionais quando as propriedades da Web Part, o conteúdo vinculado ou o comportamento comercial diferirem materialmente dentro de um padrão.

Defina IncludePattern=False padrões fora da migração planejada. Para cada página selecionada, defina Selected=True e preencha ExpectedVisibleContent e ValidationOwner.

Execute a etapa de agrupamento no mesmo computador que gerou os CSVs de Avaliação. AssessmentTimeZoneId Registra o fuso horário usado para interpretar o valor sem ModifiedAt deslocamento.

Mantenha páginas de partes zero, páginas iniciais, páginas de publicação e páginas com mapeamentos não resolvidos em filas de revisão separadas. As páginas fora da biblioteca padrão SitePages também permanecem no caminho de página única revisado separadamente.

Entender os padrões de preservação de origem

Cuidado

-TakeSourcePageName Renomeia a página de origem clássica e -Overwrite substitui uma página de destino existente. Não use nenhuma das opções até que as páginas geradas sejam aprovadas e exista um plano de reversão.

Opção Diretrizes de primeira onda
Nomenclatura padrão Manter o nome da fonte e criar Migrated_<source-page>.aspxarquivos .
-TakeSourcePageName Não use inicialmente. Ele renomeia a fonte clássica com um Previous_ prefixo.
-Overwrite Não use inicialmente. Revise uma meta existente em vez de substituí-la automaticamente.
-ReplaceHomePageWithDefault Não use em uma onda representativa.
-DontPublish Use para a primeira onda para que a página gerada permaneça um rascunho durante a validação.
-SkipItemLevelPermissionCopyToClientSidePage Use com o aplicativo, a AllSites.Manage menos que permissões exclusivas precisem ser copiadas.

Reverter um rascunho da primeira onda

O fluxo de trabalho em lotes não renomeia nem substitui a página de origem clássica. Se um rascunho gerado falhar na validação:

  1. Mantenha a página de origem clássica em serviço.
  2. Manter TransformationStatus=Created, definir ValidationStatus=Failede preencher ValidationNotes, ValidatedBye ValidatedAt.
  3. Preserve TargetPageUrl e LogPath com a evidência de validação com falha.
  4. Recicle o rascunho gerado Migrated_ da biblioteca de Páginas do Site quando ele não for mais necessário para investigação e a política de retenção da organização permitir a remoção.
  5. Corrija a regra ou correção candidata e tente novamente uma página representativa antes de retomar a onda.

-Overwrite e -TakeSourcePageName estão fora do fluxo de trabalho em lotes. Antes de usar qualquer uma das opções em um procedimento separado, preserve as versões da página e as URLs, registre a configuração atual da página inicial, teste o processo de renomeação ou restauração reversa em um site que não seja de produção e obtenha aprovação explícita.

Transformar uma página selecionada de Wiki ou Web Part

Use o script de página representativa com uma linha marcada Selected=Truecomo . Isso mantém o teste de uma página no mesmo contrato de validação, autenticação e resultado de uma onda maior.

Os scripts em lote dão suporte a páginas Wiki e Web Part na biblioteca padrão SitePages . Elas excluem páginas iniciais, páginas de partes zero, páginas com permissões exclusivas e páginas modificadas após a Avaliação. Manipule essas páginas por meio de um caminho revisado separadamente.

Transformar todas as páginas representativas

Salve os três arquivos inseridos da referência de script de onda de página na mesma pasta.

Em representative-page-groups.csv:

  1. Definido IncludePattern=True para cada padrão de transformação na migração planejada.
  2. Definido Selected=True em pelo menos uma página em cada padrão incluído.
  3. Preencher ExpectedVisibleContent e ValidationOwner para cada página selecionada.

Visualize o ciclo completo sem autenticar ou gravar páginas do SharePoint:

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

A visualização dos registros PlannedAction CSV e PlannedTargetPageUrl. Porque -WhatIf não autentica, TargetExists é NotChecked.

Execute uma simulação somente leitura autenticada para verificar a fonte atual, a página inicial, as permissões, os carimbos de data/hora e a ausência de destino:

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

Todas as linhas devem reportar TransformationStatus=PreflightPassed antes da conversão ao vivo.

Execute interativamente com confirmação de alto impacto:

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

O script grava cada resultado imediatamente no representative-page-results.csv. As páginas geradas permanecem rascunhos e cada linha criada começa com ValidationStatus=Pending.

Siga Validar páginas clássicas transformadas. Defina ValidationStatus=Passed, ValidationNotes, ValidatedBy, e ValidatedAt somente depois que a página atender a todos os critérios de aceitação.

Expandir para todas as páginas especificadas pelo usuário

Crie approved-pages.csv copiando as linhas adicionais incluídas que o usuário aprovou do original representative-page-groups.csv. Reter todos os campos gerados e preencher ExpectedVisibleContent e ValidationOwner.

Execute o script de página selecionada com -PreflightOnly -Confirm:$false -Force o primeiro. Cada linha deve relatar PreflightPassed.

Execute o script de expansão:

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

O script se recusa a expandir quando:

  • O manifesto representativo e os resultados não correspondem.
  • Qualquer página representativa não Created é e Passed.
  • As notas de validação, o validador ou o carimbo de data/hora de validação estão ausentes.
  • A versão PnP do PowerShell ou qualquer um dos três arquivos de script difere da execução representativa.
  • Uma página aprovada não é uma linha incluída inalterada do manifesto original.
  • Uma página aprovada pertence a um padrão sem um representante aprovado.

O ciclo expandido também cria páginas de rascunho e escreve selected-page-results.csv. Valide essas páginas antes de publicá-las.

Opções que exigem revisão explícita

Use a referência de cmdlet ConvertTo-PnPPage gerada para o contrato de parâmetro completo.

Os scripts em lote não dão suporte a mapeamentos de Web Part personalizados, páginas de publicação ou destinos entre sites. Lide com esses cenários por meio de um procedimento avançado, de página única ou revisado separadamente.

Examine essas opções somente fora do fluxo de trabalho em lotes:

  • -CopyPageMetadata e -KeepPageCreationModificationInformation.
  • -UrlMappingFile, -UserMappingFilee -TermMappingFile.
  • -Overwrite e -TakeSourcePageName após aprovação e planejamento de reversão.

Solucionar problemas de recurso de página moderna

Os scripts de onda de página não habilitam recursos do SharePoint. Esse caminho de solução de problemas se aplica somente a um site de equipe clássico com suporte. Não habilite o recurso em um portal de publicação clássico; roteia a publicação de páginas para o backlog e o modelo de publicação entre sites separados. Consulte Personalizações com suporte para páginas modernas.

Conecte-se com uma conta autorizada a gerenciar a Web e liste os recursos da Web ativados:

$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."
}

O aplicativo delegado AllSites.Manage usado pelos scripts em lote não é suficiente para ativar recursos da Web. Se o recurso não estiver ativo em um site de equipe clássico com suporte, obtenha a aprovação do proprietário do site e conecte-se com:

  • Um aplicativo delegado separado com o SharePoint AllSites.FullControl.
  • Uma conta conectada com Controle Total na 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

Executar novamente a comprovação autenticada depois de habilitar o recurso.

Autenticação autônoma e outros tipos de página

O aplicativo cliente público delegado criado anteriormente não pode ser reutilizado para autenticação somente de aplicativo de certificado, a menos que seja configurado separadamente para acesso somente de aplicativo.

Antes da execução autônoma:

  1. Crie um registro e certificado separados somente para aplicativo seguindo Registrar um aplicativo Entra ID para acesso somente ao aplicativo.
  2. Configure permissões de aplicativo do SharePoint ou atribuições de site para cada site de origem seguindo Determinar as permissões necessárias do PowerShell PnP.
  3. Conceda o consentimento necessário do administrador.
  4. Execute o script em lotes com -PreflightOnly -Confirm:$false e o modo de autenticação de certificado.
  5. Remova -PreflightOnly somente depois que a comprovação autenticada for aprovada em um locatário de teste.

Importante

Os caminhos de parâmetro do certificado são testados pelo Pester, mas o locatário ativo do Estágio 2 executa a autenticação interativa delegada validada. Valide o perfil de permissão somente aplicativo escolhido em seu locatário antes de gravações autônomas.

Páginas de publicação, páginas de blog, páginas externas SitePages, home pages, mapeamentos de Web Part personalizados e origens do Servidor do SharePoint não são suportados pelos scripts em lote. Use estas referências avançadas:

Próximas etapas

  1. Valide cada página transformada.
  2. Executar Convert-SelectedPages.ps1 somente depois que cada página representativa passar na validação.

Referências