当我将参数传递给嵌套的 Start-Process 命令时,PowerShell 删除了多个连续的空格 [英] PowerShell removes multiple consecutive whitespaces when I pass arguments to a nested Start-Process command

查看:18
本文介绍了当我将参数传递给嵌套的 Start-Process 命令时,PowerShell 删除了多个连续的空格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个 powershell 代码运行良好:

This powershell code works fine:

powershell -NoProfile -Command {Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '"C:UsersTestAccountDesktopcartella  con  spazi	est.vbs" "/CurrentDirectory:C:UsersTestAccountDesktopCartella  con  spazi" "/AppData:C:UsersTestAccountAppDataRoaming"'}

但是当我输入完整的命令时,powershell 在单词之间只留下一个空格,但在我的路径中有两个连续的:

But when I enter the complete command, powershell leaves only one space between the words but in my path there are two consecutive ones:

Start-Process -FilePath powershell.exe -WorkingDirectory "$env:ALLUSERSPROFILE" -Credential $credential -WindowStyle Hidden -ArgumentList "-NoProfile -Command & {Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '`"C:UsersTestAccountDesktopcartella  con  spazi	est.vbs`" `"/CurrentDirectory:C:UsersTestAccountDesktopCartella  con  spazi`" `"/AppData:C:UsersTestAccountAppDataRoaming`"'}"

同样的错误:

Start-Process -FilePath powershell.exe -WorkingDirectory "$env:ALLUSERSPROFILE" -Credential $credential -WindowStyle Hidden -ArgumentList "-NoProfile -Command Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '`"C:UsersTestAccountDesktopcartella  con  spazi	est.vbs`" `"/CurrentDirectory:C:UsersTestAccountDesktopCartella  con  spazi`" `"/AppData:C:UsersTestAccountAppDataRoaming`"'"

这是错误信息:

如您所见,在错误消息中,路径在单词之间仅包含一个空格,而在代码中我正确输入了两个连续的空格.

As you can see, in the error message the path contains only one space between words, while in the code I have correctly entered two consecutive ones.

这是输入凭据的代码(就在给出错误的行之前):

This is the code to enter the credentials (just before the line that gives an error):

$username = 'Username'
$password = 'Password'
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword

几天来我一直在让一行代码正常工作,但没有成功.
我输入的那些示例路径实际上是变量(具有不定数量的连续空格),因此通过将 -ArgumentList 括在单引号中,变量不会被扩展.
您可以采用您认为最适合帮助我的策略.
Windows 10 专业版 64 位
Powershell 版本:5.1.19041.1237(集成在 Windows 10 中).

I've been getting a single line of code to work properly for days but without success.
Those example paths I entered are actually variables (with an indefinite number of consecutive spaces) and therefore by enclosing -ArgumentList in single quotes, the variables are not expanded.
You can adopt the strategy you think is most appropriate to help me.
Windows 10 Pro 64-bit
Powershell Version: 5.1.19041.1237 (Integrated in Windows 10).

更新:

@mklement0 问题在于,实际上有问题的行包含一个可扩展变量:

@mklement0 There is the problem that in reality the line in question contains an expandable variable:

Start-Process -FilePath powershell.exe -WorkingDirectory "$env:ALLUSERSPROFILE" -Credential $credential -WindowStyle Hidden -ArgumentList @"
-NoProfile -Command "Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '"$PWD	est.vbs" "/CurrentDirectory:$PWD" "/AppData:$env:APPDATA"'"
"@

因此,如果路径包含单引号,则该行会出错.

so if the path contains single quotes, the line goes in error.

更新 2:

@mklement0 您的解决方案已停止工作,因为我将它放入我需要的脚本中,并显示以下错误消息:

@mklement0 Your solution has stopped working since I put it in a script, which is what I need, with the following error message:

推荐答案

注意:这个答案解决了 Start-Process 问题;对于 .ps1 文件的不相关问题,在文件资源管理器中双击时,路径中有空格的文件无法运行,请参阅 这个答案.

Note: This answer addresses the Start-Process problem; for the unrelated problem with .ps1 files whose paths have spaces in them failing to run when they are double-clicked in File Explorer, see this answer.

尝试以下操作,参数通过逐字逐句:

Try the following, with the arguments passed verbatim:

Start-Process `
  -FilePath powershell.exe `
  -WorkingDirectory "$env:ALLUSERSPROFILE" `
  -Credential $credential `
  -WindowStyle Hidden `
  -ArgumentList @'
    -NoProfile -Command "Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '"C:UsersTestAccountDesktopcartella  con  spazi	est.vbs" "/CurrentDirectory:C:UsersTestAccountDesktopCartella  con  spazi" "/AppData:C:UsersTestAccountAppDataRoaming"'"
'@

  • -Command 参数包含在 "..." 中,以便按原样保留命令内部空间.

    • The -Command argument is enclosed in "..." in order to preserve the command-internal spaces as-is.

      命令字符串中的嵌入 "字符转义为"

      The embedded " characters in the command string are escaped as "

      外部 -ArgumentList 使用 here-string 以简化嵌入的引用.

      The outer -ArgumentList uses a here-string to simplify the embedded quoting.

      • 这里使用逐字逐句形式(@'<newline>...<newline>'@);如果您需要字符串插值(嵌入变量引用和表达式的能力),请使用 _expandable 形式 @"<newline>...<newline><@ - 请参阅下一节.
      • The verbatim form (@'<newline>...<newline>'@) is used here; use the _expandable form, @"<newline>...<newline>"@, if you need string interpolation (the ability to embed variable references and expressions) - see next section.

      而 PowerShell-在内部`,即反引号,用作转义字符,PowerShell 的 CLI 期望 " 字符为 -在命令行转义,以符合最广泛使用的转义约定.

      While PowerShell-internally it is `, the backtick, that serves as the escape character, PowerShell's CLI expects " characters to be -escaped on the command line, so as to conform to the most widely used escaping convention.

      • The cross-platform PowerShell (Core) 7+ edition now also accepts "" as an alternative to ", another common convention on Windows.

      虽然您可能需要结合这两种转义方法,即使用 `" 来引用 " first 用于 CLI,then 用于 PowerShell 内部使用,在解释 -Command 参数的上下文中,这不是在上面的命令中需要,因为内部 -ArgumentList 参数使用 single-quoting,其中 " 可以按原样使用.

      While you may situationally have to combine the two escaping approaches, i.e. to use `" in order to quote a " first for the CLI and then for PowerShell-internal use, in the context of interpreting a -Command argument, this isn't needed in the command above, because the inner -ArgumentList argument uses single-quoting, inside of which " can be be used as-is.

      广义解决方案,通过变量提供参数:

      Generalized solution, with arguments provided via variables:

      假设要使用其值的变量名为 $dir1$dir2$dir3(并且它们的值没有嵌入的 " 字符.但 Windows 上的文件系统路径不支持 ").

      The assumption is that the variable whose value are to be used are named $dir1, $dir2, and $dir3 (and that their values have no embedded " chars., but " aren't supported in file-system paths on Windows anyway).

      Start-Process `
        -FilePath powershell.exe `
        -WorkingDirectory "$env:ALLUSERSPROFILE" `
        -Credential $credential `
        -WindowStyle Hidden `
        -ArgumentList @"
          -NoProfile -Command "Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '"$($dir1 -replace "'", "''")" "/CurrentDirectory:$($dir2 -replace "'", "''")" "/AppData:$($dir3 -replace "'", "''")"'"
      "@
      

      • here-string (@"<newline>...<newline>"@) 的 插值 形式现在必须是用于外部 -ArgumentList 参数.

        • The interpolating form of a here-string (@"<newline>...<newline>"@) must now be used for the outer -ArgumentList argument.

          由于变量值被插入到 powershell.exe 将被视为单引号字符串 ('...') 的内容中,因此任何 >' 嵌入在变量值中的字符必须转义为 '',这就是 - 替换 ""'", "''"在嵌入式 $(...) 子表达式 可以.

          Since the variable values are interpolated inside what powershell.exe will see as a single-quoted string ('...'), any ' characters embedded in the variable values must be escaped as '', which is what -replace "'", "''" in the embedded $(...) subexpressions does.

          很难诊断调用外部程序的问题,尤其是在这样的嵌套调用中.

          It can be difficult to diagnose problems with calls to external programs, especially in a nested call such as this.

          以下创建一个辅助可执行文件,echoArgsPause.exe,它回显调用它的完整命令行,以及它解析命令行的各个参数,然后等待一个按键.

          The following creates a helper executable, echoArgsPause.exe, which echoes the full command line it was called with, as well as the individual arguments it has parsed the command line into, and then waits for a keystroke.

          注意:

          • 作为基于 .NET 的 *.exe,它使用 .NET 的命令行解析规则,而后者又基于 微软的 C/C++约定.不幸的是,并非所有可执行文件都保证使用相同的约定.而且,确实,WSH CLI(cscript.exewscript.exe)不支持 embedded "例如,参数中的字符.

          • As a .NET-based *.exe, it uses .NET's rules for command-line parsing, which in turn is based on Microsoft's C/C++ conventions. Unfortunately, not all executables are guaranteed to use the same conventions. And, indeed, the WSH CLIs (cscript.exe and wscript.exe) do not support embedded " characters in arguments, for instance.

          Windows PowerShell 运行代码,因为从 PowerShell (Core) 7.2 开始,通过 可执行文件="https://docs.microsoft.com/powershell/module/microsoft.powershell.utility/add-type" rel="nofollow noreferrer">Add-Type 不是支持.

          Run the code from Windows PowerShell, because, as of PowerShell (Core) 7.2, creating executables via Add-Type isn't supported.

          为了以后重用,将生成的 .echoArgsPause.exe 文件放在 PATH 中的目录中(在 $env:PATH 中列出的目录中).

          For later reuse, place the resulting .echoArgsPause.exe file in a directory in your PATH (in a directory listed in $env:PATH).

          要创建不等待击键的变体,请删除 Console.Write("Press a key to exit: ");Console.ReadKey(true); 行并将 -OutputAssembly .echoArgsPause.exe 更改为 -OutputAssembly ./echoArgs.exe

          To create a variant that doesn't wait for a keystroke, remove the Console.Write("Press a key to exit: "); and Console.ReadKey(true); lines and change -OutputAssembly .echoArgsPause.exe to, say, -OutputAssembly ./echoArgs.exe

          Add-Type -OutputType ConsoleApplication -OutputAssembly .echoArgsPause.exe -TypeDefinition @'
            using System;
            static class ConsoleApp {
              static int Main(string[] args) {
                Console.WriteLine("
          raw: [{0}]
          ", Environment.CommandLine);
                for (int i = 0; i < args.Length; ++i) {
                    Console.WriteLine("arg #{0}: [{1}]", i, args[i]);
                }
                Console.Write("Press a key to exit: ");
                Console.ReadKey(true);
                return 0;
              }
            }
          '@
          

          使用 echoArgsPause.exe 解决呼叫问题

          • 以下自包含示例代码使用您的命令的简化版本,并使用 echoArgsPause.exe 代替您的目标可执行文件 (wscript.exe)打印命令行和解析的参数.
          • Use of echoArgsPause.exe to troubleshoot a call

            • The following, self-contained sample code uses a simplified version of your command, and uses the echoArgsPause.exe in lieu of your target executable (wscript.exe) to print the command line and the parsed arguments.
            • # Specify the full path to the helper executable.
              # Here I'm assuming it is in the current dir.
              $echoArgsPausePath = "$($PWD.ProviderPath)echoArgsPause.exe"
              
              # Sample variable values.
              $dir1='c:	emp''o  1'
              $dir2='c:	emp   2'
              $dir3='c:	emp    3'
              
              # Call your command, with echoArgsPause.exe in lieu
              # of the target executable (wscript.exe)
              Start-Process `
                -FilePath powershell.exe `
                -WorkingDirectory "$env:ALLUSERSPROFILE" `
                -WindowStyle Hidden `
                -ArgumentList @"
                -NoProfile -Command "Start-Process -FilePath "$echoArgsPausePath" -Verb RunAs -ArgumentList '"$($dir1 -replace "'", "''")" "/CurrentDirectory:$($dir2 -replace "'", "''")" "/AppData:$($dir3 -replace "'", "''")"'"
              "@
              

              这篇关于当我将参数传递给嵌套的 Start-Process 命令时,PowerShell 删除了多个连续的空格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆