如何使用PowerShell将DOS样式的命令行拆分为其参数

时间:2015-08-12 07:16:40

标签: windows powershell

我有一个Powershell脚本(作为其中一个选项)从文件中读取用户定义的预执行命令,并需要执行它。 用户定义的预执行命令应该是普通的DOS样式命令。 我可以用空格分割命令,然后将它提供给PowerShell“&”执行它:

"C:\Program Files\Tool\program1" 25 "the quick brown fox"

但是如果用户定义的命令字符串有空格需要进入参数,或者命令的路径有空格,那么我需要更聪明地解析用户定义的字符串。

肉眼很明显,以下字符串在前面有一个命令后跟2个参数:

{{1}}

是否有人已经有一个函数可以解析这样的字符串并返回一个DOS样式命令的数组或列表以及每个参数?

3 个答案:

答案 0 :(得分:2)

有一个非常简单的解决方案。您可以滥用Powershell参数解析机制:

> $paramString = '1 blah "bluh" "ding dong" """foo"""'
> $paramArray = iex "echo $paramString"
> $paramArray 
1
blah
bluh
ding dong
"foo"

答案 1 :(得分:0)

最后我使用CommandLineToArgvW()来解析命令行。 有了这个,我可以在需要时将双引号字面地传递给参数,并且在双引号参数中有空格。 e.g:

abc def
23
"z"

成为具有3个参数的目录命令:

function Split-CommandLine
{
    <#
    .Synopsis
        Parse command-line arguments using Win32 API CommandLineToArgvW function.

    .Link
        https://github.com/beatcracker/Powershell-Misc/blob/master/Split-CommandLine.ps1
        http://edgylogic.com/blog/powershell-and-external-commands-done-right/

    .Description
        This is the Cmdlet version of the code from the article http://edgylogic.com/blog/powershell-and-external-commands-done-right.
        It can parse command-line arguments using Win32 API function CommandLineToArgvW . 

    .Parameter CommandLine
        A string representing the command-line to parse. If not specified, the command-line of the current PowerShell host is used.
    #>
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$CommandLine
    )

    Begin
    {
        $Kernel32Definition = @'
            [DllImport("kernel32")]
            public static extern IntPtr LocalFree(IntPtr hMem);
'@
        $Kernel32 = Add-Type -MemberDefinition $Kernel32Definition -Name 'Kernel32' -Namespace 'Win32' -PassThru

        $Shell32Definition = @'
            [DllImport("shell32.dll", SetLastError = true)]
            public static extern IntPtr CommandLineToArgvW(
                [MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine,
                out int pNumArgs);
'@
        $Shell32 = Add-Type -MemberDefinition $Shell32Definition -Name 'Shell32' -Namespace 'Win32' -PassThru
    }

    Process
    {
        $ParsedArgCount = 0
        $ParsedArgsPtr = $Shell32::CommandLineToArgvW($CommandLine, [ref]$ParsedArgCount)

        Try
        {
            $ParsedArgs = @();

            0..$ParsedArgCount | ForEach-Object {
                $ParsedArgs += [System.Runtime.InteropServices.Marshal]::PtrToStringUni(
                [System.Runtime.InteropServices.Marshal]::ReadIntPtr($ParsedArgsPtr, $_ * [IntPtr]::Size)
                )
            }
        }
        Finally
        {
            $Kernel32::LocalFree($ParsedArgsPtr) | Out-Null
        }

        $ret = @()

        # -lt to skip the last item, which is a NULL ptr
        for ($i = 0; $i -lt $ParsedArgCount; $i += 1) {
            $ret += $ParsedArgs[$i]
        }

        return $ret
    }
}

$executionCommand = Get-Content .\commands.txt
$executionArgs = Split-CommandLine $executionCommand
$executionCmd = $executionArgs[0]
$executionNumArgs = $executionArgs.Length - 1
if ($executionNumArgs -gt 0) {
    $executionArgs = $executionArgs[1..$executionNumArgs]
    echo $executionCmd $executionArgs
    & $executionCmd $executionArgs
} else {
    echo $executionCmd
    & $executionCmd
}

代码是:

<?php
if (ob_get_level() == 0) ob_start();

for ($i = 0; $i<10; $i++){
        echo "<br> Line to show.";
        echo str_pad('',4096)."\n";  

        ob_flush();
        flush();
}
echo "Done.";
ob_end_flush();
?>

答案 2 :(得分:0)

function ParseCommandLine($commandLine)
{
  return Invoke-Expression ".{`$args} $commandLine"
}