Non usare le variabili globali a meno che non ci sia letteralmente nessun’altra opzione, punto. Va bene per piccole cose come questa, ma penso che sia importante capire come fare le cose bene all’inizio.
Quindi, le variabili globali sono abbastanza terribili in generale… a meno che tu non le stia usando solo come riferimento e non le cambi mai dall’interno di una funzione. Perché questo è importante? Perché se avete dieci funzioni che usano tutte la stessa variabile che, diciamo, cambiano ciò che stanno facendo in base a quella variabile, e ognuna di loro potrebbe cambiarla, improvvisamente il comportamento di tutte diventa estremamente imprevedibile.
Quello con cui dovete familiarizzare è invece catturare l’output di una funzione. Voi emettete dati, oggetti, testo, qualsiasi cosa vogliate, e poi memorizzate quell’output in qualcosa quando chiamate la funzione. Una volta che la funzione completa, quel contenitore contiene il valore di cui avete bisogno.
Questo è molto più facile da seguire, perché vi ritrovate con linee come questa:
$variable = Function-Name -Parameter1 'ParameterValue'
Sapete a colpo d’occhio che questa variabile contiene l’output di quella funzione, e potete semplicemente guardare la funzione per vedere cosa state ottenendo. Confronta con le variabili globali:
$global:Var = 'initial value'Function-Name -Parameter1 'ParameterValue'# check the value of $global:Var$global:Var
E non hai idea se quella variabile contiene ancora il valore originale. Questo effetto è aggravato quando iniziate a usare pesantemente le variabili globali, e avrete molte difficoltà a seguire quello che il vostro codice sta facendo.
Allora, cosa fate per mantenere le cose sensate?
Nell’esempio della vostra funzione:
function Get-DiskSize { param( $Drives ) $Drives | ForEach-Object { $Vol = ("$_" + ":") $WMIPriorDisk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='$Vol'" | Select-Object Size, FreeSpace $PriorDiskObject = @{ DriveLetter = $Vol DiskSizePrior = "{0:N2}" -f ($WMIPriorDisk.Size / 1GB) DiskFreePrior = "{0:N2}" -f ($WMIPriorDisk.FreeSpace / 1GB) } Write-Output $PriorDiskObject } }$Drives = (::GetDrives() | Where-Object {$_.DriveType -eq "Fixed"} | Select-Object -ExpandProperty 'Name').Replace(":\","")$DisksPrior = Get-DiskSize -Drives $Drives
Lasciate che vi spieghi:
- Funzioni prima. Definite le vostre funzioni prima di fare qualsiasi altra cosa. Le funzioni possono essere usate ovunque nel codice, quindi è molto più utile se avete un posto coerente per controllare le vostre funzioni. È più semplice tenerle all’inizio, così non dovrai cercare in tutto lo script dove hai messo quella funzione che devi cambiare.
- Definire i parametri. Tutti i dati che la tua funzione ha bisogno di usare dallo script più ampio dovrebbero essere definiti nei suoi parametri. Questo ti permette di vedere a colpo d’occhio di quali dati ha bisogno una funzione, e ti permette anche di essere sicuro che le darai i dati giusti, e che non li hai pasticciati accidentalmente da qualche altra parte nel tuo script.
- Output!
Write-Output
è un modo molto chiaro di farlo, ma per default lasciare semplicemente che i dati “cadano” nel flusso di output non catturandoli (ad esempio, lasciandoli stare su una linea da soli) causerà l’output. Preferisco la sintassi più chiara di specificare che “sì, sto emettendo questi dati”. - Cattura! Fare
$var = function-name
significa fondamentalmente “chiamare questa funzione e catturare qualsiasi output nella variabile$var
“. Questo ti permette di usare questi dati in seguito, e poiché li stai definendo nello stesso posto in cui li stai usando, è molto più facile seguire quello che stai facendo con il tuo codice. - Tipi di oggetti. Stai usando il tipo PSObject e lo costruisci usando un hashtable. Quello che sto facendo io è molto simile, ma generalmente troverete PsCustomObject un tipo più flessibile per qualsiasi cosa abbiate bisogno di fare. Si formatta più facilmente e funziona più facilmente con tutti i cmdlets.
-
Particolari aggiuntivi: quelle parentesi quadre sono noti come “attributi”. Sono bit extra che puoi applicare alle tue funzioni con vari usi.
dichiara che questa è una “funzione avanzata” (nome stupido per me, ma è come hanno scelto di chiamarla). Fondamentalmente questo vi permette di fare uso dei parametri di default che PS permette alle funzioni di avere. Puoi fare cose come chiamare
Write-Verbose
per lasciare informazioni su ciò che stai facendo che normalmente sono nascoste (perché di solito non sono necessarie), ma poi chiamare la funzione con il parametro-Verbose
per vedere i messaggi (se qualcosa non sta andando come ti aspetti, così puoi vedere dove si sta incasinando).gli attributi possono essere definiti per ogni parametro come quello. Si possono definire posizioni specifiche, se sono obbligatori, e molte altre cose, come ad esempio se accettano l’input della pipeline.
Quindi, con questo in mente, ecco come gestirei io stesso questa funzione:
function Get-DiskSize { param( ] $Drives ) process { $Drives | ForEach-Object { $Vol = ("$_" + ":") Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='$Vol'" | Select-Object -Property @{ Name = 'TotalSpace' Expression = { "{0:N2}" -f ($_.Size / 1GB) } }, @{ Name = 'FreeSpace' Expression = { "{0:N2}" -f ($_.FreeSpace / 1GB) } } } } }$DisksPrior = (::GetDrives() | Where-Object {$_.DriveType -eq "Fixed"} | Select-Object -ExpandProperty 'Name').Replace(":\", "") | Get-DiskSize
Più o meno l’ho solo accorciata, ho fatto alcune cose più fantasiose e l’ho fatta funzionare con la pipeline in modo da poter fare la stessa cosa in meno passaggi. Mi rendo conto che probabilmente vi sto sommergendo completamente qui, quindi per favore non abbiate paura di spulciarlo pezzo per pezzo e di fare domande su qualsiasi cosa di cui non siete sicuri. Ci sono cose qui che non ho menzionato sopra, ma ehi! Puoi fare un uso copioso di Get-Help
o di Google, e io sono proprio qui per qualsiasi cosa di cui hai bisogno di una spiegazione ‘in-a-nutshell’, o qualsiasi cosa che hai difficoltà a capire.
Buona fortuna là fuori, può diventare un po’ selvaggio 😀