{"id":10270,"date":"2015-11-30T06:00:00","date_gmt":"2015-11-30T14:00:00","guid":{"rendered":"https:\/\/www.sapien.com\/blog\/?p=10270"},"modified":"2015-12-04T16:30:16","modified_gmt":"2015-12-05T00:30:16","slug":"passing-parameters-to-a-script-in-an-executable-file","status":"publish","type":"post","link":"https:\/\/dev.sapien.com\/blog\/2015\/11\/30\/passing-parameters-to-a-script-in-an-executable-file\/","title":{"rendered":"Passing Parameters to a Script in an Executable File"},"content":{"rendered":"<p>This is the first blog in a multi-part series about designing a Windows PowerShell script that will be packaged in an executable file.<\/p>\n<ul>\n<li><strong>Passing Parameters to a Script in an Executable File<\/strong> explains how to use the special parsing features of PowerShell Studio and PrimalScript to make passing parameters easy for PowerShell users and authors.\n<\/p>\n<\/li>\n<li><a href=\"https:\/\/wp.me\/p3tXTf-2HV\" target=\"_blank\">Parsing Parameters for a Script in an Executable File<\/a> explains how to parse parameters manually for special uses.\n<\/p>\n<\/li>\n<li><a href=\"https:\/\/wp.me\/p3tXTf-2Hg\" target=\"_blank\">Displaying Help for a Script in an Executable File<\/a> explains how to display help for a script in an executable file.\n<\/p>\n<\/li>\n<li><a href=\"https:\/\/wp.me\/p3tXTf-2L5\" target=\"_blank\">Output from a Script in an Executable File<\/a> explains how to manage string output from a script in an executable file.<\/li>\n<\/ul>\n<p>&#8212;&#8211;<\/p>\n<p>PowerShell Studio and PrimalScript have great support for packing scripts in executable files. Windows PowerShell is an interpreted language, so you cannot compile it, but you can wrap scripts (.psm1) and simple modules (.psm1) files in an executable file<\/p>\n<p>I typically build executable files for GUI apps don&#8217;t have parameters, but you can build executable files for any script, including scripts that take parameters.<\/p>\n<p>However, passing parameters to a script inside a native .exe is not simple, because executable files don&#8217;t have built-in features to support objects other than strings or to support PowerShell&#8217;s parameter name and parameter value syntax.<\/p>\n<p>In the past, all parameters had to be positional, users had to enter parameter values without names, and enter them in the specified order, or your script would have to parse the input string and associate the values with the correct parameters.<\/p>\n<p>But, a new feature of <a href=\"https:\/\/www.sapien.com\/software\/powershell_studio\" target=\"_blank\">PowerShell Studio<\/a> (beginning in 4.2.96) and <a href=\"https:\/\/www.sapien.com\/software\/primalscript\" target=\"_blank\">PrimalScript<\/a> (beginning in 7.1.72), makes this much easier. You are still limited to strings values (and types that can parse string values). But, users can now enter parameter names and values, just as they do for a script. And new code in the executable file that PowerShell Studio and PrimalScript\u00a0builds\u00a0parses the input string and associates the parameter values with the correct parameters, so you don&#8217;t have to.<\/p>\n<h1>New input parsing for scripts in .exe files<\/h1>\n<p>An executable file can pass a string or an array of string values to the PowerShell script inside. It can&#8217;t handle any other value type. So, the first rule of writing scripts for exes is to use only parameters that take string values.<\/p>\n<p>Let&#8217;s start with a very simple script, New-WordTree.ps1, that repeats a specified word for an increasing number of specified times (default = 1). (Credit to PowerShell MVP <a href=\"https:\/\/www.twitter.com\/dfinke\">Doug Finke<\/a> for the <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2014\/09\/22\/fun-formatting-ones-part-1-the-task.aspx\" target=\"_blank\">neat idea<\/a>.) The script has a string parameter, Word, and an integer parameter, Number.<\/p>\n<pre lang=\"PowerShell\">Param\r\n(\r\n    [Parameter(Mandatory = $true)]\r\n    [String]$Word,\r\n    [int]$Number = 1\r\n)\r\n1..$Number | foreach { \"$Word\" * $_}<\/pre>\n<p>When you run this script as a .ps1 file, you can use parameter names and values.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.ps1 -Word PowerShell -Number 3\r\nPowerShell\r\nPowerShellPowerShell\r\nPowerShellPowerShellPowerShell<\/pre>\n<p>When you wrap this script in an executable file and use the same command line, it used to fail, because all input strings were interpreted as parameter values. In this case, &#8216;-Parameter&#8217; was interpreted as the value of the Word parameter and &#8216;PowerShell&#8217; was interpreted as the value of the Number parameter. The script failed when Windows PowerShell couldn&#8217;t convert &#8216;PowerShell&#8217; to a integer.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.exe -Word PowerShell -Number 3 \r\nLine 1: A positional parameter cannot be found that accepts argument 'PowerShell'.PS C:\\&gt;<\/pre>\n<p>But, the new input string parsing feature of PowerShell Studio and PrimalScript parses the input string for you so commands with parameter names and parameter values work correctly. You do not need to give the user special instructions or do any parsing in your script.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.exe -Word PowerShell -Number 3\r\nPowerShell \r\nPowerShellPowerShell \r\nPowerShellPowerShellPowerShell<\/pre>\n<p>I can even enter the parameters in an unspecified order, just as I can do in a script.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.exe\u00a0 -Number 3 -Word PowerShell\r\nPowerShell\r\nPowerShellPowerShell\r\nPowerShellPowerShellPowerShell<\/pre>\n<p>If the parameters are positional, which they are by default in a script or function with only one parameter set, you can omit parameter names, just as you can in a script.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.exe PowerShell 3\r\nPowerShell\r\nPowerShellPowerShell\r\nPowerShellPowerShellPowerShell<\/pre>\n<h1>Change Parameter Values to Strings<\/h1>\n<p>When writing a script that will be wrapped in an exe, use parameters that take string values. When you convert existing scripts for use in an exe, remember to change parameter input types to strings.<\/p>\n<p>You don&#8217;t need to rely solely on string parameters . Notice that the Number parameter in New-WordTree takes an Integer value, but you can use it in an executable file, because Windows PowerShell automatically converts the values from String to Integer for you. This conversion works for System.Double, too. For more complex objects, like process objects (System.Diagnostics.Process), the conversion associates only the name of the process with a string parameter. Its utility depends on what you intend to do with the object inside your script.<\/p>\n<p>This version of the New-WordTree.ps1 script has a Switch parameter that adds a space between the repeated words.<\/p>\n<pre lang=\"PowerShell\">Param\r\n(\r\n    [Parameter(Mandatory = $true)]\r\n    [String]$Word,\r\n\r\n    [int]$Number = 1,\r\n\r\n    [Switch]$AddSpace\r\n)\r\n\r\n$space = ''\r\nif ($AddSpace){ $space = ' ' }\r\n\r\n1..$Number | foreach { \"$Word$space\" * $_}<\/pre>\n<p>I can run this as a script.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\"C:\\ps-test\\New-WordTree.ps1\" -Word PowerShell -Number 3\r\nPowerShell\r\nPowerShellPowerShell\r\nPowerShellPowerShellPowerShell\r\n\r\nPS C:\\&gt; .\"C:\\ps-test\\New-WordTree.ps1\" -Word PowerShell -Number 3 -AddSpace\r\nPowerShell\r\nPowerShell PowerShell\r\nPowerShell PowerShell PowerShell<\/pre>\n<p>But, if I run it as an executable file, the AddSpace switch parameter is ignored.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.exe -Word PowerShell -Number 3 -AddSpace\r\nPowerShell \r\nPowerShellPowerShell \r\nPowerShellPowerShellPowerShell<\/pre>\n<p>If I add a value for the AddSpace parameter, such as $True, the command fails, because Windows PowerShell cannot convert the string to a type that the Switch parameter accepts.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.exe -Word PowerShell -Number 3 -AddSpace $True\r\nLine 1: A positional parameter cannot be found that accepts argument 'True'.PS C:\\&gt;\r\n\r\nPS C:\\&gt; .\\New-WordTree.exe -Word PowerShell -Number 3 -AddSpace \"$True\"\r\nLine 1: A positional parameter cannot be found that accepts argument 'True'.PS C:\\&gt;\r\n\r\nPS C:\\&gt; .\\New-WordTree.exe -Word PowerShell -Number 3 -AddSpace:$True\r\nLine 1: A parameter cannot be found that matches parameter name 'Addspace:True'.PS C:\\&gt;<\/pre>\n<p>Instead, you need to change the switch parameter to a type that takes a string value. In this example, I change the AddSpace switch parameter to a string parameter that takes values of True and False. I also change the IF statement to interpret the new values.<\/p>\n<pre lang=\"PowerShell\">Param\r\n(\r\n    [Parameter(Mandatory = $true)]\r\n    [String]$Word,\r\n\r\n    [int]$Number = 1,\r\n\r\n    [ValidateSet('True', 'False')]\r\n    [string]$AddSpace                #Change Switch to String\r\n)\r\n$space = ''\r\nif ($AddSpace -eq 'True'){ $space = ' ' }\r\n\r\n1..$Number | foreach { \"$Word$space\" * $_}<\/pre>\n<p>When I package this script in an executable, you can now run it by submitting a string value.<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.exe -Word PowerShell -Number 3 -AddSpace True\r\nPowerShell\r\nPowerShell PowerShell\r\nPowerShell PowerShell PowerShell\r\n\r\nPS C:\\&gt; .\\New-WordTree.exe -Word PowerShell -Number 3 -AddSpace $True\r\nPowerShell\r\nPowerShell PowerShell\r\nPowerShell PowerShell PowerShell<\/pre>\n<h1>Handling Multiple Values for a Parameter<\/h1>\n<p>If any script in an executable file has a parameter that takes multiple values, like a collection of strings or integers, the end-user must submit the value collection in a single comma-separated string enclosed in quotation marks. Then, in your script, you need to split the quoted string.<\/p>\n<p>Because the quoted string is submitted to the executable, not to Windows PowerShell, the <a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkID=113253\">standard PowerShell rules for quoted strings<\/a> do <b><u>not<\/u><\/b> apply.<\/p>\n<p>For example, in this version of New-WordTree.exe, the Word parameter takes multiple words.<\/p>\n<pre lang=\"PowerShell\">[Parameter(Mandatory = $true)]\r\n[String[]]$Word<\/pre>\n<p>To call the script in an exe, the user must enclose the value collection in single or double quotes. (This is unusual, so be sure to show the user how to do this in your <a href=\"https:\/\/wp.me\/p3tXTf-2Hg\" target=\"_blank\">help topic<\/a>.)<\/p>\n<pre class=\"output\">PS C:\\&gt; .\\New-WordTree.exe -Word \"PowerShell, NanoServer, DSC\" -Number 3 -AddSpace True\r\nPowerShell\r\nPowerShell PowerShell\r\nPowerShell PowerShell PowerShell\r\nNanoServer\r\nNanoServer NanoServer\r\nNanoServer NanoServer NanoServer\r\nDSC\r\nDSC DSC\r\nDSC DSC DSC\r\n<\/pre>\n<p>To handle these quoted strings in the script, you have to split the parameter value string on each comma. Also, to get rid of spaces, I call the Trim() method of strings. It&#8217;s a good habit to develop.<\/p>\n<pre lang=\"PowerShell\">$words = ($Word -split ',').Trim()<\/pre>\n<p>And, as you would in any script, you need to change your code to to handle multiple values, such as using a ForEach statement.<\/p>\n<pre lang=\"PowerShell\" escaped=\"true\">foreach ($item in $words)\r\n{\r\n     \r\n}<\/pre>\n<p>Here&#8217;s the result.<\/p>\n<pre lang=\"PowerShell\">Param\r\n(\r\n    [Parameter(Mandatory = $true)]\r\n    [String[]]$Word,\r\n\r\n    [int]$Number = 1,\r\n\r\n    [ValidateSet('True', 'False')]\r\n    [string]$AddSpace\r\n)\r\n\r\n# Split the parameter value array into strings\r\n$words = ($Word -split ',').Trim()\r\n\r\nforeach ($item in $words)\r\n{\r\n    $space = ''\r\n    if ($AddSpace -eq 'True')\r\n    { $space = ' ' }\r\n\r\n    1..$Number | foreach { \"$item$space\" * $_ }\r\n}<\/pre>\n<p>This once-difficult task of parsing input in an exe-wrapped script is now much easier. But, if you need to parse the input string manually, you can do that, too. In the a href=&#8221;https:\/\/wp.me\/p3tXTf-2Hg&#8221; target=&#8221;_blank&#8221;&gt;next post, we&#8217;ll display help for an executable file.<\/p>\n<p><i>June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at <\/i><a href=\"mailto:juneb@sapien.com\"><em>juneb@sapien.com<\/em><\/a><em> or follow her on Twitter at <\/em><a href=\"https:\/\/twitter.com\/juneb_get_help\"><em>@juneb_get_help<\/em><\/a><em>.<\/em><a href=\"https:\/\/wp.me\/p3tXTf-2HV\" target=\"_blank\">Parsing Parameters for a Script in an Executable File<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the first blog in a multi-part series about designing a Windows PowerShell script 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. [&hellip;]<\/p>\n","protected":false},"author":31,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[946,703,410],"tags":[1042,28,94,988,1016,37],"class_list":["post-10270","post","type-post","status-publish","format-standard","hentry","category-guiprogramming","category-powershell-studio","category-primalscript-software-news","tag-executable-files","tag-powershell","tag-powershell-development","tag-powershell-gui","tag-powershell-studio","tag-primalscript"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/10270","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/users\/31"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/comments?post=10270"}],"version-history":[{"count":63,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/10270\/revisions"}],"predecessor-version":[{"id":10621,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/10270\/revisions\/10621"}],"wp:attachment":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/media?parent=10270"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/categories?post=10270"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/tags?post=10270"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}