Ograniczenia transkrypcji programu PowerShell

Mieszanie Write-Host danych wyjściowych z obiektami wyjściowymi, ciągami i transkrypcją programu PowerShell jest skomplikowane. Istnieje subtelna interakcja między skryptem a sposobem współdziałania transkrypcji z potokami programu PowerShell, które mogą mieć nieoczekiwane wyniki.

Podczas emitowania obiektów ze skryptu formatowanie tych obiektów jest obsługiwane przez element Out-Default. Jednak formatowanie może wystąpić po zakończeniu działania skryptu i zatrzymaniu transkrypcji. Oznacza to, że dane wyjściowe nie otrzymują transkrypcji. Ciągi są obsługiwane inaczej. Czasami dane wyjściowe ciągu są przekazywane przez formatowanie, ale nie zawsze. Write-Host tworzy natychmiastowy zapis w procesie hosta. Write-Object jest wysyłany za pośrednictwem systemu formatowania. Połączenie danych wyjściowych złożonych obiektów z zapisami na hoście utrudnia przewidywanie, co jest rejestrowane w transkrypcji.

Scenariusz 1 — dane wyjściowe obiektu strukturalnego na końcu wszystkich pozostałych operacji

Rozważmy następujący skrypt i jego dane wyjściowe:

PS> Get-Content scenario1.ps1
Start-Transcript scenario1.log -UseMinimalHeader
Write-Host '1'
Write-Output '2'
Get-Location
Write-Host '4'
Write-Output '5'
Stop-Transcript

PS> ./scenario1.ps1
Transcript started, output file is scenario1.log
1
2

4
Path
----
/Users/user1/src/projects/transcript
5
Transcript stopped, output file is /Users/user1/src/projects/transcript/scenario1.log

Dane wyjściowe w konsoli zawierają oczekiwane dane wyjściowe, ale nie w oczekiwanej kolejności. Write-Host 4 jest widoczny przed Get-Location , ponieważ Write-Host jest zoptymalizowany pod kątem zapisywania bezpośrednio na hoście. Istnieje kod w transkrypcji, który kopiuje dane wyjściowe do pliku transkrypcji i konsoli. Następnie mamy regularne dane wyjściowe i Write-Output 5 są wysyłane jako dane wyjściowe Get-Location skryptu.

PS> Get-Content scenario1.log
**********************
PowerShell transcript start
Start time: 20191106114858
**********************
Transcript started, output file is s2
1
2

4
**********************
PowerShell transcript end
End time: 20191106114858
**********************

Ponieważ transkrypcja jest wyłączona przed zamknięciem skryptu, nie jest renderowana w transkrypcji. Obiekty zostały wysłane do następnego konsumenta w potoku. W takim przypadku jest to Out-Default, który program PowerShell wstawił automatycznie. Aby jeszcze bardziej skomplikować kwestie, dane wyjściowe ciągów są również zoptymalizowane w systemie formatowania. Pierwszy Write-Output 2 jest emitowany i przechwytywany przez transkrypcję. Jednak wstawianie Get-Location obiektu powoduje wypchnięcie jego danych wyjściowych do stosu elementów, które wymagają rzeczywistego formatowania, co ustawia trochę stanu dla pozostałych obiektów, które również mogą wymagać formatowania. Dlatego drugi Write-Output 5 nie jest dodawany do transkrypcji.

Scenariusz 2 — przenoszenie emisji obiektu na początek

Rozważmy następujący skrypt i jego dane wyjściowe:

PS> Get-Content scenario2.ps1
Start-Transcript scenario2.log -UseMinimalHeader
Get-Location
Write-Host '1'
Write-Output '2'
Get-Location
Write-Host '4'
Write-Output '5'
Stop-Transcript

PS> ./scenario2.ps1
Transcript started, output file is scenario2.log

1
4
Path
----
/Users/user1/src/projects/transcript
2
5
Transcript stopped, output file is /Users/user1/src/projects/transcript/scenario2.log

Widzimy, że Write-Host polecenia są wykonywane przed czymkolwiek, a następnie obiekty zaczynają wychodzić. Ciąg Write-Output wymusza renderowanie obiektu na ekranie, ale zwróć uwagę, że transkrypcja zawiera tylko dane wyjściowe elementu Write-Host. Dzieje się tak, ponieważ te obiekty ciągów są przesyłane potokami do Out-Default formatowania po wyłączeniu transkrypcji skryptu.

PS> Get-Content scenario2.log
**********************
PowerShell transcript start
Start time: 20220606094609
**********************
Transcript started, output file is s3

1
4
**********************
PowerShell transcript end
End time: 20220606094609
**********************

Scenariusz 3 — obiekt emitowany na końcu skryptu

W tym scenariuszu dane wyjściowe złożonego obiektu są na końcu skryptu.

PS> Get-Content scenario3.ps1
Start-Transcript scenario3.log -UseMinimalHeader
Write-Host '1'
Write-Output '2'
Write-Host '4'
Write-Output '5'
Get-Location
Stop-Transcript

PS> ./scenario3.ps1
Transcript started, output file is scenario3.log
1
2
4
5

Path
----
/Users/user1/src/projects/transcript
Transcript stopped, output file is /Users/user1/src/projects/transcript/scenario3.log

Dane wyjściowe ciągu z obu elementów Write-Host i Write-Object sprawiają, że są w transkrypcji. Jednak dane wyjściowe z Get-Location tych danych występują po zatrzymaniu transkrypcji.

**********************
PowerShell transcript start
Start time: 20220606100342
**********************
Transcript started, output file is scenario3.log
1
2
4
5

**********************
PowerShell transcript end
End time: 20220606100342
**********************

Sposób zapewnienia pełnej transkrypcji

Ten przykład jest niewielką odmianą oryginalnego scenariusza, ale teraz wszystko jest rejestrowane w transkrypcji. Oryginalny kod jest opakowany w blok skryptu, a formater jawnie wywoływany za pomocą metody Out-Default.

PS> Get-Content scenario4.ps1
Start-Transcript scenario4.log -UseMinimalHeader
. {
    Write-Host '1'
    Write-Output '2'
    Get-Location
    Write-Host '4'
    Write-Output '5'
} | Out-Default
Stop-Transcript

PS> ./scenario4.ps1
Transcript started, output file is scenario4.log
1
2

4
Path
----
/Users/user1/src/projects/transcript
5

Transcript stopped, output file is /Users/user1/src/projects/transcript/scenario4.log

Zwróć uwagę, że ostatnie Write-Host wywołanie jest nadal poza kolejnością, wynika to z optymalizacji, która Write-Host nie przechodzi do strumienia wyjściowego.

PS> Get-Content scenario4.log
**********************
PowerShell transcript start
Start time: 20220606101038
**********************
Transcript started, output file is s5
1
2

4
Path
----
/Users/user1/src/projects/transcript
5

**********************
PowerShell transcript end
End time: 20220606101038
**********************