PowershellへのClosedXMLの導入
ClosedXMLをPowershellで使うためのメモ
目次
interop問題
Excel作業を自動化しようとすると、「interopサービスを使いましょう」という古い情報に当たることがあります。最近(2019年夏現在)は幸いにもそんな古い情報に当たることはそうそう無いんですが、それでも「マクロのあるファイルを操作する」とか「Web上のContents Management Service上のファイルを直接操作する」とかExcelじゃないと動かせない場合もあります。
そういった時のためにinteropサービスでExcel作業を自動化する際に当たりがちなエラーをまとめました。結構苦労します(^_^;)
ということで、Excelをオブジェクト化するのではなくxlsxファイルを直接操作するライブラリを調べると、NPOI,ClosedXML,ExcelPackagePlus,ImportExcelなんかがヒットします。
それのうち、Microsoftが作っているClosedXMLを使うためのメモ。
ExcelPackagePlusは下記をご覧ください
ImportExcelはこちらをご覧ください。
ライブラリの入手
まずは入手する方法から
git-hubからソースをダウンロードしてCompileする
linux環境なら常道ですが、Windowsだとあんまり無い気がします。
nugetからライブラリを入手する
コマンドラインがNuget Galleryの上の方に書かれています。
ClosedXML -Nuget Gallery
例えばこんな感じ
1 |
Install-Package ClosedXML -Version 0.94.2 |
Install-Packageを使ってもいいんですが「proxyを通じて社外アクセスしてる環境ではコケる」ことが多々あります。Powershell5.1以降であればProxyの内側からインストールできます。-Proxyおよび-ProxyCredentialオプションが使えます。詳しくは下記Qiita記事を参照してください。6とありますが、5.1でも使えます
PowerShell 6にプロキシ経由でモジュールインストール
ただ、こうやっても直接関係しないライブラリを大量にダウンロードします。恐らくDependencies(依存関係)に「System.IO.Packaging」が含まれているせいかと思います。
nugetのサイトからライブラリを直接ダウンロードする。
Nuget Galleryの右の方に「Download package」と書かれています。これをダウンロードするとWebから直接ダウンロードできます。2019年9月現在の安定最新版は0.94.2です。
ClosedXML 0.94.2
これをダウンロードすると、「closedxml.0.94.2.nupkg」という拡張子で落ちてきます。
「nupkgなんて拡張子知らないよ」って思うかも知れませんが、これ単にlibファイルとxmlファイルをzip圧縮しただけのものです。拡張子をzipに変えれば普通に展開できます(^_^;)
NugetのDependenciesにあるライブラリとその先のDependenciesをすべて落とします。面倒ですが、関係しないライブラリが落ちまくるよりマシでは?と思います。
v0.94.2版の.NETFramework 4.6での依存先は以下の3つです。
- DocumentFormat.OpenXml (>= 2.7.2)
- ExcelNumberFormat (>= 1.0.3)
- FastMember (>= 1.3.0)
更に、DocumentFormat.OpenXml の依存先として以下が必要です。
- System.IO.Packaging (>= 4.5.0)
最新版の依存関係はNuget Galleryを参照してください。
ClosedXML -Nuget Gallery
ライブラリのロード
今回はC:¥scropt¥にダウンロードしました。
入手できたら次はライブラリのロードです。
PowerShellだと[Reflection.Assembly]::LoadFile()という命令があります。
これは、エラーが起こりませんが、実際にはObject作成の段階で失敗します。
試してみるとAdd-Typeだと実行時にエラーが発生します。
5年くらい前の記事ですが、[Reflection.Assembly]::LoadFile()とAdd-Typeの差は下記を参照しました。
PowerShell の Add-Type と [Reflection.Assembly]
1 2 3 4 5 |
Add-Type -Path C:\script\system.io.packaging.4.5.0\lib\net46\System.IO.Packaging.dll Add-Type -Path C:\script\documentformat.openxml.2.9.1\lib\net46\DocumentFormat.OpenXml.dll Add-Type -Path C:\script\excelnumberformat.1.0.7\lib\net20\ExcelNumberFormat.dll Add-Type -Path C:\script\fastmember.1.5.0\lib\net461\FastMember.dll Add-Type -Path C:\script\closedxml.0.94.2\lib\net46\ClosedXML.dll |
これを実行すると、下記のエラーが発生します。
1 2 3 4 5 6 |
Add-Type : 要求された型のうち 1 つまたは複数を読み込めませんでした。詳細については、LoaderExceptions プロパティを取得してください。 発生場所 行:5 文字:1 + Add-Type -Path C:\script\closedxml.0.94.2\lib\net46\ClosedXML.dll + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Add-Type], ReflectionTypeLoadException + FullyQualifiedErrorId : System.Reflection.ReflectionTypeLoadException,Microsoft.PowerShell.Commands.AddTypeCommand |
…なるほど、わからん。LoaderExceptions プロパティを取得してください。ってどうやるねん?
英語で検索したら、下記で取れるとわかりました。結局英語なのね(´;ω;`)
1 |
$error[0].Exception.GetBaseException().LoaderException |
これを表示した結果がこちら!
1 2 3 4 5 6 7 |
LoaderExceptionを見るとこう表示されます。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 #> |
え、2.7.2.0が読み込めないってどういう事。2.9.1使ってるねんで?Dependenciesは、(>= 2.7.2)って書いてあるやん。最新版入手したやん。
訝しみながらもライブラリをv2.7.2にしたら…動きやがった(ー_ー;)
Hellor Worldを動かす
これでようやくClosedXMLが動かせます。一ヶ月無駄にした
A1セルにHello Worldを入力して保存するscriptがこちら
1 2 3 4 |
$WorkBook = new-object ClosedXML.Excel.XLWorkbook $WorkSheet = $WorkBook.Worksheets.Add() $Worksheet.Cell("A1").Value = "Hello world"; $WorkBook.SaveAs("$PSScriptRoot\helloworld.xlsx") |
やっと動いた…(^_^;)
全体のソースのメモはこちら。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<# [Reflection.Assembly]::LoadFile()は、エラーが起こりませんが、実際にはObject作成の段階で失敗します。 #> Add-Type -Path C:\script\system.io.packaging.4.5.0\lib\net46\System.IO.Packaging.dll #2.9.1では動作しませんでした。 #Add-Type -Path C:\script\documentformat.openxml.2.9.1\lib\net46\DocumentFormat.OpenXml.dll Add-Type -Path C:\script\documentformat.openxml.2.7.2\lib\net46\DocumentFormat.OpenXml.dll Add-Type -Path C:\script\excelnumberformat.1.0.7\lib\net20\ExcelNumberFormat.dll Add-Type -Path C:\script\fastmember.1.5.0\lib\net461\FastMember.dll <# Add-Typeだと、ロードの段階でエラーが発生します。 Add-Type : 要求された型のうち 1 つまたは複数を読み込めませんでした。詳細については、LoaderExceptions プロパティを取得してください。 発生場所 行:4 文字:1 + Add-Type -Path C:\script\closedxml.0.94.2\lib\net46\ClosedXML.dll + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Add-Type], ReflectionTypeLoadException + FullyQualifiedErrorId : System.Reflection.ReflectionTypeLoadException,Microsoft.PowerShell.Commands.AddTypeCommand #> try { Add-Type -Path C:\script\closedxml.0.94.2\lib\net46\ClosedXML.dll } catch { $error[0].Exception.GetBaseException().LoaderException } <# LoaderExceptionを見るとこう表示されます。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 ファイルまたはアセンブリ 'DocumentFormat.OpenXml, Version=2.7.2.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。 #> $WorkBook = new-object ClosedXML.Excel.XLWorkbook $WorkSheet = $WorkBook.Worksheets.Add() $Worksheet.Cell("A1").Value = "Hello world"; $WorkBook.SaveAs("$PSScriptRoot\helloworld.xlsx") |
“PowershellへのClosedXMLの導入” に対して2件のコメントがあります。