Changes between Version 1 and Version 2 of Programming/PowerShell/HowToPassCommandLineArgumentsBetweenScripts


Ignore:
Timestamp:
Feb 19, 2016, 3:38:42 PM (8 years ago)
Author:
Vijay Varadan
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Programming/PowerShell/HowToPassCommandLineArgumentsBetweenScripts

    v1 v2  
    1111
    1212A bit of code would help make the example concrete:
    13 {{{#!html
    14 <pre><strong>push0.ps1</strong>
    15 <span style="color: #008000;"># $args is the array of input arguments to any script
    16 # Do some work here common to all projects</span>
    17 <span style="color: #008000;"># like pushing code to the master repo for developer scripts, etc.</span>
    18 
    19 <span style="color: #008000;"># invoke project specific scripts here
    20 # $Env:Project will be set to quake, doom or wolf</span>
    21 <span style="color: #008000;"># call project specific push0 script if it exists </span>
    22 <span style="color: #008000;"># and pass all arguments to it</span>
     13**`push0.ps1`**
     14{{{#!powershell
     15# $args is the array of input arguments to any script
     16# Do some work here common to all projects
     17# like pushing code to the master repo for developer scripts, etc.
     18
     19# invoke project specific scripts here
     20# $Env:Project will be set to quake, doom or wolf
     21# call project specific push0 script if it exists
     22# and pass all arguments to it
    2323$scriptName = $Env:Project + ".push0.ps1"
    2424if (Test-Path $scriptName) {
    2525    &amp; $scriptName $args
    26 }</pre>
    27 }}}
    28 
    29 ----
    30 
    31 {{{#!html
    32 <pre><strong>quake.push0.ps1</strong>
    33 <span style="color: #008000;"># do quake specific work here
    34 </span>$pushFolder = Join-Path $Env:QuakeBaseDir "win32"
     26}
     27}}}
     28
     29----
     30
     31**`quake.push0.ps1`**
     32{{{#!powershell
     33# do quake specific work here
     34$pushFolder = Join-Path $Env:QuakeBaseDir "win32"
    3535cd $pushFolder
    3636hg push
     
    4040hg push
    4141
    42 <span style="color: #008000;"># now push any external sub-repos
    43 </span>$quakeExtBaseDir = Join-Path $Env:ExtBaseDir $QuakeExtWin32SubDir
     42# now push any external sub-repos
     43$quakeExtBaseDir = Join-Path $Env:ExtBaseDir $QuakeExtWin32SubDir
    4444$args | % {
    4545    $extFolder = Join-Path $quakeExtBaseDir $_
     
    4747    hg push
    4848}
    49 </pre>
    50 }}}
    51 
    52 ----
    53 
    54 {{{#!html
    55 <pre><strong>doom.push0.ps1</strong>
    56 <span style="color: #008000;"># do doom specific work here
    57 </span>$pushFolder = Join-Path $Env:DoomBaseDir "win16"
     49}}}
     50
     51----
     52
     53**`doom.push0.ps1`**
     54{{{#!powershell
     55# do doom specific work here
     56$pushFolder = Join-Path $Env:DoomBaseDir "win16"
    5857cd $pushFolder
    5958hg push
     
    6362hg push
    6463
    65 <span style="color: #008000;"># now push assembly language library repos
    66 </span>$doomAsmBaseDir = Join-Path $Env:AsmLibBaseDir $doomAsmSubDir
     64# now push assembly language library repos
     65$doomAsmBaseDir = Join-Path $Env:AsmLibBaseDir $doomAsmSubDir
    6766$args | % {
    6867    $asmFolder = Join-Path $doomAsmBaseDir $_
    6968    cd $asmFolder
    7069    hg push
    71 }</pre>
    72 }}}
    73 
    74 ----
    75 
    76 {{{#!html
    77 <pre><strong>wolf.push0.ps1</strong>
    78 <span style="color: #008000;"># do wolf specific work here
    79 </span>$pushFolder = Join-Path $Env:WolfBaseDir "dos"
     70}
     71}}}
     72
     73----
     74
     75**`wolf.push0.ps1`**
     76{{{#!powershell
     77# do wolf specific work here
     78$pushFolder = Join-Path $Env:WolfBaseDir "dos"
    8079cd $pushFolder
    8180hg push
     
    8584hg push
    8685
    87 <span style="color: #008000;"># now push dos assembly language library repos
    88 </span>$wolfAsmBaseDir = Join-Path $Env:AsmLibBaseDir $wolfAsmSubDir
     86# now push dos assembly language library repos
     87$wolfAsmBaseDir = Join-Path $Env:AsmLibBaseDir $wolfAsmSubDir
    8988$args | % {
    9089    $asmFolder = Join-Path $wolfAsmBaseDir $_
     
    9291    hg push
    9392}
    94 </pre>
    9593}}}
    9694
     
    103101The issue is that when `$args` is passed to `push0.ps1`, it's an array of parameters, but when you invoke another script from within `push0.ps1`, the `$args` array (i.e. all the parameters) is treated as a single parameter passed to the callee script. If I add a line to print out the arguments in `quake.push0.ps1` like this:
    104102
     103**`quake.push0.ps1`**
     104{{{#!powershell
     105...
     106...
     107Write-Host "Quake:- args[=" $args.Count "]: " $args
     108...
     109...
     110}}}
     111
     112And invoke `push0.ps1` passing in some arguments, then the output looks like this:
     113
    105114{{{#!html
    106 <pre><strong>quake.push0.ps1</strong>
    107 ...
    108 ...
    109 Write-Host "Quake:- args[=" $args.Count "]: " $args
    110 ...
    111 ...</pre>
    112 }}}
    113 
    114 And invoke `push0.ps1` passing in some arguments, then the output looks like this:
    115 
     115<pre>    $&gt; .\push0.ps1 boost libssl lua
     116    Quake:- args[=<span style="color: #ff0000;"><strong>1</strong></span>]: boost libssl lua</pre>
     117}}}
     118
     119As you can see, even though all 3 parameters are passed in, they are seen as ''a single parameter''.
     120
     121Essentially it would appear, that when the callee script is invoked, all 3 parameters as passed in as `$args[0]`. Now, Powershell is an object scripting language and it seems to pass an **array of strings** from the caller script as the first and only parameter to the callee script.
     122
     123Knowing that since Powershell is built on top of .NET and deals with objects, we can verify this by checking the type of `$args[0]` like this:
     124
     125**`quake.push0.ps1`**
     126{{{#!powershell
     127...
     128...
     129Write-Host $args[0].GetType().IsArray
     130...
     131...
     132}}}
     133
     134**`Output`**
    116135{{{#!html
    117 <pre>$&gt; .\push0.ps1 boost libssl lua
    118 Quake:- args[=<span style="color: #ff0000;"><strong>1</strong></span>]: boost libssl lua</pre>
    119   }}}
    120 
    121 As you can see, even though all 3 parameters are passed in, they are seen as <em>a single parameter</em>.
    122 
    123 Essentially it would appear, that when the callee script is invoked, all 3 parameters as passed in as `$args[0]`. Now, Powershell is an object scripting language and it seems to pass an <em>array of strings</em> from the caller script as the first and only parameter to the callee script.
    124 
    125 Knowing that since Powershell is built on top of .NET and deals with objects, we can verify this by checking the type of $args[0] like this:
    126 
    127 {{{#!html
    128 <pre><strong>quake.push0.ps1</strong>
    129 ...
    130 ...
    131 Write-Host $args[0].GetType().IsArray
    132 ...
    133 ...
    134 
    135 <strong>OUTPUT</strong>
    136 <span style="color: #0000ff;">True</span></pre>
     136<span style="color: #0000ff;"><pre>    True</pre></span></pre>
    137137}}}
    138138
     
    141141=== Solution ===
    142142
    143 What we need to do in the callees, is check if the incoming $args has only 1 parameter and if it's an array. If so, then simply use $args[0] as the actual list of arguments and process it below.
     143What we need to do in the callees, is check if the incoming $args has only 1 parameter and if it's an array. If so, then simply use `$args[0]` as the actual list of arguments and process it below.
    144144
    145145Since this bit of the code is common to multiple scripts, I put it in a function and stick it in the $PROFILE file or some other file that can be dot-sourced. Here's the function:
    146 {{{#!html
    147 <pre><strong><span style="color: #0000ff;">function UnwrapArguments($params) {</span></strong>
    148 <strong><span style="color: #0000ff;">    $unwrapped = @()</span></strong>
    149 <strong><span style="color: #0000ff;">    if ($params.Count -gt 0) {</span></strong>
    150 <strong><span style="color: #0000ff;">        if ($params.Count -eq 1 -and $params[0].GetType().IsArray) {</span></strong>
    151 <strong><span style="color: #0000ff;">            $unwrapped = $params[0]</span></strong>
    152 <strong><span style="color: #0000ff;">        } else {</span></strong>
    153 <strong><span style="color: #0000ff;">            $unwrapped = $params</span></strong>
    154 <strong><span style="color: #0000ff;">        }</span></strong>
    155 <strong><span style="color: #0000ff;">    }</span></strong>
    156 <strong><span style="color: #0000ff;">    return $unwrapped</span></strong>
    157 <strong><span style="color: #0000ff;">}</span></strong></pre>
    158 }}}
    159 
    160 So our scripts end up looking like this (changes in blue):
    161 
    162 {{{#!html
    163 <pre><strong>push0.ps1
    164 <span style="color: #0000ff;"># NOTE: No changes to the caller.</span></strong>
    165 <span style="color: #008000;"># $args is the array of input arguments to any script
    166 # Do some work here common to all projects</span>
    167 <span style="color: #008000;"># like pushing code to the master repo for developer scripts, etc.</span>
    168 
    169 <span style="color: #008000;"># invoke project specific scripts here
    170 # $Env:Project will be set to quake, doom or wolf</span>
    171 <span style="color: #008000;"># call project specific push0 script if it exists </span>
    172 <span style="color: #008000;"># and pass all arguments to it</span>
    173 $scriptName = $Env:Project + ".push0.ps1"
    174 if (Test-Path $scriptName) {
    175     &amp; $scriptName $args
    176 }</pre>
    177 }}}
    178 
    179 ----
    180 
    181 {{{#!html
    182 <pre><strong>quake.push0.ps1
    183 <span style="color: #0000ff;">$myargs = UnwrapArguments($args)
    184 </span></strong>
    185 <span style="color: #008000;"># do quake specific work here
    186 </span>$pushFolder = Join-Path $Env:QuakeBaseDir "win32"
     146
     147{{{#!powershell
     148function UnwrapArguments($params) {
     149    $unwrapped = @()
     150    if ($params.Count -gt 0) {
     151        if ($params.Count -eq 1 -and $params[0].GetType().IsArray) {
     152            $unwrapped = $params[0]
     153        } else {
     154            $unwrapped = $params
     155        }
     156    }
     157    return $unwrapped
     158}
     159}}}
     160
     161We make 0 (zero) changes in the caller and only 2 changes per callee. At the top of each callee file, we call `UnwrapArguments` and store it in `$myargs` (marked with comment: ` CHANGE #1 `) and further down in the script, we use `$myargs` instead of `$args` (marked with comment: ` CHANGE #2 `).
     162
     163So our scripts end up looking like this:
     164
     165**`push0.ps1`** - no changes.
     166
     167----
     168
     169**`quake.push0.ps1`**
     170{{{#!powershell
     171$myargs = UnwrapArguments($args) # CHANGE #1
     172
     173# do quake specific work here
     174$pushFolder = Join-Path $Env:QuakeBaseDir "win32"
    187175cd $pushFolder
    188176hg push
     
    192180hg push
    193181
    194 <span style="color: #008000;"># now push any external sub-repos
    195 </span>$quakeExtBaseDir = Join-Path $Env:ExtBaseDir $QuakeExtWin32SubDir
    196 <span style="color: #0000ff;"><strong>$myargs</strong></span> | % {
     182# now push any external sub-repos
     183$quakeExtBaseDir = Join-Path $Env:ExtBaseDir $QuakeExtWin32SubDir
     184$myargs</span> | % { # CHANGE #2, we use the unwrapped $myargs instead of $args
    197185    $extFolder = Join-Path $quakeExtBaseDir $_
    198186    cd $extFolder
    199187    hg push
    200188}
    201 </pre>
    202 }}}
    203 
    204 ----
    205 
    206 {{{#!html
    207 <pre><strong>doom.push0.ps1
    208 <span style="color: #0000ff;">$myargs = UnwrapArguments($args)
    209 </span></strong>
    210 <span style="color: #008000;"># do doom specific work here
    211 </span>$pushFolder = Join-Path $Env:DoomBaseDir "win16"
     189}}}
     190
     191----
     192
     193**`doom.push0.ps1`**
     194{{{#!powershell
     195$myargs = UnwrapArguments($args) # CHANGE #1
     196
     197# do doom specific work here
     198$pushFolder = Join-Path $Env:DoomBaseDir "win16"
    212199cd $pushFolder
    213200hg push
     
    217204hg push
    218205
    219 <span style="color: #008000;"># now push assembly language library repos
    220 </span>$doomAsmBaseDir = Join-Path $Env:AsmLibBaseDir $doomAsmSubDir
    221 <strong><span style="color: #0000ff;">$myargs</span></strong> | % {
     206# now push assembly language library repos
     207$doomAsmBaseDir = Join-Path $Env:AsmLibBaseDir $doomAsmSubDir
     208$myargs</span> | % { # CHANGE #2, we use the unwrapped $myargs instead of $args
    222209    $asmFolder = Join-Path $doomAsmBaseDir $_
    223210    cd $asmFolder
    224211    hg push
    225 }</pre>
    226 }}}
    227 
    228 ----
    229 
    230 {{{#!html
    231 <pre><strong>wolf.push0.ps1
    232 <span style="color: #0000ff;">$myargs = UnwrapArguments($args)
    233 </span></strong>
    234 <span style="color: #008000;"># do wolf specific work here
    235 </span>$pushFolder = Join-Path $Env:WolfBaseDir "dos"
     212}
     213}}}
     214
     215----
     216
     217**`wolf.push0.ps1`**
     218{{{#!powershell
     219$myargs = UnwrapArguments($args) # CHANGE #1
     220
     221# do wolf specific work here
     222$pushFolder = Join-Path $Env:WolfBaseDir "dos"
    236223cd $pushFolder
    237224hg push
     
    241228hg push
    242229
    243 <span style="color: #008000;"># now push dos assembly language library repos
    244 </span>$wolfAsmBaseDir = Join-Path $Env:AsmLibBaseDir $wolfAsmSubDir
    245 <strong><span style="color: #0000ff;">$myargs</span></strong> | % {
     230# now push dos assembly language library repos
     231$wolfAsmBaseDir = Join-Path $Env:AsmLibBaseDir $wolfAsmSubDir
     232$myargs</span> | % { # CHANGE #2, we use the unwrapped $myargs instead of $args
    246233    $asmFolder = Join-Path $wolfAsmBaseDir $_
    247234    cd $asmFolder
    248235    hg push
    249236}
    250 </pre>
    251237}}}
    252238