Azure Pipelines:如何在 Powershell 任务中成功执行 BITS 传输?

Azure Pipelines: How to do successful BITS-Transfer in Powershell task?

找不到任何地方的答案。

我需要我的管道调用必须多次执行 BITS 传输的 powershell 脚本。起初,脚本总是会因以下错误而退出:

Start-BitsTransfer : The operation being requested was not performed because the user has not 
logged on to the 
network. The specified service does not exist. (Exception from HRESULT: 0x800704DD)

然后,在 Powershell 任务中,我没有调用文件,而是将其更改为执行以下内联脚本:

powershell -File $(Build.Repository.LocalPath)\installer\assembly.win10.x64.ps1 -Credential Get-Credential [Domain]\[Username]

现在脚本运行了,但我在 Azure Pipelines 的日志中看到了这个:

Microsoft Visual C++ 2015 Redistributable x64 : downloading...
Start-BitsTransfer : The operation being requested was not performed because the user has not 
logged on to the 
network. The specified service does not exist. (Exception from HRESULT: 0x800704DD)
At C:\agents\_work\s\installer\assembly.win10.x64.ps1:9 char:5
+     Start-BitsTransfer -Source $Url -Destination $Target
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [Start-BitsTransfer], COMException
+ FullyQualifiedErrorId : 
System.Runtime.InteropServices.COMException,Microsoft.BackgroundIntelligentTransfer.Management.NewBitsTransferCommand

Microsoft Visual C++ 2015 Redistributable x64 : download completed

管道通过了,但是当我检查实际的可再发行组件的 .exe 时,它​​的大小为 0 字节。所以,文件夹似乎已经制作好并压缩了,文件也放在了它们需要的地方,但下载实际上并没有起作用。 我也在本地机器上测试了 powershell 脚本,没有问题。我该如何解决这个问题?

这是相关代码。前三块是下载相关的方法,最后是方法调用:

function Get-FileSha256([string]$Src) {
  return (Get-FileHash "$Src" -Algorithm SHA256).Hash
}

function Download-File([string]$Comment, [string]$Url, [string]$Target) {
  Write-Host "$Comment : downloading..."
  New-Item -ItemType File -Path "$Target" -Force | Out-Null
  Import-Module BitsTransfer
  Start-BitsTransfer -Source $Url -Destination $Target
  Write-Host "$Comment : download completed"
}

function Download-FileIfNecessary([string]$Comment, [string]$Url, 
  [string]$Target, [string]$Sha256) {
  If (!(Test-Path $Target)) {
    Download-File "$Comment" "$Url" "$Target"
    return
  }

  $TargetSha256 = Get-FileSha256 $Target
  If ($TargetSha256 -eq $Sha256) {
    Write-Host "$Comment : already downloaded"
  }
  Else {
    Download-File "$Comment" "$Url" "$Target"
  }
}

Download-FileIfNecessary "Microsoft Visual C++ 2015 Redistributable x64" `
  "https://download.microsoft.com/download/6/A/A/6AA4EDFF-645B-48C5-81CC-ED5963AEAD48/vc_redist.x64.exe" `
  "$target_downloaded_vc_redist_dir15.v14.0.24215\vc_redist.x64.exe" `
  "da66717784c192f1004e856bbcf7b3e13b7bf3ea45932c48e4c9b9a50ca80965"

我将提供使用 BITS 的替代方法,因为 BITS 设计为在请求者是本地经过身份验证的用户时使用,not by remote sessions, service accounts, or other non-interactive contexts。我已经 re-written Download-File 使用 Invoke-WebRequest 而不是
Start-BitsTransfer:

Function Download-File {
  Param(
    [string]$Comment,
    [string]$Url,
    [string]$Target
  )

  Write-Host "$Comment : downloading..."

  # We need to check that the target folder exists later
  $targetFolder = Split-Path -Parent $Target

  # Prepare cmdlet arguments for splatting
  $iwrArgs = @{
    UseBasicParsing = $true
    Uri             = $Url
    OutFile         = $Target
  }

  $newDirArgs = @{
    ItemType = 'Directory'
    Path     = $targetFolder
  }

  # Create the target parent dir, if it doesn't exist
  if ( !( Test-Path -PathType Container $targetFolder ) ) {

    Write-Host "Creating directory $targetFolder"
    New-Item @newDirArgs | Out-Null
  }

  # Workaround progress bar performance bug with Invoke-WebRequest
  # (also affects Invoke-RestMethod) by disabling it
  $OldProgressPreference = $ProgressPreference
  $ProgressPreference = 'SilentlyContinue'

  # Use a try / finally block to guarantee the
  # original progress preference is changed back
  try {

    Invoke-WebRequest @iwrArgs -EA Stop
  }
  finally {

    $ProgressPreference = $OldProgressPreference
  }
}

如果您对每个部分的作用感兴趣,我已经对代码进行了评论。如果有问题我可以澄清。

您应该可以删除它来代替您当前的 Download-File 定义。我会推荐这个而不是尝试 hacky OS 技巧来使 BITS 在它不是设计的上下文中工作。也不建议将 BITS 与关键自动化一起使用,因为它的下载可以随时被 OS 暂停(例如,在下载更新时)。

请注意,我所说的 non-interactive 登录是正确的。从计划任务或 user-run 脚本中使用 BITS 应该是安全的,而不是从 Windows 服务(Azure 代理是)中使用。