service status using powershell

This topic contains 6 replies, has 5 voices, and was last updated by Profile photo of Bjorn Houben Bjorn Houben 2 years, 5 months ago.

  • Author
    Posts
  • #16157
    Profile photo of Lalit Kumar
    Lalit Kumar
    Participant

    Hi,

    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) = $service.name
    $c.Cells.Item($intRow,2) = $service.state

    $intRow = $intRow + 1
    }
    $d.EntireColumn.AutoFit()
    cls

  • #16161
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

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

  • #16172
    Profile photo of Martin Nielsen
    Martin Nielsen
    Participant

    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) = $s.name
            $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.

  • #16190
    Profile photo of Lalit Kumar
    Lalit Kumar
    Participant

    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.

  • #16195
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    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
            
            $row++
        }
    }
    
    $range.EntireColumn.AutoFit()
    $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.

  • #16197
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    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 https://powershell.org/2014/06/04/quick-tip-wmi-vs-cim-syntax/). Have fun.

  • #16228
    Profile photo of Bjorn Houben
    Bjorn Houben
    Member

    What also might be useful to you is:
    Export-Xlsx http://gallery.technet.microsoft.com/office/Export-XLSX-PowerShell-f2f0c035

You must be logged in to reply to this topic.