PowerShell脚本执行后无法退出,子进程未终止致删除步骤阻塞
问题解决:PowerShell远程安装软件后无法删除安装文件
问题概述
PowerShell脚本从机器A向机器B推送并静默安装软件,安装完成后尝试删除远程机器上的安装文件时失败,脚本卡住无法退出。经排查,原因是安装程序启动的子进程未正常退出,导致安装文件被占用。
原脚本代码
# Define the remote computer name and Software installation package path $ComputerName = "user1" $DestFolderPath = "C:\Temp\Test.exe" $FilePath ="C:\temp\test.exe" # Create a new PowerShell session to the remote computer $Session = New-PSSession -ComputerName $ComputerName #Create the destination folder if not already exist Invoke-Command -ComputerName $ComputerName -ScriptBlock { param($DestFolderPath) if (!(Test-Path $DestFolderPath)) { } } -ArgumentList $DestFolderPath # Copy the software installation package to the remote computer Copy-Item $FilePath -Destination $DestFolderPath -ToSession $Session # Install the Software silently on the remote computer Invoke-Command -Session $Session -ScriptBlock { param($DestFolderPath) Start-Process -FilePath $DestFolderPath -ArgumentList "/silent" -wait} -ArgumentList $DestFolderPath # Remove the installation package from the remote computer Invoke-Command -ComputerName $ComputerName -ScriptBlock { param($DestFolderPath) Remove-Item $DestFolderPath -Force -Recurse } -ArgumentList $DestFolderPath # Close the PowerShell session to the remote computer Remove-PSSession $Session
解决方法
1. 修复创建文件夹的空逻辑
原脚本中创建目标文件夹的代码块无实际执行语句,先补上这部分确保目录存在:
# Create the destination folder if not already exist Invoke-Command -ComputerName $ComputerName -ScriptBlock { param($DestFolderPath) $destDir = Split-Path $DestFolderPath -Parent if (!(Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force } } -ArgumentList $DestFolderPath
2. 等待安装程序的所有子进程退出
Start-Process -Wait仅等待主安装进程退出,若存在未终止的子进程会占用安装文件。修改安装步骤,主动检测并处理子进程:
# Install the Software silently on the remote computer Invoke-Command -Session $Session -ScriptBlock { param($DestFolderPath) # 启动安装程序并获取进程对象 $installProcess = Start-Process -FilePath $DestFolderPath -ArgumentList "/silent" -PassThru -Wait # 查找并等待所有子进程退出,超时后强制终止 $childProcesses = Get-CimInstance Win32_Process | Where-Object { $_.ParentProcessId -eq $installProcess.Id } foreach ($child in $childProcesses) { if (Get-Process -Id $child.ProcessId -ErrorAction SilentlyContinue) { Wait-Process -Id $child.ProcessId -Timeout 30 -ErrorAction SilentlyContinue if (Get-Process -Id $child.ProcessId -ErrorAction SilentlyContinue) { Stop-Process -Id $child.ProcessId -Force -ErrorAction SilentlyContinue } } } } -ArgumentList $DestFolderPath
3. 删除文件时添加重试机制
针对偶发的文件占用问题,在删除步骤中加入重试逻辑:
# Remove the installation package from the remote computer Invoke-Command -ComputerName $ComputerName -ScriptBlock { param($DestFolderPath) $retryCount = 3 $retryDelay = 5 do { try { Remove-Item $DestFolderPath -Force -Recurse -ErrorAction Stop break } catch { Write-Host "删除失败,重试中... ($retryCount次剩余)" Start-Sleep -Seconds $retryDelay $retryCount-- } } while ($retryCount -gt 0) } -ArgumentList $DestFolderPath
完整修复后的脚本
# Define the remote computer name and Software installation package path $ComputerName = "user1" $DestFolderPath = "C:\Temp\Test.exe" $FilePath ="C:\temp\test.exe" # Create a new PowerShell session to the remote computer $Session = New-PSSession -ComputerName $ComputerName # Create the destination folder if not already exist Invoke-Command -ComputerName $ComputerName -ScriptBlock { param($DestFolderPath) $destDir = Split-Path $DestFolderPath -Parent if (!(Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force } } -ArgumentList $DestFolderPath # Copy the software installation package to the remote computer Copy-Item $FilePath -Destination $DestFolderPath -ToSession $Session # Install the Software silently on the remote computer Invoke-Command -Session $Session -ScriptBlock { param($DestFolderPath) $installProcess = Start-Process -FilePath $DestFolderPath -ArgumentList "/silent" -PassThru -Wait # 查找并等待所有子进程退出 $childProcesses = Get-CimInstance Win32_Process | Where-Object { $_.ParentProcessId -eq $installProcess.Id } foreach ($child in $childProcesses) { if (Get-Process -Id $child.ProcessId -ErrorAction SilentlyContinue) { Wait-Process -Id $child.ProcessId -Timeout 30 -ErrorAction SilentlyContinue if (Get-Process -Id $child.ProcessId -ErrorAction SilentlyContinue) { Stop-Process -Id $child.ProcessId -Force -ErrorAction SilentlyContinue } } } } -ArgumentList $DestFolderPath # Remove the installation package from the remote computer Invoke-Command -ComputerName $ComputerName -ScriptBlock { param($DestFolderPath) $retryCount = 3 $retryDelay = 5 do { try { Remove-Item $DestFolderPath -Force -Recurse -ErrorAction Stop break } catch { Write-Host "删除失败,重试中... ($retryCount次剩余)" Start-Sleep -Seconds $retryDelay $retryCount-- } } while ($retryCount -gt 0) } -ArgumentList $DestFolderPath # Close the PowerShell session to the remote computer Remove-PSSession $Session
内容的提问来源于stack exchange,提问作者Anthony
相关产品推荐
相关产品推荐

