如何在Azure DevOps Pipeline中强制使用PowerShell 7执行远程脚本?
之前使用Azure DevOps Pipelines结合PowerShell Remoting执行PS1脚本,Pipeline配置如下:
trigger: none jobs: - job: PSRemoting timeoutInMinutes: 5760 pool: name: 'DevOps-Agent2-VM' steps: - checkout: none - task: PowerShellOnTargetMachines@3 displayName: 'PSRemoting' inputs: Machines: '$(VM-PublicIP)' UserName: '$(VM-UserName)' UserPassword: '$(VM-Password)' InlineScript: | . C:\Scripts\Test-Parallel.ps1
后续脚本中加入了PowerShell 7专属的-Parallel特性,执行后失败,错误日志如下:
2022-11-02T13:37:18.3246154Z ForEach-Object : Parameter set cannot be resolved using the specified named parameters. At line:1 char:1 + & 'C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe' -NoLogo ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (ForEach-Object ...med parameters.:String) [], RemoteException + FullyQualifiedErrorId : NativeCommandError At C:\Scripts\Test-Parallel.ps1:3 char:10 + $items | ForEach-Object -Parallel { + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : MetadataError: (:) [ForEach-Object], ParentContainsErrorRecordExcep tion + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.ForEachObjectCo mmand ##[error]Non-Zero exit code: '1' for ComputerName: 'VM1' ##[error]Atleast one remote job failed. Consult logs for more details. ErrorCodes(s): 'RemoteDeployer_NonZeroExitCode' ##[section]Finishing: PSRemoting
涉及的Test-Parallel.ps1脚本内容:
$items = 1..100 $items | ForEach-Object -Parallel { Write-Host "$(Get-Date) | Sleeping for 1 second..." Start-Sleep 1 } -ThrottleLimit 10
ForEach-Object -Parallel是PowerShell 7及以上版本才引入的特性,而PowerShellOnTargetMachines@3任务默认会调用Windows系统内置的WindowsPowerShell(版本为5.1,路径C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe),该版本不支持-Parallel参数,因此触发参数解析错误。
前提条件
确保目标虚拟机($(VM-PublicIP)指向的机器)已经安装了PowerShell 7,安装后默认可执行文件路径为C:\Program Files\PowerShell\7\pwsh.exe(64位)或C:\Program Files (x86)\PowerShell\7\pwsh.exe(32位)。
方法1:显式调用PowerShell 7执行脚本
修改Pipeline中PowerShellOnTargetMachines@3任务的InlineScript内容,直接调用pwsh.exe来运行目标脚本,替代默认的WindowsPowerShell:
- task: PowerShellOnTargetMachines@3 displayName: 'PSRemoting' inputs: Machines: '$(VM-PublicIP)' UserName: '$(VM-UserName)' UserPassword: '$(VM-Password)' InlineScript: | # 调用PowerShell 7执行脚本 & "C:\Program Files\PowerShell\7\pwsh.exe" -File "C:\Scripts\Test-Parallel.ps1"
如果需要在当前会话中点源脚本(而非单独运行),可以使用-Command参数:
InlineScript: | & "C:\Program Files\PowerShell\7\pwsh.exe" -Command ". C:\Scripts\Test-Parallel.ps1"
方法2:设置环境变量优先调用PowerShell 7(可选)
如果希望在远程会话中默认使用PowerShell 7,可以在InlineScript中临时修改环境变量的PATH,将PowerShell 7的路径放在最前面:
InlineScript: | $env:PATH = "C:\Program Files\PowerShell\7;$env:PATH" # 此时调用powershell会优先使用pwsh.exe . C:\Scripts\Test-Parallel.ps1
修改Pipeline后重新运行,确认脚本中的ForEach-Object -Parallel能够正常执行,不再出现参数解析错误。
内容的提问来源于stack exchange,提问作者WinBoss

