通过变量执行cmdlet?

时间:2017-11-25 05:54:07

标签: windows powershell cmdlets

我想使用if \ else语句来确定运行哪个cmdlet,同时为两个命令保留相同的参数:

例如我有这个电话:

    New-AzureRmResourceGroupDeployment `
        -ResourceGroupName $ResourceGroup `
        -TemplateFile $TemplateUri `
        -TemplateParameterFile $TemplateParamFile 

但我想用变量来确定动词:

    $myVerb = if ($booleanTest) {"Test"} else {"New"}
    [$myVerb]-AzureRmResourceGroupDeployment `
         -ResourceGroupName $ResourceGroup `
         -TemplateFile $TemplateUri `
         -TemplateParameterFile $TemplateParamFile 

或类似的东西:

    $command = if ($booleanTest) {"Test-AzureRmResourceGroupDeployment"} else {"New-AzureRmResourceGroupDeployment"}
    $command `
         -ResourceGroupName $ResourceGroup `
         -TemplateFile $TemplateUri `
         -TemplateParameterFile $TemplateParamFile 

我尝试了$command版本,但它失败了:

  

目前   C:\用户\管理\ Dropbox的\项目\德勤\芯光伏\开发\脚本\ AZ-d   eploy.ps1:36 char:13   + -ResourceGroupName $ ResourceGroup + ~~~~~~~~~~~~~~~~~~ Unexpected token '-ResourceGroupName' in expression or statement. At C:\Users\Administrator\Dropbox\projects\deloitte\Suncore\Dev\scripts\az-d eploy.ps1:36 char:32 + -ResourceGroupName $ResourceGroup   + ~~~~~~~~~~~~~~

4 个答案:

答案 0 :(得分:6)

要完全按照您的描述进行操作,您需要将整个命令包装为字符串,然后使用Invoke-Expression调用它。例如:

$MyCommand = "$myVerb-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroup -TemplateFile $TemplateUri"
Invoke-Expression $MyCommand

但我认为这不是编写脚本的非常明确的方法。更好的选择是使用Splatting,您可以在其中创建参数的哈希表,然后可以通过带有变量名称的特殊@字符发送cmdlet。例如:

$AzureParams = @{ 
    ResourceGroupName = $ResourceGroup
    TemplateFile = $TemplateUri
    TemplateParameterFile = $TemplateParamFile 
}

If ($booleanTest) {
    Test-AzureRmResourceGroupDeployment @AzureParams
} Else {
    New-AzureRmResourceGroupDeployment @AzurParams
}

这也有利于避免使用反引号字符,这通常是鼓励的,因为它很难发现并且容易破坏。

答案 1 :(得分:3)

我建议不要在其他答案上使用它,但要直接回答您的问题,请添加调用运算符&

$command = if ($booleanTest) {
    "Test-AzureRmResourceGroupDeployment"
} else {
    "New-AzureRmResourceGroupDeployment"
}

& $command `
     -ResourceGroupName $ResourceGroup `
     -TemplateFile $TemplateUri `
     -TemplateParameterFile $TemplateParamFile 

答案 2 :(得分:2)

补充现有的有用答案:

  • Invoke-Expression应该始终是 last 度假胜地,此处不需要。使用Invoke-Expression,获得正确的引用是很棘手的,并且它的使用可能是一种安全风险(执行任意命令作为字符串传递,类似于类似POSIX的shell中的eval)。

  • Splatting Get-Help about_Splatting)总值得考虑:

    • 正如Mark's answer所解释的那样,它是更强大的替代多行参数传递和行延续,
    • 允许参数值集的增量条件构造以及在多次调用中的使用
  • 但是,在目前的情况下,由于只有命令名称是可变的Patrick's answer基于 & },调用运算符最简单(参见Get-Help about_Operators)。

通常,只要命令名称​​不 未加引号的文字就需要&(例如notepad foo.txt虽然有效,但'notepad' foo.txt没有。

换句话说:您需要& ,如果您的命令名称是:

  • 引号(无论'...'还是"...");例如,'notepad'
  • 或是变量引用;例如,$cmdName
  • 或是表达式的结果 (例如('get' + '-item')
在这种情况下需要

&,以告诉PowerShell您的意图是调用命令,而不是评估表达式;如果没有&,则此类令牌将被解释为启动表达式;请参阅Get-Help about_Parsing,了解 PowerShell的两种基本解析模式,参数模式表达模式

虽然它可能不是最易读的解决方案,但您甚至可以将可扩展字符串与嵌入式子表达式($(...) - 再次组合,请参阅Get-Help about_Operators)组合起来,无需辅助。变量:

& "$( if ($booleanTest) {'Test'} else {'New'} )-AzureRmResourceGroupDeployment" `
     -ResourceGroupName $ResourceGroup `
     -TemplateFile $TemplateUri `
     -TemplateParameterFile $TemplateParamFile 

答案 3 :(得分:0)

Splatting建议使用Mathias R. Jessen

Function Do-AzureRmResourceGroupDeployment ([ValidateSet("Test", "New")]$Verb, $ResourceGroupName, $TemplateFile, $TemplateParameterFile) {
    $PSBoundParameters.Remove("Verb")
    & "$Verb-AzureRmResourceGroupDeployment" @PSBoundParameters 
}