簡體   English   中英

是否可以不調用而解析PowerShell腳本塊參數?

[英]Can I resolve PowerShell scriptblock parameters without invoking?

我正在看寫一些PowerShell代碼,這些代碼可以立即執行,也可以生成將作為生成腳本執行的命令。

我想避免這種情況:

if($Generating){
  write-Output "somecommand.exe"
} 
else{
  somecommand.exe  
}

我看到了ScriptBlocks,起初看起來很有希望,因為我可以將ScriptBlock的內容寫到控制台而無需執行它。 如:

$sc = { somecommand.exe }
$sc
 somecommand.exe

我的具體問題是,如果我的腳本塊包含參數,那么當我將腳本塊內容寫入控制台時,是否可以解析它們,而無需調用腳本塊?

例如,給出以下腳本塊:

$b2 = { Param([string]$P) Write-Host "$P" }

當我在控制台上鍵入“ $ b2”並按Enter時,我看到以下內容:

Param([string]$P) Write-Host "$P"

我想看的是這個(如果參數值為“ Foo”):

Param([string]$P) Write-Host "Foo"

我意識到可以通過“&”或使用Invoke()調用它來完成此操作,但是可以通過任何方式獲取要解析的參數,而無需調用使我的腳本生成更加優雅,而無需使用大量條件整個代碼中的語句?

在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...

適用於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

當顯示帶有雙引號@ 的here-string時,它將擴展變量。對於不應該擴展的變量,請使用反引號(`)對該變量進行轉義。

所以試試這個:

$P = "Foo"

$b2 = @"
{ Param([string]`$P) Write-Host "$P" }
"@

測試:

PS-ADMIN > $b2
{ Param([string]$P) Write-Host "Foo" }

如果要再次將其轉換為腳本塊類型:

#Convert it into scriptblock
$b3 = [Scriptblock]::Create($b2)

PS-ADMIN > $b3
{ Param([string]$P) Write-Host "Foo" }

PS-ADMIN > $b3.GetType().name
ScriptBlock

通過使用一些建議,我認為我已經找到了滿足自己需求的最佳解決方案。 考慮以下代碼

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等的所有好處。我還可以輕松地生成該功能將執行的代碼或僅讓其執行的代碼。 感謝您的所有投入,這絕對是一次很好的學習體驗。

如果要將塊表示為塊而不是字符串,則可以使用以下方法:

$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"
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM