如何 运行 具有详细输出的 PowerShell 脚本?

How to run a PowerShell script with verbose output?

我想知道是否有办法 运行 PowerShell 脚本,以便打印命令和脚本每一行的输出。例如,在 Bash 中,您可以在脚本顶部编写 bash -x myscript 或放置 set -x。在 Batch 中,您将省略传统上留在脚本顶部的 @echo off。 PowerShell 是否具有这些构造的等效项?

我尝试过的方法: 运行 powershell -? | sls verbose,但没有任何结果。

如果您在脚本中使用 write-verbose,这将自动发生,

但是,如果您需要手动编写函数的详细输出,则需要手动检查是否使用详细标志调用了每个函数。这可以通过 checking$PSCmdlet.MyInvocation.BoundParameters["Verbose"] 从你的函数内部。

您始终可以在脚本中使用以下内容。

$VerbosePreference="Continue"

注意:您必须在提升模式下打开shell

以下截图供参考。

希望对您有所帮助。

这实际上非常简单,每个 PowerShell CMDLET 都有一个内置的 Verbose 标记。例如:

Test-Connection -ComputerName www.google.com -Verbose

就是这样。希望对您有所帮助

只是为了表明,@JamesKo,如果你问错了问题,你会得到错误的答案:-(。有几个人在这里基于 (a) 缺乏 Linux 曝光率提出了善意的答案和 (b) 您对术语 verbose 的使用。在下文中,我将向您介绍 Linux 如何与 PowerShell 在此主题上相关,但请随时跳转到答案最后,如果你赶时间的话。:-)

背景

在 PowerShell 中,verbose 具有非常具体的含义,PowerShell man page 对此甚至相当模糊:

Displays detailed information about the operation performed by the command. This information resembles the information in a trace or in a transaction log. This parameter works only when the command generates a verbose message.

它甚至听起来像您想要的...但让我们将其与 set -x 的 Linux 文档进行比较,根据您对 Linux 的喜好,它可能是这样的(来自 man-pages project)...

The shell shall write to standard error a trace for each command after it expands the command and before it executes it.

或这个(来自gnu)...

Print a trace of simple commands, for commands, case commands, select commands, and arithmetic for commands and their arguments or associated word lists after they are expanded and before they are executed.

你问题的第一行清楚而简洁地同意这些。但是 PowerShell 中的冗长是不同的。简而言之,打开详细模式(使用 -Verbose 命令行开关或 $VerbosePreference 变量)只是启用从详细流到控制台的输出。 (就像 Linux 提供两个流,stdout 和 stderr,PowerShell 提供多个流:输出流、错误流、警告流、详细流和调试流。您使用这些流的方式与 Linux--例如,您甚至可以使用 commands 4>&1 将详细流合并到标准输出。(您可以在 [=28= 的基本写入流部分阅读更多关于 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 的痕迹。它打印带有 DEBUG 前缀的命令、赋值等,与实际输出混合在一起,在本例中是仅包含 0.

的单行

为了让 PowerShell 脚本能够从 arguments/command 行接收参数,需要添加 [CmdletBinding()] param () 即使没有任何参数。

示例脚本:测试输出。ps1

[CmdletBinding()] param ()
Write-Host "Test output on OS $($Env:OS)"
Write-Verbose "Test VERBOSE output on OS $($Env:OS)"
  1. 在 PowerShell 中执行脚本:
PS C:\> .\Test-Output.ps1 -Verbose
  1. 在 Linux:
  2. 上在 PowerShell 中执行脚本
/$ pwsh
PS /> ./Test-Output.ps1 -Verbose
  1. 在 Windows 上使用 PowerShell.exe 执行脚本:
C:\> powershell.exe Test-Output.ps1 -Verbose
  1. 在 Windows:
  2. 上使用 pwsh.exe PowerShell Core 执行脚本
C:\> pwsh.exe Test-Output.ps1 -Verbose
  1. 在 Linux:
  2. 上使用 pwsh PowerShell Core 执行脚本
/$ 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 

注意:此答案最初是为了回应 Windows Powershell needs to print out information for a particular command regardless of whether it successfully executed or Not 上的重复问题而发布的。

补充和阐述

有限制,您可以使用Set-PSDebug -Trace 1让PowerShell在脚本语句执行前为您回显;然而,这更像是 bashset -o verbose / set -v 选项而不是 set -o xtrace / set -x,因为回显的命令是 未展开;详情如下:

# 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 开始,使用续行跨越多行的命令只会回显它们的 first 行(请参阅 GitHub issue #8113)。

  • 也许最重要的是,被回显的语句是它们的文字源代码表示因此可以包含未展开的变量引用和表达式,例如上例中的$HOME

    • GitHub issue #9463 建议 扩展 值(即,变量和表达式 替换为它们的值 ),如你所见例如 bash 中的 set -x
    • 虽然这对于调用 外部程序 是可行的 - 其参数总是 strings 无论如何,挑战在于调用 PowerShell 命令 支持任意 .NET 类型的参数,并非所有类型都具有忠实的 字符串文字表示;也就是说,即使是仅针对人类眼球的字符串表示也可以说比 未扩展的 值更可取。

如果需要查看expanded参数值and/or控制输出格式/目标:

注:

  • 虽然,由于其固有的安全风险,并且通常有更好、更安全的选择,它确实在这里提供了一个解决方案——一如既往,请确保您完全控制传递给 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>"@) 用于简化字符串内部引用。

    • 选择 可扩展 形式以确保可执行路径和所有参数都预先扩展 并因此嵌入为它们的 结果字符串中的文字值,因此回显字符串将显示所有实际值。
  • &call operator,用于调用msbuild,这在语法上是必要的,因为它的路径是通过引用的,如果 $msbuild 包含带空格的路径 ,这又是必需的

输出看起来像这样:

VERBOSE: Executing: & "C:\Program Files (x86)\Microsoft Visual Studio19\BuildTools\MSBuild\Current\Bin" .\blabBlah.csproj /t:Clean
# ... (output)

VERBOSE: Executing: & "C:\Program Files (x86)\Microsoft Visual Studio19\BuildTools\MSBuild\Current\Bin" .\blabBlah.csproj /t:Build /p:Configuration=Dev
# ... (output)