如何从C#向powershell.exe传递包含a的参数< SPACE>

jucafojl  于 2023-10-18  发布在  Shell
关注(0)|答案(2)|浏览(147)

我想在C#中启动一个进程,导致powershell启动另一个需要参数的程序,如:“M=a B”。我试过各种文字字符串格式,都无济于事。在PowerShell中,以下内容可以正常工作:

Start-Process -FilePath 'C:\MY.exe' -ArgumentList 'A','"M=a b"'

在C#中,以下内容无法正常工作(My.exe抛出:未找到“M=a”。)

string arg = @"Start-Process -FilePath 'C:\MY.exe' -ArgumentList 'A','""M=a b""'";
psTry("powershell.exe",arg)

static void psTry(string file,string arg)
{
    Process process = new Process();
    process.StartInfo.FileName = file;
    process.StartInfo.Arguments = arg;
    process.Start();
}

我在PowerShell和C#中尝试了各种“s”和“s”的组合。我试过

arg = @"...".ToString() + @"'""M=a b""'".ToString()
zwghvu4y

zwghvu4y1#

  • @"... '""M=a b""'"替换为@"... '\""M=a b\""'"
  • 这将在 *process命令行 * 上转换为逐字的'\"M=a b\"',这使得PowerShell最终将'"M=a b"'视为Start-Process调用中的-ArgumentList参数之一(如在您成功的会话中调用),其中-由于一个长期存在的错误,不会被修复,请参阅GitHub issue #5576-在MY.exe的进程命令行上作为逐字"M=a b"放置,完整内容如下:
  • "C:\MY.exe" A "M=a b"
  • 因此,在解析其命令行后,MY.exe将看到两个参数,分别具有逐字值AM=a b

也就是说,在C#逐字字符串中,使用\""生成\",这是将"通过 * 逐字 * 传递给最终执行的PowerShell命令所必需的。
powershell.exe,Windows PowerShell CLI,需要"字符。作为命令的一部分保留,作为\"进行转义[1]

  • 未转义 * "字符。假设仅在命令行上具有语法函数 *,因此在将参数(的串联)作为PowerShell代码进行评估之前被 * 删除 *。

完整地说明解决方案:

//  Note the `\` before `""`
string arg = @"-NoProfile Start-Process -FilePath 'C:\MY.exe' -ArgumentList 'A', '\""M=a b\""'";
psTry("powershell.exe", arg);

static void psTry(string file, string arg)
{
    Process process = new Process();
    process.StartInfo.FileName = file;
    process.StartInfo.Arguments = arg;
    process.Start();
}

退一步
如果唯一的意图是启动另一个带有参数的应用程序,则根本不需要涉及PowerShell CLI(powershell.exe-您可以**直接调用C:\MY.exe *,如下所示。

唯一需要注意的是,你必须设置process.StartInfo.UseShellExecute = true,以模仿Start-Process的默认行为,即**在 * 新窗口 * 中启动应用程序(进程):[2]

// Note how the arguments are passed *inside a single string*,
// with embedded double-quoting.
psTry("C:\MY.exe", @"A ""M=a b""");
void psTry(string file, string args)
{
    Process process = new Process();
    process.StartInfo.FileName = file;
    process.StartInfo.Arguments = args;
    process.StartInfo.UseShellExecute = true; // execute in NEW WINDOW
    process.Start();
}

如果您的C#应用程序使用的是**.NET Core/ .NET 5+而不是.NET Framework,参数传递甚至可以通过.ArgumentList属性简化/在概念上更清晰**,该属性-作为单字符串.Arguments属性的替代-接受 literal(未加引号)参数数组 *,.NET负责任何所需的引号和/或转义:

// .NET Core / .NET 5+ only:
// Pass the arguments as an *array* of *literal* tokens.
psTry("dep.exe", new [] { "A", "M=a b" });
void psTry(string file, string[] args)
{
    Process process = new Process();
    process.StartInfo.FileName = file;
    foreach (string arg in args)
    {
        process.StartInfo.ArgumentList.Add(arg);
    }
    process.StartInfo.UseShellExecute = true;
    process.Start();
}

[1]这同样适用于pwsh.exe,PowerShell(核心)CLI;后者可选择地接受"";此外,后者需要将-Command-c)放在命令参数之前,这在Windows PowerShell中是 * 隐含 * 的。
[2]事实上,这正是PowerShell的Start-Process插件在幕后所做的-它只是一个围绕System.Diagnostics.ProcessSystem.Diagnostics.ProcessStartInfo.NET API的PowerShell友好 Package 器。

gr8qqesn

gr8qqesn2#

实际上,cmd.exe显示了我的代码出错的地方。我不得不为 * powershell.exe * 和 * MY.exe * 分别添加一个 * \,其中*@**使错误不那么明显。感谢有耐心的助手。

相关问题