Revisiting The Packager and Command Line Arguments
- Details
- Written by David Corrales
- Last Updated: 22 April 2016
- Created: 25 October 2012
- Hits: 12930
The original The Packager and Command line Arguments blog article discussed how to pass parameters to a packaged executable. In this article we will revisit this subject and update the functions introduced in the previous article. The article will also cover how to simulate the packager parameters so that you can test your script without having to package it each time. This article’s example uses PowerShell Studio, but it is also applicable to PrimalScript.
Command Line Parsing Functions:
The original Convert-ArgumentsToDictionary function is no longer valid since PowerShell converts the Dictionary to an array when you return the object down the pipeline. Therefore, the function was updated so the Dictionary is passed to the function as a reference instead of being returned via the pipeline. The new function no longer requires you to call the Parse-Commandline function beforehand and thus it was renamed to Convert-CommandLineToDictionary to reflect these changes.
function Convert-CommandLineToDictionary { <# .SYNOPSIS Parses and converts the command line of a packaged executable into a Dictionary .DESCRIPTION Parses and converts the command line of a packaged executable into a Dictionary .PARAMETER Dictionary The Dictionary to load the value pairs into. .PARAMETER CommandLine The command line of the package executable .PARAMETER ParamIndicator The character used to indicate what is a parameter. .EXAMPLE $Dictionary = New-Object System.Collections.Specialized.StringDictionary Convert-CommandLineToDictionary -Dictionary $Dictionary `
-CommandLine $Commandline -ParamIndicator '-' #> Param( [ValidateNotNull()] [System.Collections.Specialized.StringDictionary]$Dictionary, [string]$CommandLine, [char] $ParamIndicator) $Params = Parse-Commandline $CommandLine for($index = 0; $index -lt $Params.Count; $index++) { [string]$param = $Params[$index] #Clear the values $key = "" $value = "" if($param.StartsWith($ParamIndicator)) { #Remove the indicator $key = $param.Remove(0,1) if($index + 1 -lt $Params.Count) { #Check if the next Argument is a parameter [string]$param = $Params[$index + 1] if($param.StartsWith($ParamIndicator) -ne $true ) { #If it isn’t a parameter then set it as the value $value = $param $index++ } } $Dictionary[$key] = $value }#else skip } }
The following is the updated Parse-Commandline function:
function Parse-Commandline { <# .SYNOPSIS Parses the command line of a package executable .DESCRIPTION Parses the command line of a package executable .PARAMETER Commandline The command line of the package executable .EXAMPLE $arguments = Parse-Commandline -Commandline $Commandline .INPUTS System.String .OUTPUTS System.Collections.Specialized.StringCollection #> [OutputType([System.Collections.Specialized.StringCollection])] Param([string]$CommandLine) $Arguments = New-Object System.Collections.Specialized.StringCollection if($CommandLine) { #Find First Quote $index = $CommandLine.IndexOf('"') while ( $index -ne -1) {#Continue as along as we find a quote #Find Closing Quote $closeIndex = $CommandLine.IndexOf('"',$index + 1) if($closeIndex -eq -1) { break #Can’t find a match } $value = $CommandLine.Substring($index + 1,$closeIndex – ($index + 1)) [void]$Arguments.Add($value) $index = $closeIndex #Find First Quote $index = $CommandLine.IndexOf('"',$index + 1) } } return $Arguments }
Simulating Packager Command line:
There are times you might want to test your command line inputs but don’t want to make debugging more difficult by having to package the script. As an alternative, you can simulate the packager’s command line and pass it as an argument to the debugger, thus bypassing the packaging stage.
Preparation:
A PowerShell Studio project is used as a basis for this example, but the same steps can apply to a single Form file (GUI Script) or a typical script.
Step 1: Define a parameter to accept the test command line
In the project’s startup.pfs file we define a parameter block as follows:
Param ($TestCommandline)
Note: Parameter blocks should always be defined at the top of the script. The same hold true if you are working with a Form.
Step 2: Replacing $CommandLine variable with the test variable
The packager creates the $CommandLine variable which contains the command line arguments that were used to call the packaged executable. In this case, we want to use a simulated command line but at the same time ensure our script will still run when packaged. In order to accommodate this, one must check if the $CommandLine variable has any contents before replacing its value.
In the case of a project, we add the check in the project’s Main function and only replace the $Commandline variable if its content is empty or null. Afterwards you can use the parsing functions to handle the $Commandline variable.
function Main { Param ([String]$Commandline) if(-not $Commandline) { $Commandline = $TestCommandline } $Dictionary = New-Object System.Collections.Specialized.StringDictionary Convert-CommandLineToDictionary -Dictionary $Dictionary -CommandLine $Commandline -ParamIndicator '-' #Output the original command line string "Command Line: {0}`r`n" -f $CommandLine | Write-Output #Display all the parsed command line values: $Dictionary | Format-Table @{label="Key";Expression={$_.Key}},@{label="Value";Expression={$_.Value}} | Write-Output ...
In normal scripts, insert the check right after the parameter definition.
For Form files you might want to consider calling the parsing functions in the Form’s Load event.
Step 3: Format the input to match that of the packager
In the original article we discussed how the $Commandline variable contains the parameters passed to the packaged exe. The packager’s $Commandline variable has each parameter and parameter value surrounded by individual double quotes.
For example:
mypackage.exe -Parameter1 Value1 -Parameter2 Value2
Results in $CommandLine variable containing the following string:
“-Parameter1” “Value1” “-Parameter2” “Value2”
In order to simulate the packager arguments you must alter your test parameter input as follows:
1. Wrap each individual parameter and parameter value in Double Quotes in order to mirror the packager’s behavior.
2. Wrap the whole parameters / values within single quotes, so that PowerShell treats it as a single string:
‘“-Parameter1” “Value1” “-Parameter2” “Value2”’
If you do not make the parameters into a single string, the TestCommandline variable would only contain the first item (in this case would be “-Parameter1”).
Now you are ready to simulate and test the packager command line!
When the script is executed, the $Commandline variable will be replaced with the $TestCommandline’s contents and you will be able to process the results correctly:
Debugging Tip:
In some instances you want to use the same test parameters every time you debug a particular script; therefore, we recommend using the DebugParameters meta-tag at the top of the script:
# %DebugParameters% = '"-Parameter1" "Value1" "-Parameter2" "Value2"'
Now when you debug the script, the specified parameters will be automatically selected.
New Snippet:
Snippets containing the command line parsing functions are included in PowerShell Studio v3.1.9 or greater and PrimalScript v6.5.134 or greater.
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.