有一个PowerShell where-object过滤器的问题

时间:2012-01-18 18:50:42

标签: powershell

我正在尝试构建一个接收服务列表并执行以下代码段的通用函数。如果我发送一个值,它可以工作,如果我尝试发送多个值,它就会失败。

有更好的方法可以解决这个问题,还是我错过了一些简单的事情?

cls

$host_name = "."
    #works
$ary_param = "sql"
    #fails
#$ary_param = "sql,ftp"

$services = @($ary_param)

$colItems = Get-WmiObject -Class Win32_Service -ComputerName $host_name | 
            Select-Object Name, DisplayName, State, ProcessID, StartMode, StartName  | 
            Where-Object{$_.Name -like '*' + $services + '*'}

$ServiceInfo = @()

foreach ($objItem in $colItems)
{       
    $tempServiceInfo = "" | Select Name, DisplayName, State, ProcessID, PriorityClass, StartMode, StartName

    [string]$tempServiceInfo.Name = $objItem.Name.ToString()
    [string]$tempServiceInfo.DisplayName = $objItem.DisplayName.ToString()
    [string]$tempServiceInfo.State = $objItem.State.ToString()
    [string]$tempServiceInfo.ProcessID = $objItem.ProcessID.ToString()
    [string]$tempServiceInfo.StartMode = $objItem.StartMode.ToString()
    [string]$tempServiceInfo.StartName = $objItem.StartName.ToString()

    $svc_pid = $objItem.ProcessID
    $priority_class = Get-Process -ComputerName $host_name | Select Id, PriorityClass | Where-Object{$_.Id -eq $svc_pid }
    [string]$tempServiceInfo.PriorityClass = $priority_class.PriorityClass

    $ServiceInfo += $tempServiceInfo        
}

$ServiceInfo | Format-Table 

3 个答案:

答案 0 :(得分:4)

您可能遇到了经典的PowerShell问题,将此调用包装在数组子表达式中:

$colItems = @(Get-WmiObject -Class Win32_Service -ComputerName $host_name | 
              Select-Object Name, DisplayName, State, ProcessID, StartMode, StartName  | 
              Where-Object{$_.Name -like '*' + $services + '*'})

如果不是这样,您是否可以更具体地说明脚本失败的位置?

更新:我建议您使用带有-match运算符的简单正则表达式,例如“

$services = "ftp|sql"
$colItems = @(Get-WmiObject -Class Win32_Service -ComputerName $host_name | 
              Where-Object{$_.Name -match $services} |
              Select-Object Name, DisplayName, State, ProcessID, StartMode, StartName)

您还可以先使用Where-Object进行过滤然后再运行Select-Object来优化此命令。通常,最好在管道中尽早进行过滤。

答案 1 :(得分:0)

首先,如果您想要$ary_param中的一组值,请执行类似"sql","ftp"而不是"sql,ftp"的操作 - 在后一种情况下,它只是一个字符串。当您分配服务并且想要使用后者时,您可能必须这样做:

$services = $ary_param.split(",")

这将确保$ services是一个数组。

where-object中,你正在做的是这样的:

 "sql server" -like "*" + $services + "*"

上面的内容是真的,$ary_param只有一个元素就是这种情况。

但是$ services = "sql","ftp"之类的内容会使上述返回为false。

您可能希望管道服务并在foreach-object中执行您想要的操作:

$services | %{
#logic goes here
#use $_ to represent each service type and use it in the Where-Object

}

请注意,您无需使用Get-WmiObject中的Where-Object,您可以直接过滤:

Get-WmiObject -Class Win32_Service -Filter "Name LIKE '$_'" -ComputerName $host_name

你还必须强制Get-WmiObject输出到一个数组中,以避免一个对象出现问题或没有对象返回,就像@Keith Hill建议的那样。

答案 2 :(得分:0)

另一种方法是动态创建WQL过滤器:

$services = 'ftp','sql','iis'
$filter=($services | foreach { "Name LIKE '%$_%'" }) -join ' OR '
#$filter
#Name LIKE '%ftp%' OR Name LIKE '%sql%' OR Name LIKE '%iis%'

Get-WmiObject -Class Win32_Service -ComputerName $host_name -Filter $filter | `
Select-Object Name, DisplayName, State, ProcessID, StartMode, StartName