让WMI过滤器中的变量起作用?

时间:2015-01-05 18:04:40

标签: powershell escaping wmi

以下是我的WMI查询:

$Query = "SELECT * from MSVM_ComputerSystem where ElementName='$Gen2'"
$VMs = gwmi -Query $Query -Namespace "root\virtualization\v2"

但我希望有一个变量而不是虚拟机名Gen2。像

这样的东西
$Query = "SELECT * from MSVM_ComputerSystem where ElementName='$VMName'"
$VMs = gwmi -Query $Query -Namespace "root\virtualization\v2"

命令Get-Help about_Quoting_Rules没有帮助,或者我无法正确解释规则。我尝试了几十种不成功的变种,试图把它弄好。

3 个答案:

答案 0 :(得分:1)

如果在定义查询时已经定义了嵌套变量,那么带变量的查询应该可以正常工作。像这样:

$VMName = 'Gen2'
$Query  = "SELECT * FROM MSVM_ComputerSystem WHERE ElementName='$VMName'"

$VMs = gwmi -Query $Query -Namespace 'root\virtualization\v2'

如果您先定义$Query,之后定义$VMName

,它将无效
$Query  = "SELECT * FROM MSVM_ComputerSystem WHERE ElementName='$VMName'"
$VMName = 'Gen2'

因为嵌套变量会自动扩展为空字符串,因为它尚未定义,因此$Query的值变为SELECT * FROM MSVM_ComputerSystem WHERE ElementName=''

如果由于某种原因你必须首先定义查询(例如作为排序的模板),并在稍后的时间点(来自用户输入或其他)定义变量,你必须这样做:

$Query  = "SELECT * FROM MSVM_ComputerSystem WHERE ElementName='{0}'"
$VMName = 'Gen2'

$VMs = gwmi -Query ($Query -f $VMName) -Namespace 'root\virtualization\v2'

或者像这样:

$Query  = "SELECT * FROM MSVM_ComputerSystem WHERE ElementName='`$VMName'"
$VMName = 'Gen2'

$VMs = gwmi -Query ($ExecutionContext.InvokeCommand.ExpandString($Query)) `
       -Namespace 'root\virtualization\v2'

第一个示例将$Query定义为带占位符({0})的格式字符串,并使用格式运算符(-f)填充实际值,而第二个示例展开转义变量(`$VMName)。

你也可以通过“切换”引号来做第二个例子的变体,这样你就不需要转义$

$Query  = 'SELECT * FROM MSVM_ComputerSystem WHERE ElementName="$VMName"'
$VMName = 'Gen2'

$VMs = gwmi -Query ($ExecutionContext.InvokeCommand.ExpandString($Query)) `
       -Namespace 'root\virtualization\v2'

答案 1 :(得分:0)

试试这样:

"ElementName=`"$Gen2`""

答案 2 :(得分:0)

似乎我自己找到了答案,感谢命令Get-Help about_Quoting_Rules。诀窍是使用所谓的Here String。我将它发布在这里供将来参考。

我不得不稍微重新设计代码。这是有效的代码。只需确保正确对齐Here String $ filter并在Here字符串的所有行的末尾使用CRLF。也许还有很多其他解决方案。

$filter=@"
ElementName='$VMName'
"@
$VMs = gwmi -class "MSVM_ComputerSystem" `
            -namespace "root\virtualization\v2" `
            -computername "." `
            -filter $filter

完整代码在这里:

Function WaitForVMShutDown($VMName){   
$filter=@"
ElementName='$VMName'
"@

$job = Start-Job { 
$state=""
    while ($state -ne "Stopped")
    {
    Start-Sleep -Seconds 1

    $VMs = gwmi -class "MSVM_ComputerSystem" `
                -namespace "root\virtualization\v2" `
                -computername "." `
                -filter $filter  
        foreach ($VM IN $VMs)
        {
            switch ($VM.EnabledState)
            {
            2{$state="Running"}
            3{$state="Stopped"}
            32768{$state="Paused"}
            32769{$state="Suspended"}
            32770 {$state="Starting"}
            32771{$state="Taking Snapshot"}
            32773{$state="Saving"}
            32774{$state="Stopping"}
            }
        } 
    }
}
Wait-Job $job
}
WaitForVMShutDown("LondonDC")