Przyspieszenie działania poleceń w skryptach PowerShell

Skrypty PowerShell wykorzystujące bezpośrednio .NET i unikające wykorzystywania potoków są szybsze w działaniu.

Pomijanie wyjścia.
Często w skryptach chcemy uniknąć wypisywania efektów danego polecenia na ekran. Klasycznym rozwiązaniem jest użycie na końcu potoku funkcji Out-Null np.:
New-VM -ComputerName VM132 -Name Windows10 | Out-Null
Nie jest to jednak rozwiązanie optymalne pod względem wydajności. Lepszym rozwiązaniem jest skorzystanie z poniższych opcji wykorzystując zmienną $Null lub [void] np.:
$Null=New-VM -ComputerName VM132 -Name Windows10
lub
[void](New-VM -ComputerName VM132 -Name Windows10)

Dodawanie elementów do listy (ang. array)
Lista jest strukturą danych do przechowywania kolekcji wartości różnych typów. Od PowerShell w wersji 3 kolekcja o zerowej ilości elementów lub tylko z jednym także posiada pewne właściwości listy.
Podstawowe polecenia:
- utworzenie nowej listy: $Lista=1,4,77,4,'Ala ma kota'
- utworzenie pustej listy: $Lista=@()
- sprawdzenie typu danych listy: $Lista.GetType()
- utworzenie listy o zdefiniowanym typie: [int32[]]$Lista=1232323,4440333,4000

Użycie list jest bardzo przydatne do przechowywania wyników poleceń np.:









W celu dopisania kolejnego elementu do listy najczęściej stosuje się operator += np.:
$Lista=@()
$Lista+=Zrób coś
$Lista+=Zrób coś jeszcze
$Lista

Nie jest to jednak najlepsze rozwiązanie pod względem wydajności, gdyż tablice same w sobie są nieznienne. Każde dodanie do tablicy elementu powoduje utowrzenie nowej tablicy, na tyle dużej by pomieścić istniejące elementy i dodany nowy element. W przypadku małej ilości danych nie ma to większego znaczenia, ale w przypadku dużych ilości danych może to stanowić problem. Istnieje kilka alternatyw. Jeżeli świadomie nie potrzebujemy listy możemy wykorzystać listę list (ArrayList) do zapisania danych a następnie utworzyć z niej listę.
$Zmienna1=[System.Collections.ArrayList]::new()
$Zmienna1.AddRange((Do-Something))
$Zmienna1.AddRange((Do-SomethingElse))
$Zmienna1

PowerShell może zrobić to samo za nas. Wystarczy użyć poniższej formuły:
$Zmienna1=@(
Do-Something
Do-SomethingElse
)

Poniżej przykładowy kod z wykorzystaniem rozwiązania z operatorem += i powyższej formuły.
Przykład nr 1 z użyciem operatora +=.
$VMList=Get-VM
 ForEach ($i in $VMList)
 {
 $VMNetAdapter=Get-VMNetworkAdapter -VMName $i.Name
  $Temp=New-Object PSObject -Property @{
  Name=$i.Name
  State=$i.VMState
  IPAddresses=@($VMNetAdapter.SwitchName,$VMNetAdapter.IPAddresses)
  }
 $VMList2+=$Temp
 }
$VMList2 | Format-Table Name,State,IPAddresses -Autosize


Przykład nr 2 z efektywniejszym zapisem danych do listy.
$VMList=Get-VM
$VMList2=@(
 ForEach ($i in $VMList)
 {
 $VMNetAdapter=Get-VMNetworkAdapter -VMName $i.Name
  $Temp=New-Object PSObject -Property @{
  Name=$i.Name
  State=$i.VMState
  IPAddresses=@($VMNetAdapter.SwitchName,$VMNetAdapter.IPAddresses)
  }
 }
)
$VMList2 | Format-Table Name,State,IPAddresses -Autosize


Odczyt z pliku.
Tu także można przyspieszyć działanie skryptu. Zamiast użycia przykładowego polecenia, które odczyta z pliku wiersze mające długość większą niż 10 znaków: Get-Content $path | Where-Object {$_.Length -gt 10}, możemy skorzystać z interfejsu progrmowania aplikacji (API) do platformy .NET:
try
{
 $stream = [System.IO.StreamReader]::new($path)
 while ($line = $stream.ReadLine())
 {
  if ($line.Length -gt 10)
  {
  $line
  }
 }
}
finally
{
 $stream.Dispose()
}


Przekierowanie do konsoli.
Klasycznym poleceniem używanym do wyświetlenia wyników do konsoli użytkownika (ekran monitora) służy polecenie Write-Host. Jeżeli jednak ilość informacji jakie należy wyświetlić jest duża, optymalniejszym sposobem jest skorzystanie z polecenia [Console]::WriteLine() lub Write-Output. Przykład:
$a=Get-VM
Write-Host $a
[Console]::WriteLine($a)
Write-Output $a


Dodatkowe informacje:
- Microsoft Docs: About Arrays.
- Microsoft Docs: Write-Output.