- Register-ArgumentCompleter consente di creare riempimenti dinamici per i parametri del cmdlet e comandi nativo utilizzando gli oggetti ScriptBlock e CompletionResult.
- Gli attributi ValidateSet, ArgumentCompletions e ArgumentCompleter offrono livelli crescenti di flessibilità per la definizione di elenchi di valori suggeriti o convalidati.
- PowerShell La versione 7.2 introduce i completatori basati su classi e su fabbriche che facilitano il riutilizzo e la parametrizzazione di logiche di completamento automatico complesse.
- La combinazione di PSReadLine, riempitivi personalizzati e supporto per CLI e API esterne avvicina l'esperienza di completamento automatico di PowerShell a quella di shell avanzate come zsh.

Nelle righe che seguono vedremo, con calma e con esempi chiari, come utilizzare Register-ArgumentCompleter, gli attributi ArgumentCompletion, ArgumentCompletions e ValidateSet e le classi personalizzate per ottenere un'esperienza di completamento automatico molto avanzata in PowerShell. Vedrai sia casi semplici che scenari molto più sofisticati, incluso come integrarlo nel tuo Profilo PowerShell per mantenerlo sempre attivo e come utilizzarlo anche con comandi nativi come dotnet o CLI di terze parti.
Che cos'è Register-ArgumentCompleter e quale problema risolve?
Il cmdlet Register-ArgumentCompleter serve a registrare un completatore di argomenti personalizzatoIn altre parole, dici a PowerShell cosa suggerire quando l'utente preme il tasto Linguetta quando si inserisce il valore di un parametro o di un comando nativo.
Questo completatore funziona su tempo di esecuzioneIn questo modo puoi calcolare i suggerimenti in modo dinamico: cerca cmdlet come Get-TimeZoneservizi di filtraggio con Get-Service, chiama una CLI come dotnet completeLa lettura di un'API REST, il controllo del file system, ecc., vengono eseguiti tramite... Blocco script che restituisce i possibili valori di completamento automatico.
Un dettaglio importante riguarda il comportamento del parametro CommandName : se lo si utilizza senza specificare ParameterName o Native , PowerShell interpreta la chiamata come se fosse stata aggiunta l'opzione -Native . Ciò significa che il completamento automatico non funzionerà sui parametri dei cmdlet di PowerShell, ma solo sui comandi nativi. Pertanto, se l'obiettivo è completare i parametri di un cmdlet o di una funzione di PowerShell, è sempre necessario specificare ParameterName.
Sintassi di base di Register-ArgumentCompleter
Set di parametri per comandi nativi (NativeSet)
Per registrare un completatore di argomenti per un comando nativo, si utilizza la seguente sintassi, dove la chiave si trova nel modificatore -Native :
Sintassi tipica: Register-ArgumentCompleter -CommandName <String[]> -ScriptBlock <ScriptBlock> -Native
In questo caso , CommandName è obbligatorio perché PowerShell deve sapere a quale comando nativo associare il completamento automatico. Lo ScriptBlock riceverà un set di parametri diverso rispetto ai completatori dei cmdlet di PowerShell, come vedremo in seguito, e sarà progettato per interpretare l'intera riga e la posizione del cursore.
Set di parametri del cmdlet di PowerShell (PowerShellSet)
Se si desidera aggiungere il completamento automatico a uno o più parametri di cmdlet o funzioni di PowerShell, la sintassi più comune è:
Sintassi tipica: Register-ArgumentCompleter -ParameterName <String> -ScriptBlock <ScriptBlock> >]
Qui, ParameterName è obbligatorio e definisce a quale parametro verrà applicato il completamento. Il parametro CommandName è facoltativo : è possibile limitare il completamento a uno o più comandi specifici oppure, se lo si omette, PowerShell registrerà tale completamento per quel nome di parametro su tutti i comandi che lo possiedono.
Parametri chiave di Register-ArgumentCompleter
Parametro -CommandName
Il parametro `-CommandName` specifica per quale o quali comandi verrà registrato il completamento automatico. Accetta un array di stringhe , consentendo di associare lo stesso `ScriptBlock` a più cmdlet o strumenti nativi contemporaneamente.
Quando utilizzato nel set di parametri NativeSet , è obbligatorio , poiché i completatori nativi non possono essere registrati in modo generico senza specificare un binario o un comando particolare. In PowerShellSet, è facoltativo, ma, come accennato in precedenza, se lo si utilizza senza ParameterName o Native , PowerShell interpreterà la situazione come la creazione di un completatore nativo.
Parametro -Nativo
Il modificatore -Nativo indica a PowerShell che il completatore deve essere applicato a comandi nativiVale a dire, eseguibili esterni in cui PowerShell non controlla né può completare i nomi dei parametri. Consideriamo dotnet, winget, aws o qualsiasi altra CLI basata su .NET, Python o simili.
In questa modalità, ScriptBlock riceve meno parametri e per uno scopo diverso: il testo che è stato scritto, l'AST del comando e la posizione del cursoreDa lì, normalmente il copione Chiama la CLI stessa per restituire suggerimenti, come accade con dotnet complete.
Parametro -NomeParametro
Parametro -NomeParametro Specifica il nome del parametro a cui verrà applicato il completamento degli argomenti. Esiste un'importante limitazione: il tipo di quel parametro. Non può essere una listaAd esempio, se il parametro utilizza un tipo come Colore di primo piano de Write-HostNon è possibile utilizzare Register-ArgumentCompleter per completarlo.
Quando si registrano i completatori per i cmdlet o le funzioni PowerShell, è fortemente consigliato utilizzare sempre ParameterName . Se ci si dimentica e si utilizza solo CommandName, si registrerà accidentalmente un completatore nativo e non si visualizzeranno i suggerimenti per il parametro di interesse.
Parametro -ScriptBlock
Il cuore di ogni completista è il Blocco scriptQuesto blocco di script definisce la logica che genera i valori da suggerire quando l'utente preme LinguettaLa cosa più importante è che ScriptBlock deve restituire gli elementi tramite la pipelineAd esempio, con ForEach-Object o Where-Object, invece di restituire un singolo array, perché se viene restituito un array non pipelined, PowerShell lo interpreterà come un singolo valore di completamento automatico.
Inoltre, ScriptBlock può restituire direttamente stringhe o oggetti System.Management.Automation.CompletionResult , il che offre molta più flessibilità, poiché consente di definire il testo da completare, il testo da visualizzare nell'elenco, il tipo di risultato e una descrizione o un tooltip.
Parametri ScriptBlock per i completatori di PowerShell
Nei completatori standard (non nativi), ScriptBlock deve accettare cinque parametri in quest'ordine, indipendentemente dai loro nomi:
- $nomecomando: stringa con il nome del comando per il quale viene calcolato il completamento.
- $parametroName: stringa con il nome del parametro da completare.
- $wordToComplete: stringa contenente ciò che l'utente ha digitato appena prima di premere Linguetta.
- $commandAst: oggetto CommandAst che rappresenta il albero sintattico astratto della linea corrente.
- $fakeBoundParameters: tipo di dizionario Dizionario che replica il contenuto di
$PSBoundParametersal momento della pressatura Linguetta.
Parametro $wordToComplete Viene spesso utilizzato per filtrare i valori con operatori come -likein modo che vengano suggeriti solo gli elementi che iniziano con ciò che l'utente ha già digitato. Nel frattempo, $fakeBoundParameters Permette di creare riempitivi che dipendono da altri parametri, come vedremo con gli esempi di frutta e verdura.
Parametri ScriptBlock per i filler nativi
Quando si utilizza -Native , lo ScriptBlock riceve tre parametri, anch'essi per posizione:
- $wordToComplete (posizione 0): testo che l'utente ha digitato prima del tasto Linguetta.
- $commandAst (posizione 1): albero sintattico del comando completo, non solo dell'argomento corrente.
- $cursorPosition (posizione 2): indice della posizione del cursore sulla riga.
Questo formato si adatta molto bene alle CLI che espongono già il proprio sistema di completamento automatico. Il caso tipico è dotnet complete, che riceve la riga e la posizione del cursore e restituisce suggerimenti di testo normale che vengono poi trasformati in Risultato di completamento.
Esempi pratici con Register-ArgumentCompleter
Esempio 1: Popolamento dinamico dei fusi orari
Immagina di voler rendere l'utilizzo del cmdlet il più semplice possibile. Set-TimeZone consentendo all'utente di completare il parametro Id con il tasto Tab. È possibile creare uno ScriptBlock che recupera tutti i fusi orari con Get-TimeZone -ListAvailableFiltra in base a ciò che l'utente ha digitato e racchiudi ogni valore tra virgolette nel caso in cui ci siano spazi:
Esempio di script 1: $script = {<br> param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)<br> (Get-TimeZone -ListAvailable).Id |<br> Where-Object { $_ -like "$wordToComplete*" } |<br> ForEach-Object { "'$_'" }<br>}<br>Register-ArgumentCompleter -CommandName Set-TimeZone -ParameterName Id -ScriptBlock $script
Con questo, quando scrivi Set-TimeZone -Id e inizia a digitare, quando premi Linguetta ne avrai uno Elenco degli ID dei fusi orari filtrati In base a ciò che hai scritto. Gli apici singoli sono stati aggiunti per evitare problemi con gli identificatori che contengono spazi.
Esempio 2: suggerimenti arricchiti con CompletionResult
In un secondo scenario, vuoi che quando usi Stop-Service -Name apparire solo servizi in corsoe vuoi anche visualizzare informazioni aggiuntive nell'elenco dei suggerimenti quando l'utente preme Ctrl+Espacio.
Esempio di script 2 (CompletionResult): $script = {<br> param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)<br> $services = Get-Service | Where-Object {<br> $_.Status -eq 'Running' -and $_.Name -like "$wordToComplete*"<br> }<br> $services | ForEach-Object {<br> New-Object -TypeName System.Management.Automation.CompletionResult -ArgumentList @(<br> $_.Name, # completionText<br> $_.Name, # listItemText<br> 'ParameterValue', # resultType<br> $_.Name # toolTip<br> )<br> }<br>}<br>Register-ArgumentCompleter -CommandName Stop-Service -ParameterName Name -ScriptBlock $script
Presta attenzione a questi campi: in ogni oggetto CompletionResult, puoi controllare questi campi chiave per un'esperienza più raffinata:
- completamentoTesto: testo che viene effettivamente inserito nel comando quando si sceglie il suggerimento.
- testo dell'elemento elenco: testo visualizzato nell'elenco delle proposte; potrebbe differire dalla stringa inserita.
- tipo di risultato: tipo di risultato (ad esempio,
ParameterValue). - suggerimento: descrizione che appare quando selezioni l'elemento nell'elenco completato, particolarmente utile con Ctrl+Espacio.
Esempio 3: Completatore nativo per la CLI dotnet
È anche possibile utilizzare Register-ArgumentCompleter per estendere il completamento automatico. strumenti nativiUn esempio classico è dotnet, che include il sottocomando dotnet complete per restituire gli elementi completati in base alla riga corrente.
Esempio di script nativo: $scriptblock = {<br> param($wordToComplete, $commandAst, $cursorPosition)<br> dotnet complete --position $cursorPosition $commandAst.ToString() | ForEach-Object {<br> ::new(<br> $_, # completionText<br> $_, # listItemText<br> 'ParameterValue', # resultType<br> $_ # toolTip<br> )<br> }<br>}<br>Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock $scriptblock
In questo esempio, il comando stesso dotnet complete È quello che esegue il calcolo dei suggerimenti. Lo ScriptBlock trasforma semplicemente l'output in oggetti CompletionResult. In questo modo si ottiene un Integrazione perfetta tra PowerShell e una CLI esterna, con schede che conoscono tutte le opzioni dotnet native.
Altri modi per implementare i completatori di argomenti
ValidateSet: valori fissi con validazione rigorosa
L' attributo ValidateSet offre un modo semplice per limitare un parametro o una variabile a un insieme chiuso di valori, consentendo al contempo il completamento automatico tramite Tab senza dover scrivere un ScriptBlock personalizzato.
Immagina un parametro "Frutta " che accetta solo "Mela", "Banana" o "Pera". Potresti definirlo in questo modo:
Definizione di esempio: param (<br> <br> <br> ]$Fruit<br>)
Se l'utente inserisce un valore non presente nell'insieme, PowerShell genererà un errore di convalida . Lo stesso vale per le variabili normali, non solo per i parametri, ad esempio:
Dichiarazione di variabile: <br>$Flavor = 'Strawberry'
Ogni volta che qualcosa viene assegnato a $FlavorLo script verificherà se il valore appartiene all'insieme. Se in qualsiasi punto dello script si esegue questa operazione:
param(<br> <br> $Message<br>)<br>$Message = 'bye'
PowerShell restituirà un MetadataError , indicando che la variabile non sarebbe più valida se venisse applicato quel valore, il che contribuisce a mantenere contratti rigorosi nei tuoi script.
ValidateSet dinamico con classi
Oltre ai set statici, PowerShell consente di generare valori da ValidateSet dinamicamente utilizzando le classi che implementano l'interfaccia System.Management.Automation.IValidateSetValuesGeneratorIn questo modello, la classe espone un metodo GetValidValues() che restituisce le possibili opzioni.
Un esempio tipico è la classe SoundNames , che attraversa varie cartelle di sistema alla ricerca di file audio e restituisce i loro nomi base come valori validi:
Classe di esempio (SoundNames): class SoundNames : System.Management.Automation.IValidateSetValuesGenerator {<br> ] GetValidValues() {<br> $SoundPaths = '/System/Library/Sounds/', '/Library/Sounds', '~/Library/Sounds'<br> $SoundNames = foreach ($SoundPath in $SoundPaths) {<br> if (Test-Path $SoundPath) {<br> (Get-ChildItem $SoundPath).BaseName<br> }<br> }<br> return ] $SoundNames<br> }<br>}
Successivamente, implementerai la classe come un ValidateSet dinamico su un parametro o una variabile:
Utilizzo di ValidateSet dinamico: param (<br> )]<br> $Sound<br>)
In questo modo si ottiene un completamento automatico tramite tasti che riflette lo stato effettivo del file system ogni volta che lo script viene eseguito.
ArgumentCompletions: suggerimenti senza convalidare il valore
L' attributo ArgumentCompletions consente di aggiungere un elenco di valori suggeriti a un parametro, ma a differenza di ValidateSet, non esegue una convalida rigorosa . Ciò significa che l'utente può scegliere uno dei suggerimenti o digitare qualsiasi altra cosa, anche se non è presente nell'elenco.
La sua sintassi è molto semplice. Ad esempio, è possibile definire una funzione con un parametro Tipo che suggerisce "Frutta" e "Verdura", e parametri Frutta e Verdura con elenchi di valori possibili:
Definizione di funzione: function Test-ArgumentCompletions {<br> <br> param (<br> <br> <br> $Type,<br;<br> <br> <br> $Fruit,<br;<br> <br> <br> $Vegetable<br> )<br>}
Questo attributo è perfetto quando si desidera guidare l'utente con esempi di valori comuni, ma non si vuole impedirgli di inserirne di diversi per esigenze aziendali o di compatibilità con casi particolari.
ArgumentCompleter: completatori a livello di attributo dei parametri
Attributo ArgumentCompleter Viene utilizzato per allegare uno ScriptBlock a un parametro con la stessa firma dei completer registrati con Register-ArgumentCompleterma senza dover invocare questo cmdlet. È un modo elegante per incapsulare logica di completamento automatico complessa direttamente nella definizione della funzione.
Esempio di base: Un esempio di utilizzo potrebbe essere:
Esempio di attributo: function MyArgumentCompleter {<br> param (<br> <br> <br> $ParamName<br> )<br>}
Proprio come con Register-ArgumentCompleter, ScriptBlock dovrebbe restituire i valori tramite pipeline e può sfruttare sia $wordToComplete che $fakeBoundParameters o persino analizzare l' AST per tenere conto del contesto completo del comando.
Esempio avanzato di ArgumentCompleter dipendente da un altro parametro
Un modello molto utile consiste nel creare elementi completi che dipendono dal valore di altri parametri. Immaginate una funzione con un parametro Tipo che può essere "Frutta" o "Verdura", e un parametro Valore il cui insieme di suggerimenti cambia a seconda del tipo scelto.
Implementazione del motore: function MyArgumentCompleter {<br> param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)<br><br> $possibleValues = @{<br> Fruits = @('Apple','Orange','Banana')<br> Vegetables = @('Onion','Carrot','Lettuce')<br> }<br><br>> if ($fakeBoundParameters.ContainsKey('Type')) {<br> $possibleValues |<br> Where-Object { $_ -like "$wordToComplete*" }<br> } else {<br> $possibleValues.Values | ForEach-Object { $_ }<br> }<br>}
Consumo di riempitivo: function Test-ArgumentCompleter {<br> <br> param (<br> <br> <br> $Type,<br;<br> <br> <br> $Value<br> )<br>}
In questo scenario, se scrivi, ad esempio Test-ArgumentCompleter -Type Fruits -Value A e premi Tab, grazie all'uso di -Like e dal dizionario $fakeBoundParametersIl filler restituirà solo valori di frutta che iniziano con "A", ovvero, MelaÈ una tecnica molto potente per costruire interfacce a riga di comando intuitive anche quando ci si trova di fronte a dati non banali.
Completatori di argomenti basati su classi (a partire da PowerShell 7.2)
A partire da PowerShell 7.2, è stata aggiunta una funzionalità che consente di definire filler riutilizzabili basati su classi , il che facilita notevolmente la creazione di filler parametrizzabili e generici.
L'idea è di derivare da ArgumentCompleterAttribute e implementare l' interfaccia IArgumentCompleterFactory . La classe derivata può avere proprietà configurabili (ad esempio, intervalli numerici, profondità della directory, date, rami Git, ecc.) che vengono utilizzate per costruire il completatore vero e proprio.
Codice classe (esempio): using namespace System.Collections<br>using namespace System.Collections.Generic<br>using namespace System.Management.Automation<br>using namespace System.Management.Automation.Language<br><br>class NumberCompleter : IArgumentCompleter {<br> $From<br> $To<br> $Step<br><br> NumberCompleter( $from, $to, $step) {<br> if ($from -gt $to) {<br> throw ::new("from")<br> }<br> $this.From = $from<br> $this.To = $to<br> $this.Step = $step -lt 1 ? 1 : $step<br> }<br><br> ] CompleteArgument(<br> $CommandName,<br> $parameterName,<br> $wordToComplete,<br> $commandAst,<br;> $fakeBoundParameters<br> ) {<br> $resultList = ]::new()<br> $Local:to = $this.To<br> $Local:step = $this.Step<br><br> for ($i = $this.From; $i -lt $to; $i += $step) {<br> $resultList.Add(::new($i.ToString()))<br> }<br><br> return $resultList<br> }<br>}<br><br>class NumberCompletionsAttribute : ArgumentCompleterAttribute, IArgumentCompleterFactory {<br> $From<br> $To<br> $Step<br><br> NumberCompletionsAttribute( $from, $to, $step) {<br> $this.From = $from<br> $this.To = $to<br> $this.Step = $step<br> }<br><br> Create() {<br> return ::new($this.From, $this.To, $this.Step)<br> }<br>}
Utilizzo degli attributi: function Add {<br> param(<br> <br> $X,<br;<br> <br> $Y<br> )<br> $X + $Y<br>}
Mentre scrivi la funzione e inizi a inserire i parametri, Tab suggerirà valori numerici compresi tra 0 e 100 con incrementi di 5 , senza che tu debba ripetere la logica di completamento automatico in ogni funzione. Questa stessa tecnica può essere applicata a percorsi di directory, date calcolate, commit Git per un determinato ramo e, in generale, a qualsiasi scenario in cui siano necessari elementi di riempimento riutilizzabili e configurabili.
Completamento automatico in stile Linux in PowerShell utilizzando PSReadLine e Register-ArgumentCompleter
Se provenite dal mondo GNU/Linux, probabilmente siete abituati all'esperienza avanzata di completamento automatico offerta da shell come zsh , con menu interattivi e suggerimenti molto intelligenti. PowerShell, pur essendo diverso, permette di ottenere un'esperienza molto simile combinando PSReadLine e Register-ArgumentCompleter.
Da un lato, con Set-PSReadlineKeyHandler È possibile modificare il comportamento del tasto Tab. Un trucco molto utile è configurare Tab per visualizzare un menu navigabile di opzioni invece di completare semplicemente l'elemento successivo:
Comando PSReadLine: Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
Se inserisci questa riga nel tuo file di profilo da PowerShell, ad esempio modificandolo con notepad $profileCiò garantirà che ogni nuova sessione di PowerShell inizi con quel comportamento Tab, rendendo molto più piacevole esplorare le opzioni disponibili. Tuttavia, potrebbe essere necessario... adeguare la politica di esecuzione nel tuo sistema in modo che il profilo funzioni senza eccessive restrizioni.
D'altra parte, combinando questa funzionalità PSReadLine con i riempitivi registrati tramite Register-ArgumentCompleter (ad esempio, per winget, dotnet o i tuoi moduli), puoi avvicinarti molto alla fluidità del completamento automatico LinuxMolti team condividono ScriptBlocks completi nei loro repository, consentendo all'intera organizzazione di avere un un ambiente a riga di comando coerente e altamente produttivo.
Scrittore appassionato del mondo dei byte e della tecnologia in generale. Adoro condividere le mie conoscenze attraverso la scrittura, ed è quello che farò in questo blog, mostrarti tutte le cose più interessanti su gadget, software, hardware, tendenze tecnologiche e altro ancora. Il mio obiettivo è aiutarti a navigare nel mondo digitale in modo semplice e divertente.
