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()メソッドを呼ぶ必要があります。 つまり以下です。

※ Windows 8では稼働しています。

#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を指定します。

(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の開閉をすると以下になります。

$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 &gt>ripting > E> CD/DVD tray--simpe JavaScript

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紹介です。