You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

注意事项

  1. 方案一使用后台作业避免阻塞主线程,适合需要动态进度提示的场景;
  2. 若控制台窗口大小发生变化,需重新计算底部行位置,可添加窗口尺寸监听逻辑;
  3. -NoProgress参数在部分早期PowerShell v5.0版本中未支持,此时优先使用输出重定向方案。

内容的提问来源于stack exchange,提问作者ElektroStudios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:55:16