New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parameter invalid when it contains a colon. Works prior to 7.3.0. #18554
Comments
Use: $PSNativeCommandArgumentPassing = 'Legacy' for now as a workaround. We probably need to add |
@rmegal if you can confirm using |
Using $PSNativeCommandArgumentPassing = 'Legacy' works for sqlcmd. I will use Legacy for the scripts I have that use sqlcmd directly. Will I need to keep doing this once sqlcmd is in the legacy list? Not sure how the "legacy list" works. |
Once we have the list updated and backported to 7.3.x, the idea is that you can keep |
it is also likely that the triple back-tick is no longer needed (a single might do the trick with this new behavior) |
@rmegal, note that there's generally no reason to use The problem boils down to the following call, which is a workaround that builds on the fundamentally broken handling of embedded & sqlcmd -v MDF_FILEPATH=`"C:\Databases\junk.mdf`" In your particular case, given that value & sqlcmd -v MDF_FILEPATH=C:\Databases\junk.mdf However, if the value part - to the right of A workaround is then needed, because - behind the scenes, justifiably - PowerShell passes something like However, a workaround like A built-in, program-agnostic workaround that would make (non-workaround) calls simply work as-is going forward, was proposed in #15143, but, unfortunately, not implemented. The upshot is:
|
@mklement0 Right. I could have reproduced the problem without using The
Thanks for the nice explanation. I remember building that script years ago and wondering why including the back ticks made it work. Regardless, your point is, if I'm understanding correctly, I tried entering Is there something I'm missing regarding passing a colon in the value? Note: This is the same behavior in the |
You can still do that without Invoke-Expression $sqlCmdArgs = @(
'arg that is always set'
if ($someCondition) { 'args for sqlcml' }
'arg that is always set'
)
sqlcmd @sqlCmdArgs You can also splat multiple arrays or use args inline with splats so you aren't restricted to just this. Using
You need to quote the argument to avoid pwsh parameter binder from reading it differently sqlcmd -v 'MDF_FILEPATH=c:\test\junk.mdf' |
@jborean93 , good point about avoiding
In principle, yes, but there seems to be another wrinkle: PowerShell - again, justifiably - never uses double quotes behind the scenes if an argument doesn't contain spaces, even if in the original PowerShell command line quotes were used; that is, It seems that If that is the case, then truly only partial quoting helps; that is, the following must be placed on the process command line:
P.S.: I've written up a generalization of the above with additional background information in this Stack Overflow answer (albeit without discussing the specific |
@rmegal Can you please set $test = "&sqlcmd -v MDF_FILEPATH=`"C:\Databases\junk.mdf`""
invoke-expression $test In your original repro, the extra two backticks surrounding
When running with
In 7.3.0, the
With the above explanation, you should be able to make your script work again by just removing the extra two backticks when constructing |
@daxian-dbw, it seems to me this issue is entirely unrelated to The legacy workaround places the following on the process command line, which, I presume, worked:
In 7.3.0, the following is placed on the process command line:
If the former worked, why would you expect the latter to work, which is obviously different? Only if you interpreted the latter verbatim would you end up with |
@daxian-dbw I agree with @mklement0, the issue is unrelated to |
I'm not saying it's related to When the extra 2 backticks are removed, the original repro should just work in 7.3.0, and that's why I asked @rmegal to try if the following works in 7.3.0 after setting
Can you please provide another repo without using |
can be reduced to Since there are no embedded As @rmegal reports, such an unquoted token appears not to work with The workaround is to ensure double-quoting, selectively around the value part, so that verbatim
& { $PSNativeCommandArgumentPassing = 'Legacy'; sqlcmd -v MDF_FILEPATH=`"C:\Databases\junk.mdf`" } |
This is the part that I'm confused with. See my screenshots below (running in 7.2.7, which essentially uses the I replaced |
You need to look at the raw command line to see the difference, which Allow me to use some canned advice on how to get a utility that does:
The difference is that your first command places To an executable that uses the runtime-provided Microsoft C/C++/.NET argument parsing of the process command line, as However, here we're talking about an executable, To an executable that uses the runtime-provided Microsoft C/C++/.NET argument parsing, all of the following are equivalent, but to
The related executable-agnostic accommodation I proposed as part of #15143 focuses on values (the part of the argument to the right of However, it seems that |
@mklement0 This makes perfect sense to me now, thank you! |
@mklement0 One more question regarding When using the utility compiled from this answer, the However, when using the Both were on PS 7.2.7. |
Indeed, a .NET (Core) application (as opposed to a .NET Framework application) does not report the true raw command line: see dotnet/runtime#11305 (comment) |
@daxian-dbw and @mklement0 This was an eye opening conversation. Thanks a ton for weighing in. |
@daxian-dbw if it helps this is what I use to test out argv stuff on Windows Add-Type -OutputType ConsoleApplication -OutputAssembly print_argv.exe -TypeDefinition @'
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace PrintArgv
{
class Program
{
[DllImport("Kernel32.dll")]
public static extern IntPtr GetCommandLineW();
static void Main(string[] args)
{
IntPtr cmdLinePtr = GetCommandLineW();
string cmdLine = Marshal.PtrToStringUni(cmdLinePtr);
Console.WriteLine(cmdLine);
for (int i = 0; i < args.Length; i++)
{
Console.WriteLine("[{0}] {1}", i, args[i]);
}
}
}
}
'@ This unfortunately needs to run in WinPS but it can be run anywhere. It will output the raw command line value as well as the arguments as parsed by dotnet Note I haven't updated to 7.3.0 yet For Linux I've also used the following before #include<stdio.h>
int main(int argc, char *argv[])
{
int i;
for(i = 1;i < argc;i++)
{
printf("[%d] %s\n", i, argv[i]);
}
return 0;
} You can compile it with It is a bit more confusing there because Linux doesn't have a command line string but uses |
@jborean93 Thank you for sharing the code! |
Looks good, I have no idea what dotnet does for |
I assume you meant However, is there really a need for a new, separate option? Can't the existing
|
Glad to hear it.
I know I'm repeating myself, but I feel it bears repeating: such a legacy command list is a terrible idea; while it may selectively, obscurely help backward compatibility, it guarantees everlasting confusion going forward. |
@mklement0 |
Thanks for clarifying, @daxian-dbw. |
Hi, we are facing the same problem with msbuild and property values containing a semicolon or comma. We dont want to set $PSNativeCommandArgumentPassing script-wide because it may cause incompatibilities when including 3rd party modules/scripts which dont expect this. So we decided to go with local changes in scripts with the help of the following function: function Use-LegacyNativeCommandArgumentPassing {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[scriptblock]
$Script
)
if (!(test-path variable:PSNativeCommandArgumentPassing)) {
& $Script
return
}
$oldPSNativeCommandArgumentPassing = $PSNativeCommandArgumentPassing
try {
$PSNativeCommandArgumentPassing = 'Legacy'
& $Script
}
finally {
$PSNativeCommandArgumentPassing = $oldPSNativeCommandArgumentPassing
}
}
Which we are using this way: Use-LegacyNativeCommandArgumentPassing {
& 'msbuild.exe' @('test.target', "/p:Category=`"CI,Nightly`"")
}
Hope this helps someone else. |
Prerequisites
Steps to reproduce
Enter:
Expected behavior
Actual behavior
Error details
n/a
Environment data
Visuals
The text was updated successfully, but these errors were encountered: