Omezení přepisů PowerShellu

Kombinování Write-Host výstupu s výstupními objekty, řetězci a přepisem PowerShellu je složité. Mezi skriptem a tím, jak přepis funguje s kanály PowerShellu, je malá interakce, která může mít neočekávané výsledky.

Při generování objektů ze skriptu je formátování těchto objektů zpracováno Out-Default. Formátování ale může nastat po dokončení skriptu a zastavení přepisu. To znamená, že výstup se nepřepíše. Řetězce se zpracovávají jinak. Někdy se výstup řetězce předává formátováním, ale ne vždy. Write-Host provede okamžitý zápis do hostitelského procesu. Write-Object se odesílá prostřednictvím systému formátování. Kombinace výstupu složitých objektů s zápisy do hostitele znesnadňuje predikci toho, co se do přepisu zaprotokoluje.

Scénář 1 – výstup strukturovaného objektu na konci všech ostatních operací

Zvažte následující skript a jeho výstup:

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

Výstup konzoly zobrazuje očekávaný výstup, ale ne v pořadí, ve jakém ho očekáváte. Write-Host 4 je viditelný dříve Get-Location , protože Write-Host je optimalizovaný pro zápis přímo do hostitele. V přepisu je kód, který zkopíruje výstup do souboru přepisu a konzoly. Pak máme běžný výstup Get-Location a Write-Output 5 odešleme ho jako výstup skriptu.

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
**********************

Protože se přepis vypne před ukončením skriptu, nevykreslí se v přepisu. Objekty byly odeslány dalšímu příjemci v kanálu. V tomto případě je Out-Defaultto , který PowerShell vložili automaticky. Aby se věci dále komplikovaly, výstup řetězců je také optimalizovaný v systému formátování. První Write-Output 2 se vygeneruje a zachytí přepisem. Vložení objektu Get-Location ale způsobí, že se jeho výstup vloží do zásobníku věcí, které potřebují skutečné formátování, což nastaví trochu stavu pro všechny zbývající objekty, které můžou také potřebovat formátování. Proto se druhý Write-Output 5 do přepisu nepřidá.

Scénář 2 – Přesunutí emise objektu na začátek

Zvažte následující skript a jeho výstup:

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

Vidíme, že Write-Host příkazy probíhají před čímkoli a pak se objekty začnou vycházet. Řetězec Write-Output vynutí vykreslení objektu na obrazovku, ale všimněte si, že přepis obsahuje pouze výstup .Write-Host Důvodem je to, že tyto řetězcové objekty se předávají Out-Default pro formátování po vypnutí přepisu skriptu.

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
**********************

Scénář 3 – Objekt vygenerovaný na konci skriptu

V tomto scénáři je výstup komplexního objektu na konci skriptu.

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

Výstup řetězce z obou Write-HostWrite-Object a vytvoří ho do přepisu. Výstup se Get-Location však vyskytuje po zastavení přepisu.

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

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

Způsob, jak zajistit úplný přepis

Tento příklad je mírné variace původního scénáře, ale teď se všechno zaprotokoluje do přepisu. Původní kód je zabalen do bloku skriptu a formátovač explicitně vyvolán prostřednictvím 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

Všimněte si, že poslední Write-Host volání je stále mimo pořadí, důvodem je optimalizace v Write-Host tom, že se nepřechází do výstupního datového proudu.

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
**********************