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 fungováním přepisu s kanály PowerShellu je malá interakce, která může mít neočekávané výsledky.

Při generování objektů ze skriptu formátování těchto objektů je zpracována 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í odlišně. Výstup řetězce se někdy předává prostřednictvím formátování, ale ne vždy. Write-Host vytvoří okamžitý zápis do hostitelského procesu. Write-Object se odesílá prostřednictvím systému formátování. Kombinací výstupu složitých objektů s zápisy do hostitele je obtížné předpovědět, co se zaprotokoluje v přepisu.

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 zobrazí očekávaný výstup, ale ne v pořadí, v 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
**********************

Vzhledem k tomu, ž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ě se Out-Defaultjedná o powershell, který se automaticky vloží. Aby se věci dále komplikovaly, výstup řetězců je také optimalizovaný v systému formátování. Write-Output 2 První 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í určitý stav pro všechny zbývající objekty, které můžou také potřebovat formátování. To je důvod, proč se druhý Write-Output 5 nepřidá do přepisu.

Scénář 2 – Přesunutí emisí objektů 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 Je to proto, že tyto objekty řetězců 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-Host a Write-Object převede ho do přepisu. K výstupu Get-Location dojde však 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ým rozdílem v původním scénáři, ale teď se všechno zaprotokoluje do přepisu. Původní kód je zabalen do bloku skriptu a formátovací modul explicitně vyvolá pomocí 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í, je to kvůli optimalizaci, Write-Host která 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
**********************