PowerShellでClosedXMLを利用する

## ClosedXMLとは

マイクロソフトのOfficeは2007から既定のファイル形式がOpen XML形式となっており。
それ以前の独自形式から標準化された形式となっています。

このOpen XML形式で作成されたドキュメントを取り扱うSDKとして、OpenXML SDKが提供されていますが、ClosedXMLはこのOpenXML SDKにユーザーフレンドリーなインターフェースを提供することを目的とした.NETライブラリとなります。

- [dotnet/Open-XML-SDK](https://github.com/dotnet/Open-XML-SDK)
- [ClosedXML/ClosedXML](https://github.com/ClosedXML/ClosedXML)

## PowerShellからClosedXMLをあつかう

ClosedXMLは.NETライブラリなのでPowerShellから扱うことができます。
PowerShellから簡易にExcelを扱える有名なライブラリとしては、[dfinke/ImportExcel](https://github.com/dfinke/ImportExcel)がありますが、今回はあえてPowerShellからClosedXMLを取り扱ってみます。

## 今回取り扱っている環境

- Windows 11 23H2
- .NET 8.0
- PowerShell 7.5.0-preview.2
- ClosedXML.0.102.2




## nugetクライアントツールでライブラリを取得

VisutoStudioだったり、Visuto Stuido Codeの拡張だったりを利用してnugetのライブラリを取り扱う事もできますが。
今回はPowerShellからClosedXMLを利用するためにdllが入手したいので、nugetクライアントツールを使ってライブラリをダウンロードしてみます。

### nuget.exeをインストールする

- [NuGet クライアント ツールをインストールする](https://learn.microsoft.com/ja-jp/nuget/install-nuget-client-tools?tabs=windows)
- [Windows に .NET をインストールする](https://learn.microsoft.com/ja-jp/dotnet/core/install/windows?tabs=net80)

まずはnuget.exeをドキュメントに従ってインストールします。

[nuget.exeをインストールする](https://learn.microsoft.com/ja-jp/nuget/install-nuget-client-tools?tabs=windows#install-nugetexe)

ドキュメントに記載がありますがダウンロードできる`nuget.exe`はそのままバイナリとなっているため、適当な場所に配置してPATHを通すなりして利用してください。

### nugetギャラリーからClosedXMLをダウンロード

[Nuget Gallery ClosedXML](https://www.nuget.org/packages/ClosedXML/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/99d50484-1c15-8394-7ab0-ab3d3c307222.png)

[NuGet.exe CLI を使用して NuGet パッケージを管理する](https://learn.microsoft.com/ja-jp/nuget/consume-packages/install-use-packages-nuget-cli)

上記ドキュメントにあるようにサブディレクトリにパッケージをインストールする場合は`nuget install パッケージ名 -OutputDirectory ディレクトリ` とすればよいので今回は`c:\qiita\closedxml\lib\`というディレクトリにパッケージをインストールしてみます。

```powershell
nuget install ClosedXML -OutputDirectory c:\qiita\closedxml\lib\
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/ff5dd10c-ff55-f0c3-1445-b98fdf8aa5a5.png)

依存するパッケージ含めてインストールされました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/816b9be6-4a0a-6581-f553-dfb94aafe375.png)

## PowerShellからClosedXMLを利用する

[ClosedXML wiki](https://docs.closedxml.io/en/latest/)

今回は上記、Wikiの冒頭に書いてる部分をPowerShellでやってみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/51ec9127-753e-530d-4bb9-6dee00cad2f6.png)

### 必要なライブラリを読み込む

今回はPowerShell 7.5.0-preview.2からダウンロードしたClosedXML.0.102.2の.NET Standard 2.1なライブラリを利用してみます。

.NET Standard 2.1のライブラリをDependenciesをみるといくつかのパッケージが依存関係になっているようなので、こららのライブラリも読み込んでおきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/e0de07b0-05fd-d120-0c09-3441eb1309e7.png)

```PowerShell
# DocumentFormat.OpenXml (>= 2.16.0 && < 3.0.0)
Add-Type -Path "C:\qiita\closedxml\lib\DocumentFormat.OpenXml.2.16.0\lib\netstandard2.0\DocumentFormat.OpenXml.dll"
# ExcelNumberFormat (>= 1.1.0)
Add-Type -Path "C:\qiita\closedxml\lib\ExcelNumberFormat.1.1.0\lib\netstandard2.0\ExcelNumberFormat.dll"
# SixLabors.Fonts (>= 1.0.0)
Add-Type -Path "C:\qiita\closedxml\lib\SixLabors.Fonts.1.0.0\lib\netstandard2.1\SixLabors.Fonts.dll"
# System.IO.Packaging (>= 6.0.0)
Add-Type -Path "C:\qiita\closedxml\lib\System.IO.Packaging.6.0.0\lib\netstandard2.0\System.IO.Packaging.dll"
# System.Net.Http (>= 4.3.4)
Add-Type -Path "C:\qiita\closedxml\lib\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll"
# System.Text.RegularExpressions (>= 4.3.1)
Add-Type -Path "C:\qiita\closedxml\lib\System.Text.RegularExpressions.4.3.1\lib\net463\System.Text.RegularExpressions.dll"
# XLParser (>= 1.5.2)
Add-Type -Path "C:\qiita\closedxml\lib\XLParser.1.5.2\lib\netstandard1.6\XLParser.dll"
# closedxml .NETStandard 2.1
Add-Type -Path "C:\qiita\closedxml\lib\ClosedXML.0.102.2\lib\netstandard2.1\ClosedXML.dll"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/97102b72-55b9-1cab-0b52-764e9d72fd43.png)

### サンプルをやってみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/51ec9127-753e-530d-4bb9-6dee00cad2f6.png)

上記サンプルの部分をPowerShellで同様にやってみます。
必要なライブラリを読み込んだ状態で下記のスクリプトを実行してみます。

```powershell
# ワークブックインスタンスをインスタンス化
$workBook = New-Object ClosedXML.Excel.XLWorkbook
# ワークブックにシート（"Sheet1")を追加
$workSheet = $workBook.Worksheets.Add("Sheet1")
# A1セルにHello worldを入力
$workSheet.Cell("A1").Value = "Hello world"
# A2に数式を入力（FormulaA1でA1形式で数式入力）
$workSheet.Cell("A2").FormulaA1 = "MID(A1, 7, 5)"
# SaveAsでファイルを保存
$workBook.SaveAs("c:\qiita\closedxml\helloworld.xlsx")
```

実行している所。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/b29bcf4b-673c-0860-4a3e-044859cc9c17.png)

作成されたエクセルファイル（helloworld.xlsx）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/d2ac44aa-665d-3f65-b9d5-68e47eb90155.png)

ClosedXMLを利用して簡単にエクセルファイルが作成できました。

## Windows PowerShellでClosedXML .0.102.2を利用できるか

今回、PowerShell 7.5.0-preview.2で利用してみましたが、Windows Powershell 5.1でClosedXML.0.102.2を利用できるかについて。

[.NET Standard のバージョンの選択](https://learn.microsoft.com/ja-jp/dotnet/standard/net-standard?tabs=net-standard-2-1#select-net-standard-version)

.net frameworkが基盤となっているWindows PowerShellでは.net standard2.0 or .net standard 2.1なライブラリを依存関係含めて利用しようとするのは無理な気がするので。
.NETFramework 4.6向けが提供されているClosedXML 0.96.0を利用するのがよさそうです。

### nuget.exeでバージョン0.96.0のダウンロード

```powershell
nuget install ClosedXML -Version 0.96.0 -OutputDirectory c:\qiita\closedxml\ClosedXML0.96.0\
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/62422f39-1700-5310-1e28-92d94f1288b8.png)

### Windows PowerShell 5.1からClosedXML 0.96.0を利用する

```PowerShell
# DocumentFormat.OpenXml (>= 2.16.0)
Add-Type -Path "C:\qiita\closedxml\ClosedXML0.96.0\DocumentFormat.OpenXml.2.16.0\lib\net46\DocumentFormat.OpenXml.dll"
# ExcelNumberFormat (>= 1.1.0)
Add-Type -Path "C:\qiita\closedxml\ClosedXML0.96.0\ExcelNumberFormat.1.1.0\lib\net20\ExcelNumberFormat.dll"
# Microsoft.CSharp (>= 4.7.0)
Add-Type -Path "C:\qiita\closedxml\ClosedXML0.96.0\Microsoft.CSharp.4.7.0\lib\netstandard1.3\Microsoft.CSharp.dll"
# ClosedXML
Add-Type -Path "C:\qiita\closedxml\ClosedXML0.96.0\ClosedXML.0.96.0\lib\net46\ClosedXML.dll"

# ワークブックインスタンスをインスタンス化
$workBook = New-Object ClosedXML.Excel.XLWorkbook
# ワークブックにシート（"Sheet1")を追加
$workSheet = $workBook.Worksheets.Add("Sheet1")
# A1セルにHello worldを入力
$workSheet.Cell("A1").Value = "Hello world"
# A2に数式を入力（FormulaA1でA1形式で数式入力）
$workSheet.Cell("A2").FormulaA1 = "MID(A1, 7, 5)"
# SaveAsでファイルを保存
$workBook.SaveAs("c:\qiita\closedxml\helloworld.xlsx")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/8e48bb09-2a58-8aa4-ed92-5580b163cb7c.png)

上記のように、ClosedXML 0.96.0はWindows PowerShell 5.1から利用する事ができました。

## 総評

PowerShellからExcelを利用する場合は、COMオブジェクトを利用するか、ClosedXML(OpenXML SDK)を利用するか、importExcel（EPPlus v4）を利用するか、etcetcといった感じかと思いますが。
今回はClosedXMLを利用するケースについて書いてみました。

ClosedXMLを利用すればOfficeがインストールされていない環境でOpemXML形式のExcelファイルを取り扱えるので、いろいろなケースで用途があるかと思います。
（PowerShellからエクセルファイルを利用する場合は、importExcelが一番楽な気もしますが）