Hostwinds Tutorials
Search results for:
Table of Contents
Tags: Cloud Servers, Dedicated Server
PowerShell is a cross-platform solution commonly used for automating the management of computer systems but it can be used for general coding as well. PowerShell is made up of a command-line shell, a scripting language, and a configuration management framework. PowerShell runs on Windows, Linux, and the macOS operating systems. Because of fundamental differences in operating systems, some PowerShell commands (called cmdlets) do not make sense. For example, the PowerShell Get-Acl cmdlet is not applicable for Linux systems in that the Linux file system does not use NTFS access control lists (ACLs). To view a list of the available Linux PowerShell cmdlets, run Get-Command.
In Linux, the output of one command can be piped into another command. For example:
ls | sort -r | more
This reverse sorts the contents of the current directory and paginates the list (if necessary). That is, the data stream output of the ls command is piped to the sort command whose data stream output is then piped to the more command. The PowerShell analog of this is as follows:
Get-ChildItem | Sort-Object -Descending | Out-Host -Paging
Which begs the question, why would you want to use PowerShell over the native version? One key reason is that objects, and not simple data streams, are piped between PowerShell cmdlets. For example, there's no need to parse text to extract information from another output stream. And because PowerShell objects generally have a plethora of properties associated with them, you can do some fairly powerful things relatively easily. For example, say you would like to find the PID of the cron service. A first attempt might be as follows:
ps -aux | grep cron
This results in output similar to the following:
root 1041 0.0 0.1 126384 1584 ? Ss 22:25 0:00 /usr/sbin/crond -n
root 3519 0.0 0.0 123360 728 ? Ss 23:01 0:00 /usr/sbin/anacron -s
root 4089 0.0 0.0 112808 976 pts/1 R+ 23:09 0:00 grep --color=auto cron
The cron PID appears to be 1041 although it's hard to tell without seeing the table headers. Assuming this is the case, we need to access the second column in the first line. The first step might be to reduce excessive whitespace:
ps -aux | grep cron | tr -s ' '
This yields:
root 1041 0.0 0.1 126384 1584 ? Ss 22:25 0:00 /usr/sbin/crond -n
root 3519 0.0 0.0 123360 728 ? Ss 23:01 0:00 /usr/sbin/anacron -s
root 4167 0.0 0.0 112808 972 pts/1 R+ 23:11 0:00 grep --color=auto cron
Now we can isolate the second column with cut:
ps -aux | grep cron | tr -s ' ' | cut -d ' ' -f 2
Which produces:
1041
3519
4274
Finally, we can grab the first line, as follows, to get the desired result, namely 1041:
ps -aux | grep cron | tr -s ' ' | cut -d ' ' -f 2 | head -1
Using the fact that PowerShell cmdlets output objects rather than data streams, the PowerShell version of the above is simply:
(Get-Process -Name crond).Id
In this case, Get-Process -Name crond returns an object representing the cron process. This object has a series of useful properties, one of which is the process Id (or PID). To access a property of a PowerShell object, you can wrap it in parentheses and then use standard "dot" notation, as shown.
To install PowerShell on your favorite flavor of Linux, refer to Microsoft's Installing PowerShell on Linux. If your Linux distribution is not listed, consider Alternate ways to install PowerShell on Linux.
As an example, the following four commands install the latest version of PowerShell on Centos 7:
# Optionally update all software packages:
sudo yum -y update
# Register the Microsoft repository:
curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo
# Install PowerShell:
sudo yum -y install powershell
# Start PowerShell:
pwsh
As can be seen, installing PowerShell is straightforward.
One key technique is determining what properties a PowerShell object actually has. This can easily be accomplished with the Get-Member cmdlet. For example, to determine the properties of a PowerShell process object, you can use:
Get-Process | Get-Member -Force
This reveals that there's a Path property for process objects. Thus, we can use it to list the top 10 processes, with respect to CPU usage, as follows:
Get-Process | Sort-Object -Property CPU | Select-Object -Property Name, Path, CPU -Last 10
This produces output similar to the following:
Name Path CPU
---- ---- ---
xfwm4 /usr/bin/xfwm4 1.95
systemd /usr/lib/systemd/systemd 3.63
rngd /usr/sbin/rngd 7.39
xfce4-terminal /usr/bin/xfce4-terminal 9.35
xrdp /usr/sbin/xrdp 22.05
ksoftirqd/0 26.21
pwsh /opt/microsoft/powershell/7/pwsh 27.37
rcu_sched 45.44
Xvnc /usr/bin/Xvnc 59.27
NetworkManager /usr/sbin/NetworkManager 955.19
Although useful, we may want to calculate an overall system usage metric. A first cut might be to simply sum the non-paged memory (NPM), page memory (PM), working set (WS), and CPU usage values. That is, we define our overall usage metric as follows:
OverallUsage = NPM + PM + WS + CPU.
In PowerShell, this can be accomplished as follows:
Get-Process | Select-Object -Property @{Label = 'OverallUsage'; Expression = {$_.NPM + $_.PM + $_.WS + $_.CPU}}
The @{} hash table (i.e., key/value pairs) allows us to define a property called OverallUsage whose definition is the expression shown above. In this expression, $_ represents a pipeline object. In this case, an individual process object that Get-Process returns (one per running Linux process). We then sum the four properties. This results in the following (first few lines):
OverallUsage
------------
520192
815104.03
794624
1093632
4902912.01
3330048.37
Now we can combine these two concepts as follows:
Get-Process | Select-Object -Property Name, Path, @{Label = 'OverallUsage'; Expression = {$_.NPM + $_.PM + $_.WS + $_.CPU}} | Sort-Object -Property OverallUsage -Bottom 10
This produces a top 10 overall usage table, similar to the following:
Name Path OverallUsage
---- ---- ------------
Thunar /usr/bin/thunar 14073856.2
xfce4-power-manager /usr/bin/xfce4-power-manager 15970304.3
xfce4-panel /usr/bin/xfce4-panel 16195584.9
xfdesktop /usr/bin/xfdesktop 17588224.59
tuned /usr/bin/python2.7 18898945.66
yum-cron /usr/bin/python2.7 22335488.2
xfce4-terminal /usr/bin/xfce4-terminal 23642123.4
xrdp /usr/sbin/xrdp 26570776.34
Xvnc /usr/bin/Xvnc 82710598.14
pwsh /opt/microsoft/powershell/7/pwsh 298852382.66
And if you prefer to display rounded usage values, you can use:
Get-Process | Select-Object -Property Name, Path, @{Label = 'OverallUsage'; Expression = {[Math]::Round($_.NPM + $_.PM + $_.WS + $_.CPU)}} | Sort-Object -Property OverallUsage -Bottom 10
The [Math]::Round() function is used to round the individual sums to their nearest whole values.
There are plenty of scenarios where standard Linux commands make more sense than PowerShell cmdlets, and in a number of cases, the other way around but what's particularly appealing is that you can use both paradigms together. As a simple example, consider:
Get-Process | Select-Object -Property Name, Path, Responding, Id | grep cron
This produces:
anacron /usr/sbin/anacron True 3018
crond /usr/sbin/crond True 1033
yum-cron /usr/bin/python2.7 True 4760
The third column indicates whether or not the process is responsive.
As you can see, PowerShell and the combination of PowerShell with Linux commands provide ample opportunity for solving and simplifying various problems and tasks.
Written by Karlito Bonnevie / April 26, 2022