2022-11-12

師走に向けて PowerShell モジュールの大掃除

PowerShell あるあるなのだけど、過去のモジュールが溜まってしまって自分で掃除しないといけない。 開発中でもない限りモジュールを切り戻することもないので、一気に消す。これが PowerFighter(勝手に作った PowerShell 使いの呼び名)の嗜み。

ゆーてもこしらえてあるスクリプトを流すだけ。以下の通り。個人的に -Scope AllUsers でモジュールを入れてるからそれに合わせた形となっている。 簡単のため改行を入れている。

# $PSGetPath.AllUsersModules をロードするために一度流す。
Get-InstalledModule
# Uninstall 対象の取り方。 AllUser 向けに入れてる場合。
Get-Module -ListAvailable | Where-Object -Property Path -Like "$($PSGetPath.AllUsersModules)*" `
| Group-Object -Property Name | Where-Object -Property Count -GT 1 `
| ForEach-Object { $_.Group | Sort-Object -Descending -Property Version | Select-Object -Skip 1 } `
| ForEach-Object { [pscustomobject]@{
Name = $_.Name;
RequiredVersion = "$($_.Version)$(if ($_.PrivateData.Values.PreRelease) {'-'+$_.PrivateData.Values.PreRelease} else {''})"
} }

# 心配なときは以下の出力の最新バージョンが Hit してないことを目検する。
# Get-Module -ListAvailable | ? -Property Path -like "$($PSGetPath.AllUsersModules)*"

# エグゼキューション。
# はじめは -WhatIf アリで流し、処理する時心配なら Confirm で一個ずつ確認する。
Get-Module -ListAvailable | Where-Object -Property Path -Like "$($PSGetPath.AllUsersModules)*" `
| Group-Object -Property Name | Where-Object -Property Count -GT 1 `
| ForEach-Object { $_.Group | Sort-Object -Descending -Property Version | Select-Object -Skip 1 } `
| ForEach-Object { [pscustomobject]@{
Name = $_.Name
RequiredVersion = "$($_.Version)$(if ($_.PrivateData.Values.PreRelease) {'-'+$_.PrivateData.Values.PreRelease} else {''})"
} } | Uninstall-Module -AllowPrerelease

prerelease なモジュールの削除も一緒に含めるため、ごちゃごちゃしている。 -Version の指定を楽にする場合は Get-InstalledModule を使ったらいいけど、モジュールごとに実行すると遅いし...と思って使ってない。

これで消しきれるかなと思ったけど、依存関係を忘れてたことでいくつかエラーをもらった。 2 周したらきれいになるかなと思いきや、以下のモジュールに関しては消しきれなかった。

  • Configuration
  • Metadata
  • PackageManagement
  • PowerShellGet

これらは AWS.Tools.InstallerPowerShellGet が依存しており消せないとのこと。 先述のスクリプトでは最新版は確保するようになってあるし、壊れても入れ直したらいから、古いものに関してはやや強引に -Force を付与して消し去る。

Get-Module -ListAvailable | Where-Object -Property Path -Like "$($PSGetPath.AllUsersModules)*" `
| Group-Object -Property Name | Where-Object -Property Count -GT 1 `
| ForEach-Object { $_.Group | Sort-Object -Descending -Property Version | Select-Object -Skip 1 } `
| ForEach-Object { [pscustomobject]@{
Name = $_.Name
RequiredVersion = "$($_.Version)$(if ($_.PrivateData.Values.PreRelease) {'-'+$_.PrivateData.Values.PreRelease} else {''})"
} } | Uninstall-Module -AllowPrerelease -Force

この如何にも PowerFighter な近距離パワー型アプローチ、まさに PowerShell って感じ(いいたいだけ)。 穢れたモジュールフォルダを綺麗にできた。