Gebruik geen globale variabelen tenzij er letterlijk geen andere optie is, punt. Het is prima voor kleine dingen zoals dit, maar ik denk dat het belangrijk is om al vroeg uit te zoeken hoe je dingen goed kunt doen.
Dus, globals zijn vrij verschrikkelijk in het algemeen… tenzij je ze alleen gebruikt als referentie en je ze nooit vanuit een functie wijzigt. Waarom is dat belangrijk? Omdat als je tien functies hebt, die allemaal dezelfde variabele gebruiken, en die veranderen wat ze doen op basis van die variabele, en elk van hen kan het mogelijk veranderen, dan wordt het gedrag van hen allemaal extreem onvoorspelbaar.
Waar je jezelf mee vertrouwd moet maken, is het vastleggen van de uitvoer van een functie. Je output data, objecten, tekst, wat je maar wilt, en dan sla je die output op in iets wanneer je de functie aanroept. Zodra de functie is voltooid, bevat die container de waarde die je nodig hebt.
Dit is veel gemakkelijker te volgen, omdat je eindigt met regels als deze:
$variable = Function-Name -Parameter1 'ParameterValue'
Je weet in een oogopslag dat deze variabele de uitvoer van die functie bevat, en je kunt gewoon naar de functie kijken om te zien wat je krijgt. Vergelijk met globale variabelen:
$global:Var = 'initial value'Function-Name -Parameter1 'ParameterValue'# check the value of $global:Var$global:Var
En je hebt geen idee of die variabele nog steeds de oorspronkelijke waarde bevat. Dit effect wordt nog versterkt wanneer je veel gebruik gaat maken van globale variabelen, en je zult veel moeite hebben om te volgen wat je eigen code doet.
Dus, wat doe je om dingen zinnig te houden?
In het voorbeeld van je functie:
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
Laat me het uitsplitsen:
- Functies eerst. Definieer je functies voordat je iets anders doet. Functies kunnen overal in de code worden gebruikt, dus het is veel nuttiger als je een consistente plaats hebt om je functies te controleren. Het is gewoon eenvoudiger om ze aan het begin te bewaren, zodat je niet het hele script hoeft af te zoeken naar waar je die functie hebt gezet die je moet veranderen.
- Define parameters. Alle gegevens die uw functie moet gebruiken uit het bredere script moeten worden gedefinieerd in de parameters. Zo kun je in één oogopslag zien welke gegevens een functie nodig heeft, en je kunt er ook zeker van zijn dat je de functie de juiste gegevens geeft, en dat je die niet per ongeluk ergens anders in je script hebt gemunderd.
- Output!
Write-Output
is een heel duidelijke manier om het te doen, maar standaard zal het simpelweg laten “vallen” van gegevens op de uitvoerstroom door ze niet vast te leggen (bijvoorbeeld door ze op zichzelf op een regel te laten staan) ertoe leiden dat ze worden uitgevoerd. Ik geef de voorkeur aan de duidelijker syntaxis van het specificeren dat “ja, ik voer deze gegevens uit”. - Opvangen!
$var = function-name
doen betekent in feite “roep deze functie aan en vang de output op in de variabele$var
“. Hierdoor kunt u deze gegevens later gebruiken, en omdat u ze op dezelfde plaats definieert als u ze gebruikt, is het veel gemakkelijker om te volgen wat u met uw code doet. - Objecttypen. Je gebruikt het PSObject type, en construeert het door gebruik te maken van een hashtable. Wat ik doe is vergelijkbaar, maar over het algemeen vind je PsCustomObject een flexibeler type voor alles wat je gedaan moet krijgen. Het formatteert gemakkelijker en werkt naadloos samen met alle cmdlets.
-
Aanvullende weetjes: die vierkante haakjes zijn wat bekend staat als “attributen”. Het zijn extra bits die je kunt toepassen op je functies met verschillende toepassingen.
verklaart dat dit een “geavanceerde functie” is (wat een rare naam, maar zo noemen ze hem nu eenmaal). In principe kun je hiermee gebruik maken van de standaard parameters die PS toestaat aan functies. Je kunt bijvoorbeeld
Write-Verbose
aanroepen om informatie achter te laten over wat je aan het doen bent die normaal verborgen blijft (omdat het meestal niet nodig is), maar dan de functie aanroepen met de-Verbose
parameter om de boodschappen te zien (als iets niet gaat zoals je verwacht, zodat je kunt zien waar het fout gaat).attributen kunnen worden gedefinieerd voor elke parameter op die manier. Je kunt specifieke posities definiëren, of ze verplicht zijn, en vele andere dingen, zoals of ze invoer via een pijplijn accepteren.
Dus, met dat in gedachten, dit is hoe ik deze functie zelf zou aanpakken:
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
Ik heb hem min of meer ingekort, wat chiquere dingen gedaan, en hem met de pijplijn laten werken, zodat je hetzelfde in minder stappen kunt doen. Ik geef toe dat ik je hier waarschijnlijk volledig overdonder, dus wees niet bang om stukje bij beetje te porren en vragen te stellen over alles waar je niet zeker over bent. Er zijn hier dingen die ik hierboven niet genoemd heb, maar hé! Je kunt overvloedig gebruik maken van Get-Help
of Google, en ik ben hier voor alles waar je een ‘in-a-nutshell’ uitleg voor nodig hebt, of iets wat je moeilijk kunt begrijpen.
Geluk daarbuiten, het kan een beetje wild worden. 😀