Introdução
Field Notes aprovou duas mudanças de sala de oficinas após o aumento da participação. Vários títulos de sessões e nomes de salas se repetem, portanto um plano seguro precisa de identidades exatas, escopo aprovado e capacidade suficiente no destino.
Você visualizará uma pequena alteração funcional e criará um validador de planos reutilizável com PowerShell. Este laboratório pressupõe objetos, JSON, filtragem, parâmetros e tratamento de erros de PowerShell for Beginners; não exige scripts Bash. Ferramentas e dados sintéticos originais do evento estão preparados em um espaço de trabalho separado e independente. A duração é uma estimativa do autor que inclui leitura e erros comuns.
Criar um plano completo baseado em IDs
Nesta etapa, você visualizará uma alteração preparada e criará um validador reutilizável que salva o plano de trabalho completo sem alterar a programação.
Entrar no PowerShell e visualizar uma solicitação
Abra Terminal. Inicialmente, ele executa um shell Linux. O comando a seguir define UTF-8 apenas para esta sessão do PowerShell; não altera seu shell global. env fornece esses valores de ambiente ao programa. -NoLogo oculta a mensagem inicial e -NoProfile ignora scripts pessoais de inicialização:
env LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 pwsh -NoLogo -NoProfile
Aguarde o prompt que começa com PS. Todos os comandos restantes são executados dentro do PowerShell. Set-Location altera seu diretório de trabalho:
Set-Location /home/labex/project/room-changes
O script preparado preview-one.ps1 trata apenas a única solicitação de ensaio fornecida. Ele oferece suporte ao parâmetro nativo -WhatIf do PowerShell: descrever uma ação em vez de executá-la. Este é um pequeno exemplo funcional, ainda não seu validador reutilizável para várias solicitações. ./ identifica um script no diretório atual:
./preview-one.ps1 -WhatIf
Espere uma mensagem nativa contendo Move s-a: r-old -> r-equal e o destino ./rehearsal-only.json. Os IDs identificam a sessão e suas salas anterior e proposta. Ele não moveu todas as sessões com esse título. Leia o JSON de origem real com Get-Content -Raw, que retorna o arquivo inteiro como uma única string:
Get-Content ./event.json -Raw
O registro s-a ainda tem RoomId igual a r-old. Test-Path verifica a existência sem criar nada:
Test-Path ./rehearsal-only.json
False
Se você omitiu -WhatIf por engano, o ensaio pode criar esse arquivo separado, mas não sobrescreve a entrada. Remove-Item -LiteralPath ./rehearsal-only.json remove somente essa saída de ensaio; use-o apenas se o arquivo existir e repita a visualização corretamente. -LiteralPath interpreta um caminho literalmente, sem expandir caracteres curinga. Não remova o evento nem as solicitações originais para se recuperar de um erro.
Ler os relacionamentos antes de criar a ferramenta
O local já verificou que as salas de destino estão livres nesses horários. Você verificará o escopo aprovado e a capacidade, sem resolver conflitos de calendário. Leia os mapeamentos solicitados e use o leitor preparado, somente leitura, para ver a programação original real:
Get-Content ./requests.json -Raw
./Show-RoomSchedule.ps1 -Path ./event.json
As solicitações movem s-a para r-equal e s-c para r-large. s-a e s-b compartilham o título Shared maps; apenas s-a está aprovada para esta solicitação. Duas salas também se chamam Studio. Relacione por SessionId e RoomId, nunca pelos nomes exibidos. A primeira sessão solicitada tem 24 participantes e seu destino comporta exatamente 24: a igualdade é permitida.
É preciso preservar os originais event.json, requests.json, small-request.json, bad-request.json e o arquivo não relacionado notes.txt, incluindo seus bytes, modo de arquivo, proprietário e horário de modificação (mtime). Não edite as ferramentas preparadas. Você pode criar seus scripts e os novos resultados nomeados neste laboratório. Os caminhos do curso e toda a cadeia de diretórios são diretórios reais. Uma saída deve ser nova, diferente das entradas, e ter um diretório pai real já existente; um arquivo, diretório ou link existente, mesmo um link sem destino, deve ser recusado sem alterações. Trabalhe sem outras gravações concorrentes.
O JSON fornecido é UTF-8 bem formado: um objeto de evento com Rooms, Sessions e ApprovedSessionIds, e um array não vazio de solicitações com IDs exatos únicos de sessões e os IDs das salas de destino. Os IDs são strings sensíveis a maiúsculas e minúsculas. Contagens e capacidades são valores inteiros não negativos. Metadados desconhecidos podem conter objetos aninhados, arrays ordenados, strings, booleanos, null e números JSON finitos limitados, dentro de 20 níveis de aninhamento. Chaves de objeto exatamente duplicadas, esquemas malformados e entradas maliciosas arbitrárias estão fora do escopo deste curso.
Validar cada solicitação antes de salvar qualquer plano
Você criará Build-RoomPlan.ps1 com três parâmetros nomeados: EventPath, PlanPath e OutputPath. Ele deve funcionar com outros eventos e IDs fornecidos, usando esses argumentos e comandos instalados sem arquivos auxiliares vizinhos. O resultado é um array JSON na ordem das solicitações. Cada linha tem exatamente SessionId, OldRoomId, NewRoomId, Attendees e Capacity. É um plano de trabalho que descreve os relacionamentos atuais entre objetos, não um marcador que afirma que o trabalho terminou. Ele não altera a programação. O próximo laboratório escreverá um evento atualizado completo.
Leia estas adições antes de salvar o script:
[CmdletBinding()]o transforma em um script avançado parametrizado;[Parameter(Mandatory)]exige um argumento e[string]declara texto.try,catch,throweexit 1seguem o laboratório prévio de tratamento de erros.$ErrorActionPreference = 'Stop'faz com que erros de comandos encerrem a operação atual. O blococatchusaWrite-Error -ErrorAction Continuepara exibir a explicação e depois chegar aoexit 1explícito.$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath(...)do PowerShell resolve a saída em relação ao diretório atual do PowerShell.Split-Path -LiteralPathretorna seu pai.Get-Item -Forcetambém encontra objetos ocultos e links sem destino. Aqui,-ErrorAction SilentlyContinuepermite a ausência esperada de uma saída nova.Test-Path -PathType Containerexige seu diretório pai.ConvertFrom-Json -AsHashtablemantém objetos JSON como dicionários, incluindo chaves desconhecidas que diferem apenas na capitalização.-DateKind Stringmantém strings com aparência de data como strings, preservando seus deslocamentos originais; a versão preparada do PowerShell oferece essa opção.-NoEnumeratemantém o array de solicitações inteiro mesmo quando há apenas um membro.@(...)reúne correspondências em um array, mesmo quando há zero ou uma.-ceqcompara com distinção entre maiúsculas e minúsculas.-ccontainstesta associação exata;-cnotcontainsé seu inverso.-nesignifica diferente,-gtmaior que e-orque qualquer condição basta.-isnot [array]recusa um valor que não seja um array.$seen += ...e$changes += ...adicionam elementos às coleções. Um ID desconhecido, uma sessão não aprovada, uma solicitação duplicada ou participantes demais provocam um erro antes de qualquer saída ser escrita.-gtpermite capacidade exatamente igual ao número de participantes.[pscustomobject]@{...}reúne os campos conhecidos do plano.ConvertTo-Json -InputObject $changes -Depth 5serializa o array inteiro; uma profundidade suficiente evita converter objetos aninhados em strings de apresentação. A ordem das propriedades JSON e a indentação não importam; a ordem do array importa. Booleanos diferem de números, enquanto representações finitas iguais, como1e1.0, representam o mesmo número JSON.- O PowerShell pode chamar métodos .NET com
[Type]::Method(...).[System.IO.File]::WriteAllTextescreve o texto selecionado no caminho de arquivo selecionado.[Environment]::NewLineadiciona uma quebra de linha e[System.Text.UTF8Encoding]::new($false)cria codificação UTF-8 sem marca de ordem de bytes. Esse método não respeita WhatIf automaticamente; no próximo laboratório você o colocará dentro de uma ramificação explícita de autorização.
Uma here-string literal salva o script completo: @' abre e '@ fecha em uma linha exclusiva. Aspas simples preservam as variáveis do script durante a gravação. Set-Content -Encoding utf8 substitui apenas esse arquivo de script:
Set-Content -Path ./Build-RoomPlan.ps1 -Encoding utf8 -Value @'
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$EventPath,
[Parameter(Mandatory)][string]$PlanPath,
[Parameter(Mandatory)][string]$OutputPath
)
try {
$ErrorActionPreference = 'Stop'
$fullOutput = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputPath)
if (Get-Item -LiteralPath $fullOutput -Force -ErrorAction SilentlyContinue) {
throw 'Output already exists; choose a new path.'
}
$parent = Split-Path -LiteralPath $fullOutput
if (-not (Test-Path -LiteralPath $parent -PathType Container)) {
throw 'Output parent must already exist.'
}
$event = Get-Content -LiteralPath $EventPath -Raw | ConvertFrom-Json -AsHashtable -DateKind String
$requests = Get-Content -LiteralPath $PlanPath -Raw | ConvertFrom-Json -AsHashtable -DateKind String -NoEnumerate
if ($requests -isnot [array] -or $requests.Count -eq 0) { throw 'Plan must be a nonempty array.' }
$changes = @()
$seen = @()
foreach ($request in $requests) {
if ($seen -ccontains $request.SessionId) { throw "Duplicate session ID: $($request.SessionId)" }
$seen += $request.SessionId
$sessions = @($event.Sessions | Where-Object { $_.SessionId -ceq $request.SessionId })
$rooms = @($event.Rooms | Where-Object { $_.RoomId -ceq $request.RoomId })
if ($sessions.Count -ne 1) { throw "Unknown or ambiguous session ID: $($request.SessionId)" }
if ($rooms.Count -ne 1) { throw "Unknown or ambiguous room ID: $($request.RoomId)" }
if ($event.ApprovedSessionIds -cnotcontains $request.SessionId) { throw "Unapproved session ID: $($request.SessionId)" }
if ($sessions[0].Attendees -gt $rooms[0].Capacity) { throw "Capacity exceeded: $($request.SessionId) -> $($request.RoomId)" }
$changes += [pscustomobject]@{
SessionId = $request.SessionId
OldRoomId = $sessions[0].RoomId
NewRoomId = $request.RoomId
Attendees = $sessions[0].Attendees
Capacity = $rooms[0].Capacity
}
}
$json = ConvertTo-Json -InputObject $changes -Depth 5
[System.IO.File]::WriteAllText($fullOutput, $json + [Environment]::NewLine, [System.Text.UTF8Encoding]::new($false))
Write-Output "Saved plan: $fullOutput"
}
catch {
Write-Error ("Plan failed: {0}" -f $_.Exception.Message) -ErrorAction Continue
exit 1
}
'@
Execute o validador em um processo filho do PowerShell. -NonInteractive proíbe prompts sem supervisão e -File escolhe o script. O exit 1 do filho não pode fechar sua sessão interativa:
pwsh -NoLogo -NoProfile -NonInteractive -File ./Build-RoomPlan.ps1 -EventPath ./event.json -PlanPath ./requests.json -OutputPath ./validated-plan.json
$LASTEXITCODE é o status de saída nativo do último programa externo. Leia-o imediatamente:
$LASTEXITCODE
0
Reabra o artefato real:
Get-Content ./validated-plan.json -Raw
Ele contém ambas as linhas solicitadas: s-a, r-old, r-equal, 24, 24; e s-c, r-old, r-large, 18, 40. A programação original permanece intacta. Uma saída existente é recusada deliberadamente em vez de substituída silenciosamente. Se precisar recriar seu plano, remova somente validated-plan.json com Remove-Item -LiteralPath ./validated-plan.json e execute novamente o validador corrigido.
Recusar por inteiro uma solicitação posterior inválida
bad-request.json contém uma primeira alteração válida seguida de uma sala de destino desconhecida. O próximo comando falha intencionalmente:
pwsh -NoLogo -NoProfile -NonInteractive -File ./Build-RoomPlan.ps1 -EventPath ./event.json -PlanPath ./bad-request.json -OutputPath ./bad-plan-result.json
Espere Plan failed: e uma explicação sobre a sala desconhecida. Leia imediatamente o resultado nativo:
$LASTEXITCODE
1
Test-Path ./bad-plan-result.json
False
A linha válida anterior não foi publicada como plano parcial. IDs de sessão desconhecidos, IDs não aprovados, duplicatas e capacidade excedida também devem recusar a invocação antes de escrever. Um arquivo de solicitações vazio ou ausente não é um trabalho vazio bem-sucedido.
Para um erro comum de digitação em um caminho, use Get-Location e Get-ChildItem para verificar o diretório e os nomes e volte com Set-Location /home/labex/project/room-changes. Para um erro no script, salve novamente a here-string completa corrigida, substituindo apenas seu script. Não edite os dados de origem para fazer um erro desaparecer. A verificação final lê o plano de trabalho real e as propriedades originais e executa os bytes exatos do seu script em eventos isolados com outros IDs. Ela não aceita uma lista fixa de respostas iniciais nem altera sua programação real.
Resumo
Você usou uma visualização nativa honesta, relacionou sessões a salas por IDs exatos, verificou aprovação e capacidade e salvou um plano de trabalho validado completo. A igualdade de capacidade foi aceita, registros com o mesmo título permaneceram distintos e uma solicitação posterior inválida não produziu plano parcial. O evento original e as notas continuaram intactos; o próximo laboratório aplica todo um plano validado por confirmação nativa.



