Application icons on the Windows Taskbar have some useful features such as an overlay badge, thumb buttons and a progress indicator. Since they are easy to access as a UI and they can also notify the users of some information, I thought it would be fantastic if we could easily use them from PowerShell. This was the reason why I made the PoshTaskbarItem module and in this article, I would like to show some examples of what is possible with this module.
Module Usage
Install the module with this command:
Install-Module -Name PoshTaskbarItem -Scope CurrentUser
then, you can create a clickable taskbar icon with this one-liner:
New-TaskbarItem -OnClicked {Write-Host 'Hi'} | Show-TaskbarItem
The ScriptBlock passed by the OnClicked
parameter runs when the icon is clicked.
Another typical task of the taskbar tools is executing a ScriptBlock periodically at a certain interval and notifying the user of some information with an overlay badge or a progress indicator. This can be achieved by the following code:
# Counter.ps1
$onClicked = {
Write-Host 'Hi'
}
$count = 0
$onUpdate = {
$script:count = ($script:count + 1) % 10
$progress = $script:count / 10
$script:ti | Set-TaskbarItemOverlayBadge -Text $count
$script:ti | Set-TaskbarItemProgressIndicator -Progress $progress -State Normal
}
$ti = New-TaskbarItem -Title 'Counter' -OnClicked $onClicked
$ti | Set-TaskbarItemTimerFunction -IntervalInMillisecond 1000 -ScriptBlock $onUpdate
$ti | Show-TaskbarItem
Finally, we create a shortcut to assign an app icon to the script. You can use existing icon resources stored in dll
and exe
, or image files such as png
.
$params = @{
Path = "$env:userprofile\Desktop\Counter.lnk"
IconResourcePath = 'imageres.dll'
IconResourceIndex = 204
TargetPath = 'pwsh.exe'
Arguments = '-ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -File "{0}"' -f 'D:\Counter.ps1'
WindowStyle = 'Minimized'
}
New-TaskbarItemShortcut @params
This is the common structure of the tools we make in this article. We'll mainly customize $onClicked
and $onUpdate
ScriptBlocks for each tool. Let's see more practical examples from here!
๐ Folder Cleaner
If you are working in an environment with small storage, you might want to monitor the size of some folders, e.g. TEMP or Downloads, and want a quick way to delete the files under that folder. It could be nice if we have a shortcut on the taskbar with the size notification.
The size monitoring is pretty easy. We can calculate the size of the folder and show it as a description text. The progress indicator shows the percentage with an 80% color alert.
# Monitors Downloads folder as an example
$folderPath = "$env:userprofile\Downloads"
$sizeLimitMb = 64
$onUpdate = {
$totalSize = (Get-ChildItem $script:folderPath -Recurse | Measure-Object -Property Length -Sum).Sum
$totalSizeMb = [Int]($totalSize / 1MB)
$desc = '{0} / {1} MB' -f $totalSizeMb, $script:sizeLimitMb
$script:ti | Set-TaskbarItemDescription -Description $desc
$progress = [Math]::Min($totalSizeMb / $script:sizeLimitMb, 1.0)
$progressState = 'Normal'
if ($progress -gt 0.8) {
$progressState = 'Error'
}
$script:ti | Set-TaskbarItemProgressIndicator -Progress $progress -State $progressState
}
Let's add a thumb button to delete the files. For a better UI response, OnClicked
ScriptBlock needs to return quickly so we use a ThreadJob for the message box and the actual delete operation.
$emptyFolder = {
param($folderPath)
$okCancel = [System.Windows.Forms.MessageBox]::Show(
"Empty folder [$folderPath]?",
'Folder Cleaner',
'OKCancel')
if ($okCancel -eq 'OK') {
Remove-Item "$folderPath\*" -Force
}
}
$params = @{
Description = 'Empty Folder'
IconResourcePath = 'imageres.dll'
IconResourceIndex = 233
OnClicked = {
Start-ThreadJob -ScriptBlock $emptyFolder -ArgumentList $script:folderPath
}
}
$thumbButton = New-TaskbarItemThumbButton @params
$ti | Add-TaskbarItemThumbButton -ThumbButton $thumbButton
Finally, clicking the icon opens the folder.
$onClicked = {
& explorer $script:folderPath
}
๐ Taskmgr Shortcut
Let's say you have to work with a machine that has a small amount of memory. You should be more interested in the memory size that each app consumes and should want to open the Task Manager quickly in case you have to stop some processes.
The percentage of memory usage can be shown as an overlay badge. It should be also helpful if we can see the top 5 process names when we hover over the icon.
$onUpdate = {
$os = Get-CimInstance Win32_OperatingSystem
[Int]$usage = 100 * ($os.TotalVisibleMemorySize - $os.FreePhysicalMemory) / $os.TotalVisibleMemorySize
$groups = Get-Process | Group-Object Name | ForEach-Object {
$workingSetSum = 0
foreach ($process in $_.Group) {
$workingSetSum += $process.WorkingSet
}
@{
Name = $_.Name
WorkingSetSum = $workingSetSum
}
}
$groups = $groups | Sort-Object -Property WorkingSetSum -Descending
$top5 = $groups[0..4]
$description = "--- Memory Top 5 ---`n"
$description += $top5.Name -join "`n"
$color = 'LightSeaGreen'
if ($usage -ge 50) {
$color = 'DeepPink'
}
$script:ti | Set-TaskbarItemOverlayBadge -Text $usage -FontSize 10 -BackgroundColor $color
$script:ti | Set-TaskbarItemDescription -Description $description
}
$onClicked
simply opens the Task Manager:
$onClicked = {
Start-Process 'Taskmgr.exe'
}
๐ GitHub Notifier
GitHub has a nice notifications page where you can manage your notifications. However, as far as I know, there is no push notification support at this time. You could use email notifications but a dedicated icon and notifications on the taskbar might be more useful.
First, you need to get your unread notifications using the GitHub notifications API. Once you've created a personal access token with the notifications
scope, you can just send a GET method with Invoke-WebRequest
. Refer to the API documentation for more information about the token and the API.
This code gets the unread notifications and shows their titles in the description text. The unread count is displayed as an overlay badge. I used SecureString
to store my personal access token locally but if you are not familiar with SecureString
, I recommend that you read this blog post.
$githubToken = Get-Content "$env:userprofile\github_token.txt" | ConvertTo-SecureString | ConvertFrom-SecureString -AsPlainText
$onUpdate = {
$headers = @{
'Accept' = 'application/vnd.github+json'
'Authorization' = "Bearer $githubToken"
'X-GitHub-Api-Version' = '2022-11-28'
}
$response = Invoke-WebRequest -Uri 'https://api.github.com/notifications' -Method GET -Headers $headers
if ($response.StatusCode -ne 200) {
# Status is not OK
return
}
$unreadNotifications = @($response.Content | ConvertFrom-Json)
$description = ''
foreach ($notification in $unreadNotifications) {
$description += $notification.subject.title + "`n"
}
$script:ti | Set-TaskbarItemDescription -Description $description
$unreadCount = $unreadNotifications.Count
if ($unreadCount) {
$script:ti | Set-TaskbarItemOverlayBadge -Text $unreadCount -BackgroundColor DodgerBlue
} else {
$script:ti | Clear-TaskbarItemOverlay
}
}
In the web response, there is an X-Poll-Interval
header that specifies how often in seconds you are allowed to poll. Let's follow this poll interval and show the waiting time as a progress bar.
$pollInterval = 60
$lastPollDate = [DateTime]::MinValue
$onUpdate = {
$elapsedSeconds = ((Get-Date) - $script:lastPollDate).TotalSeconds
$progress = [Math]::Min($elapsedSeconds / $pollInterval, 1.0)
$ti | Set-TaskbarItemProgressIndicator -Progress $progress -State Normal
if ($elapsedSeconds -lt $pollInterval) {
return
}
# The previous code to get notifications here...
$newPollInterval = [Int]($response.Headers.'X-Poll-Interval'[0])
if ($newPollInterval) {
$script:pollInterval = $newPollInterval
}
$script:lastPollDate = Get-Date
}
When you click the icon, it opens the GitHub notifications page.
$onClicked = {
& explorer 'https://github.com/notifications'
}
โ Work Time Tracker
This is a tool I personally use. It tracks your work time and notifies you of overtime. I created this tool so that it can be used as a template project and all the code is available on the GitHub repo. The repository includes the PoshTaskbarItem module as a git submodule. It also includes a GitHub action to make a zip file as a release package so you can refer to it if you would like to distribute the tool to the users.
Conclusion
With PoshTaskbarItem module, you can quickly create simple taskbar tools in PowerShell. If you use PowerShell daily, I guess you already have 1 or 2 scripts that are good to stay on the taskbar.
I hope you come up with a cool tool that helps you improve your daily process. Enjoy toolmaking!
References
PoshTaskbarItem module
https://github.com/mdgrs-mei/PoshTaskbarItemGitHub Notifications API
https://docs.github.com/en/rest/activity/notificationsHow to encrypt credentials & secure passwords with PowerShell - Part 1
https://www.pdq.com/blog/secure-password-with-powershell-encrypting-credentials-part-1/Posh Work Time Tracker template project
https://github.com/mdgrs-mei/posh-work-time-tracker