PowerShellのGetObject相当操作の違い

PowerShellではNew-ObjectコマンドレットのComObjectオプションを指定することで新規COMオブジェクトのインスタンスが可能[^1]です。
しかし、状況によっては新規インスタンスではなく、既存のインスタンスを取得したい場合があります。

その場合、

+ Microsoft.Visualbasic 名前空間の Interaction.GetObject メソッド
+ System.Runtime.InteropServices 名前空間の Marshal.GetActiveObject / BindToMoniker メソッド

などを使用することで既存のインスタンスを取得することができます。

[^1]: 一部COMオブジェクトは既存インスタンスを再利用します（例：PowerPoint）。

# 実際に試してみる

各方法で、Excelを取得・型名を表示させるスクリプトです。
`$xlFileName`には実在するExcelファイルのパスを指定してください。

```ps1:色々な取得方法
[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
```

私の環境では以下のような結果となりました。

```text:結果
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 のプロセス インスタンス制御について][OfficeProcess]
> [Office オートメーション サーバーの GetObject および CreateObject の動作](https://support.microsoft.com/ja-jp/kb/288902 "Office オートメーション サーバーの GetObject および CreateObject の動作")

メソッド
> [Marshal.GetActiveObject メソッド (String)](https://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.marshal.getactiveobject(v=vs.110).aspx "Marshal.GetActiveObject メソッド (String)")
> [Marshal.BindToMoniker メソッド (String)](https://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.marshal.bindtomoniker(v=vs.110).aspx "Marshal.BindToMoniker メソッド (String)")

他参考サイト
> [C# 4.0 からの dynamic 型を使った Excel 操作　[プログラム（全般）]](http://kyano30.blog.so-net.ne.jp/2014-10-25)

[OfficeProcess]:https://blogs.msdn.microsoft.com/office_client_development_support_blog/2012/02/14/office-4/ "Office のプロセス インスタンス制御について"

# 関連（宣伝）

[GetObject(, "Excel~")だけで無く、GetObject(ファイル名)も活用しよう](http://qiita.com/nukie_53/items/12cc0a3fc295a446a045)
GetObject('パス', '')やBindToMonikerメソッドは状況によっては便利。