4 min read
Bulk Testing PowerShell Scripts with the Tokenizer
In Part 1, we explored the internal PowerShell parser to see how it analyzes code and breaks it down into individual...
Unlocking the Power of PowerShell: Tips for Success
In part 3, we identified a useful .NET method to display system dialogs and then wrapped it inside a new PowerShell function to make it conveniently usable when your script needs to catch the user's attention.
Add-Type -AssemblyName PresentationFramework
function Show-MessageBox
{
param
(
[Parameter(Mandatory)]
[string]
$Message,
[string]
$Caption = 'Attention',
[System.Windows.MessageBoxButton]
$Buttons = [System.Windows.MessageBoxButton]::'YesNo',
[System.Windows.MessageBoxImage]
$Icon = [System.Windows.MessageBoxImage]::Question
)
return [System.Windows.MessageBox]::Show($Message, $Caption, $Buttons, $Icon)
}
#endregion reusable code
$result = Show-MessageBox -Message "I need to restart your server`r`n`r`nMay I proceed?"
if ($result -eq [System.Windows.MessageBoxResult]::Yes)
{
Write-Warning 'I am restarting...'
}
else
{
Write-Warning 'Ok, I am aborting...'
}
The function, as it is now, is a simple wrapper around the underlying .NET method Show(), shielding the user from the complexities. It does not add any other benefits.
In this final part, we’ll take the wrapper function and add new functionality that the original .NET type lacks. This demonstrates the true potential of PowerShell cmdlets: they can simplify .NET access and also enhance .NET functionality.
The dialog created by Show() has a serious disadvantage: it can be covered by other windows, causing the dialog to go unnoticed. It can even be covered by your own PowerShell code editor when you test-drive the code, and the PowerShell script may then appear to "hang" when it is actually waiting for the user to respond to the dialog.
Let’s add a reliable way to the Show-MessageBox function that can be easily invoked by the end user:
Add-Type -AssemblyName PresentationFramework
function Show-MessageBox
{
param
(
[Parameter(Mandatory)]
[string]
$Message,
[string]
$Caption = 'Attention',
[System.Windows.MessageBoxButton]
$Buttons = [System.Windows.MessageBoxButton]::YesNo,
[System.Windows.MessageBoxImage]
$Icon = [System.Windows.MessageBoxImage]::Question,
[System.Windows.MessageBoxResult]
$DefaultResult = [System.Windows.MessageBoxResult]::Yes,
[switch]
$TopMost
)
if ($TopMost)
{
$window = [System.Windows.Window]::new()
$window.Topmost = $true
$window.Left = -10000 # Move it far off-screen
$window.Top = -10000
$window.Show()
$window.Hide()
[System.Windows.MessageBox]::Show($window, $Message, $Caption, $Buttons, $Icon, $DefaultResult)
$window.Close()
}
else
{
[System.Windows.MessageBox]::Show($Message, $Caption, $Buttons, $Icon, $DefaultResult)
}
}
When the user adds -TopMost, the dialog becomes uncoverable. Try it for yourself:
PS> Show-MessageBox -Message "I am always visible" -DefaultResult No -Caption 'I am topmost' -TopMost
And here is how it works:
When the user specifies -TopMost, the code first creates a topmost window, moves it off-screen, and then passes its window handle to the .NET method. This way, the dialog window becomes a child of the newly created window. Since this newly created window is topmost in the window stack (albeit invisible itself), the dialog is now also topmost and can no longer be covered by other windows.
On a side note, the original Show() method does have advanced options, and the option “DefaultDesktopOnly” claims to create uncoverable “topmost” dialogs. Unfortunately, though, due to a .NET bug, this only works for single-display systems. Once you connect a second display, the dialog no longer appears at all with this option. The approach above seems to work much better.
This last part has completed painting the picture, and illustrated how PowerShell cmdlets/functions and .NET are related:
Unleash the full potential of PowerShell with our handy poster. Whether you're a beginner or a seasoned pro, this cheat sheet is designed to be your go-to resource for the most important and commonly used cmdlets.
The poster is available for download and in paper form.
Apr 16, 2025 by Aleksandar Nikolić and Dr. Tobias Weltner
In Part 1, we explored the internal PowerShell parser to see how it analyzes code and breaks it down into individual...
Apr 11, 2025 by Aleksandar Nikolić and Dr. Tobias Weltner
The internal PowerShell parser processes any code before execution. With full access to this parser, you can analyze...
Apr 3, 2025 by Aleksandar Nikolić and Dr. Tobias Weltner
In part 3, we identified a useful .NET method to display system dialogs and then wrapped it inside a new PowerShell...
Tobias Weltner and Aleksandar Nikolić joinly wrote the blog post series 'Tobias&Aleksandar's PowerShell tips'. So we introduce both of them here:
----------------------------
Aleksandar Nikolić is a Microsoft Azure MVP and co-founder of PowerShellMagazine.com, the ultimate online source for PowerShell enthusiasts. With over 18 years of experience in system administration, he is a respected trainer and speaker who travels the globe to share his knowledge and skills on Azure, Entra, and PowerShell. He has spoken at IT events such as Microsoft Ignite, ESPC, NIC, CloudBrew, NTK, and PowerShell Conference Europe.
----------------------------
Tobias is a long-time Microsoft MVP and has been involved with the development of PowerShell since its early days. He invented the PowerShell IDE "ISESteroids", has written numerous books on PowerShell for Microsoft Press and O'Reilly, founded the PowerShell Conference EU (psconf.eu), and is currently contributing to the advancement of PowerShell as member in the "Microsoft Cmdlet Working Group". Tobias shares his expertise as a consultant in projects and as a trainer in in-house trainings for numerous companies and agencies across Europe.