しばたテックブログ

気分で書いている技術ブログです。

PowerShellでmountvolコマンドを代用する

ディスクボリュームのマウント・アンマウントやドライブレターの割り当てを行うのに便利なmountvolコマンドですが、本エントリではこれをPowerShellで代用する方法について説明します。

Storage Cmdletの使用

Windows 8/Windows Server 2012以降であれば、Storage Cmdletに追加されたコマンドレットで概ね代用できます。
ただし、一部の機能についてはコマンドレットでは代用できずWMIでWin32_Volumeクラスの機能を利用する必要があります。

PowerShellでmountvolコマンドを代用する

最初にWindows Server 2012 R2でmountvolコマンドのヘルプを見ると以下の様になっています。

PS C:\> mountvol /?
ボリューム マウント ポイントを作成、削除、一覧を表示します。

MOUNTVOL [ドライブ:]パス ボリューム名
MOUNTVOL [ドライブ:]パス /D
MOUNTVOL [ドライブ:]パス /L
MOUNTVOL [ドライブ:]パス /P
MOUNTVOL /R
MOUNTVOL /N
MOUNTVOL /E

    パス        マウント ポイントを常駐させる既存の NTFS ディレクトリ
                を指定します
    ボリューム名
                マウント ポイントのターゲットとなるボリューム名を指定しま
                す。
    /D          指定されたディレクトリからボリューム マウント ポイント
                を削除します。
    /L          指定されたディレクトリのマウントされているボリューム
                の一覧を表示します。
    /P          指定されたディレクトリからボリューム マウント ポイントを削除
                してボリュームをマウント解除し、ボリュームをマウントできな
                くします。
                ボリューム マウント ポイントを作成して、もう一度ボリュームを
                マウントできるようにします。
    /R          システムに存在しないマウント ポイント ディレクトリとレジストリ
                設定を削除します。
    /N          新しいボリュームの自動マウントを無効にします。
    /E          新しいボリュームの自動マウントを再び有効にします。

これからこの各オプションについてどう代用するか説明していきます。*1

ボリューム情報を表示する(MOUNTVOL /L)

ボリュームの表示はGet-Volumeコマンドが使えます。
mountvolコマンドと同等の情報を出力するには以下の様にすればOKです。

Get-Volume | Format-Table ObjectID, DriveLetter -AutoSize

実行例は以下。

PS C:\> Get-Volume | Format-Table ObjectID, DriveLetter -AutoSize

ObjectID                                          DriveLetter
--------                                          -----------
\\?\Volume{a8cbd0fc-83fc-11e4-80b3-806e6f6e6963}\           
\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\           
\\?\Volume{a8cbd0fd-83fc-11e4-80b3-806e6f6e6963}\           C
\\?\Volume{99d153e8-2248-11e6-80d0-08002724e199}\           D    

ただし、ボリュームをドライブではなくディレクトリ上にマウントした場合はWin32_VolumeクラスのNameプロパティから情報をとる必要があります。
以下はボリューム\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\D:\OtherDrive\にマウントした場合の例になります。

PS C:\> Get-WmiObject -Class Win32_Volume | Format-Table DeviceID, Name

DeviceID                                                    Name
--------                                                    ----
\\?\Volume{a8cbd0fc-83fc-11e4-80b3-806e6f6e6963}\           \\?\Volume{a8cbd0fc-83fc-11e4-80b3-806e6f6e6963}\
\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\           D:\OtherDrive\
\\?\Volume{a8cbd0fd-83fc-11e4-80b3-806e6f6e6963}\           C:\
\\?\Volume{99d153e8-2248-11e6-80d0-08002724e199}\           D:\

ドライブレターを割り当てる(MOUNTVOL)

ドライブレターの割り当てについて、当初Set-Volumeが使えるのかなと思っていたのですが、こいつはボリュームのラベルを設定するためのコマンドレットでドライブレターの割り当てには使う事ができませんでした...
かなりわかりにくいのですが、ドライブレターの割り当てはボリュームからではなく、Add-PartitionAccessPathコマンドレットを使ってパーティションからアクセスパスを指定する形で行う必要があります。

上記の例でボリューム\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\にドライブレターEを割り当てる場合は以下の様にします。

$Drive = "E:\"
$ID = '\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\'
Get-Volume -ObjectId $ID | Get-Partition | Add-PartitionAccessPath -AccessPath $Drive

結果を確認すると以下の様になりドライブレターが割り当たっていることが確認できます。

PS C:\> Get-Volume | Format-Table ObjectID, DriveLetter -AutoSize

ObjectID                                          DriveLetter
--------                                          -----------
\\?\Volume{a8cbd0fc-83fc-11e4-80b3-806e6f6e6963}\           
\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\           E
\\?\Volume{a8cbd0fd-83fc-11e4-80b3-806e6f6e6963}\           C
\\?\Volume{99d153e8-2248-11e6-80d0-08002724e199}\           D

ちなみに、Win32_Volumeクラスを使ってドライブレターを割り当てる場合はAddMountPointメソッドを使います。
Storage Cmdletが使えない環境では以下の様にすれば良いでしょう。

$Drive = "E:\"
$ID = '\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\'
$Volume = Get-WmiObject -Class Win32_Volume | Where-Object { $_.DeviceID -eq $ID }
$Volume.AddMountPoint($Drive)

ドライブレターの割り当てを解除する(MOUNTVOL /D)

ドライブレターの割り当てを解除するにはRmove-PartitionAccessPathコマンドレットを使います。
ドライブレターがわかっていればGet-Partitionから直ちにパーティションの情報はとれますので、以下の様にしてアクセスパスを削除してやればドライブレターも解除されます。

Get-Partition -DriveLetter "E" | Remove-PartitionAccessPath -AccessPath "E:\"

実行結果は以下となりドライブレターの割り当てがなくなっていることがわかります。

PS C:\> Get-Volume | Format-Table ObjectID, DriveLetter -AutoSize

ObjectID                                          DriveLetter
--------                                          -----------
\\?\Volume{a8cbd0fc-83fc-11e4-80b3-806e6f6e6963}\           
\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\           
\\?\Volume{a8cbd0fd-83fc-11e4-80b3-806e6f6e6963}\           C
\\?\Volume{99d153e8-2248-11e6-80d0-08002724e199}\           D

また、Win32_Volumeクラスを使う場合はDriveLetterプロパティを$nullにすればOKです。
設定後Put()メソッドを使い変更を確定させる必要があります。

$Drive = "E:"
$Volume = Get-WmiObject -Class Win32_Volume | Where-Object { $_.DriveLetter -eq $Drive }
$Volume.DriveLetter = $null
$Volume.Put()

ボリュームをアンマウントする(MOUNTVOL /P)

ボリュームをアンマウントするのはStorage Cmdletから出来ず、Win32_VolumeクラスのDismount()メソッドを使うしかない様です。

Dismount()メソッドを使うには、あらかじめドライブレターを解除しておく必要があり、MOUNTVOL /Pと同等にするには第2引数を$trueにする必要があります。
これらをまとめると以下の様にすることでアンマウントできます。

$Drive = "E:"
$Volume = Get-WmiObject -Class Win32_Volume | Where-Object { $_.DriveLetter -eq $Drive }
$Volume.DriveLetter = $null
$Volume.Put()
$Volume.Dismount($false, $true)

尚、MOUNTVOL /DMOUNTVOL /Pの違いについては以下の記事を参考にしてください。

blogs.technet.microsoft.com

この記事の内容を踏まえて実行結果を確認すると以下の様になります。

PS C:\> Get-Volume | Format-Table ObjectID, DriveLetter -AutoSize

ObjectID                                          DriveLetter
--------                                          -----------
\\?\Volume{a8cbd0fc-83fc-11e4-80b3-806e6f6e6963}\           
\\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\           
\\?\Volume{a8cbd0fd-83fc-11e4-80b3-806e6f6e6963}\           C
\\?\Volume{99d153e8-2248-11e6-80d0-08002724e199}\           D

PS C:\> mountvol

・・・(中略)・・・

現在のマウント ポイントとボリューム名の考えられる値:

    \\?\Volume{a8cbd0fc-83fc-11e4-80b3-806e6f6e6963}\
        *** マウント ポイントなし ***

    \\?\Volume{2ddbd13b-25b8-11e6-80d2-08002724e199}\
        *** ボリューム マウント ポイントが作成されるまでマウントできません ***

    \\?\Volume{a8cbd0fd-83fc-11e4-80b3-806e6f6e6963}\
        C:\

    \\?\Volume{99d153e8-2248-11e6-80d0-08002724e199}\
        D:\

新しいボリュームの自動マウントの設定を行う(MOUNTVOL /N)(MOUNTVOL /E)

新しいボリュームの自動マウント設定(MOUNTVOL /NおよびMOUNTVOL /EまたはDISKPART AUTOMOUNT)について、PowerShellで代替するにはレジストリの値を直接変更するしかない様です。

該当するレジストリキーは、Mountvol /N and diskpart automount disableKB822653によれば、

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MountMgr\NoAutoMountで、
0が"自動マウントする"、1が"自動マウントしない"との事です。

ただ、私が検証した範囲だとレジストリの変更とDISKPART AUTOMOUNTコマンドの結果が同期しませんでした...
原因は特定できなかったのですがこの程度であればPowerShellで代替せずmountvolコマンドをそのまま使った方が手っ取り早く確実でしょう。

システムに存在しないマウントポイント設定をクリアする(MOUNTVOL /R)

残念ながらMOUNTVOL /RをPowerShellで代替することはできない様で、この場合は素直にmountvolコマンドを使うしかないです。
正直なところあまり使用頻度の高いコマンドとも思えませんので代替できなくても問題ないと思います。

最後に

とりあえずこんな感じです。

ここまでの内容でわかるかと思いますが、mountvolコマンドとStorage Cmdlet、Win32_Volumeクラスの機能は綺麗に対比できる感じにはなっていません。

なので現実的にPowerShellで何かしようとする場合は両方を使い分ける必要があると思います。
基本はStorage Cmdletを使いつつ、どうしようもない場合はmountvolコマンドで対処するのが良いのではないでしょうか。

Storage cmdletで統一して操作できる様になればうれしいのですが、それはもうしばらく先の話になりそうです。

*1:MOUNTVOL /Sオプションについては情報を集めることができなかったので今回はスルーします...