Question:
Inspired by this post, I created the script below DOSCommands.ps1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Function Invoke-DOSCommands { Param( [Parameter(Position=0,Mandatory=$true)] [String]$cmd, [String]$tmpname = $(([string](Get-Random -Minimum 10000 -Maximum 99999999)) + ".cmd"), [switch]$tmpdir = $true) if ($tmpdir) { $cmdpath = $(Join-Path -Path $env:TEMP -ChildPath $tmpname); } else { $cmdpath = ".\" + $tmpname } Write-Debug "tmpfile: " + $cmdpath Write-Debug "cmd: " + $cmd echo $cmd | Out-File -FilePath $cmdpath -Encoding ascii; & cmd.exe /c $cmdpath | Out-Null } Invoke-DOSCommands "Echo ""Hello World""", -tmpdir $false |
However, on execution it returns this error:
1 2 3 4 5 6 |
Invoke-DOSCommands : Cannot process argument transformation on parameter 'cmd'. Cannot convert value to type S ystem.String. At DOSCommands.ps1:20 char:19 + Invoke-DOSCommands <<<< "Echo ""Hello World""", -tmpdir $false + CategoryInfo : InvalidData: (:) [Invoke-DOSCommands], ParameterBindin...mationException + FullyQualifiedErrorId : ParameterArgumentTransformationError,Invoke-DOSCommands |
I’ve searched for this error but can’t figure it out. It seems to me that it can’t convert the string type correctly! Please help!
Answer:
Your best bet is to use --%
in PowerShell V3 or higher. See this blog post I wrote on using --%
. In V1/V2 the situation is just bad as you can see in this Connect bug on the issue. The common workaround in V1/V2 is to use Start-Process or .NET’s Process.Start. From those list of workarounds, I kind of like this one:
1 2 |
[System.Diagnostics.Process]::Start("Cmd", "/c anything you want to put here with embedded quotes, and variables") |
Which is effectively what --%
does to the parsing of all parameters following it i.e. it parses them in a dumbed down mode similar to cmd.exe parameter parsing including expanding env vars referenced with %envVarName%
.