service status using powershell


I have created a powershell script to retrive the Service status for list of computers but its only giving the first servive status. so kindly help me on this. my code is mention below.

$erroractionpreference = “SilentlyContinue”

$a = New-Object -comobject Excel.Application
$a.visible = $True

$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)

$c.Cells.Item(1,1) = “Service Name”
$c.Cells.Item(1,2) = “State”

$d = $c.UsedRange
$d.Interior.ColorIndex = 19
$d.Font.ColorIndex = 11
$d.Font.Bold = $True

$intRow = 2

$colComputers = get-content D:\list.txt
foreach ($strComputer in $colComputers)
$service = get-wmiobject Win32_service -computername $strComputer

$c.Cells.Item($intRow,1) = $
$c.Cells.Item($intRow,2) = $service.state

$intRow = $intRow + 1

So do you want the spreadsheet to have information about every service on every computer? Or are you only looking for a particular service?

Dave pretty much nails it.

$service is a collection of services.

To add a specific service, you’ll have to first pick it out of the collection like so:

# This is a Wmi query filter
$service = get-wmiobject Win32_service -computername $strComputer -Filter { Name = 'serviceName' }

# This is a where-object filter with PSv2 syntax. I'm assuming this is the version you're using since you use Get-WmiObject?
# Note: It's much slower than using a Wmi query filter. 
$service = get-wmiobject Win32_service -computername $strComputer | Where { $_.Name -eq 'serviceName' } 

To add every service you’ll have to do

foreach ($strComputer in $colComputers)
    $service = get-wmiobject Win32_service -computername $strComputer

    foreach($s in $service) {
        $c.Cells.Item($intRow,1) = $
        $c.Cells.Item($intRow,2) = $s.state

        $intRow = $intRow + 1

On a completely different note, may I suggest you don’t use single letter variable for anything but iterators? It may not be an issue right with this script, but as they get bigger and longer, eventually you’ll find yourself scratching your head over why everything is called $a, $b, $c, $d and $e.

Yes Dave,

I need every service name and service status of every computers which is stored in (D:\list.txt) and i need output in csv or xls. so that i can filter it and find the stopped service on those computers.

OK, as Martin mentioned, you will need another loop over the collection returned by Get-WmiObject in your code. I’ve revised your original code to reflect this, and also renamed several variables to have more descriptive and useful meaning:

$excel = New-Object -ComObject Excel.Application

$workbook = $excel.Workbooks.Add()
$worksheet = $workbook.Worksheets.Item(1)

$worksheet.Cells.Item(1,1) = "Computer Name"
$worksheet.Cells.Item(1,2) = "Service Name"
$worksheet.Cells.Item(1,3) = "State"
$range = $worksheet.UsedRange
$range.Interior.ColorIndex = 19
$range.Font.ColorIndex = 11
$range.Font.Bold = $true
$row = 2
$computers = Get-Content D:\list.txt

foreach ($computer in $computers)
    $services = @(Get-WmiObject Win32_service -ComputerName $computer)
    foreach ($service in $services)
        $worksheet.Cells.Item($row, 1) = $computer
        $worksheet.Cells.Item($row, 2) = $service.Name
        $worksheet.Cells.Item($row, 3) = $service.State

$excel.Visible = $True

However, if you run this, you will notice that it’s extremely slow. Manipulating Excel spreadsheets via PowerShell takes a while, and every single cell update (3 of them per service, per computer) adds up. Personally, I would prefer to just generate a CSV file using PowerShell’s Export-Csv cmdlet. You can open that in Excel, pretty up the formatting and save it back as a spreadsheet if you like. (You can probably even script that with much less time than it would take to build the whole thing via the Excel COM objects directly.)

Here’s what the CSV-based code might look like:

$computers = Get-Content D:\list.txt

Get-WmiObject Win32_Service -ComputerName $computers |
Select-Object -Property PSComputerName, Name, State |
Export-Csv -Path D:\ServicesReport.csv

This will execute much, much faster than the original version. For starters, it gets rid of all the overhead of working with the Excel COM objects. It also passes all of the computer names to Get-WmiObject, and Get-WmiObject will perform parallel queries against several computers at once.

If you refer to Martin’s post, you can just modify $strComputer with (Get-Content D:\List.txt), which the filter would return a single service.

$service = get-wmiobject Win32_service -computername (Get-Content D:\List.txt) -Filter { Name = 'serviceName' }

Before you port anything outside of Powershell, you should validate the data is what you want. You can get services in Powershell with WMI or the Get-Service cmdlet, which both take string arrays (e.g. string[]) as arguments for the computer. Try running some of these commands:

Get-Service -ComputerName Computer1, Computer2 | Where{$_.Status -eq 'Stopped'}

Get-WMIObject -Class Win32_Service -ComputerName Computer1, Computer2 -Filter "State = 'Stopped'"

The results should produce Stopped services on the machines, however, the second method filters out Stopped services BEFORE it returns results where the first method returns all results and THEN filters. This won’t make a huge difference for 5 computers, but if you are doing a 100, then you want to only return exactly what you want from the computers. If you want or need to send the Excel spreadsheet somewhere else, then you can use the methodology you are using. However, if you just want to compare services quickly in a GUI form, then you should try something like this:

Get-WMIObject -Class Win32_Service -ComputerName Computer1, Computer2 -Filter "State = 'Stopped'" |  Select PSComputerName, Name, State | Out-GridView

Lastly, if you are using Powershell above V2, you should start using Get-CIMInstance (see Have fun.

What also might be useful to you is: