Verwenden Sie keine globalen Variablen, es sei denn, es gibt buchstäblich keine andere Möglichkeit, Punkt. Für kleine Dinge wie diese ist es in Ordnung, aber ich denke, es ist wichtig, frühzeitig herauszufinden, wie man die Dinge richtig macht.
So, globale Variablen sind im Allgemeinen ziemlich schrecklich… es sei denn, man verwendet sie nur als Referenz und ändert sie nie innerhalb einer Funktion. Warum ist das wichtig? Weil, wenn Sie zehn Funktionen haben, die alle dieselbe Variable verwenden und die, sagen wir mal, das, was sie tun, auf der Grundlage dieser Variable ändern, und jede von ihnen könnte sie möglicherweise ändern, wird das Verhalten aller plötzlich extrem unvorhersehbar.
Womit Sie sich stattdessen vertraut machen müssen, ist die Erfassung der Ausgabe einer Funktion. Du gibst Daten, Objekte, Text, was auch immer du willst, aus und speicherst diese Ausgabe in einem Container, wenn du die Funktion aufrufst. Sobald die Funktion abgeschlossen ist, enthält dieser Container den Wert, den Sie benötigen.
Dies ist viel einfacher zu verstehen, weil Sie Zeilen wie diese erhalten:
$variable = Function-Name -Parameter1 'ParameterValue'
Sie wissen auf einen Blick, dass diese Variable die Ausgabe dieser Funktion enthält, und Sie können einfach die Funktion betrachten, um zu sehen, was Sie erhalten. Im Vergleich zu globalen Variablen:
$global:Var = 'initial value'Function-Name -Parameter1 'ParameterValue'# check the value of $global:Var$global:Var
Und Sie haben keine Ahnung, ob diese Variable noch den ursprünglichen Wert enthält. Dieser Effekt wird noch verstärkt, wenn Sie anfangen, globale Variablen in großem Umfang zu verwenden, und Sie werden große Schwierigkeiten haben, zu verfolgen, was Ihr eigener Code tut.
Was können Sie also tun, um die Dinge vernünftig zu halten?
Im Beispiel Ihrer Funktion:
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
Lassen Sie es mich aufschlüsseln:
- Funktionen zuerst. Definieren Sie Ihre Funktionen, bevor Sie etwas anderes tun. Funktionen können überall im Code verwendet werden, daher ist es viel nützlicher, wenn Sie einen konsistenten Ort haben, um Ihre Funktionen zu überprüfen. Es ist einfach einfacher, sie an den Anfang zu stellen, damit Sie nicht das ganze Skript nach der Stelle durchsuchen müssen, an der Sie die Funktion, die Sie ändern müssen, eingefügt haben.
- Definieren Sie Parameter. Alle Daten, die Ihre Funktion aus dem allgemeinen Skript verwenden muss, sollten in ihren Parametern definiert werden. So können Sie auf einen Blick sehen, welche Daten eine Funktion benötigt, und Sie können auch sicher sein, dass Sie ihr die richtigen Daten geben und sie nicht versehentlich irgendwo anders in Ihrem Skript vermischt haben.
- Ausgabe!
Write-Output
ist eine sehr klare Art, dies zu tun, aber standardmäßig werden Daten einfach in den Ausgabestrom „fallen“ gelassen, indem sie nicht erfasst werden (z.B. indem man sie in einer eigenen Zeile stehen lässt), so dass sie ausgegeben werden. Ich bevorzuge die klarere Syntax, die besagt: „Ja, ich gebe diese Daten aus“. - Erfassen!
$var = function-name
bedeutet im Grunde „rufe diese Funktion auf und fange die Ausgabe in der Variablen$var
auf“. Dadurch können Sie diese Daten später verwenden, und da Sie sie an der gleichen Stelle definieren, an der Sie sie verwenden, ist es viel einfacher zu verfolgen, was Sie mit Ihrem Code tun. - Objekttypen. Du verwendest den Typ PSObject und konstruierst ihn mit Hilfe einer Hashtable. Was ich tue, ist sehr ähnlich, aber Sie werden feststellen, dass PsCustomObject ein flexiblerer Typ für alles ist, was Sie erledigen müssen. Er lässt sich einfacher formatieren und arbeitet nahtlos mit allen Cmdlets zusammen.
-
Zusätzliche Informationen: Diese eckigen Klammern sind so genannte „Attribute“. Sie sind zusätzliche Bits, die Sie auf Ihre Funktionen mit verschiedenen Verwendungen anwenden können.
erklärt, dass es sich um eine „fortgeschrittene Funktion“ handelt (ein dummer Name, wie ich finde, aber so wurde sie genannt). Im Grunde können Sie damit die Standardparameter nutzen, die PS für Funktionen zulässt. Man kann z.B.
Write-Verbose
aufrufen, um Informationen über das, was man tut, zu hinterlassen, die normalerweise verborgen bleiben (weil sie normalerweise nicht benötigt werden), aber dann die Funktion mit dem Parameter-Verbose
aufrufen, um die Meldungen zu sehen (wenn etwas nicht so läuft, wie man es erwartet, so dass man sehen kann, wo es schief läuft).Attribute können für jeden solchen Parameter definiert werden. Sie können bestimmte Positionen definieren, ob sie obligatorisch sind und viele andere Dinge, wie zum Beispiel, ob sie Pipeline-Eingaben akzeptieren.
So, mit diesem Gedanken im Hinterkopf, hier ist, wie ich diese Funktion selbst handhaben würde:
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
Ich habe sie mehr oder weniger nur gekürzt, einige ausgefeiltere Dinge getan und sie mit der Pipeline arbeiten lassen, so dass man die gleiche Sache in weniger Schritten tun kann. Mir ist klar, dass ich Sie hier wahrscheinlich völlig überfordere, also scheuen Sie sich bitte nicht, es Stück für Stück durchzugehen und Fragen zu stellen, wenn Sie sich nicht sicher sind. Es gibt hier Dinge, die ich oben nicht erwähnt habe, aber hey! Du kannst entweder Get-Help
oder Google ausgiebig nutzen, und ich bin für alles da, wofür du eine kurze Erklärung brauchst oder was du nicht verstehst.
Viel Glück da draußen, es kann ein bisschen wild werden 😀