質問: $Ap2.ActiveSheet $Ap.Intersect($Sh.UsedRange, $Sh.Rows(3)).Address($false, $false) # New-Object 取得できない(エラー表示で「オーバーロードで引数が2つのものが見つからない」っとでる) $Ap2.Intersect($Sh2.UsedRange, $Sh2.Rows(3)).Address($false, $false) # Marshal 取得できる $Ap.Workbooks | foreach { $_.Close($false) } $Ap.quit() Remove-Variable Ap, Bk, Sh, Ap2 [GC]::Collect() ``` ### やりたいこと 新規インスタンス(New-Object)でExcelを起動して EnableEvents を False に設定してから 指定ファイルを読取専用で開いて 特定行の条件に一致したセルからデータを取得したい。 特定行の条件に一致したセルを検索するときにUserRange外のセルは確認する必要がない為 UserRange内の指定行のセルだけ取得したかったです。 そのために Intersect を利用しようとしましたが使えませんでした。 New-Object を使用した場合Intersect は引数2つでは使えないのでしょうか? 教えて頂きたいです。 ### やりたいこと内の操作の理由 下記条件を満たすためです。 * 処理を行うパソコンでExcelを使用中の可能性がある * 使用中のExcelには影響は与えたくない * 使用中のExcelはVBAが使用されている可能性がある(イベント含み) * 操作対象のExcelファイルにはVBAが使用されている(イベント含み) * 操作対象のExcelファイルのVBAは動作させてはいけない * 操作対象のExcelファイルは変更(上書き保存)してはいけない * 操作対象のExcelファイルは共有場所にある * 操作対象のExcelファイルはいつ別PCで利用されるか分からない * 別PCでの作業の邪魔はしてはならない ### 試したこと 再現用のソースコードに記載しましたが New-Objectで生成したExcelインスタンスでは引数が2つではIntersectが利用できませんでしたが [Marshal]で取得したインスタンスでは問題なく利用できました。 そこからNew-Objectで生成したExcelインスタンス を [Marshal]で取得したインスタンスと同じ型に キャストしてみようと試みましたが失敗に終わりました。 ### 補足情報(FW/ツールのバージョンなど) Win10 powershell V5
回答: 原因の推測 ===== 経験上、PowerShellの`~のオーバーロードで、引数の数が "2" であるものが見つかりません。`のエラーは、引数の型が一致していない場合にも発生します。 それを踏まえて、`$Ap.Intersect.OverloadDefinitions`を確認すると、 引数1,2は`Microsoft.Office.Interop.Excel.Range`と、PIA(プライマリ相互運用アセンブリ)の型を要求していることがわかります。 これは、`New-Object`で取得した`$Ap`の型が、PIAで定義されている`Microsoft.Office.Interop.Excel.Application`であるためです。 しかしPowerShell上では、`New-Object`以外の方法で取得したCOMオブジェクトは全て`__ComObject`になってしまい、`__ComObject`からPIAの型にキャストすることができません(経験上・C#などでは可能)。 そのため、`$Ap`の型だけがPIAで定義されている型で、それ以外がCOMオブジェクトになってしまい、型が一致しないため`~のオーバーロードで~`のエラーになったと思われます。 対策 == 型を明示する 以下のように、変数の型を明示すると動作するようになりました。 `[Microsoft.Office.Interop.Excel.~]`でも動く理由は不明ですが、COMオブジェクト用の特別処理が行われているのかもしれません。 また、C#などでは`__ComObject`の型は指定できないため注意が必要です。 ``` # 以下の型宣言ならどれでも動作する [__ComObject]$AP = New-Object -ComObject "Excel.Application" [Microsoft.Office.Interop.Excel.Application]$AP = New-Object -ComObject "Excel.Application" [Microsoft.Office.Interop.Excel.ApplicationClass]$AP = New-Object -ComObject "Excel.Application" # 以下の場合(型を明示しない場合含む)は動作しない [object]$AP = New-Object -ComObject "Excel.Application" ``` `New-Object`を使わない `New-Object`の代わりに以下の記述でもExcelのインスタンスを生成できます。 ``` $AP = [Activator]::CreateInstance([type]::GetTypeFromProgID('Excel.Application')) ``` `New-Object`の結果を直接使わない 以下のように、`New-Object`の結果のApplicationプロパティを参照することでもエラーは発生しなくなりました。 ``` $AP = (New-Object -ComObject "Excel.Application").Application ```