January 2025 PowerShell Potluck
Time to wrap up the first month of the new year. I hope you are off to a good start. I have a few things to share with you this month.
Top Process
Recently, I saw someone post a PowerShell snippet on social media.
While (1) { ps | sort -des cpu | select -f 15 | ft -a; sleep 1; cls }
The code is intentionally short because it is to be run at the console. Hopefully, you can look at the code and figure out what it does. The code is displaying the top 15 processes by CPU usage and refreshing the display every second. Go ahead and try it. You can stop the loop by pressing Ctrl+C
.
It works, but let's see if we can refine it. My first variation is to clear the screen in the loop.
While (1) { cls; ps | sort -des cpu | select -f 15 | ft -a; sleep 1 }
A little bit nicer. But there is a noticeable flicker with each refresh, not to mention the blinking cursor. I can improve this by using ANSI escape sequences. You've seen me us them or $PSStyle
to format text. But you can also use ANSI escape sequences to control the cursor.
First I can hide the cursor with this.
"`e[?25l"
To restore it you can run $PSStyle.Reset
or `
e[0m`. We can also use these sequences to move the cursor to a specific location.
`
e[nA` Moves the cursor up by n lines`
e[nB` Moves the cursor down by n lines`
e[nC` Moves the cursor right by n characters`
e[nD` Moves the cursor left by n characters`
e[2K` Clears the line`
e[2J` Clears the screen
With this in mind, I can rewrite the loop.
Clear-Host ; While (1) { "`e[20A"; ps | sort -des cpu | select -f 15 | ft -a; sleep 1; }
This will move the cursor up 20 lines before displaying the process list. The screen will not flicker. The cursor is still visible in this example. You can stop the loop by pressing Ctrl+C
. Here's a variation that will move the cursor to the first row and first column.
Clear-Host ; While (1) { "`e[1H"; ps | sort -des cpu | select -f 15 | ft -a; sleep 1; }
Better, but let's clean up the code a bit.
Clear-Host ; While (1) {
"`e[?25l"
"`e[1H"
ps |
where name -NotMatch '^(System|Idle)$' |
sort -des WS |
select -f 15 | Out-Host
sleep -Seconds 1
}
This will filter out a few processes. I found I needed to use Out-Host
to ensure the output was displayed correctly. You can stop the loop by pressing Ctrl+C
.
If you've been trying these examples, you are probably tired of pressing Ctrl+C
. And what if you want to sort on a different property? Or select a different number? Of course, I'm going to write a function.
Function Show-Top {
[CmdletBinding(DefaultParameterSetName = 'Wait')]
Param(
[Parameter(
Position = 0,
HelpMessage = 'How many top processes do you want to display? Enter a value between 1 and 25'
)]
[ValidateNotNullOrEmpty()]
[ValidateRange(1, 25)]
[int]$Top = 10,
[Parameter(
Position = 1,
HelpMessage = 'Which property do you want to sort by?'
)]
[ValidateSet('CPU', 'WS', 'VM', 'PM', 'NPM')]
[ValidateNotNullOrEmpty()]
[string]$Property = 'WS',
[Parameter(
ParameterSetName = 'Wait',
HelpMessage = 'Wait for a key press to exit'
)]
[switch]$Wait,
[Parameter(
ParameterSetName = 'Timeout',
HelpMessage = 'Specify a time span duration'
)]
[ValidateNotNullOrEmpty()]
[TimeSpan]$Timeout
)
Clear-Host
$Running = $True
#hide the cursor
"`e[?25l"
While ($Running) {
"`e[1H"
Get-Process |
Where-Object name -NotMatch '^(System|Idle)$' |
Sort-Object -Descending $Property |
Select-Object -First $Top | Out-Host
Start-Sleep -Seconds 1
Switch ($PSCmdlet.ParameterSetName) {
'Timeout' {
$TimeOut = $TimeOut.Subtract($(New-TimeSpan -Seconds 1))
Write-Host "Ending in: $TimeOut" -ForegroundColor Cyan
if ($Timeout.TotalSeconds -le 0) {
$Running = $False
}
}
'Wait' {
Write-Host 'Press any key to quit...' -ForegroundColor Cyan
if ($host.UI.RawUI.KeyAvailable) {
$key = $host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
if ($key) {
$Running = $False
}
}
}
}
} #While
#restore the cursor
"`e[0m"
}
The function will let the user decide how may processes to display and sorted by which property.
PS C:> Show-Top 25

The default behavior is to wait for a key press to exit. You can also specify a timeout.
PS C:\> Show-Top -Top 10 -Property CPU -Timeout (New-TimeSpan -Seconds 60)

This is now even less to type with what I think is nicer output. Don't get me wrong. There's nothing inherently wrong with the original code. This is something I might have started with as a proof of concept. Then find ways to refine it. Expect that it will be process. I didn't go right to a function, I iterated and tested until I had the core functionality I wanted.
PowerShell+DevOps Global Summit 2025
Tickets are on sale now for the PowerShell+DevOps Global Summit to be held this April in Bellevue, Washington. I've written about this event in the past, and if PowerShell is critical to your work, you should find a way to attend. I've met more than a few attendees who value the event so much that they cover their own way, knowing that it will pay off in the long. You can learn more, including checking out the session agenda, and register at https://www.powershellsummit.org/.
WorkPlace Ninjas UK Edinburgh
I am thrilled to finally attend an event in the UK, and Scotland no less. I will be presenting at the Workplace Ninjas UK event in Edinburgh this June. I will have a few PowerShell-related sessions. This is a two day event so it is very affordable. You can learn more and register at https://wpninjas.uk/.
PSConfEU 2025
I'll have more on this later, but I also will be presenting in Malmo, Sweden, at the PSConfEU conference in June about a week after WorkPlace Ninjas. This is a fantastic event that is very well-organized. Like the PowerShell + DevOps Global Summit, you will be exposed to a lot of intense PowerShell content. And like the US event, the community is the real reason to attend. You can learn more and get your tickets at https://psconf.eu/
A New Scripting Challenge
Given a block of text, write a set of PowerShell functions to obfuscate and de-obfuscate the text by shifting characters in the text a fixed number of places, either positive or negative. The functions should accept pipeline input and write strings as command output.
There are probably a few ways you could tackle this, but the easiest approach I believe will use [char]
objects. Here is a tip, although not necessarily on how you should use it.
[int][char]"J"+3 -as [char]
[int][char]"M"-3 -as [char]
I'm going to suggest you set a limit of -20 to 20 for the shift value or you might need error handling to ensure the shifted characters are still valid.
Once you have working functions, download this sample text file and see if you can reveal the secret message. You might want to use PowerShell to loop through possible shift values to find the correct one.
Summary
Thanks for your ongoing support. Again, I encourage free subscribers to upgrade to a premium subscription, at least for a month or two to discover what you've been missing. You can unsubscribe at any time and go back to a free subscription. If you need to do anything to manage your subscription, use the links in the email footer.
See you next month.