PowerShell v5.0中如何将Add-AppxPackage进度条移至控制台底部?
解决PowerShell v5.0中Add-AppxPackage进度条覆盖顶部内容的问题
在PowerShell v5.0中,Add-AppxPackage的内置进度条默认会从当前光标位置开始输出,直接覆盖之前打印的顶部信息。要将进度条固定在控制台底部,需通过控制控制台光标位置或自定义进度输出实现,以下是两种可行方案:
方案一:预留底部行并自定义进度提示
核心思路是先在控制台底部预留一行作为进度区域,通过后台作业执行安装任务,同时轮询任务状态并在底部更新进度提示,避免覆盖顶部内容。
修改后的完整中文代码
# AppX包自动安装脚本 # 接收AppX包名字符串输入,解析出名称、版本、架构和发布者ID # 使用正则表达式匹配包名格式,返回包含解析信息的自定义对象 # 若输入无法解析则抛出错误 function Get-PackageInfo { param ( [Parameter(Mandatory=$true)] [string]$PackageString ) $dirname = [System.IO.Path]::GetDirectoryName($PackageString) if ([string]::IsNullOrEmpty($dirname)) { $dirname = $PWD } $filename = [System.IO.Path]::GetFileName($PackageString) -replace "(?i)\.Appx$", "" $regex = '^(?<Name>.+?)_(?<Version>.+?)_(?<Architecture>.+?)__(?<PublisherId>.+)$' $match = $filename -match $regex if (!$match) { throw "无法解析包字符串: '$PackageString'" } $packageName = $matches['Name'] $packageVersion = $matches['Version'] $packageArchitecture = $matches['Architecture'] $packagePublisherId = $matches['PublisherId'] $packageFullName = "${packageName}_${packageVersion}_${packageArchitecture}__${packagePublisherId}" $packageFullPath = [System.IO.Path]::Combine($dirname, "$filename.Appx") [PSCustomObject]@{ 名称 = $packageName 版本 = $packageVersion 架构 = $packageArchitecture 发布者ID = $packagePublisherId 完整名称 = $packageFullName 完整路径 = $packageFullPath } } $packageString = "Microsoft.VP9VideoExtensions_1.0.52781.0_x64__8wekyb3d8bbwe.Appx" $sourcePackage = Get-PackageInfo -PackageString $packageString Write-Output "源包信息:" Write-Output "包字符串.....: $packageString" Write-Output "包完整路径..: $($sourcePackage.完整路径)" Write-Output "完整名称....: $($sourcePackage.完整名称)" Write-Output "名称........: $($sourcePackage.名称)" Write-Output "版本........: $($sourcePackage.版本)" Write-Output "架构........: $($sourcePackage.架构)" Write-Output "发布者ID....: $($sourcePackage.发布者ID)" Write-Output "" Write-Output "检查源包是否已安装..." Write-Output "" $packages = Get-AppxPackage "$($sourcePackage.名称)*" -ErrorAction SilentlyContinue foreach ($package in $packages) { if ($package.Version -eq $sourcePackage.版本 -and $package.Architecture -eq $sourcePackage.架构) { Write-Warning "源包 $($sourcePackage.名称) v$($sourcePackage.版本) ($($sourcePackage.架构)) 已安装。" Write-Warning "无需重复安装。" Write-Output "" Write-Output "程序即将终止。按任意键退出..." $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") Exit 0 } } Write-Output "源包 $($sourcePackage.名称) v$($sourcePackage.版本) ($($sourcePackage.架构)) 准备安装。" Write-Output "" Write-Output "正在安装源包..." Write-Output "" # 获取控制台窗口参数 $console = $Host.UI.RawUI $windowHeight = $console.WindowSize.Height # 清空底部预留行 $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host (" " * $console.WindowSize.Width) -NoNewline try { # 启动后台安装作业 $installJob = Start-Job -ScriptBlock { param($path) Add-AppxPackage -Path $path -ErrorAction Stop } -ArgumentList $sourcePackage.完整路径 # 轮询作业状态,更新底部进度提示 while ($installJob.State -eq "Running") { $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host "安装中...请等待" -NoNewline Start-Sleep -Milliseconds 500 $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host "安装中...请等待." -NoNewline Start-Sleep -Milliseconds 500 $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host "安装中...请等待.." -NoNewline Start-Sleep -Milliseconds 500 $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host "安装中...请等待..." -NoNewline Start-Sleep -Milliseconds 500 } # 处理作业结果 Receive-Job $installJob -Wait -AutoRemoveJob if ($installJob.State -eq "Completed") { # 清空进度行并输出成功信息 $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host (" " * $console.WindowSize.Width) -NoNewline $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host "源包 $($sourcePackage.名称) v$($sourcePackage.版本) ($($sourcePackage.架构)) 安装成功。" -BackgroundColor Black -ForegroundColor Green Write-Output "" Write-Output "程序即将终止。按任意键退出..." $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") Exit 0 } } catch { # 清空进度行并输出错误信息 $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host (" " * $console.WindowSize.Width) -NoNewline $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host "安装源包 $($sourcePackage.名称) v$($sourcePackage.版本) ($($sourcePackage.架构)) 出错" -BackgroundColor Black -ForegroundColor Red Write-Output "" Write-Output "" Write-Error -Message ($_.Exception | Format-List * -Force | Out-String) Write-Output "" Write-Output "程序即将终止。按任意键退出..." $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") Exit 1 }
方案二:禁用内置进度条,手动输出状态
若不需要动态进度动画,可直接禁用Add-AppxPackage的内置进度输出,在底部固定位置显示安装状态:
# 核心修改部分 Write-Output "正在安装源包..." Write-Output "" $console = $Host.UI.RawUI $windowHeight = $console.WindowSize.Height # 在底部输出安装状态 $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host "安装进行中..." -NoNewline # 重定向进度输出到null,避免覆盖顶部内容 Add-AppxPackage -Path "$($sourcePackage.完整路径)" -ErrorAction Stop *> $null # 安装完成后更新底部信息 $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host (" " * $console.WindowSize.Width) -NoNewline $console.CursorPosition = @{X=0; Y=$windowHeight - 1} Write-Host "源包安装成功!" -ForegroundColor Green
注意事项
- 方案一使用后台作业避免阻塞主线程,适合需要动态进度提示的场景;
- 若控制台窗口大小发生变化,需重新计算底部行位置,可添加窗口尺寸监听逻辑;
-NoProgress参数在部分早期PowerShell v5.0版本中未支持,此时优先使用输出重定向方案。
内容的提问来源于stack exchange,提问作者ElektroStudios
相关产品推荐
相关产品推荐

