WinGet说大成功

开窗一看了无踪

八零零七零零五

高呼给我转人工

以上是定场诗。

Winget 说安装成功,但 Oh My Posh 根本没装上:一次 MSIX 0x80070005 排障记录

以上是副标题

缘起:办公用机最近要下载运行我之前托管在gitlab上的ps1脚本,可是平时我用的是WSL,于是我用winget给Windows装个git,然后就开始大折腾。

C 我的私钥在WSL里呢

# 看看WSL的发行版叫什么名字
wsl --list
# 复制私钥
Copy-Item "\\wsl.localhost\Ubuntu-26.04\home\<wslusername>\.ssh\id_ed25519" -Destination "$HOME\.ssh\id_ed25519" -Force

# 只允许当前用户读写
icacls "$HOME\.ssh\id_ed25519" /inheritance:r
icacls "$HOME\.ssh\id_ed25519" /grant:r "${env:USERNAME}:(R,W)"

# 可选:这个可以不用输入passphrase,将私钥安全托管到后台代理,
Start-Service ssh-agent
ssh-add "$HOME\.ssh\id_ed25519"
ssh-add -l
ssh -T [email protected]

Dm Windows 11自带的Powershell弱爆了

Windows 11 自带的 PowerShell 版本太老,很多现代模块都无法正常使用。我装个最新的 PowerShell 7,又叫pwsh。

去微软官方 GitHub 仓库下载了最新稳定版 PowerShell-7.6.6-win-x64.msi 一路 “Next” 到底,彻底重启 Windows Terminal。

初始化 PowerShell Profile

在 PowerShell 7 中安装 posh-git 模块,并通过 Winget 安装 Oh My Posh:

Install-Module posh-git -Scope CurrentUser -Force -AllowClobber
winget install JanDeDobbeleer.OhMyPosh --source winget

编辑当前用户的 PowerShell Profile:

notepad $PROFILE

写入以下内容:

# 引入 Git 状态和补全
Import-Module posh-git

# 初始化 Oh My Posh
oh-my-posh init pwsh --config "jandedobbeleer" | Invoke-Expression

Winget 看起来也非常配合:

Found Oh My Posh [JanDeDobbeleer.OhMyPosh] Version 31.3.0
Successfully verified installer hash
Starting package install...
Successfully installed

运行 . $PROFILE ,说没有Oh My Posh!

关上Windows Terminal再开,还是没有!

很好,下一步测试:

oh-my-posh version

结果:

oh-my-posh: The term 'oh-my-posh' is not recognized...

Em 故事就从这里开始了

PATH在哪?

这是最常见的情况。

关闭 PowerShell,重新打开,再试:

Get-Command oh-my-posh -ErrorAction SilentlyContinue
where.exe oh-my-posh

全部为空。

再检查 Winget:

winget list --id JanDeDobbeleer.OhMyPosh

结果更加奇怪:

No installed package found matching input criteria.

也就是说:

  • Winget 刚刚告诉我 Successfully installed
  • PATH 里没有 oh-my-posh
  • Winget 自己也认为 Oh My Posh 没安装

这就不是简单的 PATH 刷新问题了。

开启 Winget verbose log

重新安装:

winget install `
  --id JanDeDobbeleer.OhMyPosh `
  --source winget `
  --exact `
  --verbose-logs

依然:

Successfully installed

查看日志后发现 Winget 下载的是:

install-x64.msix

安装过程使用的是 MSIX/AppX。

Winget 日志里甚至能看到:

StagePackageAsync
RegisterPackageByFullNameAsync

乍看起来一切正常。

但是安装结束后:

Get-AppxPackage | Where-Object Name -Like '*ohmyposh*'

仍然什么都没有。

AppX Deployment Event Log

于是直接查看 Windows AppX Deployment 日志:

Get-WinEvent `
  -LogName 'Microsoft-Windows-AppXDeploymentServer/Operational' `
  -MaxEvents 100 |
Where-Object {
    $_.Message -match 'ohmyposh|96v55e8n804z4'
} |
Select-Object TimeCreated, Id, LevelDisplayName, Message |
Format-List

终于抓到了真正的错误:

Deployment Stage operation ... finished successfully.

Started deployment RegisterByPackageFullName operation ...

AppX Deployment operation failed for package
ohmyposh.cli_31.3.0.0_x64__96v55e8n804z4
with error 0x80070005.

0x80070005:

E_ACCESSDENIED
Access is denied.

而且连续多次安装,每次都是完全相同的结果。

能下载,但是不让装。

然后 Winget:

Successfully installed

嗯。

谢谢你,Winget。

F 这不是我的Windows

这是一台企业管理的 Windows 11。

具体是哪项企业策略导致 MSIX 注册被拒绝,我没有继续深挖。可能涉及 AppX/MSIX 策略、应用控制或者其他企业安全配置。

对我来说知道一点就行:不让装:

Oh My Posh 的 MSIX 能成功 Stage,但无法为当前用户完成 Register。

而且我只是想在PowerShell提示符看清楚repo的状态,并不打算和公司的 Windows 安全策较劲。

绕过 MSIX:直接安装 exe

查看 Oh My Posh 31.3.0 Release 后发现,除了:

install-x64.msix

官方还提供普通 Windows 可执行文件:

posh-windows-amd64.exe

于是直接创建自己的 bin:

$bin = "$HOME\bin"

New-Item -ItemType Directory -Force $bin | Out-Null

下载:

Invoke-WebRequest `
  -Uri "https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v31.3.0/posh-windows-amd64.exe" `
  -OutFile "$bin\oh-my-posh.exe"

为了保险,再验证 SHA256:

Get-FileHash "$bin\oh-my-posh.exe" -Algorithm SHA256

31.3.0 x64 executable 对应的 SHA256 是:

CA755EA573FA0E88FF60556E8EE6CC756F361C0C223883225318A40B2DED2392

可以用下面的命令自动比对,避免只看一眼输出:

$expected = "CA755EA573FA0E88FF60556E8EE6CC756F361C0C223883225318A40B2DED2392"
$actual = (Get-FileHash "$bin\oh-my-posh.exe" -Algorithm SHA256).Hash
if ($actual -ne $expected) { throw "SHA256 不匹配:$actual" }
"SHA256 验证通过:$actual"

然后直接运行:

& "$bin\oh-my-posh.exe" version

成功。

加入 User PATH

把 $HOME\bin 加进用户 PATH。下面会保留已有用户 PATH,并避免重复添加:

$bin = "$HOME\bin"

$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')

if (($userPath -split ';') -notcontains $bin) {
    [Environment]::SetEnvironmentVariable(
        'Path',
        ($userPath.TrimEnd(';') + ';' + $bin),
        'User'
    )
}

当前 PowerShell session 临时补上:

$env:Path += ";$bin"

现在:

oh-my-posh version

正常。

整个过程不需要 MSIX、不需要 AppX registration,也不需要管理员权限。

配置 PowerShell Profile

我原来的 $PROFILE 已经使用 posh-git。前面初始化 Profile 的命令因为 Oh My Posh 安装失败而暂时无法生效;现在 exe 已能通过 PATH 找到,保留模块导入并在后面初始化 prompt:

Import-Module posh-git

所以保留它,然后让 Oh My Posh 在后面接管 prompt:

Import-Module posh-git

# Initialize Oh My Posh
oh-my-posh init pwsh --config "jandedobbeleer" | Invoke-Expression

重新加载:

. $PROFILE

完成。

G 最后的经验

这次最大的坑其实不是 Oh My Posh,而是:

不要过度相信包管理器最后打印出来的 Successfully installed。

如果 Winget 声称安装成功,但:

winget list

查不到,

Get-Command

也找不到,

那么问题可能已经发生在 installer/package registration 层,而不是 PATH。

对于 MSIX/AppX,下面这个日志尤其值得记住:

Get-WinEvent `
  -LogName 'Microsoft-Windows-AppXDeploymentServer/Operational' `
  -MaxEvents 100

这次 Winget 的日志告诉我:

我成功调用了安装流程。

而 AppX Deployment 的日志告诉我:

不,你没有。

后者显然更接近事实。

至于 Oh My Posh——它本质上就是一个 CLI executable。

既然企业 Windows 不愿意让我注册它的 MSIX,那就把 oh-my-posh.exe 扔进 $HOME\bin。

问题解决。

有时候最好的企业 Windows troubleshooting,就是及时停止 troubleshooting 企业 Windows。

好了。感谢看到这里,看过就等于会了。❤️


Am 彩蛋

我好傻啊!我直接在WSL里面装powershell不就行了吗,WSL里面装什么都没人管。费这么大劲瞎折腾。

sudo apt update
sudo apt install -y powershell
pwsh