我正在考虑编写一些可以立即执行的PowerShell代码,或者生成它将作为生成的脚本执行的命令。
我想避免这种情况:
if($Generating){
write-Output "somecommand.exe"
}
else{
somecommand.exe
}
我看过ScriptBlocks,起初很有希望,因为我可以将ScriptBlock的内容写入控制台而不执行它。如:
$sc = { somecommand.exe }
$sc
somecommand.exe
我的具体问题是,如果我的scriptblock包含参数,我可以在将scriptblock内容写入控制台但是不调用scriptblock时让它们解决吗?
例如,给定以下scriptblock:
$b2 = { Param([string]$P) Write-Host "$P" }
当我在控制台输入“$ b2”并按回车键时,我会看到:
Param([string]$P) Write-Host "$P"
我想看到的是这个(如果参数值是“Foo”):
Param([string]$P) Write-Host "Foo"
我意识到这可以通过“&”调用它来完成或者使用Invoke(),但是有没有办法让参数得到解决而不需要调用我的脚本生成更优雅而不需要整个代码中的一堆条件语句?
答案 0 :(得分:3)
在PowerShell v3中,您可以通过AST属性获取参数信息,例如:
PS> $sb = {param($a,$b) "a is $a b is $b"}
PS> $sb.Ast.ParamBlock
Attributes Parameters Extent Parent
---------- ---------- ------ ------
{} {$a, $b} param($a,$b) {param($a,$b) "a...
答案 1 :(得分:2)
适用于PowerShell v2的解决方案:
# given the script block
$b2 = { Param([string]$P) Write-Host "$P" }
# make a function of it and "install" in the current scope
Invoke-Expression "function tmp {$b2}"
# get the function and its parameters
(Get-Command tmp).Parameters
答案 2 :(得分:1)
当显示带有双引号@ “的here-string时,它会扩展变量。对于不应展开的变量,请使用反引号(`)转义变量。
所以试试这个:
$P = "Foo"
$b2 = @"
{ Param([string]`$P) Write-Host "$P" }
"@
测试:
PS-ADMIN > $b2
{ Param([string]$P) Write-Host "Foo" }
如果您想再次将其转换为scriptblock-type:
#Convert it into scriptblock
$b3 = [Scriptblock]::Create($b2)
PS-ADMIN > $b3
{ Param([string]$P) Write-Host "Foo" }
PS-ADMIN > $b3.GetType().name
ScriptBlock
答案 3 :(得分:1)
使用一些建议我认为我找到了满足我需求的最佳解决方案。请考虑以下代码
function TestFunc
{
Param(
[Parameter(Mandatory=$true)]
[string]$Folder,
[Parameter(Mandatory=$true)]
[string]$Foo
)
$code = @"
Write-Host "This is a folder $Folder"
Write-Host "This is the value of Foo $Foo"
"@
$block = [Scriptblock]::Create($code)
Write-Host "Running the block" -BackgroundColor Green -ForegroundColor Black
&$block
Write-Host "Displaying block code" -BackgroundColor Green -ForegroundColor Black
$block
}
它的输出:
Running the block
This is a folder c:\some\folder
This is the value of Foo FOOFOO
Displaying block code
Write-Host "This is a folder c:\some\folder"
Write-Host "This is the value of Foo FOOFOO"
通过这种方式,我仍然可以保留现有的函数及其参数,参数验证,CBH等所有好处。我也可以轻松生成函数执行的代码或让它执行。感谢所有的投入,这绝对是一次很好的学习经历。
答案 4 :(得分:0)
如果您想将块表示为块而不是字符串,则以下操作:
$printable = invoke-expression ('"' + ($block -replace '"', '`"') + '"')
基本上,您将所有内容包装在引号中,然后将其作为表达式调用。 -replace
调用可确保阻止块本身中的任何引号。
我在这个方便的函数中使用它,如果被调用的命令失败,它也会暂停执行。
# usage: exec { dir $myDir }
function exec($block)
{
# expand variables in block so it's easier to see what we're doing
$printable = invoke-expression ('"' + ($block -replace '"', '`"').Trim() + '"')
write-host "# $printable" -foregroundcolor gray
& $block
if ($lastExitCode -ne 0)
{
throw "Command failed: $printable in $(pwd) returned $lastExitCode"
}
}