前置き
PowerShell を使っていたら「型[~]が見つかりません。」というエラーが出たので、どう対応したかを纏めさせていただきました。
今回はMicrosoft.Office.Interop.Excel.XlDirection
というアセンブリを題材で話を進めさせていただきます。
サンプルプログラムはExcelが入っていないと動作しませんが、動作させなくても分かるように頑張って記載していきたいと思います。
※ Microsoft.Office.Interop.Excel.XlDirection
はExcelのCtrl
+ 十字キー
を押したときの動作をしてくれます
XlDirection
は、リストの最終行を取得する際によく使ったりしますが、今回はエラーの解消方法について明記したいため、サンプルプログラムではExcelの最終行を1048576
をコンソール出力するだけとなっています。
環境
Windows PowerShell 5.1
Excel 2016
確認したエディタ
Windows PowerShell ISE
Visual Studio Code
クラス内で.NETアセンブリを利用する場合
このパターンで今回のエラーを確認しました。
[Microsoft.Office.Interop.Excel.XlDirection]
に赤波線が付きます。
class HogeClass {
[void]hogeClassMethod() {
$excel = New-Object -ComObject Excel.Application
$book = $excel.Workbooks.Add()
# 「型[Microsoft.Office.Interop.Excel.XlDirection]が見つかりません。」と赤波線でエラーが発生
Write-Host $book.sheets(1).Range("A1").End([Microsoft.Office.Interop.Excel.XlDirection]::xlDown).row()
$excel.Quit()
$excel = $null
[GC]::Collect()
}
}
$hogeClass = New-Object HogeClass
$hogeClass.hogeClassMethod()
メソッドで.NETアセンブリを利用する場合
このパターンはエラーが出ませんでした。
メソッドに定義している場合は、実行前にコードのチェックが行われていないと推測しています。
function hogeMethod {
$excel = New-Object -ComObject Excel.Application
$book = $excel.Workbooks.Add()
Write-Host $book.sheets(1).Range("A1").End([Microsoft.Office.Interop.Excel.XlDirection]::xlDown).row()
$excel.Quit()
$excel = $null
[GC]::Collect()
}
hogeMethod
コードのチェックでなぜ引っかかるのか
下記のコマンドで読み込まれているアセンブリを確認したところ、Powershellを起動した時点ではMicrosoft.Office.Interop.Excel
が存在しないため、コードのチェックでエラーとして検知されいると推測しております。
[System.AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object { $_.GetName().Name }
解消方法1
個人的にこの方法は非推奨です。
別ファイルで事前にアセンブリを読み込む方法です。
Set-Location (Split-Path -Parent $MyInvocation.MyCommand.Path)
# アセンブリを読み込む
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Interop.Excel")
# Add-Type -AssemblyName Microsoft.Office.Interop.Excel ← でも同じ動作します
.".\Hoge.ps1"
$hogeClass = New-Object HogeClass
$hogeClass.hogeClassMethod()
class HogeClass {
[void]hogeClassMethod() {
$excel = New-Object -ComObject Excel.Application
$book = $excel.Workbooks.Add()
# エディタ上では「型[Microsoft.Office.Interop.Excel.XlDirection]が見つかりません。」の赤波線が残ったまま
Write-Host $book.sheets(1).Range("A1").End([Microsoft.Office.Interop.Excel.XlDirection]::xlDown).row()
$excel.Quit()
$excel = $null
[GC]::Collect()
}
}
非推奨理由
同じファイル内に記載するとコードのチェックのエラーが先に引っかかってエラーは解消されません。
そのため、使用例ではMain.ps1にアセンブリを読み込むコードを記載いています。
あと、赤波線は一度実行して、Hoge.ps1ファイルを開きなおさないと消えませんでした。
なので、テキストエディタ自体を閉じて、また開くと赤波線は復活します。
解消方法2
個人的にこの方法を推奨してます。
同一のファイル内でアセンブリを読み込みを行い、文字列で指定した値を-as [type]
で.NET型に変換しています。
ただ今回のサンプルでは、New-Object -ComObject Excel.Application
で
・Microsoft.Office.Interop.Excel
・office
・Microsoft.PowerShell.Commands.Utility.resources
の3つのアセンブリが読み込まれるため、別でアセンブリを読み込むコードは不要となってます。
Excel2013の環境で試したところNew-Object -ComObject Excel.Application
利用時に新しくアセンブリが追加されなかったため、読み込むコードは記載する方が無難です。
# アセンブリを読み込む
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Interop.Excel")
# Add-Type -AssemblyName Microsoft.Office.Interop.Excel ← でも同じ動作します
class HogeClass {
[void]hogeClassMethod() {
$excel = New-Object -ComObject Excel.Application
$book = $excel.Workbooks.Add()
# 追記箇所
$xlDirection = "Microsoft.Office.Interop.Excel.XlDirection" -as [type]
# [Microsoft.Office.Interop.Excel.XlDirection] ⇒ 上で定義した「$xlDirection」に変更
Write-Host $book.sheets(1).Range("A1").End($xlDirection::xlDown).row()
$excel.Quit()
$excel = $null
[GC]::Collect()
}
}
$hogeClass = New-Object HogeClass
$hogeClass.hogeClassMethod()
推奨理由
・1つのファイルで完結する点
・赤波線がつかない点
・コードを変数に定義することで短く記載できる点
でこちらの方が使いやすいと感じました。
いまいちなところ
$xlDirection = "Microsoft.Office.Interop.Excel.XlDirection" -as [type]
で誤字脱字があった場合、実行するまで気づけない。
まだもやもやしているところ
本文中では「コードのチェック」と記載させていただいておりますが、「クラス定義にしたらなぜチェックができるのか?」というところが疑問です。
静的解析機能がクラス内では適用されるとかの表現が正しいのでしょうか?
どなたかご存知でしたらコメント欄で教えてください。
終わりに
今回、解消方法1の方は調べたらすぐに見ったのですが、「微妙やな~」って思いながら粘って探したら解消方法2を偶然見つけれたのでラッキーでした。
ただ、一番いいのはアセンブリの読み込みをするコードの記述があったら、それをくみ取ってコードのチェックをしてほしいですね。試してないですが、PowerShell Coreだとできるんですかね。
ということで、ここまで読んでくださいまして、ありがとうございました。
この記事を見ていただいた方に少しでもお役に立てたなら嬉しいです。