Displaying Help for a Script in an Executable File
- Details
- Written by June Blender
- Last Updated: 13 June 2016
- Created: 09 December 2015
- Hits: 12624
This is the third article in a multi-part series about designing a Windows PowerShell scripts that will be packaged in an executable file.
- Passing Parameters to a Script in an Executable File explains how to use the special parsing features of PowerShell Studio and PrimalScript to make passing parameters easy for PowerShell users and authors.
- Parsing Parameters for a Script in an Executable File explains how to parse parameters manually for special uses.
- Displaying Help for a Script in an Executable File explains how to display help for a script in an executable file.
- Output from a Script in an Executable File explains how to manage string output from a script in an executable file.
—–
The Get-Help cmdlet displays help topics about concepts and modules (About topics) and about commands (cmdlets, scripts, functions, workflows, and CIM commands). It does not display help topics for applications in executable files.
When you wrap a Windows PowerShell script in an executable file, even if the script has comment-based or XML help, Get-Help cannot find the help file. However, you can use a few techniques to restore some help functionality.
Recognize Help Strings
As we learned in Part 1 of this series, all parameters in a script that is wrapped in an executable file must take string types or types that Windows PowerShell converts from strings. So, we can use selected strings to recognize that the user is looking for help, instead of trying to run the command.
For example, I have a Get-InputTypes.ps1 script that finds parameters that take pipeline input. The script has a mandatory CmdletName parameter that specifies the name of the command to analyze.
When I run the .exe normally, it returns input type information.
PS C:\> .\Get-InputTypes.exe -CmdletName Get-Command TypeNames ParameterName ValueFromPipelineByPropertyName --------- ------------- ------------------------------- System.String[] Name True
The CmdletName parameter is positional, so I don’t need to type the parameter name.
.\Get-InputTypes.exe Invoke-Command TypeNames ParameterName ValueFromPipelineByPropertyName --------- ------------- --------------------------- System.Management.Automation.PSObject InputObject True
But, when I run it with a value of ‘Help’ or ‘/?’, it displays help.
PS C:\> .\Get-InputTypes.exe /? NAME Get-InputTypes.exe SYNOPSIS Gets input types for cmdlet help topics. SYNTAX Get-InputTypes.ps1 [-CmdletName] <String> [-Full <String>] DESCRIPTION This app gets the input types for a cmdlet help topic, that is, it gets the .NET types that you can pipe to the cmdlet. By default, it gets only types that can be piped ...
Here’s how I did it.
First, I added a $HelpString variable that contains help for the cmdlet. (For details, see Create a Help String‘. Next, I changed the first parameter in the script (Position 0) to recognize values of ‘/?’ and ‘Help’. Windows PowerShell has special processing for the ‘-?’ string, so I avoid that one.
This script has a CmdletName parameter that is mandatory and, by default, position 0.
[CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [ValidateScript({Get-Command $_})] [String]$CmdletName, [Parameter()] [ValidateSet('True', 'False')] [String]$Full ) |
To add help functionality, removed the ValidateScript attribute.
[CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [String]$CmdletName, [Parameter()] [ValidateSet('True', 'False')] [String]$Full ) |
Then, I added a condition that looks for CmdletName values of ‘Help’ and ‘/?’. If found, the script displays a $HelpString string, instead of its regular processing.
if ($CmdletName -eq 'Help' -or $CmdletName -eq '/?') { $HelpString } elseif ($full -eq 'True') ... |
Add a Help Parameter
If you want to be a bit more sophisticated, rather than using the CmdletName parameter for an unintended use, you can add a Help parameter.
Here’s the original parameter set of the script:
[CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [ValidateScript({Get-Command $_})] [String]$CmdletName, [Parameter()] [ValidateSet('True', 'False')] [String]$Full ) |
I added a Help parameter that takes a string value. Then, because the CmdletName and Help parameters are exclusive, I’ve created separate ‘DefaultSet’ and ‘HelpSet’ parameter sets.
In a script or function, the parameters are positional by default. But when you add parameter sets, all parameters become named. For most cases, named parameters are a best practice. However, in this case, I want the user to be able to type: ‘Get-InputTypes.exe /?’ so I make the Help parameter mandatory and position 0 in the HelpSet parameter set.
Here’s the result.
[CmdletBinding(DefaultParameterSetName = 'DefaultSet')] param ( [Parameter(ParameterSetName = 'DefaultSet', Mandatory = $true. Position=0)] [ValidateScript({Get-Command $_})] [String]$CmdletName, [Parameter(ParameterSetName = 'DefaultSet', Position=1)] [ValidateSet('True', 'False')] [String]$Full, [Parameter(ParameterSetName = 'HelpSet', Mandatory = $true, Position = 0)] [String]$Help ) |
I also added code to take any value of the Help parameter.
if ($Help) { $HelpString } elseif ($Full -eq 'True') { ... |
Now, when I wrap the script in an exe and run it:
PS C:\>.\Get-InputTypes.exe -CmdletName Set-ExecutionPolicy TypeNames ParameterName ValueFromPipelineByPropertyName --------- ------------- -------------------------- Microsoft.PowerShell.ExecutionPolicy ExecutionPolicy True PS C:\> .\Get-InputTypes.exe -Help True NAME Get-InputTypes.exe SYNOPSIS Gets input types for cmdlet help SYNTAX Get-InputTypes.exe [-CmdletName] <String> [-Full <String>] Get-InputTypes.exe [-Help] <String> ... PS C:\> .\Get-InputTypes.exe /? NAME Get-InputTypes.exe SYNOPSIS Gets input types for cmdlet help SYNTAX Get-InputTypes.exe [-CmdletName] <String> [-Full <:String>] Get-InputTypes.exe [-Help] <String> ...
Make Help the Default
Many traditional command-line tools display help as the default. That is, if you run the command without parameters, it displays help. This is not true for Windows PowerShell. In fact, many PowerShell cmdlets, including Get-Command, Get-Process, and Get-Module, have very useful default displays. But, if you want to make your .exe file display help by default, it’s pretty easy to do that.
If you made your Position 0 parameter accepts special values, like ‘/?’ and ‘Help’, you can make that parameter optional. Then, add a case for a $Null or empty string value (if !$CmdletName…).
[CmdletBinding()] Param ( [Parameter()] [String]$CmdletName, [Parameter()] [ValidateSet('True', 'False')] [String]$Full ) if (!$CmdletName -or $CmdletName -eq 'Help' -or $CmdletName -eq '/?') { $HelpString } elseif ($full -eq 'True') ... |
If you created a Help parameter in its own parameter set, to make the Help parameter accept an empty value:
— Make the Help parameter optional
— Make the HelpSet parameter set the default
— Check for the HelpSet parameter set in the script
For example:
[CmdletBinding(DefaultParameterSetName = 'HelpSet')] param ( [Parameter(ParameterSetName = 'DefaultSet', Mandatory = $true)] [ValidateScript({Get-Command $_})] [String]$CmdletName, [Parameter(ParameterSetName = 'DefaultSet')] [ValidateSet('True', 'False')] [String]$Full, [Parameter(ParameterSetName = 'HelpSet', Mandatory = $false, Position = 0)] [String]$Help ) if ($PSCmdlet.ParameterSetName -eq 'HelpSet') { $HelpString } elseif ($Full -eq 'True') { ... |
Now, when I wrap the script in an exe and run it with no parameters, I get the help.
PS C:\> .\Get-InputTypes.exe NAME Get-InputTypes.exe SYNOPSIS Gets input types for cmdlet help topics. SYNTAX Get-InputTypes.ps1 [[-Help] <String>] Get-InputTypes.ps1 [-CmdletName] <String> [-Full <String>] DESCRIPTION This app gets the input types for a cmdlet help topic, that is, it gets the .NET types that you can pipe to the cmdlet. By default, it gets only types that can be piped ...
And, I can still use the Help parameter explicitly with any value.
PS C:\> .\Get-InputTypes.exe -Help /? NAME Get-InputTypes.exe SYNOPSIS Gets input types for cmdlet help topics. SYNTAX Get-InputTypes.ps1 [[-Help] <String>] Get-InputTypes.ps1 [-CmdletName] <String> [-Full <String>] DESCRIPTION This app gets the input types for a cmdlet help topic, that is, it gets the .NET types that you can pipe to the cmdlet. By default, it gets only types that can be piped ...
Create a Help String
There are many ways to create the $HelpString value for a Windows PowerShell script in an executable file.
To make it look like the Get-Help display, I write comment-based or XML help for script, run ‘Get-Help <ScriptName>.ps1 -Full,’ copy the content that Get-Help returns, and paste it in a here-string in my script. To make it easier to read, I add a few blank lines at the top and bottom of the string.
$helpString = @" NAME C:\ps-test\Get-InputTypes.ps1 SYNOPSIS Gets input types for cmdlet help SYNTAX Get-InputTypes.exe [-CmdletName] <String> [-Full &lt:String>] Get-InputTypes.exe [-Help] <String> DESCRIPTION This script gets the input types for a cmdlet help topic, that is, it gets the .NET types that you can pipe to the cmdlet. … "@ |
It’s much easier to use Get-Help to display help, but when it’s not available, it’s great to have easy substitutes.
June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at This email address is being protected from spambots. You need JavaScript enabled to view it. or follow her on Twitter at @juneb_get_help.
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.