【问题标题】:Executing Powershell script from command line with quoted parameters使用带引号的参数从命令行执行 Powershell 脚本
【发布时间】:2013-05-23 05:24:38
【问题描述】:

我正在自动构建旧版 MS Access 应用程序,并且在其中一个步骤中,我正在尝试制作 Access 可执行文件 (.ADE)。我想出了以下代码,它存储在一个文件(PSLibrary.ps1)中:

Add-Type -AssemblyName Microsoft.Office.Interop.Access

function Access-Compile {
param (
    [Parameter(Mandatory=$TRUE,Position=1)][string]$source,
    [Parameter(Mandatory=$TRUE,Position=2)][string]$destination
)
    Write-Output "Starting MS Access"
    $access = New-Object -ComObject Access.Application
    $access.Visible = $FALSE
    $access.AutomationSecurity = 1

    if (!(Test-Path $source)) { Throw "Source '$source' not found" }
    if ((Test-Path $destination)) {
        Write-Output "File '$destination' already exists - deleting..."
        Remove-Item $destination
    }

    Write-Output "Compiling '$source' to '$destination'"
    $result = $access.SysCmd(603, $source, $destination)

    $result

    Write-Output "Exiting MS Access"
    $access.quit()
}

如果我进入 PowerShell ISE 并运行以下命令,那么一切正常,并创建了预期的输出:

PS C:>& "C:\Temp\PSLibrary.ps1"
PS C:>Access-Compile "C:\Working\Project.adp" "C:\Working\Project.ade"

但是,我似乎无法生成正确的 hocus-pocus 以从命令行运行它,就像在自动构建中那样。例如,

powershell.exe -command "& \"C:\\Temp\\PSLibrary.ps1\" Access-Compile \"C:\\Temp\\Project.adp\" \"C:\\Temp\\Project.ade\""

我做错了什么?

【问题讨论】:

    标签: powershell command-line escaping build-automation


    【解决方案1】:

    对于复杂的参数,可以使用Powershell的-EncodedCommand参数。它将接受 Base64 编码的字符串。引号、斜线等不需要转义。

    考虑一个将打印其参数的测试函数。像这样,

    function Test-Function {
    param (
        [Parameter(Mandatory=$TRUE,Position=1)][string]$source,
        [Parameter(Mandatory=$TRUE,Position=2)][string]$destination
    )
        write-host "src: $source"
        write-host "dst: $destination"
    }
    

    创建命令以加载脚本和一些参数。像这样,

    # Load the script and call function with some parameters
    . C:\Temp\Calling-Test.ps1;  Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""
    

    命令语法OK后,编码成Base64形式。像这样,

    [System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes('. C:\Temp\Calling-Test.ps1;  Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""'))
    

    你会得到一个 Base64 字符串。像这样,

    LgAgAEMAOgBcAFQAZQBtAHAAXABDAGEAbABsAGkAbgBnAC0AVABlAHMAdAAuAHAAcwAxADsAIAAgAFQAZQBzAHQALQBGAHUAbgBjAHQAaQBvAG4AIAAiAHMAbwBtAGUAXABzAHAAZQBjAGkAYQBsADoAYwBoAGEAcgBhAGMAdABlAHIAcwA/ACIAIAAiAGAAIgBjADoAXABtAHkAIABwAGEAdABoAFwAdwBpAHQAaABcAHMAcABhAGMAZQBzACAAdwBpAHQAaABpAG4ALgBlAHgAdABgACIAIgA=
    

    最后,启动 Powershell 并将编码后的字符串作为参数传递。像这样,

    # The parameter string here is abreviated for readability purposes.
    # Don't do this in production
    C:\>powershell -encodedcommand LgAgA...
    Output
    src: some\special:characters?
    dst: "c:\my path\with\spaces within.ext"
    

    如果您以后想要反转 Base64 编码,请将其传递给解码方法。像这样,

    $str = " LgAgA..."
    [Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($str))
    # Output
    . C:\Temp\Calling-Test.ps1;  Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""
    

    【讨论】:

    • 冒着提出愚蠢问题的风险,如何从 DOS 命令行生成编码命令?
    • 在运行自动构建时是否可行,其中参数可能因构建而异?\
    【解决方案2】:

    像 Bash 这样的 PowerShell 可以使用单引号或双引号

    PS C:\Users\Steven> echo "hello"
    hello
    PS C:\Users\Steven> echo 'hello'
    hello
    

    这可以减轻一些头痛,而且我认为您可以使用文字反斜杠而无需转义。

    要运行 PowerShell,请选择

    开始菜单 程序 附件 Windows Powershell Windows Powershell

    【讨论】:

    • 从 Powershell ISE 中运行时,我遇到的问题没有表现出来;这是我尝试从 CMD 运行它的时候。
    • 作为自动化构建的一部分,我将如何做到这一点?这就是我提问的目的。
    猜你喜欢
    • 2010-10-06
    • 1970-01-01
    • 2016-01-20
    • 2013-07-25
    • 2018-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多