Windows Server 2025 / Gestire gli errori PowerShell e registrare le esecuzioni

Per individuare errori e risultati parziali nelle attività PowerShell, combinare try, catch e finally con una gestione esplicita degli errori e un log distinto per ogni esecuzione. Il completamento di un comando non dimostra, da solo, che l’intera attività amministrativa sia riuscita.

Rendere visibili gli errori

Questo esercizio legge un file e scrive un log senza modificare ruoli, servizi o rete del server. Uno script reale di installazione o gestione degli account deve registrare anche quali modifiche rimangono dopo un errore intermedio. Entrare in catch non annulla automaticamente le azioni precedenti.

Alcuni errori consentono a PowerShell di continuare e, per impostazione predefinita, non attivano catch. Inserire un comando in try non basta: -ErrorAction Stop trasforma gli errori non terminanti supportati in errori terminanti intercettabili. La documentazione sulla gestione degli errori PowerShell spiega questa distinzione.

Preparare l’input e lo script completo

Creare prima C:\LabScripts e salvare in C:\LabScripts\input.txt una sola riga contenente il testo letterale lab ready. Salvare tutto il codice seguente come C:\LabScripts\Read-LabFile.ps1, verificando le estensioni .txt e .ps1. Usare UTF-8; aggiungendo caratteri non ASCII allo script, scegliere UTF-8 con indicatore dell’ordine dei byte (BOM, byte order mark), secondo la documentazione sulla codifica. Eseguire con Windows PowerShell 5.1 e autorizzazioni per leggere l’input e creare o scrivere C:\LabLogs. Lo script salva dati strutturati in formato JSON (JavaScript Object Notation), usando un nome di file con data, ora e identificatore breve.

param(
    [Parameter(Mandatory=$true)]
    [string]$InputPath
)
$logDirectory = 'C:\LabLogs'
New-Item -ItemType Directory -Path $logDirectory -Force -ErrorAction Stop | Out-Null
$runLabel = (Get-Date -Format 'yyyyMMdd-HHmmss') + '-' + ([guid]::NewGuid().ToString('N').Substring(0,6))
$logPath = Join-Path $logDirectory ($runLabel + '.json')
$result = [ordered]@{
    StartedAt = (Get-Date).ToString('o')
    ComputerName = $env:COMPUTERNAME
    InputPath = $InputPath
    Success = $false
    LineCount = $null
    ErrorId = $null
    ErrorMessage = $null
}
$exitStatus = 0
try {
    $lines = @(Get-Content -LiteralPath $InputPath -ErrorAction Stop)
    $result.LineCount = $lines.Count
    $result.Success = $true
}
catch {
    $result.ErrorId = $_.FullyQualifiedErrorId
    $result.ErrorMessage = $_.Exception.Message
    $exitStatus = 1
    Write-Warning $result.ErrorMessage
}
finally {
    $result.FinishedAt = (Get-Date).ToString('o')
    $result | ConvertTo-Json | Set-Content -LiteralPath $logPath -Encoding UTF8 -ErrorAction Stop
}
Write-Output $logPath
exit $exitStatus

Confrontare successo ed errore nelle stesse condizioni

Eseguire le righe da una console PowerShell. Ogni powershell.exe avvia un processo figlio: exit termina quel processo e lascia disponibile la console originale. Avviare prima la lettura del file esistente e consultare subito $LASTEXITCODE; ripetere poi la coppia di comandi con missing-input.txt, che deve essere realmente assente. Non eliminare l’input valido e non modificare un file di sistema per provocare l’errore:

powershell.exe -NoProfile -File 'C:\LabScripts\Read-LabFile.ps1' -InputPath 'C:\LabScripts\input.txt'
$LASTEXITCODE
powershell.exe -NoProfile -File 'C:\LabScripts\Read-LabFile.ps1' -InputPath 'C:\LabScripts\missing-input.txt'
$LASTEXITCODE

Con l’input di una sola riga, la prima esecuzione deve restituire 0 e creare un JSON con Success=true e LineCount=1, senza dettagli di errore. Per il file inesistente sono previsti 1, Success=false e LineCount=null, con ErrorId ed ErrorMessage valorizzati. Il messaggio può variare con la lingua del sistema. Aprire con un editor di testo il JSON indicato dal percorso stampato per ciascuna esecuzione e controllare InputPath, ComputerName, StartedAt e FinishedAt. Confrontare i due nuovi log, senza confonderli con un file precedente della cartella.

Se un criterio blocca l’esecuzione dello script, rispettare i requisiti di esecuzione e firma dell’organizzazione, senza indebolire le impostazioni globali per questo esempio.

Comprendere le sezioni di gestione degli errori

Sezione Scopo in questo script
try Leggere il file e registrarne il numero di righe
catch Registrare identificatore e messaggio dell’errore intercettato; scegliere un codice di uscita di errore
finally Tentare di salvare il risultato, sia quando la lettura riesce sia quando fallisce

Il riferimento Microsoft a try, catch e finally spiega la gestione degli errori terminanti. In questo script C:\LabLogs viene creato prima di try: se questa preparazione fallisce, il catch successivo non intercetta l’errore. finally tenta il salvataggio, ma non garantisce spazio disponibile o autorizzazioni di scrittura. Success riguarda la lettura: verificare anche la creazione di un nuovo JSON valido. La scrittura del log usa a sua volta -ErrorAction Stop. L’assenza di un log non dimostra che l’attività si sia conclusa senza errori.

I programmi esterni restituiscono codici di uscita propri. In Windows PowerShell 5.1, un codice diverso da zero non attiva automaticamente catch. Controllare $LASTEXITCODE subito dopo il programma e, quando necessario, usare throw per generare un errore terminante. Un altro programma esterno può sostituire quel valore; -ErrorAction Stop da solo non converte i codici di uscita esterni in eccezioni.

Definire criteri per ripetere le attività in sicurezza

  • Registrare server, destinazione e orari di inizio e fine.
  • Verificare lo stato esistente per evitare creazioni duplicate o sovrascritture involontarie.
  • Registrare separatamente i passaggi riusciti e quelli falliti.
  • Escludere dai log password, token e contenuti non necessari dei file degli utenti.
  • Se si implementa un rollback per annullare modifiche, documentarne l’ambito e gli eventuali errori di ripristino.

Usare nuovamente il percorso di input.txt ed eseguire lo script per verificare un nuovo codice 0 e un nuovo JSON con Success=true e LineCount=1. Conservare le evidenze necessarie prima di rimuovere esclusivamente i file temporanei identificati dell’esercizio. Aggiungere SilentlyContinue a tutti i comandi nasconde gli errori e non ne sostituisce la gestione.