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 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 Out-Defaultelement . Jednak formatowanie może wystąpić po zakończeniu działania skryptu i zatrzymaniu transkrypcji. Oznacza to, że dane wyjściowe nie są transkrypowane. 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 ustrukturyzowanego na końcu wszystkich innych 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 Get-Location i Write-Output 5 wysyłane jako dane wyjściowe 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 zakończeniem działania skryptu, nie jest renderowana w transkrypcji. Obiekty zostały wysłane do następnego konsumenta w potoku. W tym przypadku jest to Out-Defaultpolecenie , które 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 wstawienie Get-Location obiektu powoduje wypchnięcie jego danych wyjściowych do stosu elementów, które wymagają rzeczywistego formatowania, co ustawia bit stanu dla pozostałych obiektów, które również mogą wymagać formatowania. Dlatego drugi Write-Output 5 nie zostanie dodany 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 wszystkimi elementami, a następnie zaczynają wychodzić obiekty. Ciąg Write-Output wymusza renderowanie obiektu na ekranie, ale zwróć uwagę, że transkrypcja zawiera tylko dane wyjściowe .Write-Host Dzieje się tak, ponieważ te obiekty ciągów są przesyłane potokiem 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 obiektu złożonego 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 Write-Host elementów i Write-Object sprawiają, że są wprowadzane do transkrypcji. Jednak dane wyjściowe z Get-Location wystąpią 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 nieznaczną odmianą oryginalnego scenariusza, ale teraz wszystko jest rejestrowane w transkrypcji. Oryginalny kod jest opakowany w blok skryptu, a formater jawnie wywoływany za pośrednictwem 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ą, co wynika z optymalizacji, Write-Host która 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
**********************