Changes between Version 1 and Version 2 of Programming/PowerShell/HowToPassCommandLineArgumentsBetweenScripts
- Timestamp:
- Feb 19, 2016, 3:38:42 PM (9 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Programming/PowerShell/HowToPassCommandLineArgumentsBetweenScripts
v1 v2 11 11 12 12 A 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 script16 # 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 here20 # $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 23 23 $scriptName = $Env:Project + ".push0.ps1" 24 24 if (Test-Path $scriptName) { 25 25 & $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 here34 </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" 35 35 cd $pushFolder 36 36 hg push … … 40 40 hg push 41 41 42 <span style="color: #008000;"># now push any external sub-repos43 </span>$quakeExtBaseDir = Join-Path $Env:ExtBaseDir $QuakeExtWin32SubDir42 # now push any external sub-repos 43 $quakeExtBaseDir = Join-Path $Env:ExtBaseDir $QuakeExtWin32SubDir 44 44 $args | % { 45 45 $extFolder = Join-Path $quakeExtBaseDir $_ … … 47 47 hg push 48 48 } 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" 58 57 cd $pushFolder 59 58 hg push … … 63 62 hg push 64 63 65 <span style="color: #008000;"># now push assembly language library repos66 </span>$doomAsmBaseDir = Join-Path $Env:AsmLibBaseDir $doomAsmSubDir64 # now push assembly language library repos 65 $doomAsmBaseDir = Join-Path $Env:AsmLibBaseDir $doomAsmSubDir 67 66 $args | % { 68 67 $asmFolder = Join-Path $doomAsmBaseDir $_ 69 68 cd $asmFolder 70 69 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 here79 </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" 80 79 cd $pushFolder 81 80 hg push … … 85 84 hg push 86 85 87 <span style="color: #008000;"># now push dos assembly language library repos88 </span>$wolfAsmBaseDir = Join-Path $Env:AsmLibBaseDir $wolfAsmSubDir86 # now push dos assembly language library repos 87 $wolfAsmBaseDir = Join-Path $Env:AsmLibBaseDir $wolfAsmSubDir 89 88 $args | % { 90 89 $asmFolder = Join-Path $wolfAsmBaseDir $_ … … 92 91 hg push 93 92 } 94 </pre>95 93 }}} 96 94 … … 103 101 The 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: 104 102 103 **`quake.push0.ps1`** 104 {{{#!powershell 105 ... 106 ... 107 Write-Host "Quake:- args[=" $args.Count "]: " $args 108 ... 109 ... 110 }}} 111 112 And invoke `push0.ps1` passing in some arguments, then the output looks like this: 113 105 114 {{{#!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> $> .\push0.ps1 boost libssl lua 116 Quake:- args[=<span style="color: #ff0000;"><strong>1</strong></span>]: boost libssl lua</pre> 117 }}} 118 119 As you can see, even though all 3 parameters are passed in, they are seen as ''a single parameter''. 120 121 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 **array of strings** from the caller script as the first and only parameter to the callee script. 122 123 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: 124 125 **`quake.push0.ps1`** 126 {{{#!powershell 127 ... 128 ... 129 Write-Host $args[0].GetType().IsArray 130 ... 131 ... 132 }}} 133 134 **`Output`** 116 135 {{{#!html 117 <pre>$> .\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> 137 137 }}} 138 138 … … 141 141 === Solution === 142 142 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.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. 144 144 145 145 Since 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 & $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 148 function 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 161 We 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 163 So 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" 187 175 cd $pushFolder 188 176 hg push … … 192 180 hg push 193 181 194 <span style="color: #008000;"># now push any external sub-repos195 </span>$quakeExtBaseDir = Join-Path $Env:ExtBaseDir $QuakeExtWin32SubDir196 <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 197 185 $extFolder = Join-Path $quakeExtBaseDir $_ 198 186 cd $extFolder 199 187 hg push 200 188 } 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" 212 199 cd $pushFolder 213 200 hg push … … 217 204 hg push 218 205 219 <span style="color: #008000;"># now push assembly language library repos220 </span>$doomAsmBaseDir = Join-Path $Env:AsmLibBaseDir $doomAsmSubDir221 <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 222 209 $asmFolder = Join-Path $doomAsmBaseDir $_ 223 210 cd $asmFolder 224 211 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 here235 </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" 236 223 cd $pushFolder 237 224 hg push … … 241 228 hg push 242 229 243 <span style="color: #008000;"># now push dos assembly language library repos244 </span>$wolfAsmBaseDir = Join-Path $Env:AsmLibBaseDir $wolfAsmSubDir245 <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 246 233 $asmFolder = Join-Path $wolfAsmBaseDir $_ 247 234 cd $asmFolder 248 235 hg push 249 236 } 250 </pre>251 237 }}} 252 238