PowerShell
オブジェクトパイプラインとエラー処理機構を持つ、Microsoftが最も堅牢で最新のWindows自動化に推奨するコマンドラインシェル兼スクリプト言語。
COM(コンポーネントオブジェクトモデル)
公開インターフェース、レジストリ登録、Apartment Modelなどを土台にした、Windowsのバイナリ互換コンポーネントモデル。
.NET(Core以降)
.NET Frameworkの後継となる、クロスプラットフォーム対応の.NETランタイム(.NET 5以降)。
モダンな.NET
PowerShell 7
PowerShell Core系譜の最新世代で、.NET(Core以降)上に構築されたPowerShellのエディション。実行ファイルはpwsh.exeで5.1のpowershell.exeとサイドバイサイドに共存し、Out-File・Set-Content・Export-Csvなどの既定書き込みencodingはBOMなしUTF-8である。
Windows PowerShell 5.1
Windowsに標準で同梱されている、.NET Framework上に構築されたレガシー世代のPowerShell(5.1系)のランタイム。実行ファイルはpowershell.exeで、.NETアプリからはMicrosoft.PowerShell.5.1.ReferenceAssembliesを介して呼び出せる。
.NET Framework
Windowsのコンポーネントとして扱われ、インストールされているOSのライフサイクルに沿ってサポートされるランタイム。System.Messagingの対象範囲。
Add-Type
C#のソースコードをその場でコンパイルしてPowerShellのセッションに型として追加できるコマンドレット。DllImportを渡せばP/InvokeでWin32 APIも呼び出せる。
P/Invoke
C#などの.NETコードからアンマネージドなC関数群を呼び出すための、.NETの標準的な相互運用機構。
New-Object -ComObject
ProgIDを指定してCOMオブジェクトのインスタンスを作成するNew-Objectコマンドレットの使い方。VBScriptのCreateObjectに相当する。
ProgID(Programmatic Identifier)
CLSIDに付けた、人が読める文字列の名前。`Excel.Application`のような形でCLSIDに対応付けられる。
WScript.Shell
ショートカット作成などWindows Script Host(WSH)由来の操作を提供するCOMオブジェクト。New-Object -ComObjectから利用できる。
WSHオブジェクト
RCW(Runtime Callable Wrapper)
.NETがCOMオブジェクトを操作するために生成するプロキシ。COMインターフェイスポインターをキャッシュし、GCに回収されるときにCOMオブジェクトへの参照を解放する。
Excel COM自動化(Excel COM Interop)
C#などの外部プログラムからCOM経由でExcelアプリケーション本体を起動・操作する自動化方式。
EXCEL.EXEのプロセス残留
Quit()を呼んでもCOM参照(RCW)が残っているために、EXCEL.EXEなどのプロセスが終了せずに残り続ける状態。
EXCEL.EXEが終了しない問題
Marshal.ReleaseComObject
RCWの内部参照カウントをデクリメントし、0になった時点でRCWが握るCOM参照を即座に解放する.NETのAPI。公式には絶対に必要な場合にのみ使うことが推奨される。
タスクスケジューラの無人実行
指定したアカウントで、スケジュールやログオンなどのトリガーに従いプログラムを実行するWindowsの仕組み。ログオン種別(対話トークン・パスワード保存・S4Uなど)の設定によっては、ユーザーがログオンしていなくても実行できる。
COMアパートメントモデル(STA/MTA)
どのスレッドからCOMコンポーネントを呼んでよいかを決める、COMのスレッドモデルの約束。
ZipFile/ZipArchive API
ZIPアーカイブの作成・展開・読み取りを行う.NETのクラス群。Compress-Archive/Expand-Archiveコマンドレットの基盤でもあり、最大ファイルサイズ2GBの制限がある。
ZipArchiveクラス
P/Invokeシグネチャ誤りによるクラッシュ
DllImportのシグネチャ(引数の型・文字セット・呼び出し規約)を誤ると、例外では済まずプロセスごと落ちることがあるP/Invoke呼び出し特有のリスク。
PowerShell 7は.NET(旧.NET Core)の上に構築されており、.NETクラスライブラリの型を直接呼び出せる
Windows PowerShell 5.1は.NET Framework 4.5系の上に構築されている
.NET(Core以降)は.NET Frameworkの後継となるクロスプラットフォームのランタイムであり、使える型やメソッドのオーバーロードが異なる
PowerShellはNew-Object -ComObjectでCOMオブジェクトを作成し、Excelなどを操作できる
Add-TypeはC#のソースコードをその場でコンパイルしてPowerShellのセッションに型を追加する
Add-TypeにDllImport付きのC#シグネチャを渡すと、その場でコンパイルされてP/Invoke経由でWin32 APIを呼び出せるようになる
COMオブジェクトはNew-Object -ComObject <ProgId>で作成する
New-Object -ComObjectはProgIDを指定してCOMオブジェクトを作成する
ショートカット作成などWSH由来のCOM資産を使いたい場合、WScript.ShellのようなCOMオブジェクトも、New-Object -ComObjectで同様に作成できる
New-Object -ComObjectでCOMオブジェクトを作成すると、.NET側にRCW(Runtime Callable Wrapper)というプロキシが作られる
Excel COM操作は、New-Object -ComObject Excel.ApplicationでExcelアプリケーションオブジェクトを作成することから始まる
Quit()を呼んでも、途中の中間オブジェクトのRCWなど参照が残っていると、EXCEL.EXEなどのプロセスが終了しないことがある
RCWが生きている限りCOM側の参照は解放されないため、参照が残るとプロセスが終了しない
finallyでQuit・Marshal.ReleaseComObjectによる解放・GCの実行までを行う後始末により、プロセスの残留を防げる(ただし2ドットルールを守って中間オブジェクトも変数で受け取っていること、QuitがExcelの応答なし等で失敗しないことが前提)
Marshal.ReleaseComObjectはRCWの参照カウントを減らし、0になった時点で基盤のCOMオブジェクトを解放する
無人・非対話のタスクスケジューラのタスクやサービスからのExcel COM操作を、Microsoftは推奨せずサポートもしないと明言している
OfficeアプリケーションはSTA(シングルスレッドアパートメント)前提で作られており、1台のサーバーで同じ処理を並列に何本も走らせる使い方に構造的に向かない
展開せずに中身を確認するなど、Compress-Archive/Expand-Archiveでは足りない細かいZIP操作をしたい場合は、.NETのZipFile/ZipArchiveクラスを直接呼び出して行う
ZipFileクラスを使うにはSystem.IO.Compression.FileSystemアセンブリへの参照が必要で、Windows PowerShell 5.1ではAdd-Typeによる明示ロードが必要になる場面が多い
DllImportのシグネチャ(引数の型、文字セット、呼び出し規約)を誤ると、例外では済まずプロセスごと落ちることがある