PowerShell - Windows

PowerShell si chiude all’avvio con l’errore totalWidth: causa e soluzione

Si apre il terminale, parte PowerShell e dopo un istante il processo termina con un errore. Nessun prompt, nessuna possibilità di digitare un comando.

La causa non è il profilo utente né un modulo installato, ma il banner con cui PowerShell 7 avvisa che è disponibile una nuova versione. Vediamo come riconoscere l’errore, perché si verifica, come risolverlo con una variabile d’ambiente e come tornare alla configurazione normale quando il difetto sarà corretto.

Il sintomo: Process terminated e totalWidth negativo

All’avvio di PowerShell 7 compare l’intestazione con la versione e subito dopo il processo viene terminato

PowerShell 7.6.7
Process terminated.
totalWidth ('-5') must be a non-negative value. (Parameter 'totalWidth')
Actual value was -5.
   at System.Environment.FailFast(...)
System.ArgumentOutOfRangeException: totalWidth ('-5') must be a non-negative value. (Parameter 'totalWidth')
   at System.String.PadRight(Int32 totalWidth, Char paddingChar)
   at Microsoft.PowerShell.UpdatesNotification.ShowUpdateNotification(PSHostUserInterface hostUI)
   at Microsoft.PowerShell.ConsoleHost.Start(String bannerText, String helpText, Boolean issProvidedExternally)
[processo terminato con codice 2148734499 (0x80131623)]

Gli elementi che identificano questo specifico problema sono tre:

  • il messaggio “totalWidth (‘-5’) must be a non-negative value”, dove il numero negativo può cambiare
  • la riga “Microsoft.PowerShell.UpdatesNotification.ShowUpdateNotification” nello stack, che indica il punto in cui il codice si interrompe
  • il codice di uscita “0x80131623”, che corrisponde a una terminazione forzata del runtime .NET: il processo viene chiuso senza alcun tentativo di recupero

Perché succede: il banner degli aggiornamenti

PowerShell 7 controlla in background, circa una volta al giorno, se è stata pubblicata una versione più recente di quella installata. Quando ne trova una, all’avvio successivo mostra un riquadro che invita ad aggiornare. Questo spiega perché il problema compare dal nulla: basta che Microsoft pubblichi una nuova release perché, dal giorno dopo, ogni avvio provi a disegnare il banner.

Per allineare il testo dentro il riquadro, PowerShell usa il metodo PadRight, che aggiunge spazi fino a raggiungere una certa larghezza. Questa larghezza viene calcolata a partire da quella della console. Se la console viene rilevata troppo stretta, il calcolo produce un numero negativo, PadRight lancia un’eccezione e, poiché l’errore avviene durante l’avvio dell’host, il processo viene terminato con FailFast.

La soluzione: disattivare il controllo con POWERSHELL_UPDATECHECK

Il comportamento del controllo degli aggiornamenti è governato dalla variabile d’ambiente POWERSHELL_UPDATECHECK che accetta tre valori:

  • Default: notifica le nuove versioni del proprio canale (comportamento predefinito)
  • LTS: notifica solo le nuove versioni LTS
  • Off: disattiva il controllo e quindi il banner

Impostando Off il banner non viene più disegnato e il codice che va in errore non viene eseguito.

Poiché PowerShell si chiude all’avvio, il comando va eseguito da una shell che funziona: il Prompt dei comandi (cmd.exe) oppure Windows PowerShell 5.1 (powershell.exe), che è un programma separato da PowerShell 7 e non ha questo banner.

Il comando setx salva la variabile nel profilo dell’utente corrente, in modo permanente

setx POWERSHELL_UPDATECHECK Off

setx scrive la variabile nel registro, ma non la comunica ai processi già in esecuzione. Ogni programma riceve le variabili d’ambiente al momento dell’avvio, copiandole dal processo che lo lancia. VS Code le ha lette quando è stato aperto, e i terminali che crea le ereditano da lui. Aprire un nuovo pannello terminale non basta, perché riceverà ancora l’ambiente vecchio.

Per rendere effettiva la modifica:

  • chiudere tutte le finestre di VS Code, non solo quella in uso
  • chiudere ogni altro terminale aperto, compresi quelli rimasti nello stato di errore
  • eseguire il comando setx
  • riaprire VS Code o il terminale

Da una nuova finestra del Prompt dei comandi, aperta dopo setx, controlliamo il valore

$env:POWERSHELL_UPDATECHECK

L’output atteso è Off.

Aggiornare PowerShell

Il controllo degli aggiornamenti è utile: senza il banner non ci si accorge delle nuove versioni, comprese quelle con correzioni di sicurezza. Quando sarà disponibile una release che corregge il difetto conviene quindi aggiornare e riattivarlo

winget upgrade Microsoft.PowerShell

Dopo l’aggiornamento rimuoviamo la variabile dall’ambiente dell’utente. Impostarla a stringa vuota non basta, ma va eliminata. Questo comando lo fa sia da PowerShell 7 sia da Windows PowerShell 5.1

[Environment]::SetEnvironmentVariable("POWERSHELL_UPDATECHECK", $null, "User")