[英]How to run a PowerShell script with verbose output?
我想知道是否有辦法運行 PowerShell 腳本,以便打印腳本每一行的命令和輸出。 例如,在 Bash 中,您可以編寫bash -x myscript
或在腳本頂部放置一個set -x
。 在 Batch 中,您可以省略傳統上留在腳本頂部的@echo off
。 PowerShell 是否具有與這些結構等效的結構?
我嘗試過的事情:運行powershell -? | sls verbose
powershell -? | sls verbose
powershell -? | sls verbose
,結果什么也沒有。
只是去表示@JamesKo,如果你提出錯誤的問題就會得到錯誤的答案:-(。有幾個人基於(a)缺乏Linux曝光和(b)你對這個術語的使用提出了真誠的答案詳細說明 。下面我將向您介紹Linux如何在這個主題上與PowerShell相關,但如果您趕時間,請隨時跳到答案。:-)
背景
在PowerShell中,verbose具有非常特定的含義, PowerShell手冊頁甚至含糊不清:
顯示有關命令執行的操作的詳細信息。 此信息類似於跟蹤或事務日志中的信息。 僅當命令生成詳細消息時,此參數才有效。
它甚至聽起來像你想要的......但是讓我們將它與set -x
的Linux文檔進行比較,這取決於你的Linux風格,可能是這個(來自man-pages項目 )......
在擴展命令之后和執行命令之前,shell應為每個命令寫入標准錯誤跟蹤。
或者這(來自gnu )......
在命令,大小寫命令,選擇命令,命令及其參數或相關單詞列表在擴展之后和執行之前,打印一系列簡單命令。
你問題的第一行清楚而簡明地同意這些。 但PowerShell中的冗長是不同的。 簡而言之,打開詳細模式(使用-Verbose
命令行開關或$VerbosePreference
變量)只需啟用從詳細流到控制台的輸出。 (就像Linux提供兩個流,stdout和stderr一樣,PowerShell提供了多個流:輸出流,錯誤流,警告流,詳細流和調試流。您可以使用與Linux相同的方式處理這些流 - 您可以例如,甚至可以使用commands 4>&1
將詳細流合並到stdout。(您可以在PowerShell One-Liners的Basic Writing Streams部分中閱讀有關PowerShell多個輸出流的更多信息:訪問,處理和寫入數據以及快速參考是PowerShell標點符號的完整指南 。)
答案
Set-PSDebug命令將為您提供bash等效跟蹤。 您甚至可以使用-Trace
參數調整跟蹤詳細信息。 首先,這是控件,在使用Set-PSDebug
之前:
PS> Get-PSDepth
0
值為1時,您會在執行時獲得每行代碼,例如:
PS> Set-PSDebug -Trace 1
PS> Get-PSDepth
DEBUG: 1+ >>>> Get-PSDepth
DEBUG: 141+ >>>> {
DEBUG: 142+ >>>> $nest = -1
DEBUG: 143+ >>>> $thisId = $pid
DEBUG: 144+ while ( >>>> (ps -id $thisId).Name -eq 'powershell') {
DEBUG: 145+ >>>> $thisId = (gwmi win32_process -Filter "processid='$thisId'").ParentProcessId
DEBUG: 146+ >>>> $nest++
DEBUG: 144+ while ( >>>> (ps -id $thisId).Name -eq 'powershell') {
DEBUG: 148+ >>>> $nest
0
DEBUG: 149+ >>>> }
值為2時,您還可以獲得變量賦值和代碼路徑:
PS> Set-PSDebug -Trace 2
PS> Get-PSDepth
DEBUG: 1+ >>>> Get-PSDepth
DEBUG: ! CALL function '<ScriptBlock>'
DEBUG: 141+ >>>> {
DEBUG: ! CALL function 'Get-PSDepth' (defined in file 'C:\Users\msorens\Documents\WindowsPowerShell\profile.ps1')
DEBUG: 142+ >>>> $nest = -1
DEBUG: ! SET $nest = '-1'.
DEBUG: 143+ >>>> $thisId = $pid
DEBUG: ! SET $thisId = '9872'.
DEBUG: 144+ while ( >>>> (ps -id $thisId).Name -eq 'powershell') {
DEBUG: 145+ >>>> $thisId = (gwmi win32_process -Filter "processid='$thisId'").ParentProcessId
DEBUG: ! SET $thisId = '10548'.
DEBUG: 146+ >>>> $nest++
DEBUG: ! SET $nest = '0'.
DEBUG: 144+ while ( >>>> (ps -id $thisId).Name -eq 'powershell') {
DEBUG: 148+ >>>> $nest
0
DEBUG: 149+ >>>> }
這些是我寫的一個名為Get-PSDepth
的簡單cmdlet Get-PSDepth
。 它使用DEBUG
前綴打印命令,賦值等,並與實際輸出混合,在這種情況下,實際輸出是僅包含0
的單行。
這實際上非常簡單,每個PowerShell CMDLET都有一個內置的詳細標記。 所有你需要做的例如:
Test-Connection -ComputerName www.google.com -Verbose
這就對了。 我希望這有幫助
為了讓 PowerShell 腳本能夠從參數/命令行接收參數,即使沒有任何參數,也需要添加[CmdletBinding()] param ()
。
示例腳本:Test-Output.ps1
[CmdletBinding()] param ()
Write-Host "Test output on OS $($Env:OS)"
Write-Verbose "Test VERBOSE output on OS $($Env:OS)"
PS C:\> .\Test-Output.ps1 -Verbose
/$ pwsh
PS /> ./Test-Output.ps1 -Verbose
C:\> powershell.exe Test-Output.ps1 -Verbose
C:\> pwsh.exe Test-Output.ps1 -Verbose
/$ pwsh Test-Output.ps1 -Verbose
Windows 上的示例輸出:
Test output on OS Windows_NT
VERBOSE: Test VERBOSE output on OS Windows_NT
Linux 上的示例輸出:
Test output on OS
VERBOSE: Test VERBOSE output on OS
如果你在腳本中使用write-verbose,這將自動發生,
但是,如果需要手動編寫函數的詳細輸出,則需要手動檢查是否使用詳細標記調用每個函數。 這可以通過從函數內部檢查$ PSCmdlet.MyInvocation.BoundParameters [“Verbose”]來完成。
注意:此答案最初是針對Windows Powershell 中的重復問題而發布的,需要打印特定命令的信息,無論它是否成功執行。
補充和詳細說明邁克爾索倫斯的有用答案:
有限制,您可以使用Set-PSDebug
-Trace 1
讓 PowerShell 在腳本語句執行之前為您回顯:
# Start tracing statements.
Set-PSDebug -Trace 1
try
{
# Sample command
cmd /c echo 'hi there' $HOME
}
finally {
Set-PSDebug -Trace 0 # Turn tracing back off.
}
以上產生:
DEBUG: 4+ >>>> cmd /c echo 'hi there' $HOME
"hi there" C:\Users\jdoe
DEBUG: 6+ >>>> Set-PSDebug -Trace 0 # Turn tracing off.
雖然這種方法幾乎不需要額外的努力,但它的局限性是:
您無法控制跟蹤語句的前綴。 (例如DEBUG: 4+ >>>>
,其中4
是行號。
關閉跟蹤總是會產生一個跟蹤語句。
無法捕獲或抑制跟蹤輸出 - 它總是打印到主機(控制台); 但是,您可以通過 PowerShell 的 CLI 從 PowerShell外部捕獲它 - 請參閱此答案。
從 PowerShell 7.2 開始,使用換行符跨越多行的命令只會回顯它們的第一行(請參閱GitHub 問題 #8113 )。
也許最重要的是,被回顯的語句是它們的字面源代碼表示,因此可以包含未擴展的變量引用和表達式,例如上面示例中的$HOME
。
bash
使用set -x
獲得的值。如果您需要查看擴展參數值和/或控制輸出格式/目標:
筆記:
雖然Invoke-Expression
( iex
) 通常應該避免,但由於其固有的安全風險,並且因為通常有更好、更安全的選項可用,它確實在這里提供了一個解決方案 - 與往常一樣,請確保您完全控制進入傳遞的字符串的內容到Invoke-Expression
,以避免可能注入不需要的命令。
該解決方案需要你構建字符串傳遞給Invoke-Expression
用的前期膨脹(串內插),使得所得到的命令行中,當被執行時,只包含文字形參,使得呼應命令行描繪的全貌什么可執行文件被調用以及它的參數是什么。
msbuild
)時才有可能實現。 首先,定義一個輔助函數,它接受一個命令行字符串,回顯它,然后通過Invoke-Expression
執行它:
# !! IMPORTANT:
# !! Only pass *trusted* strings to this function - the
# !! argument is blindly passed to Invoke-Expression.
function Invoke-AfterEchoing {
param([string] $commandLine)
# Echo the command line to be executed,
# using the verbose output stream in this example:
Write-Verbose -Verbose "Executing: $commandLine"
Invoke-Expression $commandLine
}
現在您可以構建命令行字符串並將它們傳遞給輔助函數:
Invoke-AfterEchoing @"
& "$msbuild" .\blabBlah.csproj /t:Clean
"@
Invoke-AfterEchoing @"
& "$msbuild" .\blabBlah.csproj /t:Build /p:Configuration=Dev
"@
筆記:
可擴展的here-string ( @"<newline>...<newline>"@
) 用於簡化字符串內部引用。
&
, 調用運算符,用於調用msbuild
,這在語法上是必要的,因為它的路徑被引用了,如果$msbuild
包含一個帶有空格的路徑,這又是必要的。
輸出將如下所示:
VERBOSE: Executing: & "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin" .\blabBlah.csproj /t:Clean
# ... (output)
VERBOSE: Executing: & "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin" .\blabBlah.csproj /t:Build /p:Configuration=Dev
# ... (output)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.