Last Update: Sep 04, 2024 | Published: Mar 09, 2020
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.
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 defaultsystemctl
command output is shown below.Extracting Information into PowerShell Objects
Thesystemctl
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 is0
. When using count, the starting value is1
. Therefore, we need to decrement our count by1
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 of2
.
With this basic code, we now have a$services
array of parseable objects as seen below.Creating the
Next in the process is to create a simpleGet-Service
FunctionGet-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
.
Get-Service
AbilitiesThere 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.
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.
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
Example 2
Example 3
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 aGet-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 asStop-Service
andStart-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!