Category Archives: PowerShell

In-app Update Beats Remove/Replace

Running WinGet just now on my Flo6 desktop, I got reminded that installer changes sometimes stymie its update facilities. If you look at the lead-in graphic, you’ll see that one upgrade gets blocked because of “different install technology.” Winget goes onto recommend “Uninstall each package, then install the newer version.” Not so fast: IMO, an in-app update beats remove/replace when that’s an option. I’ll explain, and use the Edge browser as an illustration.

You can jump to Edge, click the ellipsis, and get to Help and feedback in 3 clicks. Uninstall/reinstall takes 20+ keystrokes, and might fail.

Why Say: In-app Update Beats Remove/Replace?

My explanation boils down to: less time and effort, fewer keystrokes involved. Jumping to Edge, clicking the ellipsis for Settings, then visiting Help and Feedback to prompt the update process takes 3 mouse clicks (add one more click to restart, and the update is done). Uninstalling, then re-installing edge takes at least 20 keystrokes (“winget uninstall edge”). Worse, it then falls victim to exit code 93. TLDR version: Edge is considered a Windows built-in feature, so it blocks its own uninstall by default.

Sure, you can work around this. And it works for other browsers as directed for Chrome, Firefox, and so forth. But my preferred approach for browsers in particular is: try the built-in update mechanism first, if WinGet steers around an update. It usually does so for a good reason, as is the case here with Edge.

Here in Windows-World, it pays to recognize such cul-de-sacs when they pop up. It saves you the time involved in driving to the end, turning around, and doing something else. Not an unfamiliar experience for Windows warriors, but one best avoided when possible!

Facebooklinkedin
Facebooklinkedin

Fixing False Vantage Update

If you’ve ever dealt with a Lenovo Vantage false update, you know how maddening it gets. That goes double, when every install attempt fails silently and the same ghost package reappears on every subsequent scan. Sigh.

But that’s precisely what happened to me on a Lenovo ThinkStation P3 Ultra Gen 2 (Arrow Lake-S desktop). There, Lenovo Vantage’s System Update panel stubbornly flagged Intel Dynamic Tuning Technology (DTT) Driver version 9.1.10001.173 as a required update, even after reporting a successful install on the previous try. Sigh again.

Why I’m Fixing False Vantage Update

Here’s the wrinkle: DTT is a laptop-exclusive power-management feature. It’s tightly coupled to Intel’s thermal sensor bus. Specifically, it applies to SWC\VID8086_DTT_* ACPI devices. Alas desktop platforms don’t sport them. My ThinkStation doesn’t have one. It never will. Yet Vantage keeps insisting otherwise.

Furthermore, every install attempt failed without so much as an error dialog. Vantage just re-offered the driver on the very next scan, politely pretending nothing had gone wrong. Time to dig in, and get this thing outtah heah!

Ruling Out the Obvious

First, I tried some obvious remedies. Logging into Vantage directly as Administrator changed nothing. There’s no ellipsis menu, no right-click context option. That means no “suppress this update” checkbox anywhere in the System Update panel. Lenovo simply hasn’t built that in.

Next, I turned to the standalone Lenovo System Update app. After installing the optional Lenovo SoftwareComponent Driver 26.9.0.20 from Windows Update, System Update scanned the machine and correctly reported “No packages applicable.” Clean bill of health. Meanwhile, Vantage still flagged the DTT driver for update. Sigh one more time.

However, that discrepancy was actually useful. It proved the issue lived entirely inside Vantage itself. It’s an artifact of its System Update addin, not  Lenovo’s underlying package catalog. The two tools evaluate the same catalog through completely different pipelines. Importantly, only one of them is wrong.

Tracing That False Positive…

With the obvious paths ruled out, I dug into Vantage’s session data folder:
C:\ProgramData\Lenovo\Vantage\AddinData\
LenovoSystemUpdateAddin\session\
.

Inside, I found two SQLite databases: update_history.db (Vantage’s live working store, rewritten on every scan) and editable_update_history.db (which appears designed to accept external edits). I tried setting the DTT entry status to NotApplicable in the editable_update_history.db. Alas, nothing changed on screen. Vantage reads update_history.db for all rendering decisions and overwrites it with Applicable again after each rescan. The “editable” database, it turns out, is a red herring.

I also found available_updates.json.It’s a 5 KB file that’s rewritten upon each update scan. It gave me a fully parsed package definition, including a Dependencies block that pointed me toward the real culprit.

A (Bogus) WildCard in the XML

Vantage caches each package’s raw XML in its own repository subfolder. For this machine, the DTT package XML lives at:

session\Repository\m1dpf015d_p3ultrag2_25h2\m1dpf015d_p3ultrag2_25h2_2_.xml

Inside that XML, the Dependencies/_Bios/Level section contained two machine-type entries: “*” and “S0NKT*”. The S0NKT* pattern correctly targets specific Lenovo laptop lines that carry DTT-capable thermal silicon. That entry belongs there. The “*” wildcard, however, matches every machine type on the planet — including the ThinkStation’s 30J5 machine type. That entry almost certainly doesn’t belong there, and it looks like a straightforward Lenovo catalog error.

Consequently, without the wildcard, Vantage evaluates the ThinkStation’s machine type against S0NKT*, finds no match, and writes NotApplicable to update_history.db automatically on every future scan. No database patching, no registry hacks — just the correct answer from a corrected applicability list.

PowerShell to the Rescue!

I wrapped the repair into a short PowerShell script called fix_dt.ps1. The logic is straightforward: clear the file’s read-only attribute, load the XML into an XmlDocument object, locate the offending node using an XPath query, remove it, save the file, restore read-only protection, then restart the LenovoVantageService so Vantage picks up the change cleanly.

The lines that do the heavy lifting are (edit to remove line breaks):

$node = $v.SelectSingleNode("//_Bios/Level[. = '*']")
if ($node)
{ $node.ParentNode.RemoveChild($node) | Out-Null }

Setting the file back to read-only afterward is an important step. It prevents Vantage from silently re-downloading a fresh copy of the XML on its next catalog sync and re-introducing the wildcard. Sadly, that would undo the fix entirely.

To run the script, open an elevated PowerShell prompt and execute:

powershell -ExecutionPolicy Bypass -File
"C:\Temp\fix_dt.ps1"

Note: Run this from an elevated (Run as Administrator) PowerShell session. The script must stop and restart the LenovoVantageService, which requires administrator rights. Edit so it runs on one line.

Lessons Learned

This exercise surfaced a few things worth minfing for anyone who’s doing deep Vantage troubleshooting:

  • Vantage and the standalone System Update utility maintain completely separate state databases and catalog evaluation pipelines. Agreement between them is not guaranteed. Disagreement is a useful diagnostic clue, not a dead end.
  • The “editable” SQLite database is a red herring for display suppression. Vantage ignores it when rendering the System Update panel. Don’t waste time on this.
  • A single bogus wildcard in a machine-type applicability list causes a laptop-only driver to haunt a desktop indefinitely. The fix is in the XML, not in the database.
  • When the official UI offers no suppress or hide option for a persistently wrong update, the XML repository is the right lever to pull. Appearances aside, it’s not the SQLite layer above it at fault.

Ultimately, this is a reminder that catalog quality control matters. One stray “*” in a dependency block can send thousands of ThinkStation owners chasing a ghost driver that will never install. If you’ve hit the same Lenovo Vantage false update on a different ThinkStation model, or if you’ve spotted a similar wildcard problem in another Vantage package XML, please drop a comment here. I’d love to know how broadly this catalog bug extends beyond the P3 Ultra Gen 2.

Here in Windows-World, updates sometimes get weird. This time, for once in a blue moon, it’s not WU that’s the culprit. It’s Lenovo. That makes me oddly glad. Go figure!

Facebooklinkedin
Facebooklinkedin

WinGet.Config Drives Developer Config

As I was reading a Windows Latest article about a “…special Windows 11 for power users…” this morning, I found myself wondering. “Could this be a big, fancy WinGet config file at work?” Indeed, reading further into the story absolutely confirmed my hunch. The file in question, in fact, is named winget.config, in keeping with current naming conventions around desired configuration states. Thus, it’s simple truth that Winget.Config drives “Developer Config” as described in the story (and at MS Learn as well).

WinGet.Config Drives Developer Config from End to End

The MS Learn article‘s intro paragraph is worth quoting in full to put this capability into clear context:

Windows Developer Configurations are a curated, open-source collection of configuration files that take a fresh Windows machine to a ready-to-code state with a single command. Each config is a declarative file that is safe to re-run. It describes the packages, OS settings, and post-install steps for a specific scenario (a full developer workstation, a comfortable WSL shell, or a single language toolchain), so you can rebuild your environment on any machine without clicking through installers or maintaining custom scripts.

Windows Developer Config is built from the ground up on winget configure and a single .winget desired state configuration (DSC) file named dev-config.winget. It is not a new Windows SKU, a custom ISO, nor a registry script. The whole thing is one winget configure call pointing at that file.

The commands necessary to instill this configuration are (mostly) shown in the lead-in graphic. I repeat them here for completeness’ sake (and for easy cut’n’paste, by copying non-comment lines completely):


# Enable WinGet Configuration first
winget configure --enable

# Clone the repo
git clone https://github.com/microsoft/WindowsDeveloperConfig.git
cd WindowsDeveloperConfig

# Apply the config
winget configure -f .\windows-dev-config\dev-config.winget –accept-configuration-agreements –disable-interactivity

More About WinGet.Config

That .winget file is a YAML-based DSC manifest that handles everything in one shot: installing PowerShell 7, Git, GitHub CLI, VS Code, .NET SDK, Python, Node.js, PowerToys, setting up WSL with Ubuntu, tweaking Windows Terminal defaults, enabling Developer Mode and long-path support, and applying a long list of Explorer/Start/Search/Widgets settings to declutter the UI.

Indeed, Project Zenith hardware ships with those same changes baked-in by the OEM. But the underlying mechanism Microsoft used to define and apply that configuration is exactly the same winget configure + .winget file approach. In fact, the .winget config file format is doing real work here. That is, it’s not just installing apps; it’s functioning as full-blown Windows DSC, a notable expansion beyond what most people think winget does.

Here in Windows-World, it’s great to see real innovation put to useful work. Demitrius Nelon, the head of the WinGet team, has told me several times over the past few months that .winget configuration files represent a way to customize Windows seriously in one go. Now, I think I understand what he was getting at. Great work, guys!

Facebooklinkedin
Facebooklinkedin

Long DISM Pause at 63% Range

I’ve been reading online at ElevenForum about people having issues with DISM ... /restorehealth on Build 26100.8972 and 26200.8972. Naturally, I had to check to see if I fell into that same boat. On the plus side, none of my machines at that build level threw an error for the command. On the minus, I observed a long DISM pause at 63% range in completing the sequence that stretched to 70% and a bit more. Copilot tells me this is the stage during which DISM downloads files needed to repair questionable items found in the component store.

Varying Times for Long DISM Pause at 63% Range

The lead-in graphic shows a completion time of 22m 55.301s for the command on my Flo6 desktop (MSI B550 mobo, AMD Ryzen 7 5800X, 64 GB RAM, RTX 3070 Ti). Other intervals I recorded include:

  • 13m 33.008s on AsusSnap (Zenbook A14, SnapDragon X Plus X1P-42-100, 16 GB RAM, Adreno graphics)
  • 8m 36.148s on Lenovo ThinkStation P3 Ultra (Core Ultra 9 285, 64 GB RAM, RTX 4000 SFF)

In this admittedly small sample, I see a strong relationship between CPU speed and completion time. That tells me there’s a lot of thinking going on while the /restorehealth operation is underway. Download volumes were all consistently in the 3-4GB range, as measured by download values from the Network Meter gadget from GadgetPack.

Skip WU, Try ISO

Copilot suggests further that pointing the /restorehealth command at a local ISO could speed things up. But it also says that “the ISO build must match 26200.x [the reference/focus build] closely.” The only way to do that right now is to build an ISO using UUPdump.net to match the 26200.9278 build all 3 PCs are running. That can easily take an hour or longer. My total time for all 3 was under 46 minutes.

Here in Windows-World, if you don’t pay (or spend time) one way, you’ll almost always spend it another. I took the WU route, and was glad all those DISM ... /restorehealth commands completed successfully. That’s good enough for me!

 

Facebooklinkedin
Facebooklinkedin

Examining Nerd Font Glyphs

Nerd Fonts patch popular programming fonts with thousands of extra icons. These icons live in the Private Use Area (PUA) and other reserved Unicode blocks. Terminals that load Nerd Fonts gain instant access to logos, arrows, file-type icons, weather symbols, and power glyphs. Have you ever wondered exactly which glyphs your installed font contains? The Show-NerdFontGlyphs PowerShell function answers that question fast. It is the key to examining nerd font glyphs, in fact, up close and personal (see lead-in graphic).

Script for Examining Nerd Font Glyphs

The script defines one function: Show-NerdFontGlyphs. It loops through 13 named glyph ranges and renders each glyph alongside its hex code point. It also arranges the output in a configurable column grid. The default is eight columns wide. That width fits comfortably in most terminal windows. Run it, and in seconds you have a full visual catalog of every icon your font supports.

Each section prints a cyan header, making it easy to scan. Each row shows the rendered glyph followed by its four-digit hex address. That pairing is the key feature. Specifically, if you spot an icon you want, note its hex value. Then, reference it in PowerShell with [char]0xXXXX. For code points above U+FFFF, use [System.Char]::ConvertFromUtf32(0xXXXX) instead.

Unicode Ranges Covered

The script covers 13 glyph families. Here’s a quick guide to each one.

  • Pomicons (U+E000 to U+E00A): This set holds 11 miscellaneous icons from legacy Powerline themes.
  • Powerline (U+E0A0 to U+E0B3): These glyphs power the core Powerline separators and branch symbols used in prompt themes worldwide.
  • Powerline Extra (U+E0A3 to U+E0D4, scattered): This range adds rounded, flame, and diagonal separator variants to extend the Powerline set.
  • Symbols (U+E5FA to U+E6B2): These general-purpose glyphs include file-type icons and folder symbols.
  • Devicons (U+E700 to U+E7C5): This section covers programming language and framework logos including Python, JavaScript, Git, and Docker.
  • Font Awesome (U+F000 to U+F2E0): This classic set delivers social, UI, and media icons from Font Awesome 4.
  • Font Awesome Extension (U+E200 to U+E2A9): These icons extend Font Awesome with additional symbols.
  • Octicons (U+F400 to U+F4A8): GitHub Octicons cover pull requests, issues, branches, and repository actions.
  • Font Logos (U+F300 to U+F372): This range holds OS and distribution logos including Linux distros, BSD variants, and Apple.
  • Power Symbols (U+23FB to U+2B58): These glyphs represent standby, power-on, sleep, and toggle functions from the Miscellaneous Technical block.
  • Weather Icons (U+E300 to U+E3EB): This section delivers sun, cloud, rain, snow, wind, and forecast glyphs.
  • Material Design (U+F0000 to U+F0200, first 512 only): These icons come from Supplementary Private Use Area-A and represent a subset of the Material Design set.
  • Codicons (U+EA60 to U+EBEB): Visual Studio Code uses these icons for debugging, source control, and editor UI elements.

Spotlight on U+E62A: Win11 Logo

One glyph deserves special attention: U+E62A. It sits inside the Symbols range (U+E5FA to U+E6B2) and renders as the four-pane Windows 11 logo. Furthermore, it behaves as a double-width glyph. In other words, it occupies two terminal columns rather than one. That property makes it ideal for building large logo art in FastFetch or other terminal info tools.

You reference it in PowerShell with [char]0xE62A. In a Nerd Font terminal, that expression produces the Windows logo glyph directly. Yesterday’s post on this site shows how to build a custom 8×8 FastFetch logo grid in Windows blue using this glyph.

Running the Script

Save the function to showglyphs.ps1. Next, dot-source it in your PowerShell 7 session and call it:

.\showglyphs.ps1
Show-NerdFontGlyphs

You can also adjust -Columns to fit your terminal width. Narrower windows work better with -Columns 4 or -Columns 6. The function handles code points above U+FFFF using [System.Char]::ConvertFromUtf32. As a result, it does not throw errors on supplementary characters.

Download the Script

Download the complete showglyphs.ps1 script directly from this post. Save it to your PowerShell scripts folder and dot-source it in your profile or on demand. Finally, pair it with a Nerd Font in Windows Terminal for the best results. CaskaydiaCove Nerd Font and JetBrainsMono Nerd Font are both excellent choices.

I wouldn’t have found the Win11 logo without this nifty little tool. Try it yourself, and be amazed at all the icon-like images that nerd fonts can offer. They’re amazing!

Facebooklinkedin
Facebooklinkedin

WinGet Misses ARM Browser Updates

If you run winget upgrade --all on an ARM-based Windows 11 PC (e.g. an Asus Zenbook A14), you may notice something odd: Chrome and Firefox don’t show in the upgrade list, even when they’re out of date. On an x64 desktop, winget catches them without fail. So what gives? Briefly put, and for various reasons, WinGet misses ARM browser updates for certain implementations.

It turns out there are four overlapping bugs and design gaps at play. All of them affect ARM64 PCs. None of them are your fault, either. But together they form a perfect storm that makes WinGet effectively blind to certain browsers. For now, anyway.

TLDR: On ARM64 Windows PCs, WinGet fails to detect and upgrade Chrome and Firefox due to four compounding issues: a name-normalization bug (winget-cli #6490), a registry hive mismatch, a broken ARM64 manifest entry for Chrome, and an architecture-selection bug (winget-pkgs #424881). Until Microsoft patches these, a handful of workarounds fill the gap. Here goes…

Diving in: Why WinGet Misses ARM Browser Updates

On x64 machines, the registry is simple: one hive, one architecture tag, and manifests that have been battle-tested for years. WinGet’s upgrade logic originates from that x64 worldview. Alas, things on ARM64 aren’t quite so simple, and all four failure modes described next come out of various diversions from the x64 situation.

Four Root Causes

  1. The ARP Name-Normalization Bug (winget-cli #6490)

Winget matches installed apps to its catalog by reading Add/Remove Programs (ARP) registry entries and normalizing display names. It strips “x86” and “x64” — but has no handling for “arm64” or “ARM64.” When Chrome or Firefox registers with an ARM64 architecture suffix on a Snapdragon device, winget cannot correlate it to the catalog entry and silently drops it. The app becomes invisible to winget upgrade.

  1. The Registry Hive Mismatch

ARM64 Windows splits app registrations across 3 registry hives:

 

Hive Contents Who Writes There
SOFTWARE\…\Uninstall Native ARM64 apps ARM64 installers
SOFTWARE\WOW6432Node\…\Uninstall x64-emulated apps x64 installers (Chrome, Firefox legacy)
HKCU\SOFTWARE\…\Uninstall Per-user installs Either architecture

 

If Chrome or Firefox were installed via an x64 installer — the only option before both browsers shipped native ARM64 builds — it lives in WOW6432Node. Winget, running as a native ARM64 process, reads the native hive first and, when name normalization is also broken, frequently misses those emulated entries entirely.

  1. The Broken Chrome ARM64 Manifest

Even when winget finds Chrome, the Google.Chrome manifest in the community repository lists an arm64 installer entry with a blank SHA256 hash. Winget requires a valid hash to verify any upgrade — blank means the ARM64 path is present on paper but non-functional. The Google.Chrome.EXE package ID does carry a properly populated hash, which explains why some users get inconsistent results depending on which package ID is in play.

  1. The Architecture Selection Bug (winget-pkgs #424881)

Even with a complete, valid manifest, winget’s upgrade logic has a documented bug where it selects the x64 installer over arm64 on Windows on ARM machines. Best case: you get the slower, emulated build pushed onto your ARM device. Worst case: the upgrade fails outright.

Viable WinGet Workarounds

Until Microsoft ships fixes, here are some WinGet options — from most precise to most blunt:

  1. Force the architecture explicitly: Use winget upgrade Google.Chrome --architecture arm64 and winget upgrade Mozilla.Firefox --architecture arm64. This bypasses both  correlation and selection bugs in one go.
  2. Use the Chrome EXE package ID: winget upgrade Google.Chrome.EXE --architecture arm64 hits the manifest entry that actually has a valid SHA256 hash for ARM64.
  3. Let the browsers self-update: Both Chrome (Google Update/Omaha) and Firefox (Mozilla Maintenance Service) are fully architecture-aware. Help → About in either browser triggers an immediate, correct ARM64 update — no winget involved, no ARM64 drama.
  4. Add --include-unknown as a catch-all: winget upgrade --all --include-unknown is a blunt instrument, but it sometimes remcatches apps that fail normal ARP correlation.

The real, true fix requires Microsoft to patch name-normalization and upgrade architecture-selection logic in winget-cli. Two of the four bug reports were filed in the last few days, so movement could come soon. Until then, –architecture arm64 is the cleanest workaround on your Zenbook A14 — or any other Snapdragon-powered Windows machine. In Windows-World, knowing where the bodies are buried is half the battle.

Facebooklinkedin
Facebooklinkedin

Flo6 Recovery Partition Cleanup

One of the quieter but genuinely useful maintenance tasks for any Windows 11 machine is verifying the WinRE recovery partition. When necessary, you can refresh bits and pieces. On my desktop (production) rig Flo6, that job came due recently when I discovered a one-version gap between the OS and the recovery environment. Here’s exactly what I did to perform Flo6 recovery partition cleanup.

Why Do Flo6 Recovery Partition Cleanup?

Flo6 was running Windows 11 25H2 (build 26200.9168). It’s current and fully patched. A quick reagentc /info at an elevated command prompt, however, told a different story about the recovery environment: Windows RE Version 10.0.26100.9168. That’s 24H2 — one full major version behind the OS.

This kind of mismatch is typical after an in-place upgrade. Windows Update doesn’t always push a matching WinRE update alongside the OS upgrade. The recovery environment still works, but keeping it in sync with the running OS is simply good hygiene.

Finding the Right Source Media

Fortunately, I had a Windows 11 25H2 bootable UFD on hand. It is ESD-USB labeled, FAT32 formatted, carries seven editions in a split WIM (install.swm + install2.swm, totaling ~5.6 GB compressed). A quick DISM query confirmed the match:

dism /get-wiminfo /wimfile:G:\sources\install.swm /index:6

Output showed Version: 10.0.26200 / ServicePack Build: 9168 — an exact build-for-build match with Flo6’s OS. The source media was confirmed.

DISM Workflow: Four Clean Steps

Split WIMs add a wrinkle:the/swmfile parameter won’t work with /mount-wim. The workaround is to export first, then mount the resulting single WIM. Here’s the sequence I ran from an elevated command prompt:

Step 1 — Export the Pro edition to a single WIM:

dism /export-image /sourceimagefile:G:\sources\install.swm /swmfile:”G:\sources\install*.swm” /sourceindex:6 /destinationimagefile:C:\temp_pro.wim

Step 2 — Mount read-only to C:\BootMount (a pre-existing empty directory):

dism /mount-wim /wimfile:C:\temp_pro.wim /index:1 /mountdir:C:\BootMount /readonly

Step 3 — Extract winre.wim to a temp location:

copy C:\BootMount\Windows\System32\Recovery\Winre.wim D:\Temp\Winre25H2.wim

Step 4 — Unmount and delete the temp WIM:

dism /unmount-wim /mountdir:C:\BootMount /discard
del C:\temp_pro.wim

Swapping the WinRE Recovery Partition Image

With the new Winre.wim extracted, swapping it into the recovery partition takes just a few commands using reagentc (note: the copy command runs into a second line here, but should be a one-liner when run at the command line):

reagentc /disable
copy /y d:\temp\winre25h2.wim r:\recovery\windowsre\winre.wim
reagentc /enable
reagentc /info

The leading screenshot above shows this exact sequence — disable, copy, enable, and the final /info verification — all completing successfully. Note that R:is the recovery partition, temporarily assigned a drive letter for this operation.

A Nuance Worth Noting

The final reagentc /info reported Windows RE Version: 10.0.26100.9168 , and still shows 24H2. This isn’t a failure. The winre.wim packaged inside a 25H2 OS install image is itself built on the 24H2 WinPE base.

Microsoft maintains WinRE on its own separate servicing track. The embedded winre.wim version doesn’t automatically match the OS build number. The WinRE is fully functional and properly enabled — the version stamp reflects WinPE infrastructure, not a gap in recovery coverage.

Bottom Line

The Flo6 WinRE recovery partition is now refreshed, re-enabled, and confirmed healthy: Status Enabled, location correct, BCD identifier registered, and local reinstall available. Total active time at the command prompt: under ten minutes.

If you haven’t checked your own WinRE status lately, reagentc /info is a fast, zero-risk first step — and now you know exactly what to do if the version number looks off. Here in Windows-World, checking is good, and verifying is better. Today, I’m in a good place. How about you?

Facebooklinkedin
Facebooklinkedin

Windows Neofetch Alternatives

If you’re ever seen Neofetch, you’re likely to want something like it for Windows. It’s a command-line tool that displays a quick system snapshot. It shows OS version, CPU, GPU, RAM, uptime, shell, storage and more, alongside a rendering of the OS logo as “ASCII art.” But Neofetch is mostly a Linux/Unix thing that requires a Bash shell to run. It was also archived in April 24. It still works, but there are better choices for Windows. For those seeking Windows Neofetch alternatives, the best options are fastfetch and winfetch.

Windows Neofetch Alternatives Are Helpful, or Necessary

Again: Neofetch is a Bash script. That explains most of the friction inherent in running Neofetch on Windows. That is, it requires Git Bash or WSL — neither of which is a native Windows tool. The script itself froze at v7.1.0 when the repository was archived. Worse, going forward Neofetch is dead in the water: no updates, no bug fixes, no future-forward functionality.

Think about what Neofetch actually does: it reads your OS version, CPU, RAM, and a handful of other system facts, then prints them alongside an ASCII logo. Running an outdated Bash script through a compatibility layer to accomplish that feels like overkill. Native tools handle this job more cleanly, more quickly, and without the extra dependencies.

2 Strong Alternatives: Fastfetch and Winfetch

Both of these facilities are actively maintained, and update regularly. Either one can take over for Neofetch without skipping a beat.

Fastfetch

Fastfetch is written in C and installs as a native binary. Speed is its calling card — it fetches and renders system info noticeably faster than Neofetch ever did. Cross-platform support (Windows, Linux, macOS) makes it useful across mixed environments. Install it with any of the major Windows package managers:

winget install fastfetch

Once installed, launch it by typing fastfetch at any prompt. Configuration lives in a JSONC file, so customization is straightforward and version-control friendly. Here’s what it looks like on my AMD-based Flo6 desktop (click image to enlarge):

Winfetch

Winfetch is a pure PowerShell script — Windows-only, and deliberately so. It installs directly from the PowerShell Gallery:

Install-Script winfetch -Scope CurrentUser

For anyone already running Windows Terminal with an Oh My Posh prompt and Nerd Fonts, winfetch slots right in. The output renders cleanly alongside a styled prompt, and the whole setup feels native rather than bolted on. You can see it in the lead-in screencap.

The Winfetch Path Gotcha

What the lead-in graphic shows is me getting past the requirement that the winfetch script must be somewhere in $PATH to work. In fact, after I installed it, I got this error when I tried to run it:

Error

winfetch : The term ‘winfetch’ is not recognized as the name of a cmdlet, function, script file, or operable program.

This happens because the installer drops the script into a specific, pre-assigned folder:
C:\Users\Documents\Powershell\Scripts\
Powershell does not, however, automatically add that folder to the $PATH environment variable. So even though the script is installed, it doesn’t run from the command line. Easily fixed, however, as also shown in the lead-in graphic, through a series of simple steps.

Fixing Winfetch, Step-by-Step

Step 1: Confirm the install location

Run this to verify exactly where the script landed:

Get-InstalledScript winfetch | Select-Object Name, InstalledLocation

Step 2: Run it directly as a workaround

Before touching PATH, you can invoke winfetch immediately using its full location:

& "$((Get-InstalledScript winfetch).InstalledLocation)\winfetch.ps1"

That works, but typing it every time is obviously impractical. The permanent fix takes about ten seconds.

Step 3: Add the Scripts folder to PATH permanently

Open PowerShell and run the following command to append the Scripts folder to your PATH inside your profile:

Add-Content $PROFILE "`n`$env:PATH += `";`$([System.Environment]::GetFolderPath('MyDocuments'))\PowerShell\Scripts`""

Then reload your profile in the current session:

. $PROFILE

After that, typing winfetch works cleanly from any new PowerShell session. No more “not recognized” errors, no manual path juggling.

Tip: Execution Policy

If PowerShell refuses to run the script at all, check your execution policy first: Get-ExecutionPolicy. A setting of Restricted blocks all scripts. Set it to RemoteSigned with: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

Which to Use: Winfetch or Fastfetch?

The choice comes down to how you work, not which tool is objectively better.

Tool Best For Install Method Config Format
Fastfetch Speed, cross-platform use, binary simplicity winget install fastfetch JSONC file
Winfetch PowerShell-native feel, Windows Terminal + Oh My Posh setups Install-Script winfetch -Scope CurrentUser PowerShell config script

Reach for fastfetch when you want something fast, dependency-free, and portable across platforms. Winfetch makes more sense if you live inside PowerShell and want the output to feel like it belongs there — especially alongside Windows Terminal and a styled prompt. Both tools beat neofetch on Windows in 2026. Pick one and move on. Either way, you get a clean, colorful system info display — and you leave a frozen Bash script behind where it belongs. That’s about as good as tradeoffs get here in Windows-World. Cheers!

Facebooklinkedin
Facebooklinkedin

Oh My Posh Shows Real ARM vs x64 Differences

Following the Oh My Posh documentation, I recently ran oh-my-posh font list on my ASUS Zenbook A14 . It’s a Qualcomm Snapdragon X Elite ARM64 machine running Windows 11. The result? Nothing. No output, no error, no interactive list, just a blinking cursor that eventually handed the prompt back to me. That same command works beautifully on all my x64 PCs and laptops. Thus, Oh My Posh  shows real ARM vs x64 differences. Indeed, this sent me down a rabbit hole to figure out what OMP’s font subsystem does under the hood.

How Oh My Posh Shows Real ARM vs x64 Differences

When you run oh-my-posh font list on a working x64 machine, you get a list of available Nerd Fonts pulled live from GitHub. You can scroll that list, select a font, and it copies the name into the paste buffer for subsequent re-use. It’s helpful.

On my ARM64 Zenbook, none of that renders. The command exits silently. No crash, no error code, no partial output. That silence is itself a clue.

Inside the Oh-My-Posh Font Subsystem

OMP is written entirely in Go, and its font subsystem layers several platform-specific APIs and third-party frameworks. Understanding what those are and how they work explains why ARM64 falls short.

The first dependency is Bubble Tea a terminal oriented display and interaction UI. OMP’s font commands use Bubble Tea’s program model to launch, render, and manage the font list. Bubble Tea drives the terminal via ANSI/VT escape sequences and calls into Go’s golang.org/x/term package to manipulate terminal raw mode. On x64 Windows, Windows Terminal’s VT rendering pipeline handles these sequences without issue. On ARM64, subtle gaps in how the ARM64 console host processes certain VT sequences — particularly around alternate screen buffers and raw-mode toggling — can cause Bubble Tea’s rendering loop to fail before it draws a single line.

The second dependency is a live HTTPS call to the Nerd Fonts GitHub Releases API, which is how OMP fetches the current font list. This call goes out over Go’s standard net/http TLS stack. On ARM64, Go’s TLS implementation compiles natively, but the ARM64 binary links against a slightly different set of system crypto libraries. If that HTTP call fails silently, owing to a timeout, a TLS handshake hiccup, or a missing response, Bubble Tea never receives the data it needs to populate the list, and the program exits with nothing to show.

The third set of dependencies covers font installation: GDI32’s AddFontResourceW function (called via Go’s syscall and unsafe packages), Windows Registry writes through golang.org/x/sys/windows/registry, and a PostMessageW broadcast carrying WM_FONTCHANGE to notify the shell that new fonts are registered. These are the plumbing that oh-my-posh font install uses after the list is displayed. They are less relevant to the silent-exit problem, but they represent additional surfaces where ARM64’s native API behavior diverges from x64.

Where ARM Falls Down (or Out)

The core issue is that OMP’s font tooling was developed and battle-tested on x64 Windows. The Bubble Tea TUI path, the live GitHub fetch, and the GDI32 font registration flow all work reliably there. ARM64 Windows is a native platform now — not emulation — but the console host, terminal rendering, and system library behavior still carry edge cases that x64 does not.

Bubble Tea’s dependency on terminal raw mode and VT escape handling is especially fragile on ARM64 because Windows Terminal’s ARM64 build has historically lagged behind x64 in VT conformance. A Bubble Tea program that initializes correctly on x64 can silently short-circuit on ARM64 if golang.org/x/term‘s raw-mode call returns an unexpected result, causing the event loop to spin zero times and exit.

The irony is that OMP itself — the prompt rendering engine — works great on ARM64. The font management tooling sits on a different, more complex stack, and that stack exposes the seam between x64-matured tooling and an ARM64 Windows environment that is still catching up.

Takeaways for ARM Users

If you hit silent output from oh-my-posh font list on an ARM64 Windows machine, you now know it is not user error. It’s a real platform gap rooted in Bubble Tea TUI compatibility, live HTTP fetching, and ARM64 console API edge cases. The workaround for the moment is to install Nerd Fonts the old-fashioned way: grab the zip directly from the Nerd Fonts GitHub releases page and drop the TTF files into your user fonts folder manually. It’s not as elegant as OMP’s interactive installer, but it gets the job done.

This kind of difference is exactly why I find ARM Windows fascinating. The platform is capable, but it still surfaces small, instructive wrinkles like this one. Though I’ve seen nothing to make me question my investment in ARM hardware, oh-my-posh font list returning nothing is about as vivid a demonstration as I have seen of possible impacts of platform differences. That’s a thing worth watching out for, here in Windows-World.

Note: Only newer OMP versions (30.X.X) and higher support the font list capability. If you’re run the bog standard version on x64 (v29.0.2) you won’t see it, either. Winget should get the latest version (30.6.5) into its pipeline soon, after which you can see it, too. On the right kind of PC, anyway…

Facebooklinkedin
Facebooklinkedin

The Incredibly Bogus MSI BIOS Update

Windows Update pinged me yesterday, August 18, with a firmware notification: my MSI motherboard had a BIOS update available. My reaction was less “Great, let me install that…” and more “Wait! I just did.” The week before, I’d downloaded MSI’s latest BIOS package, copied it to a FAT32 USB drive, booted into MSI’s M-Flash utility, and flashed the thing the old-fashioned way. It worked perfectly. So why was Windows Update acting like none of that had ever happened? Thereby hangs the tale of the incredibly bogus MSI BIOS update. Here goes…

Hunting Down the Bogus MSI BIOS Update

The “bogus” here isn’t the update itself. Indeed, Windows Update found it and sought to deliver it. What was bogus was any awareness on WU’s part that I’d already installed it. When I flashed the BIOS using MSI’s UFD-based utility, that transaction happened entirely outside of Windows. No registry entry. Windows Update history records missing. No UEFI firmware capsule delivery for WU to track. As far as Windows Update was concerned, the update had never been applied, and it was doing its best to make sure I got it.

I confirmed the BIOS version in the UEFI settings. Indeed, it matched the version WU was offering. I checked Windows Update history: no entry for the flash, naturally. Optional updates, Driver updates: WU really wanted me to install this update. So I did, and of course it failed because MSI is smart enough to refuse a second install of the same UEFI version (I’ve had this happen on Lenovo PCs/laptops as well).

WU Remains Oblivious to OOB BIOS Updates

Windows Update tracks firmware updates it delivers itself. Typically, they come via UEFI firmware capsule updates. Those hand off to the firmware installer, and WU records the update in its history database. When you flash a BIOS using a manufacturer’s standalone tool (e.g. MSI’s M-Flash, a DOS-based utility, or a UFD flash from UEFI) Windows is completely out of the loop. There’s no handshake, no callback, no “hey, Ed already did this” signal.

The result: WU sees the target BIOS version, compares it against its own records (which show nothing). It concludes the update is needed. It’s not wrong, exactly. It just doesn’t know what it doesn’t know. And because the update failed anyway (I couldn’t figure out how to kill the pending item before it was applied, even with Copilot’s help) it appeared every time I checked updates in WU.

Until I hid the update it kept trying and failing to install after a mandatory restart. Vexatious!

PSWindowsUpdate Hides the Bogus Offer

For this case, the solution wasn’t to install the update again. Reflashing a BIOS that’s already current is unnecessary and might cause problems. The goal was to tell Windows Update, in terms it would respect, to quit offering that item. That’s a job for the PSWindowsUpdate module from the PowerShell Gallery.

I imported the module, enumerated all pending updates to confirm the BIOS entry was there, and then hid it. The complete sequence is in the lead-in graphic, but here it is in text form for easy access (info following # is purely descriptive and need not be entered):


Import-Module PSWindowsUpdate #Invokes PSWU cmdlet set
Get-WindowsUpdate -MicrosoftUpdate #Calls WU for upd chk
Hide-WindowsUpdate -Title "Micro-Star..." #Hides MSI upd

You can use the Title or the KB number for an update to block it. Then you can use the Get-WindowsUpdate -MicrosoftUpdate -IsHidden cmdlet to show you if your efforts succeeded.

Problem Solved, Mostly

After running Hide-WindowsUpdate, Windows Update stopped flagging the firmware update. No more notifications, no more badge on the WU icon, no more politely worded insistence that I was a BIOS version behind. A quick recheck of Get-WindowsUpdate showed a clean list.

One thing: hiding an update using PSWindowsUpdate is reversible. You can unhide it later with Show-WindowsUpdate if you ever want WU to see it again. And if you’re in the opposite situation (WU is offering a BIOS you genuinely haven’t installed), the Install-WindowsUpdate cmdlet handles that well. Either way, PSWindowsUpdate gives you control that the standard WU interface simply doesn’t.

Here in Windows-World, it’s always something. This time, it was a weird and unwanted BIOS update. Whatever it may be next time, count on me to tell you about it, and how to work with, through, or around it as circumstances might require. Cheers!

Facebooklinkedin
Facebooklinkedin