Check list of servers for service & status - create report

This topic contains 7 replies, has 5 voices, and was last updated by  Vikas Sukhija 3 years, 9 months ago.

  • Author
    Posts
  • #9491

    Jake Sully
    Participant

    Howdy,

    I have been trying to get a script working to check for a single service and I'm getting stuck. I have the script below which does get all services and I'm not far off, but I'm not sure how to query for the specific service name. I've read some posts where people use wmi-object and others where it is stated to use the built-in ps get-service, why is 1 option better or when is it correct to use 1 over the other? Also I want to output this as an excel report formatted "neatly" and "html" so I can compare this to provide as I was tasked with. Can anyone help, I've gathered this much so far from reading and testing. I'd also rather use a csv file for the input but got stuck there as well, so I went with a .txt file.

    $ServerArray="c:\scripts\serverlist.txt"
    $DefineSaveLocation=""
    if ($DefineSaveLocation -eq "")
    {$DefineSaveLocation="C:\Temp\ServiceandServiceAccounts\"}
    $SavetoLocaPath = Test-Path $DefineSaveLocation
    if ($SavetoLocaPath -eq $False)
    {New-Item -ItemType directory -Path $DefineSaveLocation}
    cd $DefineSaveLocation
    Foreach ($Server in $ ServerArray )
    {
    Write-Host "Retrieving Servers for $Server "
    Get-WmiObject win32_service -ComputerName $Server | select Name,
    @{N="Startup Type";E={$_.StartMode}},
    @{N="Service Account";E={$_.StartName}},
    @{N="System Name";E={$_.Systemname}} | Sort-Object "Name" > ".\$Server -Services.txt"
    }

  • #9492

    Dave Wyatt
    Moderator

    If you're using Get-WmiObject, then what you want to add is a -Filter parameter. The syntax of the filter string comes from WQL, so it'll look a little different from what you're used to in PowerShell. There are two names you can filter on; the actual service name (such as "wuauserv"), and the display name (such as "Windows Update"). Which one is up to you, but it's a common mistake to try to use a display name's value to filter on the Name field (and get zero results).

    If you're using Get-Service, you just specify the -Name or -DisplayName parameters.

    I don't know what service you're searching for, so I've used the Windows Update service in these examples.

    Get-WmiObject win32_service -ComputerName $Server -Filter "Name = 'wuauserv'"
    
    # Or
    
    Get-Service -ComputerName $Server -Name 'wuauserv'
    
    # Or
    
    Get-WmiObject win32_service -ComputerName $Server -Filter "DisplayName = 'Windows Update'"
    
    # Or
    
    Get-Service -ComputerName $Server -DisplayName 'Windows Update'
    
  • #9507

    Art Beane
    Member

    Back to your original questions... First and foremost, there is no wrong way to get a correct answer in PowerShell. However you get the correct answer is the right way to do it. True, some ways are more efficient than others, but in the end, that just comes down to personal style and doesn't affect the results.

    That said, let me make some suggestions for your foreach block based on the style that I write PowerShell scripts. First, when collecting only a subset of the available data, I like to create a new object to hold it and save it in a variable. That way, I can do multiple things with the results. So, try it this way:

    $Data = @()
    Foreach ($Server in $ ServerArray ) {
        Write-Host “Retrieving Servers for $Server ”
        foreach ($Raw in (Get-WmiObject win32_service -ComputerName $Server)) {
            $Data += New-Object PSObject -Property @{
                'Service' = $Raw.Name
                'Startup Type' = $Raw.StartMode
                'Service Account' = $Raw.StartName
                'System Name' = $Raw.Systemname
            }
        }
     }

    PowerShell makes outputting data to Excel extremely easy. Just export it to a CSV file. Sometimes, I'll go through the trouble of building an Excel COM object and importing the CSV, setting column widths, bolding the header row, and freezing panes, but that doesn't change how simple it is to send result to Excel:

    $Data | Export-Csv "$ServerServices.csv" -NoTypeInformation

    Output to HTML takes a little more work, but is still very straight forward. It uses that same $Data collection as was used for exporting to Excel:

    $head = @'
    
    '@
    $Report = $Data | Sort 'System Name',Service | ConvertTo-Html -Fragment -As Table | Out-String
    $Body = "

    Combined Server Service Report

    $(Get-Date -Format D)

    " ConvertTo-Html -head $head -PostContent $Report -Body $Body | Out-File "$ServerServices.html"

    Hopefully, this will give you some ideas to work with.

  • #9549

    Jake Sully
    Participant

    Hello,
    Thank you both for the reply.

    Art – thank you for teaching me quite a bit as well!

    I did try to get the samples you sent working and I am not having luck just pulling the service information, I didn't try to add in the output yet.
    I used the suggestion from Dave and tied that into the 1st portion of the code you sent Art, but it fails with an error regarding WMI and the get-service option ran but failed immediately with an error and I will post that shortly as I'm still working on a system down issue 🙁 In regards to whether get-service is "better" than get-wmiobject, is there one method that is more reliable? I had read that for this particular query that get-service tends to error out if the service is not found and then the script stops.
    I also was trying to add in something that would state "Access Denied" or just "failed to connect", etc if I don't have access to the server. Then if the service doesn't exist for the service status I wanted to report "Service not Found" or something shorter that makes sense.

    Here is what I have:
    $ServerArray=”c:\scripts\serverlist.txt”
    $Data = @()
    Foreach ($Server in $ServerArray ) {
    Write-Host “Retrieving Servers for $Server ”
    foreach ($Raw in (Get-WmiObject win32_service -ComputerName $Server -Filter "Name = 'wuauserv'")) {
    $Data += New-Object PSObject -Property @{
    'Service' = $Raw.Name
    'Startup Type' = $Raw.StartMode
    'Service Account' = $Raw.StartName
    'System Name' = $Raw.Systemname
    }
    }
    }

    I would definitely love to read up on how to export to excel by customizing the width and things like that so that the file looks "nice" when the script does work, any links etc would be much much appreciated!! I know that the example posted will provide me with the output and if it doesn't look great I can manually tweak the excel file now, but for future learning I'll read up on that more.

  • #9553

    Dave Wyatt
    Moderator

    In regards to whether get-service is “better” than get-wmiobject, is there one method that is more reliable? I had read that for this particular query that get-service tends to error out if the service is not found and then the script stops.
    I also was trying to add in something that would state “Access Denied” or just “failed to connect”, etc if I don’t have access to the server. Then if the service doesn’t exist for the service status I wanted to report “Service not Found” or something shorter that makes sense.

    When it comes to getting service status on remote computers, I prefer using WMI. I'm not sure of the reasoning behind this (and maybe it wasn't an intentional part of the design of the cmdlet), but Get-Service doesn't report errors if it can't contact a particular computer in the -ComputerName array. It will only report a "Cannot find any service with the service name 'whatever'." error if it can't find a service with that name on ANY of the computers in the -ComputerName array (even if the reason for that is because the computers specified don't exist or can't be reached).

    Get-WmiObject, on the other hand, will give you more specific feedback. If the computer can't be contacted, you get a non-terminating error. If the computer can be contacted, but the service specified by your filter doesn't exist, the cmdlet's result will be null, and you can test for that to produce your own errors.

  • #9611

    Lery
    Participant

    Jake,

    Might I add that Get-Service is a PowerShell cmdlet. Get-WMIObject is not a PowerShell cmdlet. By running Get-WMIObject you're utilizing another technology. My personal preference is Get-WMIObject.

    Your environment might block WMI requests. You should try a simple query first against one remote machine.

    get-wmiobject win32_service -ComputerName SomeRemoteComputer -Filter “Name = ‘wuauserv’”

  • #9612

    Dave Wyatt
    Moderator

    Might I add that Get-Service is a PowerShell cmdlet. Get-WMIObject is not a PowerShell cmdlet.

    I get what you were saying there, but the wording is a bit inaccurate. Get-WmiObject and Get-Service are both cmdlets. They just have different implementations and protocols (WMI versus whatever the ServiceController class uses, probably RPC).

  • #13669

    Vikas Sukhija
    Participant

    Here is the script that we have used for achieving this , it sends the status in HTML formal.
    stopped one are shown as REd

You must be logged in to reply to this topic.