PowerShell parameter passing with named parameters?
-
I haven't been able to find anything on this so far.
I have a PowerShell script that's basically C# code compiled and called by PowerShell. In that code is a call that uses the OLE driver to read from Excel. That driver only works in 32-bit mode for some reason. So I have a shim that relaunches 32-bit PowerShell:
&"pathtopowershellexe" -executionpolicy bypass -file "$($myInvocation.InvocationName)" $args
From what I can tell,
InvocationName
is the script path.Line
would be the full command, if it weren't a script file, but blank otherwise.$args
is the arguments and I have no idea how robust its flatting out is because PowerShell is like the worst parts of BAT with access to C# so probably not very.The immediate problem is, once you start using named parameters (
-someparameter somevalue
), they start being pulled out of$args
. So my question is, does anybody know how to pass along all of the named parameters automatically without having to specifically reference each of them? Something like this:&"pathtopowershell" -executionpolicy bypass -file "$($myInvocation.InvocationName)" $allArgsNamedAndUnnamed
So I want to run:
myscript.ps1 -named named unnamed
And have it pass:
myscript.ps1 -named named unnamed
-
Does order matter? Can you concatenate
$MyInvocation.UnboundArguments
with$MyInvocation.BoundParameters
in a meaningful way?
-
Instead of trying to coerce... can you back up a bit and explain what (not how) you are trying to accomplish....There is usually a clean way, but it often requires a change in mind set.
-
@TheCPUWizard said in PowerShell parameter passing with named parameters?:
Instead of trying to coerce... can you back up a bit and explain what (not how) you are trying to accomplish....There is usually a clean way, but it often requires a change in mind set.
Might have missed it, but he's trying to re-launch the script in 32-bit mode.
@Zenith said in PowerShell parameter passing with named parameters?:
That driver only works in 32-bit mode for some reason. So I have a shim that relaunches 32-bit PowerShell:
-
@Tsaukpaetra Order matters because they're passed into the array in the order they appear.
Let's say I want to send some text to a printer. Two ways to call that:
- A)
print.ps1 "hello world" "xerox"
- B)
print.ps1 -line "hello world" -printer "xerox"
# script A print-something $args[0] $args[1] # script B params ($line, $printer) print-something $line $printer # script C params ($line, $printer) print-something $args[0] $args[1]
Script A and script B work with command A.Command A works with script A and script B.
Script B works with command B.Command B only works with script B.
Script C doesn't work at all.So if I want to have support for named parameters,
params ($line, $printer)
, I have to manually pass$line
and$printer
to the 32-bit script.&"pathtopowershellexe32" -executionpolicy bypass -file "$($myInvocation.InvocationName)" $args
becomes
&"pathtopowershellexe32" -executionpolicy bypass -file "$($myInvocation.InvocationName)" "$line" "$printer"
And that's dumb because now I have to update it every time I add or change parameters.
@TheCPUWizard said in PowerShell parameter passing with named parameters?:
requires a change in mind set
That's great but I can neither control which version of PowerShell launches by default nor install any other way to read that Excel spreadsheet.
Edit: And I'll point out for those not following my daily escapades, I'm only doing any of this in CrippleShell because management cried about the original program being a real executable in a real programming language. If I hadn't been able to hijack the environment to compile that code more or less verbatim, I would've bailed out immediately.
- A)
-
Specify the
CmdletBinding
attribute in your script to get the desired behavior.[CmdletBinding()] param ($line, $printer) write-host $line $printer
That script works with both commands in my testing.
(Alternately I think you can specify explicit position #s for each parameter, but CmdletBinding seems simpler.)
-
@Zenith said in PowerShell parameter passing with named parameters?:
And that's dumb because now I have to update it every time I add or change parameters.
I think that's the point of named parameters though, that you eradicate position-based parameters.
Is there anything that says you absolutely must with-no-exception support positional arguments?
-
@Tsaukpaetra I think you're missing the point. With positional arguments, I just pass
$args
to the next script, whether I have 1 or 100. With named arguments, I have to explicitly specify each of them.
-
@Zenith said in PowerShell parameter passing with named parameters?:
I have to explicitly specify each of them.
@Tsaukpaetra said in PowerShell parameter passing with named parameters?:
$MyInvocation.BoundParameters
Iterate this dictionary, no need to specify anything....
-
@Zenith said in PowerShell parameter passing with named parameters?:
management cried about the original program being a real executable in a real programming language.
The real WTF
-
@HardwareGeek The joys of working in a non-IT IT department.
@Tsaukpaetra said in PowerShell parameter passing with named parameters?:
Iterate this dictionary, no need to specify anything....
Except it's still not the original command line that launched the script. It has to be escaped, it could be ordered differently, etc. Not being able to get the command line is a stupid omission. I found an example online where I can use WMI to get the process and the command line that launched it but that's a ridiculous hoop to have to jump through.
-
@Zenith can you call
System::Environment.CommandLine
perhaps (using whatever syntax powershell uses to call static properties on a .Net class).
-
@robo2 It's
[environment]::GetCommandLineArgs()
or[environment]::CommandLine
for the unsplit version.However, that would include all
-File myscript.ps1
and-executionpolicy bypass
so you would be forced to filter those out....
-
-
@Zenith I thought I wrote a reply earlier but apparently I didn't. Does the
param
command have to be the first in script? If not, maybe try copying$args
to a new variable brforehand to avoid mangling?
-
@Gąska Yes, param() has to be the first non-commented line or it throws an unrecognized command exception.
-
@Zenith
[environment]::GetCommandLineArgs()
was the key. I stripped the first item, requoted everything without a dash, and manually added-executionpolicy bypass
back in. It appears to work () and that'll have to be good enough.
-
I'm assuming there's a huge behind why you need a 32-bit shell.
-
@error said in PowerShell parameter passing with named parameters?:
I'm assuming there's a huge behind why you need a 32-bit shell.
@Zenith said in PowerShell parameter passing with named parameters?:
In that code is a call that uses the OLE driver to read from Excel. That driver only works in 32-bit mode for some reason.
I'm sure if that OLE code could work in 64-bit mode the re-launch would be unnecessary.
-
@error The is Microsoft not allowing/supporting installing both versions of the OLE driver for Excel/Access. Yes, there are some backward ways to probably get past the check against what version of Office you have, but I'm dealing with IT staff whose sophistication level is barely "clicks the big blue E to download the interwebs."
-
@Zenith said in PowerShell parameter passing with named parameters?:
@TheCPUWizard said in PowerShell parameter passing with named parameters?:
requires a change in mind set
That's great but I can neither control which version of PowerShell launches by default nor install any other way to read that Excel spreadsheet.
I was referring to a change in how YOU think. What is considered "Good" (and what is now), among many other things...
It is hard (trust me, I know) to put aside years/decades (a Quadragenarian career of thoughts)...
But when changing context (another place where this is true is moving from .Net 4.x to.Net 5.0) it can enable many things, and a failure to do so can inhibit them.