Nepoužívejte globální proměnné, pokud doslova nemáte jinou možnost, tečka. Na takovéhle drobnosti je to fajn, ale myslím, že je důležité přijít na to, jak to dělat správně už na začátku.
Takže globální proměnné jsou obecně dost hrozné… pokud je nepoužíváš jen jako odkaz a nikdy je neměníš zevnitř funkce. Proč na tom záleží? Protože pokud máte deset funkcí, které všechny používají stejnou proměnnou a řekněme mění to, co dělají na základě této proměnné, a kterákoli z nich by ji případně mohla změnit, najednou se chování všech stane extrémně nepředvídatelné.
S čím se místo toho musíte seznámit, je zachycení výstupu z funkce. Výstupem jsou data, objekty, text, cokoli chcete, a tento výstup pak při volání funkce do něčeho uložíte. Jakmile funkce skončí, v tomto kontejneru je uložena hodnota, kterou potřebujete.
Je to mnohem jednodušší na sledování, protože skončíte na řádcích, jako je tento:
$variable = Function-Name -Parameter1 'ParameterValue'
Na první pohled víte, že tato proměnná obsahuje výstup z dané funkce, a můžete se jen podívat na funkci, abyste viděli, co dostanete. Srovnejte s globálními proměnnými:
$global:Var = 'initial value'Function-Name -Parameter1 'ParameterValue'# check the value of $global:Var$global:Var
A nemáte tušení, zda tato proměnná stále obsahuje původní hodnotu. Tento efekt se ještě znásobí, když začnete ve velké míře používat globální proměnné, a budete mít velké potíže sledovat, co váš vlastní kód dělá.
Takže, co uděláte, abyste zachovali rozumné věci?
Na příkladu vaší funkce:
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
Nechte mě to rozebrat:
- Nejprve funkce. Definujte své funkce dříve, než uděláte cokoli jiného. Funkce lze použít kdekoli v kódu, takže je mnohem užitečnější, když máte konzistentní místo pro kontrolu funkcí. Je prostě jednodušší mít je na začátku, takže nemusíte hledat v celém skriptu, kam jste vložili tu funkci, kterou potřebujete změnit.
- Definice parametrů. Veškeré údaje, které vaše funkce potřebuje použít z širšího skriptu, by měly být definovány v jejích parametrech. Díky tomu na první pohled vidíte, jaká data funkce potřebuje, a také máte jistotu, že jí budete předávat správná data a že jste je omylem nepřehlédli někde jinde ve skriptu.
- Výstup!
Write-Output
je velmi jasný způsob, jak to udělat, ale ve výchozím nastavení prostě nechat data „spadnout“ do výstupního proudu tím, že je nezachytíte (např. je necháte stát na řádku samostatně), způsobí, že budou vyvedena. Dávám přednost jasnější syntaxi zadání, že „ano, tato data vypisuji“. - Zachycení! Provedení
$var = function-name
v podstatě znamená „zavolej tuto funkci a zachyť jakýkoli výstup do proměnné$var
„. To vám umožní použít tato data později, a protože je definujete na stejném místě, kde je používáte, je mnohem snazší sledovat, co děláte se svým kódem. - Objektové typy. Používáte typ PSObject a konstruujete jej pomocí hashtable. To, co dělám já, je velmi podobné, ale obecně zjistíte, že PsCustomObject je flexibilnější typ pro cokoli, co potřebujete udělat. Snadněji se formátuje a bezproblémověji spolupracuje se všemi rutinami.
-
Další zajímavosti: Ty hranaté závorky jsou takzvané „atributy“. Jsou to dodatečné bity, které můžete aplikovat na své funkce s různým využitím.
Deklaruje, že se jedná o „pokročilou funkci“ (podle mě hloupý název, ale tak se to rozhodli nazvat). V podstatě vám umožňuje využívat výchozí parametry, které PS umožňuje funkcím mít. Můžete dělat takové věci, jako že zavoláte
Write-Verbose
a necháte za sebou informace o tom, co děláte, které jsou normálně skryté (protože obvykle nejsou potřeba), ale pak zavoláte funkci s parametrem-Verbose
, abyste viděli hlášení (pokud něco neprobíhá tak, jak očekáváte, abyste viděli, kde to kazí).Atributy lze takto definovat pro každý parametr. Můžete definovat konkrétní pozice, zda jsou povinné a mnoho dalších věcí, například zda přijímají vstup z potrubí.
Takže s ohledem na to bych tuto funkci zpracoval sám takto:
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
Víceméně jsem ji jen zkrátil, udělal pár vymyšlených věcí a zajistil práci s pipeline, takže můžete udělat totéž v méně krocích. Uznávám, že jsem vás tu asi úplně zahltil, takže se prosím nebojte do toho šťourat kousek po kousku a ptát se na všechno, čím si nejste jistí. Jsou zde věci, které jsem výše nezmínil, ale hej! Buď můžete hojně využívat Get-Help
nebo Google, a já jsem tady pro všechno, co potřebujete vysvětlit „v kostce“, nebo pro cokoli, čemu máte problém porozumět.
Přeji hodně štěstí, tam venku to může být trochu divoké 😀
.