powershell - 如何在 PowerShell 脚本中写出或跟踪特定命令?
问题描述
在我正在创建的 PowerShell 脚本中,我想输出带有正在传递的参数值的特定命令。输出可以转到日志文件和/或控制台输出。以下将向控制台输出我想要的内容,但我必须复制感兴趣的脚本行,并且在某些时候会在命令不匹配的地方出现细微的错误。我试过了Set-PSDebug
,Trace-Command
但都没有给出我想要的结果。我曾考虑将脚本行放入字符串中,将其写出来,然后调用,Invoke-Expression
但我会放弃自动完成/智能感知。
用于编写和执行的重复行示例:
Write-Output "New-AzureRmResourceGroup -Name $rgFullName -Location $location -Tag $tags -Force"
New-AzureRmResourceGroup -Name $rgFullName -Location $location -Tag $tags -Force
带有扩展变量的输出结果。$tags 没有扩展到实际的哈希表值:
New-AzureRmResourceGroup -Name StorageAccounts -Location West US -Tag System.Collections.Hashtable -Force
我可以使用哪些其他选项或命令行开关来实现跟踪,而无需编写重复的代码,甚至可能扩展哈希表?
解决方案
据我所知,没有内置功能可以与使用参数中使用的变量和表达式执行的命令版本相呼应。
即使有,它也只能在简单的情况下忠实地工作,因为并非所有对象都有字面表示。
但是,有限制,您可以滚动自己的解决方案,基于&
调用运算符和参数飞溅通过预先定义的参数值的哈希表:
# Sample argument values.
$rgFullName = 'full name'
$location = 'loc'
$tags = @{ one = 1; two = 2; three = 3 }
# Define the command to execute:
# * as a string variable that contains the command name / path
# * as a hashtable that defines the arguments to pass via
# splatting (see below.)
$command = 'New-AzureRmResourceGroup'
$commandArgs = [ordered] @{
Name = $rgFullName
Location = $location
Tag = $tags
Force = $True
}
# Echo the command to be executed.
$command, $commandArgs
# Execute the command, using & and splatting (note the '@' instead of '$')
& $command @commandArgs
上述内容与以下内容相呼应(不包括实际执行的任何输出):
New-AzureRmResourceGroup
Name Value
---- -----
Name full name
Location loc
Tag {two, three, one}
Force True
如你看到的:
PowerShell 的默认输出格式会导致用于喷溅的哈希表的多行表示。
不幸的是,该
$tags
条目(哈希表本身)仅由其键表示- 缺少值。
但是,您可以以编程方式自定义输出以创建一个单行表示,该表示使用扩展参数近似命令,包括使用帮助函数convertTo-PseudoCommandLine
显示带有其值的哈希表:
# Helper function that converts a command name and its arguments specified
# via a hashtable or array into a pseudo-command line string that
# *approximates* the command using literal values.
# Main use is for logging, to reflect commands with their expanded arguments.
function convertTo-PseudoCommandLine ($commandName, $commandArgs) {
# Helper script block that transforms a single parameter-name/value pair
# into part of a command line.
$sbToCmdLineArg = { param($paramName, $arg)
$argTransformed = ''; $sep = ' '
if ($arg -is [Collections.IDictionary]) { # hashtable
$argTransformed = '@{{{0}}}' -f ($(foreach ($key in $arg.Keys) { '{0}={1}' -f (& $sbToCmdLineArg '' $key), (& $sbToCmdLineArg '' $arg[$key]) }) -join ';')
} elseif ($arg -is [Collections.ICollection]) { # array / collection
$argTransformed = $(foreach ($el in $arg) { & $sbToCmdLineArg $el }) -join ','
}
elseif ($arg -is [bool]) { # assume it is a switch
$argTransformed = ('$False', '$True')[$arg]
$sep = ':' # passing an argument to a switch requires -switch:<val> format
} elseif ($arg -match '^[$@(]|\s|"') {
$argTransformed = "'{0}'" -f ($arg -replace "'", "''") # single-quote and escape embedded single quotes
} else {
$argTransformed = "$arg" # stringify as is - no quoting needed
}
if ($paramName) { # a parameter-argument pair
'-{0}{1}{2}' -f $paramName, $sep, $argTransformed
} else { # the command name or a hashtable key or value
$argTransformed
}
}
# Synthesize and output the pseudo-command line.
$cmdLine = (& $sbToCmdLineArg '' $commandName)
if ($commandArgs -is [Collections.IDictionary]) { # hashtable
$cmdLine += ' ' +
$(foreach ($param in $commandArgs.Keys) { & $sbToCmdLineArg $param $commandArgs[$param] }) -join ' '
} elseif ($commandArgs) { # array / other collection
$cmdLine += ' ' +
$(foreach ($arg in $commandArgs) { & $sbToCmdLineArg '' $arg }) -join ' '
}
# Output the command line.
# If the comamnd name ended up quoted, we must prepend '& '
if ($cmdLine[0] -eq "'") {
"& $cmdLine"
} else {
$cmdLine
}
}
使用convertTo-PseudoCommandLine
定义(在下面的代码之前或之上),您可以使用:
# Sample argument values.
$rgFullName = 'full name'
$location = 'loc'
$tags = @{ one = 1; two = 2; three = 3 }
# Define the command to execute:
# * as a string variable that contains the command name / path
# * as a hashtable that defines the arguments to pass via
# splatting (see below.)
$command = 'New-AzureRmResourceGroup'
$commandArgs = [ordered] @{
Name = $rgFullName
Location = $location
Tag = $tags
Force = $True
}
# Echo the command to be executed as a pseud-command line
# created by the helper function.
convertTo-PseudoCommandLine $command $commandArgs
# Execute the command, using & and splatting (note the '@' instead of '$')
& $command @commandArgs
这会产生(不包括实际执行的任何输出):
New-AzureRmResourceGroup -Name 'full name' -Location loc -Tag @{two=2;three=3;one=1} -Force:$True
推荐阅读
- python-3.x - python3 接受一个回调,该回调可能接受一个参数并且可能不接受
- javascript - 如何在 MomentJS 中格式化时间/持续时间,使其以小时、分钟和秒为单位
- c++ - Visual Studio + cmake 混淆
- rabbitmq - MassTransit 中的标头序列化不正确
- reactjs - 使用钩子 POST 请求成功后重新加载页面
- android - 如何从 vimeo 帐户检索视频源以在 exoplayer android 中播放?
- apache-kafka - secor 忽略 message.timestamp.input.pattern
- python-3.x - 解包 4 字节的类会导致解包错误
- php - 在我的每个产品中创建新元框后,如何将值存储在数据库中?如何使用函数正确更改这些值?
- javascript - 如何修改 imgViewer jquery 插件以在滚动时缩放到光标