In the previous article we started exploring how to use PowerShell to manage Services. We used the Get-Service command to retrieve service objects not only locally, but from remote computers as well. We saw how to get services by name or display name. But what if you want to find services that are not running?
Avatar

Filtering with Where-Object

For that we turn to filtering using the Where-Object cmdlet. This command has an alias or shortcut of where. All we need to do is tell PowerShell to get the services and only keep those where the status property is equal to stopped.

PS C:\> get-service | where {$_.status -eq 'stopped'}

The $_ is a placeholder for the current service object in the pipeline. Or to put it in plainer language, PowerShell got all the services and piped them (|) to the next command which looked at each object. If the status property of the incoming object is equal to ‘stopped’, it remains in the pipeline, otherwise it is discarded. At the end of the expression PowerShell displays whatever objects are left in the pipeline.

You can see the results in the screenshot.

Services and PowerShell - Filtering with Where-Object

Filtering with Where-Object

This same command will work in v2 or v3. PowerShell 3.0 actually has a simplified syntax for an expression like this but I’ll skip it as if you are new to PowerShell I think you’ll be even more confused by it.

In the last part I showed how to query a single service on multiple machines. Here’s an alternative that uses filtering.

PS C:\> get-service -computername @('chi-dc01','chi-dc02','chi-dc03') | 
where {$_.name -eq 'wuauserv'} | format-table Name,Status,Machinename -autosize

Name     Status    MachineName
----     ------    -----------
wuauserv Running   chi-dc02
wuauserv Running   chi-dc01
wuauserv Running   chi-dc03

We can even combine getting specific services with filtering.

PS C:\> get-service "win*" -comp chi-dc03 | where {$_.status -eq 'running'}
Status   Name                      DisplayName
------   ----                      -----------
Running  Winmgmt                   Management Instrumentation
Running  WinRM                     Windows Remote Management (WS-Manag...

This command retrieved all the services on CHI-DC03 that started with ‘WIN’ but only kept those that are running.
Another approach you can take is to group the objects based on their status property.

PS C:\> $dc03 = get-service -computername chi-dc03 | Group-Object -Property Status

The variable $dc03 is a GroupInfo object.

PS C:\> $dc03

Count Name           Group
----- ----           -----
   64 Running        {System.ServiceProcess.ServiceController, Sy...
   79 Stopped        {System.ServiceProcess.ServiceController, Sy...

The Group property is a collection of the corresponding services.

PS C:\> $dc03.Get(0).group

This is easier to understand by looking at the following screenshot.

Services and PowerShell - Filtering with Group-Object

Filtering with Group-Object

Personally, I would prefer to use a hash table.

PS C:\> $hash = get-service -computername chi-dc03 | Group-Object -Property Status 
-AsHashTable

PS C:\> $hash
Name               Value
----               -----
Running            {System.ServiceProcess.ServiceController, Sys...
Stopped            {System.ServiceProcess.ServiceController, Sys...

Now, each name is a property of the hash table object. If you have some PowerShell experience you would think you could do this:

PS C:\> $hash.running.count

But nothing will happen. This is because the Status property is actually an enumeration of the [System.ServiceProcess.ServiceControllerStatus] .NET class and properties like Running and Stopped are actually integers. PowerShell does some conversion behind the scenes to make it easier to understand. We can still create a hash table, we just need to be clever about it.

PS C:\> $hash = get-service -computername chi-dc03 | Group-Object -Property Status –AsHashTable –AsString

The –AsString parameter does exactly what the name implies. Now, this is much easier to work with as a hash table.

PS C:\> $hash.running.count
62
PS C:\> $hash.running[0..3]

Status   Name                 DisplayName
------   ----                 -----------
Running  ADWS                 Active Directory Web Services
Running  AppHostSvc           Application Host Helper Service
Running  BFE                  Base Filtering Engine
Running  BrokerInfrastru...   Background Tasks Infrastructure Ser...

Next on our service management task list is checking server dependencies.

Required Services

PowerShell makes it very easy to display the status of all the services that are required for a given service, even on a remote computer.

PS C:\> get-service dns -ComputerName chi-dc03 –RequiredServices

Status   Name                DisplayName
------   ----                -----------
Running  Afd                 Ancillary Function Driver for Winsock
Running  Tcpip               TCP/IP Protocol Driver
Running  RpcSs               Remote Procedure Call (RPC)
Running  NTDS                Active Directory Domain Services

The –RequiredServices parameter will write objects to the pipeline for every required service. You could even take this a step further and check these services’ required services.

PS C:\> get-service dns -ComputerName chi-dc03 -RequiredServices | select
name,@{name="computername";expression={$_.machinename}} | get-service 
-RequiredServices

Status   Name                DisplayName
------   ----                -----------
Running  RpcEptMapper        RPC Endpoint Mapper
Running  DcomLaunch          DCOM Server Process Launcher

The Get-Service cmdlet’s –Computername parameter will take pipelined input but the incoming object must have a Computername property which is why I used the hash table with Select-Object. But it looks like everything is fine with the DNS service on CHI-DC03.

Dependent Services

We can do the same thing with dependent services. That is, services that depend on this service. If there are none, you’ll get nothing written to the pipeline.

PS C:\> get-service dns -ComputerName chi-dc03 -DependentServices
PS C:\> get-service lanmanworkstation -ComputerName chi-dc03 -DependentServices

Status   Name                DisplayName
------   ----                -----------
Stopped  SessionEnv          Remote Desktop Configuration
Running  Netlogon            Netlogon
Running  Dfs DFS             Namespace
Running  Browser             Computer Browser

Required and dependent services are also part of every service object.

PS C:\> get-service rpcss | Select *services

RequiredServices                       DependentServices
----------------                       -----------------
{RpcEptMapper, DcomLaunch}             {WwanSvc, wuauserv, WSearch, wscsvc...}

And while you could get all dependencies for all services, a command like this

PS C:\> get-service –DependentServices

Doesn’t really tell you much so I recommend sticking with querying specific services. Although you could query the same service on multiple computers. This command works much better in PowerShell v3.

PS C:\> get-service dns -comp chi-dc01,chi-dc03 -RequiredServices | Sort Machinename,Name | Format-table -GroupBy machinename

You can see the results in the next screenshot.

Services and PowerShell - Dependent Services

Dependent Services

To get similar results in PowerShell v2 you’ll need to pipe the computernames to Get-Service.

PS C:\> "chi-dc01","chi-dc03" | foreach { get-service dns -comp $_ -RequiredServices} | Sort Machinename,Name | format-table -GroupBy machinename

In the next article we’ll look at starting, stopping and restarting services.

5 Comments
  1. Avatar
    Matt 11 years ago

    I created a very low-tech script that I’ve found quite useful to show just services which aren’t ‘default’ within our company

    function show-nonstandardservices {
    [CmdletBinding()]
    Param ($P_SERVER = “.”)
    $ARR_USUAL_SERVICES = “x”, “x”
    $ARR_USUAL_SERVICES += “AeLookupSvc” # Application Experience
    $ARR_USUAL_SERVICES += “Alerter” # Alerter
    $ARR_USUAL_SERVICES += “ALG” # Application Layer Gateway Service

    get-wmiobject win32_service -computername $P_SERVER |
    where { $ARR_USUAL_SERVICES -notcontains $_.name } |
    select name, DisplayName |
    sort -uniq name
    }
    set-alias sserv show-nonstandardservices

    This gives me a really quick way of finding out (or reminding myself) what a server does.

  2. Avatar Author

    Nice. I hope you don’t mind but let me steer you in the right direction to make this a little better, yet still retain your quick and dirty approach. Here’s my tweak:

    function show-nonstandardservices {
    [CmdletBinding()]
    Param (
    [string]$Computername = $env:computername,
    [string[]]$UsualServices=@(“AeLookupSvc”,”Alerter”,”ALG”,”BITS”,”Spooler”,
    “LanManServer”,”LanManWorkstation”,”Wuauserv”)
    )

    get-wmiobject win32_service -computername $computername |
    where { $UsualServices -notcontains $_.name }

    }

    First, use standard parameter names like Computername. I would also make this a bit more flexible. It looks like you are defining all of your accepted services in the function. So why not make it a parameter with a default setting of array names. This way you can specify a different list for a different server.

    PS C:\> show-nonstandardservices -computername SERVER01 -UsualServices (get-content c:\work\SRV1-Allowed.txt) | Select Name,Displayname,State

    I also suggest taking out the Select and sort from the function. What if you want to see what services are non-standard but also
    their state? Or save all the information to a CSV file? Don’t script yourself into a corner. Even for “low tech”, try to maintain some flexibility.

  3. Avatar
    Matt 11 years ago

    >> I hope you don’t mind but let me steer you in the right direction

    No, I don’t mind at all – I’m really grateful for the suggestions! I like the idea of having a parameterized ‘usual’ list. The $P_SERVER is, I’m afraid, a hangover from some other programming languages convention. Old dogs can learn new tricks….but sometimes it takes a while! 🙂

    Thanks again, Matt

  4. Avatar
    AG 9 years ago

    Hello,

    These postings are really helping me learn and reduce some of my manual work. I am hoping you might be able to assist me with the below script. What I am trying to do below is to go through each service in an array and check the status and if the status is not stopped, I want to terminate the process. I am not able to capture the status message. Can you advise what I am doing wrong or steer me in the right direction

    $Services = Get-Content C:\Script\Services_UAT.txt
    $Logfile = “C:\Script\Log\Status_ $(Get-Date -f yyyy-MM-dd).log”

    Function LogWrite
    {
    Param ([string]$logstring)

    Add-content $Logfile -value $logstring
    }

    Write-Host -foregroundcolor cyan ” Check UAT Services Status on Servers …”
    LogWrite -foregroundcolor cyan ” Check UAT Services Status on Servers …”

    foreach ($strService in $Services)
    {
    IF ($strService -match “Prod_APP1_”)
    {
    $strComputer = “APP1”
    }

    IF ($strService -match “Prod_APP2_”)
    {
    $strComputer = “APP2”
    }

    IF ($strService -match “UAT_APP2_C”)
    {
    $strComputer = “APP2”
    }

    IF ($strService -match “UAT_APP1_”)
    {
    $strComputer = “APPUAT1”
    }

    $strClass = “win32_service”
    $objWmiService = Get-Wmiobject -Class $strClass -computer $strComputer -filter “name = ‘$strService'”

    Write-Host ” Checking the $strService service status on $strComputer now …”
    LogWrite ” Checking the $strService service status on $strComputer now …”
    $rtn = get-service -computer $strComputer -name “$strService” | select Status

    if($rtn -ne “@{Status=Stopped}”)
    {
    Write-Host -foregroundcolor red ” $strService service on $strComputer reports service Status as $rtn. Terminating Service now…”
    LogWrite -foregroundcolor red ” $strService service on $strComputer reports service Status as $rtn. Terminating Service now…”

    Clear-Host
    Stop-Process -name $strService -computer $strComputer

    Write-Host -foregroundcolor green ” $strService service on $strComputer Terminated…”
    LogWrite -foregroundcolor green ” $strService service on $strComputer Terminated…”
    }
    else
    {
    Write-Host -foregroundcolor green ” $strService service on $strComputer reports service Status as $rtn”
    LogWrite -foregroundcolor green ” $strService service on $strComputer reports service Status as $rtn”
    }
    }

    Thanks for all your help in advance.

    With Regards,

  5. Avatar Author

    The function you wrote, LogWrite has a single parameter, -LogString, yet you are calling it with a -foregroundcolor parameter which doesn’t exist. Get rid of it.

    LogWrite -foregroundcolor green ” $strService service on $strComputer reports service Status as $rtn”

Leave a reply

Please enclose code in pre tags: <pre></pre>

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account