PowerShellではNew-ObjectコマンドレットのComObjectオプションを指定することで新規COMオブジェクトのインスタンスが可能1です。
しかし、状況によっては新規インスタンスではなく、既存のインスタンスを取得したい場合があります。
その場合、
- Microsoft.Visualbasic 名前空間の Interaction.GetObject メソッド
- System.Runtime.InteropServices 名前空間の Marshal.GetActiveObject / BindToMoniker メソッド
などを使用することで既存のインスタンスを取得することができます。
実際に試してみる
各方法で、Excelを取得・型名を表示させるスクリプトです。
$xlFileName
には実在するExcelファイルのパスを指定してください。
[String]$xlFileName = 'C:\hoge.xlsx'
# New-Object
# キャスト不要
Write-Host "`nNew-Object -ComObject Excel.Application"
[Microsoft.Office.Interop.Excel.ApplicationClass]$xlAppNewObj = New-Object -ComObject Excel.Application
$xlAppNewObj.GetType().FullName
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($xlAppNewObj)>$null #
$xlAppNewObj = $null
# Microsoft.Visualbasic
Add-Type -AssemblyName Microsoft.Visualbasic
Write-Host "`nGetObject('', 'Excel.Application')"
[Microsoft.Office.Interop.Excel.ApplicationClass]$xlAppGetObjCls = [Microsoft.VisualBasic.Interaction]::GetObject('', 'Excel.Application') -as [Microsoft.Office.Interop.Excel.ApplicationClass]
$xlAppGetObjCls.GetType().FullName
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($xlAppGetObjCls)>$null #
$xlAppGetObjCls = $null
# [Microsoft.Office.Interop.Excel.Workbook]へキャスト不可
Write-Host "`nGetObject(`'$xlFileName`', '')"
$xlWbGetObjPath = [Microsoft.VisualBasic.Interaction]::GetObject($xlFileName, '') #-as [Microsoft.Office.Interop.Excel.Workbook]
$xlWbGetObjPath.GetType().FullName
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($xlWbGetObjPath)>$null #
$xlWbGetObjPath = $null
# System.Runtime.InteropServices.Marshal
# [Microsoft.Office.Interop.Excel.ApplicationClass]へキャスト不可
Write-Host "`nGetActiveObject('Excel.Application')"
$xlAppMarshal = [System.Runtime.InteropServices.Marshal]::GetActiveObject('Excel.Application') #-as [Microsoft.Office.Interop.Excel.ApplicationClass]
$xlAppMarshal.GetType().FullName
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($xlAppMarshal)>$null #
$xlAppMarshal = $null
# [Microsoft.Office.Interop.Excel.Workbook]へキャスト不可
Write-Host "`nBindToMoniker(`'$xlFileName`')"
$xlWbMarshal = [System.Runtime.InteropServices.Marshal]::BindToMoniker($xlFileName) #-as [Microsoft.Office.Interop.Excel.Workbook]
$xlWbMarshal.GetType().FullName
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($xlWbMarshal)>$null #
$xlWbMarshal = $null
私の環境では以下のような結果となりました。
New-Object -ComObject Excel.Application
Microsoft.Office.Interop.Excel.ApplicationClass
GetObject('', 'Excel.Application')
Microsoft.Office.Interop.Excel.ApplicationClass
GetObject('C:\hoge.xlsx', '')
System.__ComObject
GetActiveObject('Excel.Application')
System.__ComObject
BindToMoniker('C:\hoge.xlsx')
System.__ComObject
まとめ?
OfficeのインスタンスをSystem.Runtime.InteropServices.Marshalのメソッドで取得した場合、Office.Interop~型へキャストできない(少なくともPowerShellの -as演算子では)。
またファイル名指定で取得した場合は、キャスト不可。
とりあえず使う分には問題無いけど、型を気にするならMicrosoft.Visualbasicをロードした方が無難。
参考
OfficeのNew-Objectの時の挙動
Office のプロセス インスタンス制御について
Office オートメーション サーバーの GetObject および CreateObject の動作
メソッド
Marshal.GetActiveObject メソッド (String)
Marshal.BindToMoniker メソッド (String)
他参考サイト
関連(宣伝)
GetObject(, "Excel~")だけで無く、GetObject(ファイル名)も活用しよう
GetObject('パス', '')やBindToMonikerメソッドは状況によっては便利。
-
一部COMオブジェクトは既存インスタンスを再利用します(例:PowerPoint)。 ↩