Nu folosiți variabilele globale decât dacă nu există literalmente nicio altă opțiune, punct. Este în regulă pentru lucruri mici ca acesta, dar cred că este important să ne dăm seama cum să facem lucrurile corect de la început.
Atunci, variabilele globale sunt destul de teribile în general… cu excepția cazului în care le folosiți doar ca referință și nu le schimbați niciodată din interiorul unei funcții. De ce contează asta? Pentru că dacă aveți zece funcții care folosesc toate aceeași variabilă care, să zicem, schimbă ceea ce fac în funcție de acea variabilă și oricare dintre ele ar putea să o schimbe, dintr-o dată comportamentul tuturor devine extrem de imprevizibil.
Ceea cu care trebuie să vă familiarizați în schimb este capturarea ieșirii dintr-o funcție. Ieșiți date, obiecte, text, orice doriți, iar apoi stocați această ieșire în ceva atunci când apelați funcția. Odată ce funcția se termină, acel container conține valoarea de care aveți nevoie.
Aceasta este mult mai ușor de urmărit, pentru că vă treziți cu linii de genul acesta:
$variable = Function-Name -Parameter1 'ParameterValue'
Știți dintr-o privire că această variabilă conține ieșirea din acea funcție și puteți să vă uitați la funcție pentru a vedea ce obțineți. Comparați cu variabilele globale:
$global:Var = 'initial value'Function-Name -Parameter1 'ParameterValue'# check the value of $global:Var$global:Var
Și nu aveți nicio idee dacă acea variabilă mai conține valoarea originală. Acest efect este agravat atunci când începeți să folosiți masiv variabilele globale și veți avea multe dificultăți în a urmări ce face propriul cod.
Atunci, ce faceți pentru a păstra lucrurile sensibile?
În exemplul funcției dumneavoastră:
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
Lăsați-mă să o despart:
- Funcțiile mai întâi. Definiți-vă funcțiile înainte de a face orice altceva. Funcțiile pot fi utilizate oriunde în cod, așa că este mult mai util dacă aveți un loc coerent pentru a vă verifica funcțiile. Este pur și simplu mai simplu să le păstrați la început, astfel încât să nu căutați în tot scriptul unde ați pus acea funcție pe care trebuie să o modificați.
- Definiți parametrii. Orice date pe care funcția dvs. trebuie să le folosească din scriptul mai larg ar trebui să fie definite în parametrii săi. Acest lucru vă permite să vedeți dintr-o privire de ce date are nevoie o funcție și, de asemenea, vă permite să fiți sigur că îi veți da datele corecte și că nu le-ați amestecat din greșeală în altă parte în scriptul dumneavoastră.
- Output!
Write-Output
este un mod foarte clar de a face acest lucru, dar, în mod implicit, simplul fapt de a lăsa datele să „cadă” în fluxul de ieșire prin faptul că nu le capturează (de exemplu, lăsându-le să stea singure pe o linie) va face ca acestea să fie ieșite. Prefer sintaxa mai clară de a specifica că „da, scot aceste date la ieșire”. - Capturarea! A face
$var = function-name
înseamnă practic „cheamă această funcție și capturează orice ieșire în variabila$var
„. Acest lucru vă permite să folosiți aceste date mai târziu și, pentru că le definiți în același loc în care le folosiți, este mult mai ușor să urmăriți ce faceți cu codul dumneavoastră. - Tipuri de obiecte. Folosiți tipul PSObject și îl construiți folosind un hashtable. Ceea ce fac eu este foarte asemănător, dar, în general, veți considera că PsCustomObject este un tip mai flexibil pentru orice aveți nevoie să faceți. Se formatează mai ușor și funcționează mai ușor cu toate cmdlets.
-
Bucăți suplimentare: acele paranteze pătrate sunt ceea ce se numește „atribute”. Sunt biți suplimentari pe care îi puteți aplica funcțiilor dvs. cu diverse utilizări.
declară că aceasta este o „funcție avansată” (denumire prostească pentru mine, dar așa au ales să o numească). Practic, aceasta vă permite să vă folosiți de parametrii impliciți pe care PS permite funcțiilor să îi aibă. Puteți face lucruri cum ar fi să apelați
Write-Verbose
pentru a lăsa în urmă informații despre ceea ce faceți care în mod normal sunt ascunse (pentru că de obicei nu sunt necesare), dar apoi să apelați funcția cu parametrul-Verbose
pentru a vedea mesajele (dacă ceva nu merge așa cum vă așteptați, astfel încât să puteți vedea unde se încurcă).Atributele pot fi definite pentru fiecare parametru în parte în acest fel. Se pot defini poziții specifice, dacă sunt obligatorii și multe alte lucruri, cum ar fi dacă acceptă intrarea în conductă.
Așa că, având în vedere acest lucru, iată cum aș gestiona eu însumi această funcție:
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
Am scurtat-o mai mult sau mai puțin, am făcut câteva lucruri mai sofisticate și am făcut-o să funcționeze cu pipeline-ul, astfel încât să puteți face același lucru în mai puțini pași. Recunosc că, probabil, vă copleșesc complet aici, așa că vă rog să nu vă fie teamă să o cotrobăiți bucățică cu bucățică și să puneți întrebări despre orice lucru de care nu sunteți sigur. Sunt lucruri aici pe care nu le-am menționat mai sus, dar hei! Puteți folosi copios Get-Help
sau Google, iar eu sunt aici pentru orice aveți nevoie de o explicație „pe scurt” sau pentru orice aveți dificultăți în a înțelege.
Speranță bună acolo, poate deveni un pic sălbatic. 😀
.