如何飞溅一个哈希表写输出进行调试



使用powershell,我想打印散列表的结果。这是我想出的一个例子(但Write-Output并没有像我预期的那样工作(:

$SomePath = "C:testpath"
$params = @{
p = "$SomePath"
r = "Foo"
a = "Bar"
}
$destinationDir = ''
if (![string]::IsNullOrEmpty($destinationDir)) {
$params['b'] = $destinationDir
}
Write-Output "Params: @params"

Write-Output的结果是:

参数:@Params

有没有一种方法可以打印此命令的扩展以进行调试?我还想最终存储扩展的调用,以便稍后从变量中调用,如下所示(我认为它会起作用(:

$cmd = "MyProgram.exe @params"
& "$cmd"

但如果这是一个全新的蠕虫,我很高兴在我的初始示例中只使用Write-Output

这是我的powershell版本:

PS C:> $PSVersionTable.PSVersion
Major  Minor  Patch  PreReleaseLabel BuildLabel
-----  -----  -----  --------------- ----------
7      0      3

如果您想观察飞溅对当前shell中Win32 PE的影响,我建议使用Add-Type编译一个简单的调试实用程序:

$sourceCode = @'
using System;
using System.Management;
using System.Diagnostics;
public class Program
{
public static void Main(string[] args)
{
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + Process.GetCurrentProcess().Id))
using (ManagementObjectCollection procs = searcher.Get())
{
foreach (ManagementBaseObject process in procs)
{
Console.WriteLine(process["CommandLine"].ToString());
}
}
}
}
'@
Add-Type -TypeDefinition $sourceCode -OutputType ConsoleApplication -OutputAssembly ~printCmdline.exe

生成的可执行文件将打印其自身进程的命令行参数,这正是我们需要看到的。


现在我们有了一个可执行文件来测试,让我们看看会发生什么:

$SomePath = "C:testpath"
$params = @{
p = "$SomePath"
r = "Foo"
a = "Bar"
}
~printCmdline.exe @params

应该打印以下内容:

"C:Usersvoid.pointerprintCmdline.exe" -r:Foo -p:C:testpath -a:Bar

注意:Splatting只能与PowerShell命令可靠地工作,因为PowerShell将其转换为外部程序的方式(如Mathias的回答所示(不是大多数外部程序都能理解的格式。

正如Mathias在对该问题的评论中指出的那样,您无法直接将splating调用的等价项表示为单个参数
但是,您可以使用Trace-Commandcmdlet跟踪参数绑定如果您有一个命令(由下面的$yourCommand表示(,它实际上接受哈希表中指定的参数:

Trace-Command -pshost -name ParameterBinding { & $yourCommand @params }

注意:Trace-Command的输出是冗长的、技术性的;解读它需要一些练习。


考虑到PowerShell基于对象的特性,在所有情况下都不可能实现在命令行字符串中捕获等效的基于飞溅的调用:并非所有对象都可以忠实地表示为

也就是说,如果您知道传递的参数仅限于字符串数字开关,则可以执行以下操作:

# Sample hashtable used for splatting, limited to strings, numbers, switches.
$somePath = 'C:testpath'
$params = [ordered] @{
Path = "$SomePath" # string
Count = 42         # number
Skip = $True       # [switch] parameter, expressed as a [bool] value in splatting
}
# Translate the hashtable into an equivalent command-line string.
$params.GetEnumerator().ForEach({
$val = $_.Value
if ($val -is [string]) { $val = "'{0}'" -f $val.Replace("'", "''") }
'-{0}:{1}' -f $_.Key, $val
}) -join ' '

上面产生了一个包含以下内容的字符串:

-Path:'C:testpath' -Count:42 -Skip:True 

将命令名预处理为以上结果的字符串将为完整命令提供字符串表示。

例如,该字符串表示可以保存到脚本文件中。

如果要直接执行包含命令行的字符串,则必须使用Invoke-Expression,因为调用运算符&不会在整个命令行上操作,而只能在通过变量、带引号的字符串或表达式指定的命令的名称/路径上操作。

关于Invoke-Expression的强制性警告:

Invoke-Expression由于其固有的安全风险,通常应避免,并仅作为的最后手段使用。简言之:如果可能的话,尽量避免,因为通常有更好的替代品。如果真的没有其他选择,只能在您自己提供或完全信任的输入中使用它-请参阅此答案。

通常,如果可能的话,使用PowerShell自己的完全对象感知的方式来定义稍后需要执行的代码片段,即脚本块({ ... }(

最新更新