如何使用详细输出运行PowerShell脚本?

Jam*_* Ko 17 windows shell powershell windows-10

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

我尝试过的事情:跑步powershell -? | sls verbose,没有任何结果.

Mic*_*ens 27

只是去表示@JamesKo,如果你提出错误的问题就会得到错误的答案:-(.有几个人基于(a)缺乏Linux曝光和(b)你对这个术语的使用提出了真诚的答案冗长.下面我将带你的Linux通过如何与PowerShell的这个话题,但随时结束时,如果你是在急于跳到答案.:-)

背景

在PowerShell中,verbose具有非常特定的含义,PowerShell手册页甚至含糊不清:

显示有关命令执行的操作的详细信息.此信息类似于跟踪或事务日志中的信息.仅当命令生成详细消息时,此参数才有效.

它甚至听起来像你想要的......但是让我们将它与Linux文档进行比较set -x,根据你的Linux风格,这可能是这个(来自man-pages项目)......

在扩展命令之后和执行命令之前,shell应为每个命令写入标准错误跟踪.

或者这(来自gnu)......

在命令,大小写命令,选择命令,命令及其参数或相关单词列表在扩展之后和执行之前,打印一系列简单命令.

你问题的第一行清楚而简明地同意这些.但PowerShell中的冗长是不同的.简而言之,打开详细模式(使用-Verbose命令行开关或$VerbosePreference变量)只需启用从详细流到控制台的输出.(就像Linux提供两个流,stdout和stderr一样,PowerShell提供了多个流:输出流,错误流,警告流,详细流和调试流.您可以使用与Linux相同的方式处理这些流 - 您可以例如,甚至可以使用例如commands 4>&1将详细信息流合并到stdout.(您可以在PowerShell One-Liners的基本写入流部分中阅读有关PowerShell的多个输出流的更多信息:访问,处理和编写数据,以及一个很好的快速参考是在完全指南PowerShell的标点符号).

答案

设置-PSDebug命令会给你的bash等效跟踪.您甚至可以使用-Trace参数调整跟踪详细信息.首先,这是控件,在使用之前Set-PSDebug:

PS> Get-PSDepth
0
Run Code Online (Sandbox Code Playgroud)

值为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+  >>>> }
Run Code Online (Sandbox Code Playgroud)

值为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+  >>>> }
Run Code Online (Sandbox Code Playgroud)

这些是我写的一个简单的cmdlet的痕迹Get-PSDepth.它打印带有DEBUG前缀的命令,赋值等,与实际输出混合在一起,在本例中是包含just的单行0.


Ran*_*tta 17

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

$ VerbosePreference = "继续"

注意:您必须以提升模式打开shell .

下面的截图仅供参考.

$ VerbosePreference

希望能帮助到你.

  • 尽管OP使用术语“详细”,但他们真正的意思是“执行跟踪”。但是,最好了解 [首选项变量 `$VerbosePreference`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Preference_Variables#verbosepreference) 变量关于详细输出_内置到目标命令中_,但请注意,设置它_不需要海拔。此外,还不清楚屏幕截图中的“Get-Date”如何产生所示的详细输出。 (2认同)

小智 12

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

示例脚本:Test-Output.ps1

[CmdletBinding()] param ()
Write-Host "Test output on OS $($Env:OS)"
Write-Verbose "Test VERBOSE output on OS $($Env:OS)"
Run Code Online (Sandbox Code Playgroud)
  1. 在 PowerShell 中执行脚本:
PS C:\> .\Test-Output.ps1 -Verbose
Run Code Online (Sandbox Code Playgroud)
  1. 在 Linux 上的 PowerShell 中执行脚本:
/$ pwsh
PS /> ./Test-Output.ps1 -Verbose
Run Code Online (Sandbox Code Playgroud)
  1. 在 Windows 上使用 PowerShell.exe 执行脚本:
C:\> powershell.exe Test-Output.ps1 -Verbose
Run Code Online (Sandbox Code Playgroud)
  1. 在 Windows 上使用 pwsh.exe PowerShell Core 执行脚本:
C:\> pwsh.exe Test-Output.ps1 -Verbose
Run Code Online (Sandbox Code Playgroud)
  1. 在 Linux 上使用 pwsh PowerShell Core 执行脚本:
/$ pwsh Test-Output.ps1 -Verbose
Run Code Online (Sandbox Code Playgroud)

Windows 上的示例输出:

Test output on OS Windows_NT
VERBOSE: Test VERBOSE output on OS Windows_NT
Run Code Online (Sandbox Code Playgroud)

Linux 上的示例输出:

Test output on OS 
VERBOSE: Test VERBOSE output on OS 
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 6

注意:此答案最初是为了响应Windows Powershell need to print out information for a certain command without无论其是否成功执行的重复问题而发布的。

补充和详细阐述迈克尔索伦斯的有用答案

在有限制的情况下,您可以使用PowerShell 在执行脚本语句之前为您回显它们Set-PSDebug -Trace 1;然而,这更像是/bash选项set -o verboseset -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.
}
Run Code Online (Sandbox Code Playgroud)

上面的结果是:

DEBUG:    4+  >>>> cmd /c echo 'hi there' $HOME
"hi there" C:\Users\jdoe
DEBUG:    6+  >>>> Set-PSDebug -Trace 0 # Turn tracing off.
Run Code Online (Sandbox Code Playgroud)

虽然这种方法几乎不需要额外的努力,但其局限性是:

  • 您无法控制跟踪语句的前缀。(例如DEBUG: 4+ >>>> ,其中4是行号。

  • 关闭跟踪也总是会产生一个跟踪语句。

  • 无法捕获或抑制跟踪输出 - 它总是打印到主机(控制台);但是,您可以通过 PowerShell 的 CLI 从 PowerShell外部捕获它 - 请参阅此答案

  • 从 PowerShell 7.2 开始,使用续行跨越多行的命令仅回显第一行(请参阅GitHub 问题 #8113)。

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

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

如果您需要查看扩展参数值和/或控制输出格式/目标

笔记:

  • 虽然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

}
Run Code Online (Sandbox Code Playgroud)

现在您可以构建命令行字符串并将它们传递给辅助函数:

Invoke-AfterEchoing @"
& "$msbuild" .\blabBlah.csproj /t:Clean
"@


Invoke-AfterEchoing @"
& "$msbuild" .\blabBlah.csproj /t:Build /p:Configuration=Dev
"@
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 可扩展的此处字符串( @"<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)
Run Code Online (Sandbox Code Playgroud)