繁体   English   中英

PowerShell Start-Process argumentlist escape '|' 变量中的 pipe 字符

[英]PowerShell Start-Process argumentlist escape '|' pipe character in a variable

当使用-ArgumentList运行Start-Process并传递字符串数组$configArgs时,它有一个包含特殊字符的字符串,即 pipe ( | )。 pipe 字符来自添加了--windowsLogonPassword的最后一个变量$passwordtemp

由于 pipe 字符,我收到以下错误消息,

“文件名、目录名或卷 label 语法不正确。”

有什么想法可以避免这种情况吗?

[CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "NoVersion")]
param(
    [parameter(Mandatory = $false)]
    [string]$AgentDirectory = [IO.Path]::Combine($env:USERPROFILE, "VSTSAgents"),
 
    [parameter(Mandatory = $false)]
    [string]$Work,
 
    [parameter(Mandatory = $false)]
    [string]$Name = [System.Environment]::MachineName + "-$(Get-Random)",
 
    [parameter(Mandatory = $false)]
    [string]$Pool = 'Default',
 
    [parameter(Mandatory = $true)]
    [string]$PAT,
 
    [parameter(Mandatory = $true)]
    [uri]$ServerUrl,
 
    [parameter(Mandatory = $false)]
    [switch]$Replace,
 
    [parameter(Mandatory = $false)]
    [pscredential]$LogonCredential,
 
    [parameter(Mandatory = $false)]
    [string]$Cache = [io.Path]::Combine($env:USERPROFILE, ".vstsagents")
)
 
if ($PSVersionTable.Platform -and $PSVersionTable.Platform -ne 'Win32NT') {
    throw "Not Implemented: Support for $($PSVersionTable.Platform), contributions welcome."
}
 
if ( $Verbose ) { $VerbosePreference = 'Continue' }
 
$existing = Get-VSTSAgent -AgentDirectory $AgentDirectory -NameFilter $Name
if ( $existing ) { 
    if ($Replace) { 
        Uninstall-VSTSAgent -NameFilter $Name -AgentDirectory $AgentDirectory -PAT $PAT -ErrorAction Stop
    }
    else { throw "Agent $Name already exists in $AgentDirectory" }
}
 
$findArgs = @{ 'Platform' = 'win' }
if ( $MinimumVersion ) { $findArgs['MinimumVersion'] = $MinimumVersion }
if ( $MaximumVersion ) { $findArgs['MaximumVersion'] = $MaximumVersion }
if ( $RequiredVersion ) { $findArgs['RequiredVersion'] = $RequiredVersion }
 
$agent = Find-VSTSAgent @findArgs | Sort-Object -Descending -Property Version | Select-Object -First 1
if ( -not $agent ) { throw "Could not find agent matching requirements." }
 
Write-Verbose "Installing agent at $($agent.Uri)"
 
$fileName = $agent.Uri.Segments[$agent.Uri.Segments.Length - 1]
$destPath = [IO.Path]::Combine($Cache, "$($agent.Version)\$fileName")
 
if ( -not (Test-Path $destPath) ) {
 
    $destDirectory = [io.path]::GetDirectoryName($destPath)
    if (!(Test-Path $destDirectory -PathType Container)) {
        New-Item "$destDirectory" -ItemType Directory | Out-Null
    }
 
    Write-Verbose "Downloading agent from $($agent.Uri)"
    try {  Start-BitsTransfer -Source $agent.Uri -Destination $destPath }
    catch { throw "Downloading $($agent.Uri) failed: $_" }
}
else { Write-Verbose "Skipping download as $destPath already exists." }
 
$agentFolder = [io.path]::Combine($AgentDirectory, $Name)
Write-Verbose "Unzipping $destPath to $agentFolder"
 
if ( $PSVersionTable.PSVersion.Major -le 5 ) {
    Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop
}
 
[System.IO.Compression.ZipFile]::ExtractToDirectory($destPath, $agentFolder)
 
$configPath = [io.path]::combine($agentFolder, 'config.cmd')
$configPath = Get-ChildItem $configPath -ErrorAction SilentlyContinue
if ( -not $configPath ) { throw "Agent $agentFolder is missing config.cmd" }
 
[string[]]$configArgs = @('--unattended', '--url', "$ServerUrl", '--auth', `
        'pat', '--pool', "$Pool", '--agent', "$Name", '--runAsService')
if ( $Replace ) { $configArgs += '--replace' }
if ( $LogonCredential ) { $configArgs += '--windowsLogonAccount', $LogonCredential.UserName }
if ( $Work ) { $configArgs += '--work', $Work }
 
if ( -not $PSCmdlet.ShouldProcess("$configPath $configArgs", "Start-Process") ) { return }
 
$token = [System.Net.NetworkCredential]::new($null, $PAT).Password
$configArgs += '--token', $token
 
if ( $LogonCredential ) {
    $passwordtemp = [System.Net.NetworkCredential]::new($null, $LogonCredential.Password).Password
    $configArgs += '--windowsLogonPassword', $passwordtemp
        
}
 
$outFile = [io.path]::Combine($agentFolder, "out.log")
$errorFile = [io.path]::Combine($agentFolder, "error.log")
 
Write-Verbose "Registering $Name to $Pool at $ServerUrl"
Start-Process $configPath -ArgumentList $configArgs -NoNewWindow -Wait `
    -RedirectStandardOutput $outFile -RedirectStandardError $errorFile -ErrorAction Stop
 
if (Test-Path $errorFile) {
    Get-Content $errorFile  | Write-Error
}

有两个因素在起作用:

  • 不幸的是, Start-Process中的一个长期存在的错误需要在 arguments 周围使用包含空格的嵌入式双引号,例如-ArgumentList '-foo', '"bar baz"' - 请参阅此答案

  • 调用批处理文件 ( .cmd ) 时,命令行被 - 不恰当地 - 解析为好像它是由cmd.execmd.exe内部提交的,需要包含cmd.exe元字符的无空格 arguments,例如| 要么被双引号引起来,要么将元字符单独^ -转义。

您可以手动补偿这些行为,如下所示:

$configArgsEscaped = 
  switch -Regex ($configArgs) {
    '[ ^&|<>",;=()]' { '"{0}"' -f ($_ -replace '"', '""') }
    default          { $_ } # no double-quoting needed 
}

现在在Start-Process调用中使用-ArgumentList $configArgsEscaped代替-ArgumentList $configArgs

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM