Padroneggiare le funzioni di PowerShell: una guida passo dopo passo

Una volta che ti sei abituato a scrivere script PowerShell, devi imparare riguardo alla modularizzazione del codice. La modularizzazione è solo un termine elegante per creare codice in blocchi costruttivi. Nel mondo PowerShell, le funzioni PowerShell sono uno dei migliori modi per fare ciò.

Quando scrivi uno script PowerShell, hai molte opzioni su come scrivere il codice. Potresti scrivere mille righe di codice che fanno centinaia di compiti, tutto in un unico, ininterrotto blocco di codice. Sarebbe un disastro. Invece, dovresti scrivere funzioni.

Le funzioni aumentano drammaticamente l’usabilità e la leggibilità del tuo codice, rendendolo molto più facile da lavorare. In questo tutorial, imparerai a scrivere funzioni, aggiungere e gestire i parametri delle tue funzioni, e impostare le funzioni per accettare l’input della pipeline. Ma prima, diamo un’occhiata ad un po’ di terminologia.

Questo post è stato estratto dal mio libro PowerShell per Sysadmins: Automazione del Flusso di Lavoro Resa Facile. Se impari qualcosa in questo tutorial, assicurati di controllare il libro per imparare di più sulle funzioni e molto altro riguardo a PowerShell.

Funzioni vs. Cmdlet

Il concetto di funzione potrebbe sembrarti familiare perché suona un po’ come i cmdlet che probabilmente hai già usato. Comandi come Start-Service e Write-Host, ad esempio, sono simili alle funzioni. Questi sono pezzi di codice nominati che risolvono un singolo problema. La differenza tra una funzione e un cmdlet sta nel modo in cui ciascuna di queste costruzioni è fatta.

A cmdlet isn’t written with PowerShell. It’s written in another language, typically something like C#. The cmdlet is then compiled and made available inside PowerShell.

Le funzioni, d’altra parte, sono scritte in PowerShell; non in un’altra lingua.

Puoi vedere quali comandi sono cmdlet e quali sono funzioni utilizzando il cmdlet Get-Command e il suo parametro CommandType come mostrato di seguito

Get-Command –CommandType Function

Questo comando restituisce tutte le funzioni attualmente caricate nella tua sessione PowerShell o all’interno dei moduli disponibili per PowerShell.

Correlato: Comprensione e Creazione di Moduli PowerShell

Prerequisiti

Se desideri seguire tutti gli esempi, assicurati di avere una versione di PowerShell disponibile. Non ci sono requisiti specifici di versione per questo tutorial. Inoltre, assicurati di avere un buon editor di codice come Visual Studio Code per copiare, incollare ed eseguire alcuni snippet di codice.

Costruire una Funzione Semplice

Prima di poter utilizzare una funzione, è necessario definirla. Per definire una funzione, si utilizza la parola chiave “function”, seguita da un nome descrittivo definito dall’utente, seguito da un insieme di parentesi graffe. All’interno delle parentesi graffe si trova un blocco di script che si desidera eseguire in PowerShell.

Di seguito puoi vedere una funzione di base e l’esecuzione di quella funzione. Questa funzione chiamata Install-Software, utilizza Write-Host per visualizzare un messaggio nella console. Una volta definita, è possibile utilizzare il nome di questa funzione per eseguire il codice all’interno del suo blocco di script.

PS> function Install-Software { Write-Host 'I installed some software. Yippee!' }
PS> Install-Software
I installed some software, Yippee!

Nomi con verbo-sostantivo

A function’s name is important. You can name your functions whatever you want, but the name should always describe what the function does. The function-naming convention in PowerShell is the Verb-Noun syntax.

Si dovrebbe sempre iniziare il nome di una funzione con un verbo seguito da un trattino e un sostantivo. Per trovare l’elenco dei verbi “approvati”, utilizzare il cmdlet Get-Verb.

Modificare il comportamento di una funzione

Se si desidera modificare il comportamento di una funzione, è sufficiente modificare il codice che la funzione esegue come mostrato di seguito.

PS> function Install-Software { Write-Host 'You installed some software, Yay!' }
PS> Install-Software
You installed some software, Yay!

Ora che hai modificato il codice all’interno della funzione, visualizzerà un messaggio leggermente diverso.

Definizione di una funzione avanzata

È possibile definire le funzioni in molti luoghi diversi. Nella sezione precedente, il tutorial assume che tu abbia semplicemente copiato e incollato il codice direttamente nella console di PowerShell. Ma questa non è l’unica modalità. È possibile definire le funzioni anche in uno script.

Nella sezione precedente, hai lavorato con una piccola funzione, quindi definirla nella console non è stato un grosso problema. Nella maggior parte dei casi, però, avrai funzioni molto più grandi. Sarà più facile definire quelle funzioni in uno script o in un modulo e quindi chiamare quello script o modulo per caricare la funzione in memoria.

Come puoi immaginare, riscrivere una funzione più grande ogni volta che si desidera modificare la sua funzionalità potrebbe diventare un po’ frustrante.

I suggest you now open your favorite editor and store the function in a .ps1 file as you work through the rest of the tutorial.

Aggiunta di parametri alle funzioni

Le funzioni di PowerShell possono avere un numero qualsiasi di parametri. Quando crei le tue funzioni, avrai la possibilità di includere parametri e decidere come questi parametri funzionano. I parametri possono essere obbligatori o opzionali e possono accettare qualsiasi cosa o essere costretti ad accettare uno dei possibili argomenti di una lista limitata.

Correlato: Tutto quello che hai sempre voluto sapere sui parametri di PowerShell

Ad esempio, il software immaginario che stai installando tramite la funzione Install-Software potrebbe avere molte versioni. Ma attualmente, la funzione Install-Software non offre all’utente un modo per specificare quale versione desidera installare.

Se fossi l’unico a utilizzare la funzione, potresti modificare il codice al suo interno ogni volta che desideri una versione specifica, ma sarebbe uno spreco di tempo. Questo processo sarebbe anche soggetto a potenziali errori, senza considerare che desideri che altre persone possano utilizzare il tuo codice.

L’introduzione dei parametri nella tua funzione consente di renderla variabile. Proprio come le variabili ti hanno permesso di scrivere script che potevano gestire molte versioni della stessa situazione, i parametri ti consentono di scrivere una singola funzione che fa una cosa in molti modi.

In questo caso, vuoi che installi versioni dello stesso software e lo faccia su molti computer.

Aggiungiamo prima un parametro alla funzione che consente a te o all’utente di specificare la versione da installare.

Creazione di un Parametro Semplice

La creazione di un parametro su una funzione richiede un blocco param. Il blocco param contiene tutti i parametri per la funzione. Definisci un blocco param con la parola chiave param seguita da parentesi come mostrato di seguito.

function Install-Software {
	[CmdletBinding()]
	param()

	Write-Host 'I installed software version 2. Yippee!'
}

A questo punto, la funzionalità effettiva della tua funzione non è cambiata affatto. Hai appena installato la canalizzazione, preparando la funzione per un parametro.

Per ora, la funzione non sta effettivamente installando alcun software. Sta solo usando il cmdlet Write-Host per simulare l’installazione del software in modo che tu possa concentrarti sulla scrittura della funzione.

Una volta aggiunto il blocco param, puoi creare il parametro inserendolo tra le parentesi del blocco param come mostrato di seguito.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter()]
		[string] $Version
	)
	
	Write-Host "I installed software version $Version. Yippee!"

}

All’interno del blocco param sopra, dovresti prima definire il blocco del parametro. Utilizzare il blocco Parameter() in questo modo lo trasformerà in un “parametro avanzato”. Un blocco di parametro vuoto come quello qui non fa nulla ma è richiesto; spiegherò come usarlo nella prossima sezione.

Focalizziamoci invece sul tipo [string] di fronte al nome del parametro. Ponendo il tipo del parametro tra parentesi quadre prima del nome della variabile del parametro, si effettua il casting del valore del parametro a un tipo specifico. PowerShell cercherà sempre di convertire qualsiasi valore passato a questo parametro in una stringa, se non lo è già. Di seguito, qualsiasi cosa passata come $Version sarà sempre trattata come una stringa.

Eseguire il casting del parametro a un tipo non è obbligatorio, ma lo incoraggio vivamente. Definisce esplicitamente il tipo e ridurrà significativamente gli errori in seguito.

Aggiungi anche $Version nella tua istruzione Write-Host ora. Ciò significa che quando esegui la funzione Install-Software con il parametro Version e gli passi un numero di versione, dovresti ottenere un’istruzione come mostrato di seguito.

PS> Install-Software -Version 2
I installed software version 2. Yippee!

Vediamo cosa puoi fare con questo parametro ora.

L’Attributo del Parametro Obbligatorio

Puoi utilizzare il blocco del parametro per controllare vari attributi del parametro, che ti consentiranno di modificare il comportamento del parametro. Ad esempio, se desideri assicurarti che chiunque chiami la funzione debba passare un determinato parametro, potresti definire quel parametro come obbligatorio.

Per impostazione predefinita, i parametri sono opzionali. Costringiamo l’utente a passare una versione utilizzando la parola chiave Obbligatorio all’interno del blocco del parametro, come mostrato di seguito.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory)]
		[string]$Version
	)

	Write-Host "I installed software version $Version. Yippee!"

}

Se esegui la funzione sopra, dovresti ottenere il seguente prompt:

Prompting for a mandatory parameter

Una volta impostato l’attributo obbligatorio, l’esecuzione della funzione senza il parametro interromperà l’esecuzione fino a quando l’utente non inserisce un valore. La funzione ora attende finché l’utente specifica un valore per il parametro Versione. Una volta inserito, PowerShell esegue la funzione.

Per evitare il prompt del parametro obbligatorio, basta passare un valore al parametro quando si chiama la funzione come mostrato di seguito.

Install-Software -Version 2

Valori predefiniti dei parametri

Se, ad esempio, ti ritrovi a passare lo stesso valore per un parametro più volte, puoi definire un valore predefinito per il parametro. I parametri predefiniti sono utili quando ti aspetti un certo valore per un parametro la maggior parte delle volte.

Per esempio, se vuoi installare la versione 2 di questo software il 90 percento delle volte, e preferiresti non dover impostare il valore ogni volta che esegui questa funzione, potresti assegnare un valore predefinito di 2 al parametro $Versione. Puoi vedere questo esempio di seguito.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter()]
		[string]$Version = 2
	)

	Write-Host "I installed software version $Version. Yippee!"

}

Avere un parametro predefinito non ti impedisce di passarne uno. Il valore passato sovrascriverà il valore predefinito.

Aggiunta di attributi di convalida del parametro

È sempre una buona idea limitare quali valori puoi passare a una funzione tramite i parametri. Il modo migliore per farlo è con gli attributi di convalida del parametro.

Limitare le informazioni che gli utenti (o anche tu!) possono passare alle tue funzioni o script eliminerà codice non necessario all’interno della tua funzione. Ad esempio, diciamo che passi il valore 3 alla tua funzione Install-Software, sapendo che la versione 3 è una versione esistente.

La tua funzione assume che ogni utente conosca quali versioni esistono, quindi non tiene conto di cosa succede quando si cerca di specificare la versione 4. In quel caso, la funzione non riuscirà a trovare la cartella appropriata perché non esiste.

Vita Senza Validazione dei Parametri

Dai un’occhiata all’esempio qui sotto quando si utilizza la stringa $Version in un percorso di file. Se qualcuno passa un valore che non completa un nome di cartella esistente (ad esempio, SoftwareV3 o SoftwareV4), il codice fallirà.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[string]$Version
	)

	Get-ChildItem -Path \\SRV1\Installers\SoftwareV$Version

}
Failing on unexpected parameter values

Potresti scrivere del codice di gestione degli errori per risolvere questo problema, oppure potresti eliminare il problema richiedendo all’utente di passare solo una versione esistente del software. Per limitare l’input dell’utente, aggiungi la validazione dei parametri.

Aggiunta della Validazione dei Parametri

Esistono vari tipi di validazione dei parametri, ma per quanto riguarda la tua funzione Install-Software, l’attributo [ValidateSet](https://adamtheautomator.com/powershell-validateset/) funziona meglio. L’attributo di validazione ValidateSet ti consente di specificare un elenco di valori consentiti per il parametro. Se stai considerando solo la stringa 1 o 2, assicurati che l’utente possa specificare solo questi valori; in caso contrario, la funzione fallirà immediatamente e avviserà l’utente del motivo.

Aggiungi attributi di validazione dei parametri all’interno del blocco param, subito sotto il blocco Parameter originale come mostrato di seguito.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version
	)

	Get-ChildItem -Path \\SRV1\Installers\SoftwareV$Version

}

Aggiungendo un set di elementi (1 e 2) all’interno delle parentesi di chiusura dell’attributo ValidateSet, questo dice a PowerShell che i valori validi per Versione sono solo 1 o 2. Se un utente prova a passare qualcosa di diverso da ciò che è nel set, riceverà un messaggio di errore come mostrato di seguito, notificandogli che ha solo un numero specifico di opzioni disponibili.

Parameter validation stopping PowerShell function execution

L’attributo ValidateSet è un attributo di convalida comune, ma ce ne sono altri disponibili. Per una completa analisi di tutti i modi in cui i valori dei parametri possono essere limitati, consulta la documentazione di Microsoft.

Accettazione dell’input del pipeline

Fino ad ora, hai creato una funzione con un parametro che può essere passato solo utilizzando la sintassi tipica -NomeParametro <Valore>. Questo funziona, ma hai anche un’altra opzione per passare valori ai parametri utilizzando il pipeline di PowerShell. Aggiungiamo le capacità del pipeline alla nostra funzione Install-Software.

Correlato: Accettazione dell’input del pipeline nell’articolo sui parametri ATA PowerShell

Prima di tutto, aggiungi un altro parametro al tuo codice che specifica il computer su cui desideri installare il software. Inoltre, aggiungi quel parametro al riferimento Write-Host per simulare l’installazione.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[string]$Version
		[ValidateSet('1','2')],
		
		[Parameter(Mandatory)]
		[string]$ComputerName
	)

	Write-Host "I installed software version $Version on $ComputerName. Yippee!"

}

Una volta aggiunto il parametro ComputerName alla funzione, ora puoi iterare su un elenco di nomi di computer e passare i valori del nome del computer e della versione alla funzione Install-Software, come mostrato di seguito.

$computers = @("SRV1", "SRV2", "SRV3")
foreach ($pc in $computers) {
	Install-Software -Version 2 -ComputerName $pc
}

Invece di fare tutto ciò, dovresti imparare a utilizzare il pipeline invece.

Rendere la Funzione Compatibile con la Pipeline

Sfortunatamente, non puoi sfruttare la pipeline di PowerShell con una semplice funzione costruita in precedenza. Devi decidere quale tipo di input della pipeline desideri che la funzione accetti e implementare.

A PowerShell function uses two kinds of pipeline input: ByValue (entire object) and ByPropertyName (a single object property). Here, because the $computers array contains only strings, you’ll pass those strings via ByValue.

Per aggiungere il supporto per la pipeline, aggiungi un attributo del parametro al parametro che desideri utilizzare uno dei due parole chiave: ValueFromPipeline o ValueFromPipelineByPropertyName come mostrato di seguito.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version,

		[Parameter(Mandatory, ValueFromPipeline)]
		[string]$ComputerName
	)

	Write-Host "I installed software version $Version on $ComputerName. Yippee!"

}

Una volta caricata l’aggiornamento della funzione Install-Software, chiamala come segue:

$computers = @("SRV1", "SRV2", "SRV3")
$computers | Install-Software -Version 2

Esegui di nuovo lo script e dovresti ottenere qualcosa del genere:

I installed software version 2 on SRV3. Yippee!

Nota che Install-Software viene eseguito solo per l’ultima stringa nell’array. Vedrai come risolvere questo nel prossimo paragrafo.

Aggiunta di un blocco di processo

Per dire a PowerShell di eseguire questa funzione per ogni oggetto in ingresso, è necessario includere un blocco di processo. All’interno del blocco di processo, inserisci il codice che desideri eseguire ogni volta che la funzione riceve input dalla pipeline. Aggiungi un blocco di processo al tuo script come mostrato di seguito.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version,

		[Parameter(Mandatory, ValueFromPipeline)]
		[string]$ComputerName
	)

	process {
		Write-Host "I installed software version $Version on $ComputerName. Yippee!"
	}
}

Ora chiama di nuovo la funzione proprio come hai fatto in precedenza. La funzione Install-Software restituirà ora tre righe (una per ogni oggetto).

I installed software version 2 on SRV1. Yippee!
I installed software version 2 on SRV2. Yippee!
I installed software version 2 on SRV3. Yippee!

Il blocco di processo contiene il codice principale che desideri eseguire. Puoi anche utilizzare i blocchi begin e end per il codice che verrà eseguito all’inizio e alla fine della chiamata della funzione. Puoi saperne di più sui blocchi begin, process, e end tramite la documentazione di Microsoft.

Prossimi Passi

Le funzioni ti consentono di suddividere il codice in blocchi costruttivi discreti. Non solo ti aiutano a suddividere il lavoro in porzioni più piccole e gestibili, ma ti costringono anche a scrivere codice leggibile e testabile.

I now challenge you to look through some old scripts and see where you can add a PowerShell function. Look for patterns in code. Build a function from those patterns. Notice where you’re copying/pasting code snippets and turn those into PowerShell functions!

Source:
https://adamtheautomator.com/powershell-functions/