PowerShellでインストールされているソフトウェアのバージョン情報を取得する方法

PowerShellでインストールされているソフトウェアのバージョン情報を取得する方法を現在の環境で使うなら「classic desktop appは64/32bit Uninstall registryを読み、packaged appはGet-AppxPackage、package manager管理はwinget listで補います。一つのsourceで全softwareを網羅できないことを明記します。」が基本方針です。対象はWin32_ProductはMSI consistency checkを誘発し得るためinventoryの既定にしないケースです。inventory取得はread-onlyに限定し、導入・削除操作を結果判定から切り離します。

目次

machine・WOW6432・user scopeを分離する

ソフトウェア版数調査では、マシン全体とユーザー単位、32-bitと64-bitの登録場所を分けて読み、Name、Publisher、製品IDで対象を一意化します。Win32_Productは再構成を誘発する可能性があるため棚卸しには使いません。レジストリやパッケージ管理情報の出典を残し、複数版の共存を欠損扱いしません。

  • OS architectureとuser/system scopeを確認する
  • Uninstall registryの64bit/32bit両pathを読む
  • MSIX/AppXとportable appを別sourceとして扱う
  • product名、publisher、versionの正規化ruleを決める

Uninstall registryから表示情報を読む

registryとpackage一覧の読取は通常変更しません。Win32_Product query、uninstall string実行、COM application起動をinventoryに使わず、本番appへrepairや初期化を誘発しません。結果にはinstall path、publisher等が含まれるのでaccessを限定します。変更やuninstallはcurrent version、installer source、user data backup、rollback packageを確認する別作業にします。

Appx packageを別inventoryとして取得する

  • Win32_Productを全software一覧に使う
  • HKLM 64bit pathだけを見る
  • per-userとmachine-wideを混同する
  • DisplayVersionを数値として単純比較する
  • portable appを未導入と断定する

winget listは補助sourceとして扱う

machine-wide Uninstall keysを読む

$paths='HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
Get-ItemProperty $paths -ErrorAction SilentlyContinue | Where-Object DisplayName |
  Select-Object DisplayName,DisplayVersion,Publisher,InstallLocation,PSPath

registry読取はinstallerを実行しません。重複keyをproduct IDで整理します。

current user scopeを確認

Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' -ErrorAction SilentlyContinue |
  Where-Object DisplayName | Select-Object DisplayName,DisplayVersion,Publisher

別userのper-user appは見えません。scopeをinventory結果へ記録します。

packaged appを取得

Get-AppxPackage | Select-Object Name,PackageFullName,Version,Publisher

current user分です。AllUsersは権限と共有範囲を確認します。

winget inventoryを補助

winget list --accept-source-agreements

source合意やnetwork policyを確認します。すべてのappが一意にmappingされる保証はありません。

特定publisherをexactに絞る

Get-ItemProperty $paths -ErrorAction SilentlyContinue |
  Where-Object { $_.DisplayName -eq 'Target Application' -and $_.Publisher -eq 'Expected Publisher' } |
  Select-Object DisplayName,DisplayVersion,Publisher,PSChildName

-likeで似たproductを混ぜず、publisherとproduct codeも見ます。

DisplayNameとPublisherをexactに絞る

DisplayVersionはvendor文字列でsemantic versionとは限りません。更新helperやlanguage packが別entryとして出る場合があり、同じDisplayNameの32/64bitもあります。registryに無いportable app、per-user app、Store appを「未導入」と断定しません。Win32_ProductはMSI製品だけで副作用があるため避けます。

Win32_Productをinventoryへ使わない

Settings Installed apps、vendor applicationのAbout、winget list、registryをsample数件で照合します。inventoryには取得host、user scope、source、timeを付け、重複排除前後の件数を記録します。version判定はvendorのsupport表と比較し、文字列の大小だけで新旧を決めません。

Unique・Ambiguous・NotFoundを判定する

classic desktop appはHKLM/HKCUのUninstall key、MSIXはGet-AppxPackage、package manager管理分はwinget listで補います。DisplayVersionはvendor文字列なのでsemantic versionへ無条件変換せず、sourceとscopeを保ったinventoryにします。

三つのUninstall scopeを一つの表へ統合する

$roots='HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*','HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
Get-ItemProperty $roots -ErrorAction SilentlyContinue | Where-Object DisplayName | Select-Object @{n='Source';e={'UninstallRegistry'}},DisplayName,DisplayVersion,Publisher,PSChildName,PSPath

一意・複数・registry未検出を分ける

  • productを一意化:product名・publisher・IDをexactに絞り、scope/sourceごとにversionを一意に取得する
  • registry未検出:一sourceで0件でもportable/MSIX/別userの可能性を残しNotFoundInSourceとする
  • scope読取error:registry access、AppX service、winget source errorは各sourceのError状態として集計する

Win32_ProductはMSI consistency checkを誘発し得るためinventoryに使いません。DisplayNameのlike検索だけで製品を決めず、32/64bit key、Publisher、PSChildName/package IDを合わせます。

同名別publisherとuser別導入を試す

$r=@(Get-ItemProperty $roots -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -eq 'Target Application' -and $_.Publisher -eq 'Expected Publisher' })
[pscustomobject]@{State=if($r.Count -eq 1){'Unique'}elseif($r.Count){'Ambiguous'}else{'NotFoundInRegistry'};Count=$r.Count}

machine/user、32/64bit、MSIX、portable、重複entry、source failureをtestします。product ID、publisher、scope、source、raw version、path、取得host/timeを保存します。

registryにないことは未導入の確定ではありません。MSI/EXE、Appx、portable、winget sourceを分け、製品名だけでなくpublisherとscopeを合わせて判定します。

公式情報・参考資料

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次