「コマンドレットを探したが、やりたい処理が見つからない」── PowerShellをある程度使い込むと、必ずこの壁に当たります。ショートカットの一括作成、ZIPの中身を展開せずに確認する処理、ウィンドウ操作、Excelファイルの読み書き。標準のコマンドレットだけでは手が届かない要望は、中小企業の情シスや運用担当の方から日常的に相談されます。
実はこの壁の向こう側は、PowerShellの得意分野です。PowerShellは.NETの上に構築されているため、.NETクラスライブラリの型を追加インストールなしで直接呼べます。さらに Add-Type でC#コードやWin32 API(P/Invoke)をその場で組み込め、New-Object -ComObject でWScript.ShellやExcelなどのCOMオブジェクトも操作できます。VBScriptやVBAで書かれてきた「Windowsの自動化」の道具箱が、ほぼそのまま使えるということです。
ただし、この力には後始末の作法が付いてきます。特にExcelのCOM操作は「スクリプトが終わってもEXCEL.EXEが残る」という定番トラブルの温床であり、そもそも無人実行でOfficeを自動化すること自体をMicrosoftが非推奨としています。この記事では、PowerShellからの.NET呼び出し・Add-Type・COM操作の実務パターンと落とし穴、そして「どこまでスクリプトで粘り、どこからC#ツール化するか」の判断までを整理します。
1. まず結論
- PowerShellは.NETの上に載っています。Windows PowerShell 5.1は.NET Framework、PowerShell 7は.NET(旧.NET Core)の上に構築されており、
[System.IO.Path]::GetFileNameWithoutExtension()のように.NETの静的メソッドを直接呼べます。1 - インスタンスの作成は
New-Objectか、PowerShell 5.0以降なら[型]::new()です。[型]::newと(かっこなしで)打てばコンストラクタの一覧が確認でき、引数を調べながら書けます。2 Add-Typeを使うと、C#のソースコードをその場でコンパイルしてセッションに組み込めます。DllImportのシグネチャを渡せばWin32 APIのP/Invoke呼び出しも可能です。追加した型はセッション内で消せず、同名の型は定義し直せません。3- COMオブジェクトは
New-Object -ComObject <ProgId>で作成します。VBScriptのCreateObject("Shell.Application")はNew-Object -ComObject Shell.Applicationにそのまま対応し、WScript.Shellによるショートカット作成など、WSH時代の道具がPowerShellから使えます。45 - COMオブジェクトの寿命は参照カウントで管理され、.NET側ではRCW(Runtime Callable Wrapper)がそれを握ります。参照が残っているとExcelなどのプロセスは終了しません。明示的に解放するには
Marshal.ReleaseComObjectを使いますが、乱用すると別の事故を招くため「本当に必要な場合のみ」が公式の指針です。67 - 無人実行でのOffice自動化は、Microsoftが「推奨せず、サポートしない」と明言しています。サービス・タスクスケジューラ・サーバーサイドからのExcel COM操作は、動いているように見えても非サポート構成です。無人処理はOpen XML系ライブラリやCSV連携に置き換えます。8
- 5.1と7では使える型・メソッドが違います。String.Splitのオーバーロード差のように同じコードで挙動が変わる例があり、5.1ではGACのアセンブリを
Add-Typeで明示ロードする必要がある場面もあります。13 - .NETの直接呼び出しが増えてきたら、C#ツール化を検討するラインです。型の再定義ができないAdd-Typeの制約や配布の問題が目立ち始めたら、スクリプトの限界が近いサインです。
2. PowerShellは.NETの上に載っている ── [型]::メソッドとNew-Object
PowerShellのコマンドレットは、.NETクラスライブラリの一部を「運用作業向けに使いやすく包んだもの」です。包まれていない機能も、型名を角かっこで書けば直接呼べます。静的メソッドは ::、インスタンスのメソッドやプロパティは . です。
# .NETの静的メソッドを直接呼ぶ。コマンドレット不要、追加インストールも不要
[System.IO.Path]::GetFileNameWithoutExtension('C:\data\受注_20260718.csv') # -> 受注_20260718
[System.IO.Path]::Combine('C:\data', 'archive', '2026-07') # -> C:\data\archive\2026-07
[System.Math]::Round(123.456, 1) # -> 123.5
# インスタンスが必要ならNew-Objectか[型]::new()で作る
$list = [System.Collections.Generic.List[string]]::new()
$list.Add('server01')
# ::newをかっこなしで打つと、コンストラクタの一覧が返る(引数の調べ方として便利)
[System.IO.StreamWriter]::new
[型]::new() はPowerShell 5.0で追加された書き方で、New-Object より高速なうえ、上の例のようにコンストラクタのオーバーロード一覧をその場で確認できます。2 一方で注意点もあります。Get-Item などのコマンドレットが返すオブジェクトには、PowerShellが追加のプロパティ(NoteProperty)を足していることがあり、::new() で直接作った同じ型のオブジェクトとはメンバー構成が一致しない場合があります。2 「コマンドレット経由で取ったときはあったプロパティが無い」と混乱したら、この仕組みを思い出してください。
実務レシピを一つ。ZIP処理は Compress-Archive / Expand-Archive がありますが、これらの土台であるZipArchive APIにはファイルサイズ2GBの制限があり9、また「展開せずに中身の一覧だけ確認したい」といった細かい操作はコマンドレットにありません。そこで.NETの ZipFile クラスの出番です。10
# Windows PowerShell 5.1では、GACのアセンブリを明示ロードする必要がある
# (PowerShell 7では同梱アセンブリが必要時に自動ロードされるため、この行はなくても動く)
Add-Type -AssemblyName System.IO.Compression.FileSystem
# まず読み取りから ── 展開せずにZIPの中身を確認する
$archive = [System.IO.Compression.ZipFile]::OpenRead('C:\deploy\release.zip')
try {
$archive.Entries | Select-Object FullName, Length, LastWriteTime
}
finally {
$archive.Dispose() # ファイルハンドルを確実に返す
}
# 内容に問題がなければ展開する。展開先に同名ファイルがあると、この2引数版は
# 途中まで展開した状態で例外を出す(上書きしない)。既存フォルダーへの直接展開は避け、
# 毎回新しいフォルダーへ展開してから切り替えるのが安全
$dest = "C:\apps\web_$(Get-Date -Format yyyyMMddHHmmss)"
[System.IO.Compression.ZipFile]::ExtractToDirectory('C:\deploy\release.zip', $dest)
.NET Frameworkでは ZipFile クラスを使うのに System.IO.Compression.FileSystem アセンブリへの参照が必要で、これはPowerShell 5.1でも同じです。10 7では同梱アセンブリが要求時に自動ロードされるため Add-Type なしで動きますが、書いておけば両方で動くので、共用スクリプトでは明示するのが無難です。3
3. Add-Typeで自作C#とWin32 API(P/Invoke)を組み込む
.NETにある機能 の次は .NETにない機能 です。Add-Type にC#のソースコードを渡すと、その場でコンパイルされてセッションに型が追加されます。さらに -MemberDefinition にDllImport付きのシグネチャを渡せば、Win32 APIをP/Invokeで呼べます。この使い方は公式ドキュメントにも例として掲載されている、正当な手段です。3
# 手元で流した長時間処理の完了をダイアログで知らせる(user32.dllのMessageBoxWをP/Invokeで呼ぶ)
$signature = @'
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBoxW(IntPtr hWnd, string text, string caption, uint type);
'@
$native = Add-Type -MemberDefinition $signature -Name 'NativeMethods' `
-Namespace 'Win32' -PassThru
# MB_ICONINFORMATION(0x40)を付けて表示
[void]$native::MessageBoxW([IntPtr]::Zero, 'バックアップ処理が完了しました。', '長時間処理', 0x40)
ひとつ注意があります。モーダルダイアログは、自分がデスクトップの前にいる対話的な実行専用です。タスクスケジューラの無人実行やWindowsサービスのような非対話セッションでは、誰も閉じられないダイアログで処理が止まったまま帰ってこなくなります。無人ジョブの通知はログファイル・イベントログ・メール送信など、応答を待たない手段にしてください。
Add-Type には運用上の重要な制約が3つあります。3
- 追加した型はそのセッション限りです。別のセッションやリモートでは、再度
Add-Typeが必要です。 - 同名の型は定義し直せません。シグネチャを間違えて修正したいときは、名前を変えるか新しいセッションを起動します。試行錯誤は使い捨てのコンソールで行ってください。
- PowerShell 7では、同名の型が既に存在するとコンパイル自体をスキップします。「直したはずのコードが反映されない」ときはこれを疑います。
もう一つ、P/Invoke共通の注意です。シグネチャ(引数の型、文字セット、呼び出し規約)を誤ると、例外で済まずプロセスごと落ちることがあります。文字列やハンドルのマーシャリングの落とし穴は「C#からWin32 APIを安全に呼ぶ ── P/Invoke実務ガイド(DllImport / LibraryImport / CsWin32)」で詳しく整理しているので、Add-Typeで本格的にWin32 APIを使う前に一読をおすすめします。
4. COMを呼ぶ ── New-Object -ComObjectとWSHの道具箱
.NETより古くからWindowsに積まれている部品群がCOMです。New-Object -ComObject <ProgId> で作成でき、VBScriptの Set objShell = CreateObject("Shell.Application") は $objShell = New-Object -ComObject Shell.Application にそのまま対応します。4 WScript.Shell、WScript.Network、Scripting.FileSystemObjectといったWSH(Windows Script Host)由来のオブジェクトも同様に使えます。5 COMとは何かという土台の話は「COM / ActiveX / OCX とは何か - 違いと関係をまとめて解説」を参照してください。
代表的な実務レシピが、ショートカットの一括作成です。ショートカット(.lnk)の作成はコマンドレットが存在せず、公式ドキュメントも「ショートカット作成のような一部のタスクはWSHクラスを使う方が簡単」としてWScript.Shellの例を載せています。5
# 共有フォルダ上のツールへのショートカットを、全端末の公開デスクトップに配る想定
$shortcuts = Import-Csv 'C:\deploy\shortcuts.csv' # Name, Target, Args の3列
$wsh = New-Object -ComObject WScript.Shell
foreach ($item in $shortcuts) {
$lnkPath = Join-Path 'C:\Users\Public\Desktop' "$($item.Name).lnk"
$lnk = $wsh.CreateShortcut($lnkPath) # 既存の.lnkがあれば上書き対象になる
$lnk.TargetPath = $item.Target
$lnk.Arguments = $item.Args
$lnk.Save()
Write-Host "作成: $lnkPath"
}
COMオブジェクトのメンバーは $wsh | Get-Member で調べられます。5 Outlookでのメール下書き作成、Shell.Applicationでの特殊フォルダ操作など、応用範囲は広大です。ただし、Excel.ApplicationのようなActiveX実行可能ファイル(別プロセスで起動するCOMサーバー)には、次章の後始末問題が付いて回ります。公式ドキュメントも、参照を手放したときにプロセスが終了するかどうかは相手のアプリケーション次第であり、使う前に終了動作をテストすべきだと注意しています。5
5. COMの後始末 ── EXCEL.EXEが残る問題と「無人Officeは非サポート」
5.1. なぜプロセスが残るのか
COMオブジェクトの寿命は参照カウントで管理されます。.NET(=PowerShell)からCOMを触ると、COMオブジェクトごとにRCW(Runtime Callable Wrapper)というプロキシが作られ、RCWが生きている限りCOM側の参照は解放されません。RCWの回収はガベージコレクション任せです。6 つまり $excel.Quit() を呼んでも、どこかに参照(それも $excel.Workbooks.Open(...) のように変数に入れていない中間オブジェクトのRCWを含む)が残っていれば、EXCEL.EXEは終了しません。
$excel = New-Object -ComObject Excel.Application
try {
$excel.DisplayAlerts = $false
$books = $excel.Workbooks # 中間オブジェクトも変数に受けて、後で解放できるようにする
$book = $books.Open('C:\work\月次売上.xlsx')
$sheet = $book.Worksheets.Item(1)
$sheet.Cells.Item(1, 1).Value2 = "更新: $(Get-Date -Format 'yyyy-MM-dd')"
$book.Save()
}
finally {
# Closeが失敗する経路こそEXCEL.EXEが残りやすいので、
# 入れ子のfinallyでQuitと解放を必ず実行する
try {
if ($book) { $book.Close($false) }
}
finally {
# Quitが失敗しても(Excelが応答なし・COMサーバー切断など)RCWの解放は必ず行う
try {
if ($excel) { $excel.Quit() }
}
finally {
# RCWの参照カウントを明示的に減らす(子から親の順)
foreach ($obj in @($sheet, $book, $books, $excel)) {
if ($obj) { [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($obj) }
}
# 変数に受けそこねたRCWをGCに回収させる保険
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
[System.GC]::Collect()
}
}
}
Marshal.ReleaseComObject はRCWの参照カウントを減らし、0になった時点でCOM側の参照を解放します。ただし公式ドキュメントは、解放済みRCWへのアクセスは例外やアクセス違反を招くため「絶対に必要な場合にのみ使うこと」と強く注意しています。7 解放パターンの流儀(ReleaseComObject派とGC派)、2ドットルールの罠、それでも残ったプロセスの特定方法は「C#のExcel操作でEXCEL.EXEが残る問題 ── COM参照の解放パターンと置き換えの判断」で詳述しています。C#の記事ですが、RCWの仕組みはPowerShellでも同一です。
5.2. そもそも無人実行でOfficeを使わない
より根本的な判断があります。Microsoftは「無人・非対話のクライアントアプリケーションやコンポーネント(ASP、ASP.NET、DCOM、NTサービスを含む)からのOfficeの自動化を、現在推奨しておらず、サポートもしない」と公式に明言しています。Officeは対話利用を前提に設計されており、無人環境では不安定な動作やデッドロックを示すことがあるためです。8 予期しないダイアログで処理が止まる、STAベースで多重実行に耐えない、といった具体的な問題も列挙されています。8
つまり、タスクスケジューラの夜間ジョブやサービスからExcel COMを叩く構成は、動いているうちから非サポートです。無人処理では、Officeソフト本体を起動しないOpen XML系のファイル直接編集やCSV連携への置き換えが推奨されています。8 PowerShellでの具体的な代替レシピは、同時公開の「PowerShellでのExcel・CSV業務処理レシピ」にまとめています。Excel COMを使ってよいのは「人がログオンしているデスクトップで、人の作業を補助する」用途までと線を引いてください。
6. 5.1と7で「使える.NET」は違う
Windows PowerShell 5.1は.NET Framework 4.5系、PowerShell 7は.NET(旧.NET Core)の上に構築されています。1 コマンドレットだけ使っている分には差を意識する場面は限られますが、この記事のように.NETを直接呼び始めると、差が表面化します。
| 論点 | Windows PowerShell 5.1 | PowerShell 7 |
|---|---|---|
| 土台 | .NET Framework 4.5系1 | .NET(7.4は.NET 8.0など、バージョンごとに更新)1 |
| メソッドのオーバーロード | 少ない(例: String.Splitは6種)1 | 多い(同じ Split('pq') でも結果が変わる例が公式に掲載)1 |
| アセンブリのロード | GACのアセンブリは Add-Type での明示ロードが必要な場面が多い3 |
同梱アセンブリは要求時に自動ロード3 |
| 使えなくなったもの | ─ | *-EventLog などWindows専用コマンドレットの一部が削除1 |
「5.1で動いたのに7で動かない」「その逆」のどちらも起こり得ます。両対応が必要なスクリプトは、必ず両方の環境でテストしてください。移行判断の全体像は、同時公開の「Windows PowerShell 5.1とPowerShell 7の違いと移行」で扱っています。
7. 実務の定石(判断表)
| 論点 | 選択肢 | 判断の目安 |
|---|---|---|
| やりたい処理がコマンドレットにない | あきらめる / .NETクラスを直接呼ぶ | まず [型]::メソッド を探す。System.IO、System.Text、System.IO.Compressionあたりで大半の「あと一歩」は埋まる1 |
| インスタンスの作成 | New-Object / [型]::new() | 5.0以降だけなら ::new()。コンストラクタ一覧が見え、速い。COMだけはNew-Object -ComObject一択24 |
| Win32 APIが必要 | 手作業で我慢 / Add-TypeでP/Invoke | 数個のAPIならAdd-Typeで十分。シグネチャの誤りはプロセスごと落とすので、使い捨てセッションで検証3 |
| ショートカット作成などWSH由来の操作 | COM(WScript.Shell) | コマンドレットが無い領域はCOMが今も現役。公式サンプルもこの方式5 |
| 人の作業を補助するExcel操作 | COM + 確実な後始末 | finallyでQuit・ReleaseComObject・GCまでをセットで。中間オブジェクトも変数に受ける76 |
| 無人ジョブでのExcel/Office処理 | COM / Officeを起動しない方式 | 無人のOffice自動化は非サポート。Open XML系・CSVへ置き換える8 |
| スクリプトが育ちすぎた | PowerShellで粘る / C#ツール化 | Add-Typeのコードが数百行になった、型の再定義制約が開発を邪魔する、配布先で毎回コンパイルさせたくない ── のいずれかが出たら移行のサイン |
最後の行が、この記事の締めくくりの判断です。Add-Type で埋め込むC#が肥大化してきたら、それはもう「C#プログラムをPowerShellの皮で包んでいる」状態です。Visual Studioの型チェックとデバッガー、NuGetパッケージ、単体テストが使えるC#プロジェクトに移した方が、開発も保守も速くなります。C#側からPowerShellの資産を呼び戻す方法もあるため、移行は全部書き直しではありません。「C#(CSharp)でPowerShellを実行して、オブジェクトとして受け取る方法」で橋渡しのパターンを紹介しています。
8. まとめ
- PowerShellは.NETの上に構築されており、
[型]::静的メソッド・New-Object・[型]::new()で.NETクラスライブラリを直接呼べます。コマンドレットに無い機能の第一候補は.NETです。 Add-TypeでC#コードをその場でコンパイルでき、DllImportのシグネチャを渡せばWin32 APIもP/Invokeで呼べます。型はセッション限りで、同名の再定義はできません。- COMは
New-Object -ComObjectで操作します。ショートカット作成などWSH由来の道具は今も現役です。 - COMの寿命は参照カウント+RCWで管理され、参照が残るとEXCEL.EXEなどのプロセスが残留します。finallyでQuit・ReleaseComObject・GCまで含めた後始末を書きます。
- 無人実行でのOffice自動化はMicrosoftが非推奨・非サポートと明言しています。夜間ジョブはOfficeを起動しない方式に置き換えます。
- 5.1と7では土台の.NETが違い、使える型・オーバーロードが異なります。両対応スクリプトは両方でテストが必須です。
- Add-Typeが肥大化したらC#ツール化のサインです。スクリプトと実行ファイルの橋渡しは既存の型があります。
関連記事
- C#のExcel操作でEXCEL.EXEが残る問題 ── COM参照の解放パターンと置き換えの判断
- C#からWin32 APIを安全に呼ぶ ── P/Invoke実務ガイド(DllImport / LibraryImport / CsWin32)
- COM / ActiveX / OCX とは何か - 違いと関係をまとめて解説
- C#(CSharp)でPowerShellを実行して、オブジェクトとして受け取る方法
- PowerShellでのExcel・CSV業務処理レシピ
- Windows PowerShell 5.1とPowerShell 7の違いと移行
関連する相談領域
合同会社小村ソフトでは、PowerShellによる社内業務の自動化、COM資産(Excel連携・レガシー部品)を含むスクリプトの設計・改修、「スクリプトが育ちすぎた」状態からのC#ツール化を扱っています。EXCEL.EXEの残留のような不具合調査も対応します。
参考リンク
-
Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. Windows PowerShell 5.1が.NET Framework 4.5の上に、PowerShell 6.0以降が.NET Core(現.NET)の上に構築されていること、各バージョンの土台となる.NETのバージョン一覧、String.Splitのオーバーロード差により同じコードの結果が変わる例、7で削除されたコマンドレットについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Microsoft Learn, about_Object_Creation. PowerShell 5.0で全.NET型に追加された静的new()メソッド、::newと打つことでコンストラクタのオーバーロード一覧を確認できること、コマンドレット経由で取得したオブジェクトにはPowerShellがNotePropertyを追加するため::new()で作ったオブジェクトとメンバーが一致しない場合があることについて。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Add-Type. Add-TypeがC#ソースをコンパイルしてセッションに型を追加すること、MemberDefinitionによるP/Invoke(user32.dllのShowWindowAsync)の公式サンプル、追加した型はセッション限りで同名の型は再定義できないこと、PowerShell 7では同名の型が存在するとコンパイルをスキップすること、5.1ではGACのアセンブリのロードにAdd-Typeが必要で6以降は自動ロードされることについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, New-Object. New-Objectが.NETまたはCOMオブジェクトのインスタンスを作成すること、-ComObjectパラメーターにProgIdを指定すること、VBScriptのCreateObject(“Shell.Application”)がNew-Object -ComObject “Shell.Application”に対応することについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Creating .NET and COM objects (New-Object). WScript.Shell等のWSHオブジェクトの作成、ショートカット作成はWSHクラスを使う方が簡単だという記述とCreateShortcutの実例、COMオブジェクトへのGet-Memberの適用、ActiveX実行可能ファイルの終了動作がアプリケーション依存であり事前テストが必要なこと、New-Objectが.NETのRCWを使うことについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Runtime Callable Wrapper. .NETがCOMオブジェクトをRCWというプロキシ経由で公開すること、COMオブジェクトごとに1つのRCWが作られること、RCWがガベージコレクションで回収される際にCOMオブジェクトへの参照を解放することについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Marshal.ReleaseComObject(Object) Method. ReleaseComObjectがRCWの参照カウントを減らし0で基盤のCOMオブジェクトを解放すること、解放後のRCW使用が例外やアクセス違反を招くこと、「絶対に必要な場合にのみ使う」という公式の注意、FinalReleaseComObjectとの関係について。 ↩ ↩2 ↩3
-
Microsoft Learn, Considerations for unattended automation of Office in the Microsoft 365 for unattended RPA environment. Microsoftが無人・非対話のクライアントアプリやコンポーネント(ASP、ASP.NET、DCOM、NTサービスを含む)からのOffice自動化を推奨せずサポートもしないこと、無人環境での不安定動作やデッドロックの可能性、ダイアログによる停止・STA由来の多重実行制約などの具体的問題、Open XMLファイル形式の直接編集が推奨代替であることについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Expand-Archive. Expand-ArchiveがSystem.IO.Compression.ZipArchive APIを使用すること、このAPIに最大ファイルサイズ2GBの制限があることについて。 ↩
-
Microsoft Learn, ZipFile Class. ZipFileクラスがZIPの作成・展開・オープンの静的メソッドを提供すること、.NET Frameworkで使うにはSystem.IO.Compression.FileSystemアセンブリへの参照が必要なこと、CreateFromDirectory/ExtractToDirectory/OpenReadの用途について。 ↩ ↩2
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
PowerShellスクリプトの引数設計とモジュール化 ── 「動くスクリプト」から「人に渡せるスクリプト」へ
PowerShellスクリプトを他人に渡せる品質に引き上げる実務手順を整理します。paramブロックと[CmdletBinding()]による高度な関数化、型指定とMandatory、ValidateSetなどの入力検証、パイプライン入力、コメントベースヘルプ、-WhatI...
PowerShellでExcel・CSV業務処理を自動化する ── 集計・突合・帳票出力の実務レシピ
PowerShellでCSVの集計・突合・Excel帳票出力を自動化する実務レシピ。Import-Csv/Export-Csvの文字コード既定(5.1と7の違い)、Group-Objectの集計、Compare-Objectとハッシュテーブルの突合、ImportExcelと...
Windows PowerShell 5.1とPowerShell 7の違い ── 社内スクリプト移行の実務ガイド
Windows PowerShell 5.1とPowerShell 7の関係(共存・powershell.exeとpwsh.exe)、5.1は新機能追加なしという公式方針、既定エンコーディング差による文字化け、互換機能の制約、#Requiresでの防御、タスクスケジューラ更...
C#(CSharp)でPowerShellを実行して、オブジェクトとして受け取る方法
C#からPowerShellを起動し、文字列ではなくPSObjectとして結果を受け取る方法を、PowerShell SDK、AddCommand、AddParameter、BaseObject、Properties、エラー処理まで実務目線で整理します。
PowerShell実用コマンド集 ── 日常作業でよく使う小さな機能を増やす
PowerShellで日常作業に使う実用コマンドとして、Measure-Object、Group-Object、Select-String、Compare-Object、Tee-Object、Start-Transcriptなどの使いどころを整理します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
ActiveX / 移行テーマ
COM / ActiveX / OCX を残すか、包むか、置き換えるかを整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
既存資産活用・移行支援
COM / ActiveX / OCX、32bit / 64bit 制約を抱える既存資産の活用と移行を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- PowerShellから.NETのクラスを直接呼べますか?
- 呼べます。PowerShellは.NETの上に構築されているため、[System.IO.Path]::GetFileNameWithoutExtension() のように角かっこで型名を書き、:: で静的メソッドを呼び出せます。インスタンスが必要なら New-Object か、PowerShell 5.0以降で使える [型]::new() で作成します。コマンドレットが用意されていない処理でも、.NETクラスライブラリにあれば追加インストールなしでスクリプトから使えます。
- New-Objectと[型]::new()はどちらを使うべきですか?
- どちらでもオブジェクトは作れますが、[型]::new() は引数なしで打つとその型のコンストラクタ一覧が表示されるため、引数を調べながら書くのに向いています。パフォーマンスも [型]::new() の方が有利です。一方、COMオブジェクトの作成は New-Object -ComObject にしかできません。PowerShell 5.0より古い環境を考慮する場合も New-Object を使います。
- PowerShellでExcelをCOM操作するとEXCEL.EXEが残るのはなぜですか?
- COMオブジェクトは参照カウントで寿命が管理され、.NET側ではRCW(Runtime Callable Wrapper)がその参照を握ります。$excel.Workbooks.Open() のように書くと、途中のWorkbooksオブジェクトにも見えないRCWが作られ、変数に入れていない参照が残ります。Quit()を呼んでも参照が残っているとプロセスは終了しません。使い終わったらMarshal.ReleaseComObjectで明示的に解放するか、変数をnullにしてGC.Collect()とWaitForPendingFinalizers()で回収させる後始末が必要です。
- サーバーや夜間バッチでExcelをCOM操作してよいですか?
- 推奨されません。Microsoftは、無人・非対話のクライアントアプリやコンポーネントからのOfficeアプリケーションの自動化を推奨せず、サポートもしないと公式に明言しています。Officeは対話的なデスクトップ利用を前提に設計されており、無人実行では不安定な動作やデッドロックが起こり得るためです。無人処理ではOpen XML系のライブラリやCSV連携など、Officeソフト本体を起動しない方法に置き換えるのが定石です。
- Add-TypeでWin32 APIを呼べますか?
- 呼べます。Add-Type の -MemberDefinition にDllImport付きのC#シグネチャを渡すと、その場でコンパイルされてP/Invoke経由でWin32 APIを呼び出せるようになります。公式ドキュメントにもuser32.dllのShowWindowAsyncを呼ぶ例が掲載されています。ただし追加した型はセッション内に残り、同名の型は定義し直せないため、試行錯誤の際は新しいセッションで再実行してください。シグネチャを誤るとプロセスごと落ちることもあるため、動作確認は使い捨てのコンソールで行うのが安全です。
- Windows PowerShell 5.1とPowerShell 7で.NET呼び出しに違いはありますか?
- あります。5.1は.NET Framework 4.5系、PowerShell 7は.NET(旧.NET Core)の上に構築されており、使える型やメソッドのオーバーロードが異なります。たとえばString.Splitのオーバーロードは7の方が多く、同じコードでも結果が変わる例が公式に紹介されています。また5.1ではGACのアセンブリをAdd-Typeでロードする必要がある場面が多いのに対し、7では同梱アセンブリが必要時に自動ロードされます。両方で動かすスクリプトは、どちらの環境でもテストしてください。
著者プロフィール
記事の著者プロフィールページです。
小村 豪
合同会社小村ソフト 代表
Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。
公開リンク