在我正在创建的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
在不编写重复代码甚至扩展哈希表的情况下,我还可以使用其他哪些选项或Commandlet实现跟踪?
答案 0 :(得分:1)
我不知道有内置功能会回显正在使用参数 expanded 中使用的变量和表达式执行的命令版本。
即使有,它也只能在简单的情况下忠实地运行,因为并非所有对象都有 literal 表示形式。
但是,有一定的局限性,您可以通过预先定义的参数值哈希表基于&
,调用operator和parameter splatting推出自己的解决方案:
# 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
项本身就是一个哈希表,仅由其键表示-值缺失。
但是,您可以以编程方式自定义输出 ,以创建单行表示形式,以扩展的参数近似命令< / strong>,包括使用 helper函数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