How to Create a Services List in PowerShell 7 on Linux

Just like Windows, Linux has many running services that need proper management. With the advent of PowerShell 7 and it’s cross-platform ability, the idea of using PowerShell to manage Linux systems becomes more attractive. Not all cmdlets are available on all systems though, notably, one that is missing is that of the Get-Service cmdlet, an easy way to list service status. In this article, we will create an equivalent function in PowerShell 7 that allows for retrieving Linux services in a PowerShell compatible format.

Listing Service Status

Many Linux distributions use SystemD to manage services. Ubuntu 18.04 is the distribution of choice in this article. Using SystemD, how do we retrieve a listing of services and their status? Running the below command lists all SystemD services and their status.

​

​
By specifying --no-legend and --no-pager extra formatting that does not helpl in extracting the service information is removed. An example of the default systemctl command output is shown below.

Untitled 33

Extracting Information into PowerShell Objects

The systemctl command doesn't exactly return an easy to parse format by default. Using RegEx to split apart the output will create PowerShell objects that are easy to use. The \\s+ RegEx command means to match one or more whitespace characters (i.e. space, tab, form feed, etc.). By splitting on that RegEx command, only the words are returned. Although the description is separated by multiple spaces, concatenating all remaining words will store the description. When referencing an object via array notation, [#], the starting value is 0. When using count, the starting value is 1. Therefore, we need to decrement our count by 1 to match our array notation. In this case, when we split the value, our final value is an empty newline so we need to decrement the count by one more, giving us the value of 2.
​

​
​
With this basic code, we now have a $services array of parseable objects as seen below.

Untitled 34

Creating the Get-Service Function

Next in the process is to create a simple Get-Service function to return the information we want in a reusable manner.
​

​​#Requires -Version 7.0
#Requires -PSEdition Core

Function Get-Service {
  [CmdletBinding()]

  Param(
      [Parameter( Position = 0, ValueFromPipeline = $True )][String]$Name
  )

  Begin {
    # Stop Function if Not Linux
    If ( -Not $IsLinux ) {
      Write-Error "This function should only be run on Linux systems"
      Break
    }
  }

  Process {
		If ( $Name ) {
      $services = & systemctl list-units $Name --type=service --no-legend --all --no-pager
    } Else {
      $services = & systemctl list-units --type=service --no-legend --all --no-pager
    }

    $services = $services -Split "`n"

    $services = $services | ForEach-Object {
      $service = $_ -Split '\\s+'

      [PSCustomObject]@{
        "Name"        = ($service[0] -Split "\\.service")[0]
        "Unit"        = $service[0]
        "State"       = $service[1]
        "Active"      = (($service[2] -EQ 'active') ? $true : $false)
        "Status"      = $service[3]
        "Description" = ($service[4..($service.count - 2)] -Join " ")
      }
    }

    $services
  }
}

The example below shows us filtering the results to just those that are active and running. This is a very similar output to the original systemctl, but using objects that allow us to manipulation the output using standard PowerShell commands such Where-Object.

Untitled 35

Extending Get-Service Abilities

There are a couple of features that the built-in Windows Get-Service cmdlet has, such as DependentServices and RequiredServices. These will display all of the services that depend on the named service or all of the required services that allow a named service to run. To replicate this with our function we need to add some additional code.

Dependent Services

Thankfully in systemd there is the ability to find those services. Quickly, it may become apparent that there is no easy way to parse this output.

​

​

​
Untitled 36

There are a few properties that we can use to add some minimal information for required services (essential to operating) and wanted services (if they are unavailable, the service continues to function). We can modify our code to utilize these values.
​

​$services = $services | ForEach-Object {
  $service  = $_ -Split '\\s+'
  $wants    = (((& systemctl show $service[0] --no-pager --property Wants) -Split "=") -Split " ") | Where-Object { $_ -NE "" }
  $requires = (((& systemctl show $service[0] --no-pager --property Requires) -Split "=") -Split " ") | Where-Object { $_ -NE "" }

  [PSCustomObject]@{
    "Name"        = ($service[0] -Split "\\.service")[0]
    "Unit"        = $service[0]
    "State"       = $service[1]
    "Active"      = (($service[2] -EQ 'active') ? $true : $false)
    "Status"      = $service[3]
    "Description" = ($service[4..($service.count - 2)] -Join " ")
    "Wants"       = (($wants.count -GT 1) ? $wants[1..($wants.count - 1)] : $null)
    "Requires"    = (($requires.count -GT 1) ? $requires[1..($requires.count - 1)] : $null)
  }
}

The end result of these modifications is output that can easily be consumed and used in further scripts. Some examples of this output are shown below and with ways to filter the output as needed.

Example 1

​

​
Untitled 37

Example 2
​

​
Untitled 38

Example 3
​

​
Untitled 39

Conclusion

As you might be able to tell, there are many ways to accomplish pulling the needed service information. In this article, we are only pulling a few of the many properties and values that can be included in a Get-Service function. As a starting point, this function gives actionable information that can be used to control the services on the system. This is just a starting point, as many other useful functions could be created such as Stop-Service and Start-Service. The same methods shown in this article could be used to create those functions. Gluing together PowerShell and Linux command-line tools is a powerful combo that expands the functionality of both!