0

I am trying to build a generic function that receives a list of services and executes the following snippet. If I send in one value, it works, if I try to send in more than one value, it fails.

Is there a better way to go about this or am I missing something simple?

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 
1
  • What makes you think it's related to the Where-Object filter? Commented Jan 18, 2012 at 18:53

3 Answers 3

4

You might be hitting a classic PowerShell issue, wrap this call in an array subexpression:

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

If this isn't it, could you be more specific about where your script is failing?

Update: I would suggest that you use a simple regular expression with the -match operator e.g."

$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)

You can also optimize this command a bit by first filtering with Where-Object and then running Select-Object. In general, it is best to do the filtering as early as possible in the pipeline.

Sign up to request clarification or add additional context in comments.

3 Comments

This wasn't it, if i put more than one value in the $ary_param variable, it fails on this line: [string]$tempServiceInfo.Name = $objItem.Name.ToString()
BTW it fails on that line because your query is mostly likely returning no results. That means $null gets assigned to $colItems (you can check this $colItems -eq $null. In that case, the PowerShell foreach loop will iterate over the $null value once and then it tries to invoke the ToString method on a null value, it will fail. By making sure $colItems is always an array, this won't happen because PowerShell won't iterate over an empty array.
Another option is to just pipe it to ForEach-Object. I have found that a lot of problems people have with PowerShell stem from trying to write code like in other languages (which is tempting because the same constructs are there).
0

First of all, if you want a set of values in $ary_param, do something like "sql","ftp" and not "sql,ftp" - in the latter case it is just one string. When you are assigning to services and you want to use the latter, you might have to do:

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

This will make sure $services is an array.

In the where-object, what you are doing is something like this:

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

The above will give true and this is the case when $ary_param has only one element.

But something like $services = "sql","ftp", will make the above return false.

You might want to pipe services and do what you want in a foreach-object:

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

}

Note that you need not use the Where-Object in the Get-WmiObject, you can filter directly:

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

You will also have to force the Get-WmiObject output into an array to avoid issues with one object or no object returning, like @Keith Hill suggest.

Comments

0

Another way would be to create WQL filter on the fly:

$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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.