Ansible远程执行PowerShell脚本时无限期卡住问题求助
问题:Ansible远程执行PowerShell脚本无限期卡住
- 场景:调用一个创建Hyper-V虚拟机的PowerShell脚本,脚本本地运行正常,但通过Ansible远程执行时卡住
- 脚本功能:接收3个参数(Hyper-V服务器、存储分区、虚拟机名称),从NAS复制sysprepped VHD文件,完成虚拟机创建与配置
- Playbook内容:
- hosts: windows_host tasks: - name: Run remote PowerShell script win_shell: powershell.exe -ExecutionPolicy ByPass -File C:/Path/To/Script/Script.ps1 {{ server }} {{ partition }} {{ hostname }}
- 执行命令:
ansible-playbook /etc/ansible/playbook.yml --extra-var "server=server.mydomain.local partition=E: hostname=devtest" -vvvv
- 异常现象:WinRM连接建立后无后续输出,卡在
EXEC (via pipeline wrapper)阶段;但简单脚本(如创建指定名称文件)可正常执行
环境信息
Ansible版本
ansible [core 2.12.10] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3/dist-packages/ansible ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0] jinja version = 2.10.1 libyaml = True
目标主机信息(ansible -i hosts windows_host -m setup输出片段)
- 操作系统:Microsoft Windows Server 2022 Datacenter
- 网络地址:192.168.0.100(Hyper-V网络适配器)
Inventory配置
[windows_host] windows_host.MYDOMAIN.LOCAL [windows_host:vars] ansible_user=windows_user@MYDOMAIN.LOCAL ansible_password= {{ password }} ansible_connection=winrm ansible_port=5985 ansible_winrm_transport=kerberos ansible_winrm_server_cert_validation=ignore ansible_winrm_read_timeout_sec: 60 ansible_winrm_operation_timeout_sec: 58
涉问题PowerShell脚本内容
$userName="user" $File="C:\Path\To\User\user.txt" $hyperv_host=$args[0] $partition=$args[1] $host_name=$args[2] $credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "$userName", (Get-Content $File | ConvertTo-SecureString) $PSDefaultParameterValues = @{'Invoke-Command:ConfigurationName'='remote_host' } $nas_location = "Microsoft.PowerShell.Core\FileSystem::\\path\in\NAS\location\VHD\sysprep.vhdx" Invoke-Command -Credential $credentials -ScriptBlock { (New-Item -Verbose "$using:partition\$using:host_name" -type directory) (Copy-Item -Verbose -Path "$using:nas_location" -Destination "$using:partition\$using:host_name") (Write-Host "VHD successfully copied from \\NAS\") (Rename-Item -Verbose -Path "$using:partition\$using:host_name\sysprep.vhdx" -NewName "$using:host_name.vhdx") (New-VM -Verbose -Name "$using:host_name" -MemoryStartupBytes 16GB -Generation 2 -Path "$using:partition\$using:host_name" -BootDevice VHD -VHDPath "$using:partition\$using:host_name\$using:host_name.vhdx") (Set-VMProcessor -Verbose "$using:host_name" -Count 4) } -ComputerName $hyperv_host
解决建议
1. 调高WinRM超时阈值
当前配置的ansible_winrm_read_timeout_sec=60和ansible_winrm_operation_timeout_sec=58过短,复制大VHD文件、创建虚拟机属于长耗时操作,需大幅调高:
[windows_host:vars] # 根据VHD大小调整,示例设为5分钟 ansible_winrm_read_timeout_sec=300 ansible_winrm_operation_timeout_sec=290
2. 移除嵌套远程调用
脚本中通过Invoke-Command再次连接Hyper-V服务器,而Ansible已通过WinRM建立远程会话,嵌套调用易引发阻塞。修改脚本直接在Ansible会话上下文执行(需确保Ansible使用的账号拥有Hyper-V管理权限和NAS访问权限):
$hyperv_host=$args[0] $partition=$args[1] $host_name=$args[2] # 直接执行所有操作,去掉Invoke-Command嵌套 New-Item -Verbose "$partition\$host_name" -type directory Copy-Item -Verbose -Path "\\path\in\NAS\location\VHD\sysprep.vhdx" -Destination "$partition\$host_name" Write-Host "VHD successfully copied from \\NAS\" Rename-Item -Verbose -Path "$partition\$host_name\sysprep.vhdx" -NewName "$host_name.vhdx" New-VM -Verbose -Name "$host_name" -MemoryStartupBytes 16GB -Generation 2 -Path "$partition\$host_name" -BootDevice VHD -VHDPath "$partition\$host_name\$host_name.vhdx" Set-VMProcessor -Verbose "$host_name" -Count 4
3. 改用Ansible原生模块替代脚本
使用Windows专属模块更可靠,且便于调试:
- 先安装
community.windows集合:ansible-galaxy collection install community.windows - 示例Playbook片段:
- hosts: windows_host tasks: - name: 创建虚拟机目录 win_file: path: "{{ partition }}\\{{ hostname }}" state: directory - name: 从NAS复制VHD文件 win_robocopy: src: "\\\\path\\in\\NAS\\location\\VHD" dest: "{{ partition }}\\{{ hostname }}" files: sysprep.vhdx recurse: no - name: 重命名VHD文件 win_command: Rename-Item "{{ partition }}\\{{ hostname }}\\sysprep.vhdx" "{{ hostname }}.vhdx" - name: 创建Hyper-V虚拟机 community.windows.win_hyperv_vm: name: "{{ hostname }}" generation: 2 memory_startup: 16GB vhd_path: "{{ partition }}\\{{ hostname }}\\{{ hostname }}.vhdx" path: "{{ partition }}\\{{ hostname }}" state: present - name: 设置虚拟机CPU核心数 community.windows.win_hyperv_vm: name: "{{ hostname }}" processors: 4 state: present
4. 添加脚本日志排查卡点
在脚本中添加文件日志输出(WinRM无法捕获Write-Host内容),确认卡住的具体步骤:
$logPath = "C:\temp\vm_create.log" "[$(Get-Date)] 脚本启动,参数:$args" | Out-File -FilePath $logPath -Append "[$(Get-Date)] 创建目录:$partition\$host_name" | Out-File -FilePath $logPath -Append New-Item -Verbose "$partition\$host_name" -type directory 4>&1 | Out-File -FilePath $logPath -Append "[$(Get-Date)] 复制VHD文件" | Out-File -FilePath $logPath -Append Copy-Item -Verbose -Path "\\path\in\NAS\location\VHD\sysprep.vhdx" -Destination "$partition\$host_name" 4>&1 | Out-File -FilePath $logPath -Append # 后续步骤同理添加日志
内容的提问来源于stack exchange,提问作者hamaro9
相关产品推荐
相关产品推荐

