In the previous two parts, we looked at a few .NET types and ways to look inside and find their hidden methods. This provided you with granular control, such as when rounding values.
Any .NET type follows these same rules, so now youre ready to explore more with .NET types. In this part, well look at GUI dialogs and case-correcting text.
Invoking Message Boxes
When a script emits data, it typically surfaces as text in the console, which can be easily overlooked by the user.
If your script needs to catch attention, a message box dialog may be a more effective way to do so. Heres how to invoke such a dialog:
# loading the required .NET type
Add-Type -AssemblyName PresentationFramework
$result = [System.Windows.MessageBox]::Show("I need to restart your server`r`n`r`nMay I proceed?", 'Attention', 'YesNo', 'Question')
if ($result -eq 'Yes')
{
Write-Warning 'I am restarting...'
}
else
{
Write-Warning 'Ok, I am aborting...'
}
The .NET type we are using this time is [System.Windows.MessageBox]. For the first time in this series, this is a type that is not used by PowerShell. It is still present in the .NET (on Windows), but it is not loaded by default.
Thats why you need to run Add-Type first and instruct it to load the assembly (DLL) that defins this type. If you forget this, PowerShell will complain that it cannot find the type.
Examining Overloads
Lets once again look at the overload definitions for the Show() method, just like we did in the past two parts:
PS C:\> [System.Windows.MessageBox]::Show
OverloadDefinitions
-------------------
static System.Windows.MessageBoxResult Show(string messageBoxText, string caption, System.Windows.MessageBoxButton button, System.Windows.MessageBoxImage icon,
System.Windows.MessageBoxResult defaultResult, System.Windows.MessageBoxOptions options)
static System.Windows.MessageBoxResult Show(string messageBoxText, string caption, System.Windows.MessageBoxButton button, System.Windows.MessageBoxImage icon,
System.Windows.MessageBoxResult defaultResult)
static System.Windows.MessageBoxResult Show(string messageBoxText, string caption, System.Windows.MessageBoxButton button, System.Windows.MessageBoxImage icon)
static System.Windows.MessageBoxResult Show(string messageBoxText, string caption, System.Windows.MessageBoxButton button)
static System.Windows.MessageBoxResult Show(string messageBoxText, string caption)
static System.Windows.MessageBoxResult Show(string messageBoxText)
static System.Windows.MessageBoxResult Show(System.Windows.Window owner, string messageBoxText, string caption, System.Windows.MessageBoxButton button,
System.Windows.MessageBoxImage icon, System.Windows.MessageBoxResult defaultResult, System.Windows.MessageBoxOptions options)
static System.Windows.MessageBoxResult Show(System.Windows.Window owner, string messageBoxText, string caption, System.Windows.MessageBoxButton button,
System.Windows.MessageBoxImage icon, System.Windows.MessageBoxResult defaultResult)
static System.Windows.MessageBoxResult Show(System.Windows.Window owner, string messageBoxText, string caption, System.Windows.MessageBoxButton button,
System.Windows.MessageBoxImage icon)
static System.Windows.MessageBoxResult Show(System.Windows.Window owner, string messageBoxText, string caption, System.Windows.MessageBoxButton button)
static System.Windows.MessageBoxResult Show(System.Windows.Window owner, string messageBoxText, string caption)
static System.Windows.MessageBoxResult Show(System.Windows.Window owner, string messageBoxText)
Dont let the overload definitions overwhelm youonce again, they simply show different ways to call Show() to make your life easier.
Identifying Valid Options
Whats much more important is identifying the true type names for the arguments. In the example above, we submitted strings and let PowerShell automatically convert them into the appropriate types.
For example, we passed the string "Question" for the argument System.Windows.MessageBoxImage icon. As you know from the previous parts, the message box icon is supposed to be of type System.Windows.MessageBoxImage, not a string. We got away with using "Question" because this string can be converted to System.Windows.MessageBoxImage:
PS C:\> 'Question' -as [System.Windows.MessageBoxImage]
Question
The correct approach would have been to pass the System.Windows.MessageBoxImage type directly, like this:
[System.Windows.MessageBoxImage]::Question
This way, your PowerShell editor and its IntelliSense would have displayed all the other valid icon options. As explained in the previous parts, you can always list these options using Get-Member:
PS C:\> [System.Windows.MessageBoxImage] | Get-Member -Static
TypeName: System.Windows.MessageBoxImage
Name MemberType Definition
---- ---------- ----------
Equals Method static bool Equals(System.Object objA, System.Object objB)
Format Method static string Format(type enumType, System.Object value, string format)
GetName Method static string GetName(type enumType, System.Object value)
GetNames Method static string[] GetNames(type enumType)
GetUnderlyingType Method static type GetUnderlyingType(type enumType)
GetValues Method static array GetValues(type enumType)
IsDefined Method static bool IsDefined(type enumType, System.Object value)
Parse Method static System.Object Parse(type enumType, string value), static System.Object Parse(type enumType, string value, bool ignoreCase)
ReferenceEquals Method static bool ReferenceEquals(System.Object objA, System.Object objB)
ToObject Method static System.Object ToObject(type enumType, System.Object value), static System.Object ToObject(type enumType, sbyte value), static System.Object...
TryParse Method static bool TryParse[TEnum](string value, [ref] TEnum result), static bool TryParse[TEnum](string value, bool ignoreCase, [ref] TEnum result)
Asterisk Property static System.Windows.MessageBoxImage Asterisk {get;}
Error Property static System.Windows.MessageBoxImage Error {get;}
Exclamation Property static System.Windows.MessageBoxImage Exclamation {get;}
Hand Property static System.Windows.MessageBoxImage Hand {get;}
Information Property static System.Windows.MessageBoxImage Information {get;}
None Property static System.Windows.MessageBoxImage None {get;}
Question Property static System.Windows.MessageBoxImage Question {get;}
Stop Property static System.Windows.MessageBoxImage Stop {get;}
Warning Property static System.Windows.MessageBoxImage Warning {get;}
Using Appropriate Types
Here is the example script from above, this time using the correct types instead of strings:
# loading the required .NET type
Add-Type -AssemblyName PresentationFramework
$Caption = 'Attention'
$Message = "I need to restart your server`r`n`r`nMay I proceed?"
$Buttons = [System.Windows.MessageBoxButton]::'YesNo'
$Icon = [System.Windows.MessageBoxImage]::Question
[System.Windows.MessageBoxResult]$result = [System.Windows.MessageBox]::Show($Message, $Caption, $Buttons, $Icon)
if ($result -eq [System.Windows.MessageBoxResult]::Yes)
{
Write-Warning 'I am restarting...'
}
else
{
Write-Warning 'Ok, I am aborting...'
}
This code is much easier to edit in your PowerShell editor because you can now easily see the available options for dialog buttons and icons.
Cmdlets and .NET
In part 1, we explored the relationship between PowerShell cmdlets and .NET types. By now, youve seen that most cmdlets internally utilize existing .NET types and that you can call .NET types directly as well.
Now, weve reached the perfect point to illustrate why cmdlets exist and why using .NET methods directly isnt always the best choice. The message box dialog works well but requires dealing with fairly complex code and unfamiliar types.
Lets wrap a cmdlet around this code and see what happens. Of course, instead of a binary cmdlet wrapper, well use a PowerShell function:
#region reusable code
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...'
}
In the code region "reusable code," the new function Show-MessageBox is defined. It specifies the parameters with the correct types that the underlying .NET method requires.
In your script, you can now simply call Show-MessageBox whenever you need a dialog. Whats even better is that when you use parameters like -Buttons or -Icon, your PowerShell editor will display an IntelliSense list showing all the available options.
This is how most cmdlets work: they encapsulate complex .NET code so you can call a simple command. They define parameters using the exact types required by .NET, which provides you with convenient IntelliSense options.
Wrap Up
Our little journey illustrated that knowing .NET types (and how to directly call their methods) provides a lot of additional control. It is perfectly fine to directly call .NET types provided (a) there is no cmdlet for the same purpose already, and (b) calling .NET directly does not involve complex types and code.
If it does, as in the last example with the message box, you now understand why cmdlets exist: they are not in competition with .NET. Instead, they are a great way to simplify the user experience when .NET becomes too complex.
Your ultimate PowerShell Cheat Sheet
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.
Related links
- ScriptRunner ActionPacks provide ready-to-use PowerShell scripts.
- Try out ScriptRunner here
- ScriptRunner: Book a demo with our product experts