Technically Impossible

Lets look at the weak link in your statement. Anything "Technically Impossible" basically means we haven't figured out how yet.

PowerShellによるISOファイルのマウント、そしてドライブ・レターの変更 2023年版

Windowsインフラの管理に欠かせない要素技術の一つがWMI (Windows Management Instrumentation)、そして、その作業に用いるのがWMIC utility (Windows Management Instrumentation Command-line utility)だ。しかし、この機能は21H1以降のWindows 10、Windows Server (Semi-Annual Channel)では非推奨とされている。

The WMI command-line (WMIC) utility is deprecated as of Windows 10, version 21H1, and as of the 21H1 semi-annual channel release of Windows Server.

wmic | Microsoft Learn

Windows 11でも次の箇所から導入可能ではあるのだが、WMIC自体の開発が停止しているため、Windows 11でも非推奨であることに変わりはない。

Settings > Apps > Optional features

WMICに代わって利用推奨されているのが、CIM (Common Information Model) Cmdletだ。

この投稿は、かつてのWMI + PowerShellによるISOファイルのマウントに関する投稿*1を、CIM Cmdletを用いた2023年度版として、改めることにしたものだ。

WMIとCIM (Common Information MODEL)

業界標準化団体DMTF (Distributed Management Task Force)の定めた共通情報モデルがCIM*2、そして、そのプロトコルがWS-Man (Web Services-Management protocol)だ。

クラウド対応と、それが前提とする異種混合環境での運用を標準化、効率化するために、MicrosoftもCIMに対応することになった。この観点からWMIを捉えると、次のように解釈できる。

WMI Windows CIM server
WinRM Windows WS-Manプロトコル

WMICが非推奨になるとはいえ、誤解したくないのは、WMIが廃止されるわけではないことだ。CIMはWindowsに対しても、Linuxに対しても共通に機能するが、特にWindows内部処理においてはWMIを呼び出す必要がある。つまり、

  • WMI Cmdletは使用しない。
  • CIM Cmdletを代わりに使用する。
  • しかしWMI、Win32を呼び出すことに変わりはない。

WMIはビジネスの現場で多用されるからか、CIMへの移行について十分に検討、考慮されている。一部の例外を除き、基本的にはスクリプトで使用されているWMI Cmdletの名前「WMI」を「CIM」に書き換えれば済むようにデザインされている。

この例外とは、WMI独自の記述スタイルによる悪習をCIMへ持ち込まないための措置であり、例外とは言え改善要素だ。

You will also notice that in some places we have broken this rule – and script using WMI cmdlet can’t be simply changed to CIM cmdlet by changing the cmdlet name. e.g.

You will also notice that in some places we have broken this rule – and script using WMI cmdlet can’t be simply changed to CIM cmdlet by changing the cmdlet name. e.g.

Introduction to CIM Cmdlets - PowerShell Team

おさらい:デバイスパーティション~ボリューム

バイス
ディスク
ドライブ
物理機器、論理機器
それらの抽象化
オフィスのフロア
パーティション ディスク内の区切り、仕切り フロア内の仕切り
ボリューム パーティションによって区切られた空間 仕切られた部屋
会議室など
ドライブ・レター パーティション、ボリュームへのポインタ 会議室番号
部屋番号
座席番号など

まずデバイス、ディスクという概念がある。どちらも、ほぼ同義に用いられる。端的にはHDDや光学ドライブのような機器を指しているのだが、物理、論理の区別はなく抽象的な存在を指している。複数の物理機器をまとめて論理的に一つのドライブ形成する(つまりRAID)もあれば、仮想サーバーのディスクにマウントする仮想ディスク(つまりファイル)である場合もあるからだ。ここではディスクと呼ぶことにする。

ディスク内の使用領域は必要に応じて区切られる。これをパーティションと呼ぶ。パーティションは文字通り、仕切りや区切りのことを指している。区切られた空間は含まない。区切られた空間はボリュームと呼ばれる。
オフィスや部屋のパーティションを想像すると良い。それらは区切られた空間を指すのではなく、仕切りそのものを指している。

そしてドライブ・レターは、パーティションかボリュームに割り当てられる。それはマウント・ポイントとして機能する。オフィスの例に倣えば、それは部屋番号と言ったところだろうか。

考え方

フロアがパーティションで仕切られ、仕切られた空間に部屋番号を割り当てる例え話を続ける。
HDDやSSDのようなパーティションで仕切ることのできる空間というのは、オフィス・ビルの単一フロアだ。一方、光学メディアやISOファイルは、言うなればパーティション設置不可、仕切ることのできない単一フロア全体といえば、理解できるだろうか。
そのようなフロアに部屋番号(ドライブ・レター)を割り当てるならば、パーティションが存在しないため、次のいずれかに割り当てるしかない。

  • フロア空間をホストするもの(例えば光学ドライブ、その仮想ドライブ)
  • フロアそのもの(つまりボリューム)

そして、ISOファイルにドライブ・レターを割り当てるならば、それは後者になるということだ。

ISOファイルのマウント

注意

ここで紹介するスクリプトを実行するには管理者権限が必要だ。もしPowerShell、あるいはVSCodeのターミナル上で動作させる場合には、それらが「管理者として実行」されている必要があることに注意。
用いているスクリプト・コード、並びにコマンドレットなどのリファレンスは投稿末尾にまとめている。

Bad pattern

PowerShellでは、ドライブ・レターの操作はパーティション・レベルで処理される。おさらいを踏まえれば、次の手順を実施することになるのだが、これは失敗する。パーティションが存在しないからだ。

  1. 目的のISOファイルをマウントする。
  2. 1のボリュームを取得する。
  3. 2のパーティションを取得する。
  4. 取得したパーティションのドライブ・レターを変更する。

🔎MountISO_ChangeDrv-Bad.ps1
gist.github.com

CD-ROMはZドライブにマウントされている。そのディスク・イメージからボリューム情報は取得できるものの、パーティション情報は取得できない。念のためパーティションを一覧表示すると、Zドライブはパーティションとして存在していないことが分かる。
結果として、この方法では"Set-Partition"を利用してドライブ・レターを変更する手立てが通用しないことが分かる。

Good pattern

ボリュームへドライブ・レターを割り当てるには、"diskpart"や"mountvol"などのコマンドを用いるのも一案だが、ここではそれらは用いない。
UNX/Linux系のシェルはテキストの世界だ。いわゆるパイプ処理は、出力結果としてのテキストを引き継ぎながら処理していく。コマンドプロンプトも同様だ。
一方PowerShellはオブジェクトの世界だ。PowerShellでのパイプ処理はオブジェクトを引き継ぎながら処理していく。ISOファイル、それにまつわるボリュームもオブジェクトとして処理したいところだ。

ここではインスタンス化したWMIオブジェクトを用いることにした。おさらいを踏まえた上で、次の手順を実施することになる。そして、これは成功する。

  1. 目的のISOファイルをマウントする。
  2. 1のボリュームのドライブ・レターを特定する。
  3. 特定したドライブ・レターを持つWMIオブジェクトのドライブ・レターを目的にものへ変更する。

順番にコードを説明していく。まずmyISOにISOファイルの絶対パスを指定し、それをマウントする。

$myISO = 'E:\ISO\Microsoft Bookshelf Basic\BSBASIC2.ISO'
mount-diskimage $myISO

マウントしたISOファイルのボリュームを取得し、割り当てられたドライブ・レターを確認する。PowerShellではドライブ・レターは'X'、'Y'のように1文字だが、WMIでは'X:'のように「:」が必要なので付与する。
目的とする新しいドライブ・レターを定義する。

$vol = Get-DiskImage $myISO | Get-Volume
$old_drv = $vol.DriveLetter + ':'
$new_drv = 'X:'

まずボリューム情報の一覧をWMIオブジェクトとして取得する。取得したボリューム情報から、ISOファイルが割り当てられているボリュームを特定し、インスタンス化する。インスタンス化したボリュームのドライブ・レターを目的のものへ変更する。
この一連の流れをパイプを介して1行で実行している。

Get-CimObject -Class Win32_Volume | Where-Object {$_.DriveLetter -eq $old_drv} | Set-CimiInstance -Arguments @{DriveLetter=$new_drv}


結果はこの通りだ。ISOファイルが割り当てられていたドライブは、Xドライブに変更された。
一連のコードをスクリプト・ファイルとして保存し、タスクスケジューラからログオン時、あるいはスタートアップ時にでも起動するようにしておくと良い。

🔎MountISO_ChangeDrv-Good.ps1
gist.github.com