tech.guitarrapc.cóm

Technical updates

PowerShellでCD ROMドライブのエジェクトをしたい

更新ネタが溜まってるのですが、一向に更新せずにいますー。 今日は、牟田口先生の以下のエントリーの内容を見てみたり。
PowerShell Scripting Weblog - CD-ROMトレイを取り出せるPowerShell関数、「Dismount-CDDrive」作った
いくつか記事の内容では気になる点があったため、検証しました。

WMPlayer.OCXでのCD ROMの開閉

ここにも有りますが、 WMPlayer.OCXオブジェクトを使うと、Windows Media Player へのプログラムによるアクセスが可能になります。
Hey, Scripting Guy! .WMA ファイルの Title プロパティを変更する方法はあり​ますか
さて、では示されていたコードを見てみます。
(New-Object -com WMPlayer.OCX.7).cdromCollection.Item(0).Eject()
至ってシンプルでキレイですねー。 New-Object -comでWMPalayer.OCX.7のオブジェクト生成してます。 ※.7はWindows Media Player7 (XP以降搭載)を示すそうで…….8とかにしてもだめでしたw ※ただしWMPlayer.OCXだけで正常に動作します。.7の意図が読めないのですが…。

問題点

さて、CD ROMトレイの開閉は、以下で行います。
#CM ROMトレイを開ける
生成したオブジェクトで一回だけeject()メソッドを呼ぶ。

#CM ROMトレイを閉める
生成したオブジェクトで2回連続でeject()メソッドを呼ぶ。
先生の紹介では()でNew-Objectを囲むことで、ワンライナーでプロパティにアクセスしていますが…閉じられないんですね。 …そりゃそうですが。
#CD ROMトレイを開ける = 意図した通りCD ROMトレイが開きます。
(New-Object -com WMPlayer.OCX.7).cdromCollection.Item(0).Eject()
#CD ROMトレイを閉じる = 意図した通りCD ROMトレイが閉じません。
(New-Object -com WMPlayer.OCX.7).cdromCollection.Item(0).Eject()
(New-Object -com WMPlayer.OCX.7).cdromCollection.Item(0).Eject()

解決方法

WMPlayer.OCXを利用してCD Romトレイを開閉するには、生成したWMPlayer.OCXオブジェクトを介して以下のアクセスを要します。 よって、一度New-Objectで生成したオブジェクトを変数に保持して、その変数からeject()メソッドを呼ぶ必要があります。 つまり以下です。 ※.7は入れてもいれなくてもWindows8では稼働しています。
#CD ROMトレイを開ける
function Eject-CDROM{
    $wmplayer = New-Object -ComObject WMPlayer.OCX
    $wmplayer.cdromCollection.Item(0).Eject()
}

Eject-CDROM
#CD ROMトレイを閉じる
function Close-CDROM{
    $wmplayer = New-Object -ComObject WMPlayer.OCX
    $wmplayer.cdromCollection.Item(0).Eject()
    $wmplayer.cdromCollection.Item(0).Eject()
}

Close-CDROM

WMI ObjectでCD ROMの開閉

さて、上記のやり方だと、CD ROMトレイを指定しにくいですね…。 WMIを介したCD ROMドライブの確認は以下で行えます。
Get-WmiObject -Class Win32_CDROMDrive
シェルで、My Computerを指定するにはNameSpaceで17を指定します。 [22/Jan/2013追記]※なぜ17を指定するのかは、この記事で紹介しています。
(New-Object -com Shell.Application).Namespace(17)
あとは、ParseNameにWMIで取得したドライブ名を指定します。
(New-Object -com Shell.Application).Namespace(17).ParseName("A:\")
最後に、InvokeVerbで信号を送ります。
(New-Object -com Shell.Application).Namespace(17).ParseName("A:\").InvokeVerb("Eject")
※Ejectで動きますが、動かない人は"E&ject"で試してください。 WMI Object経由で全CD ROM情報を取得して、COM経由でshellを介して全部CD ROMの開閉をすると以下になります。 ※面倒なのでワンライナーにしました
(Get-WmiObject -Class Win32_CDROMDrive).Drive | %{(New-Object -com Shell.Application).Namespace(17).ParseName($_).InvokeVerb("Eject")}
ワンライナーにしましたが、これではNew-Objectしてるので閉めれなさそうですね…以下で。
$cdrom = Get-WmiObject -Class Win32_CDROMDrive
(Get-WmiObject -Class Win32_CDROMDrive).Drive | %{$cdrom.Namespace(17).ParseName($_).InvokeVerb("Eject")}
さて、色々試しましたがCD ROMトレイを開けることのは上手くいきますが、閉めることが出来ません。 どういうことか、トレイを指定してみますが…だめです。
$shell = new-object -com Shell.Application
$cd = $shell.Namespace(17).ParseName('A:\')
$cd.InvokeVerb("Eject")
$cd.InvokeVerb("Eject")
これは以下のフォーラムでも同様の問題を協議しており、残念ながらWindows Vista以降Ejectの仕様が変わり出来なくなったようです。
My Digital Life Forums > Coding Life > Scripting > Eject CD/DVD tray--simpe java script

winmm.dllを介したCD ROMの開閉

以下にサンプルがありますが……古いやり方ですしやめておきます。 PowerShell, CdAudioDoor Module

まとめ

牟田口先生の紹介されたWMPlayer.OCXを介したやり方がもっとも適してますね。 よってサンプルとしては、以下となります。 お好きにスイッチ追加して切り替えるなりどうぞ~。
#CD ROMトレイを開ける
function Eject-CDROM{
    $wmplayer = New-Object -ComObject WMPlayer.OCX
    $wmplayer.cdromCollection.Item(0).Eject()
}

Eject-CDROM
#CD ROMトレイを閉じる
function Close-CDROM{
    $wmplayer = New-Object -ComObject WMPlayer.OCX
    $wmplayer.cdromCollection.Item(0).Eject()
    $wmplayer.cdromCollection.Item(0).Eject()
}

Close-CDROM
次回は、PowerShellでのWPF紹介です。