概要
バッチファイルと同じように「Windows環境ならどこでも、何もインストールせずに実行できる」という1ファイルスクリプトを、C#で書けるようになりました!
ということに気付いて、まだプレビュー版ですがこれはぜひ紹介したいと思って記事を書きました。
正確には次の2択で、1が新しく可能になったという話です。
- 1ファイルスクリプトを1コマンドでビルドして、出来上がったexeを使う(使う環境には、.NET等のインストールは不要)
- .NET SDKをインストールし、1ファイルスクリプトをそのまま実行する(インストール必要)
そのためバッチファイルと完全に同等の手軽さではないですが・・・運用環境で使う小物スクリプトを書いたり保守する上での手軽さはかなり近くなったと思います。
※注意:この機能は .NET 10 Preview 6 で実装されたもので、まだプレビュー版です
最初に結論まとめ
- 拡張子”.cs”のC#ファイルを1つ作成する(ここではmain.csとします)
- .NET SDKをインストールしている環境で、
dotnet publish main.cs
を実行 - main.exe のできあがり。このファイルは.NET SDKもランタイムも不要で、そのままWindows上で実行できます!
説明
背景
Windowsならどこでも実行できるお手軽スクリプトといえばやはりバッチファイル、続いてPowerShellスクリプトが使われていると思います。しかしこれらの言語は独自性が強いので、それ専業ならともかくたまに使うのはけっこう辛いです。そうしたスクリプトもC#で書きたいと思っていました。
今までも dotnet-script などがあったため、1ファイルのスクリプトをC#で書いて実行することは出来ました。しかし、この方法だと .NET SDK のインストールが必須となります。自社管理のサーバーで使うスクリプトならともかく、ユーザー(クライアント)環境で使うには条件が厳しい・・・。
この問題を解決してくれる方法が登場しました。C#の1ファイルスクリプトを、 Native AOT でビルドすることで、 .NET ランタイムが無くても動くネイティブのexeを作るという方法です。
まず前提のFile-based Appsについて
まずそもそも、C#の1ファイルスクリプトを実行する機能は .NET 9 までにはリリースされておらず、先ほども触れた dotnet-script などがその用途を補っていました。
.NET 10 Preview 4 あたりで、「File-based Apps」という機能が .NET 公式に追加されました。次のようにコマンド一発で C# のファイルを実行できるものです。
dotnet run main.cs
これはこれで嬉しいですが、 .NET SDK のインストールが必要なことには変わりありませんでした。
File-based Apps の Publish と Native AOT 対応で新しい使い方が可能に
.NET 10 の Preview 6 で、 File-based apps enhancements というリリースノートが追加されました。
色々追加されていますが、今回のポイントは「Publish support and native AOT」のところです。そのまま事実しか書いていないのでうっかり見逃しそうになりますが、これはつまり、「 .NET ランタイム無しで実行可能なexeを、1ファイルスクリプトからビルドできる」ということです。
実行時に、 .NET SDK どころか、 .NET ランタイムすら不要になるということです。これは一気に使えるシーンが増えますね!
しかもビルドもとても簡単です。
dotnet publish main.cs
これだけです。プロジェクトやソリューションを作る必要すらありません。
これなら、スクリプトファイル(~.cs)はそのまますぐに読めて編集できる状態で置いておき、スクリプト変更時に必ずこのコマンドを打てばいいだけなので、バッチファイルに近い感覚で運用できるのではないでしょうか。
試してみた(上手く行った)
とりあえず、ごく簡易なファイル操作スクリプトで試してみました。このGistに入れてあります。この内容は本題と関係ないので、気になる人だけ開いてください。
dotnet publish
を打ってみると・・・
dotnet publish main.cs
復元が完了しました (3.8 秒)
プレビュー版の .NET を使用しています。https://aka.ms/dotnet-support-policy をご覧ください
main 成功しました (8.9 秒) → %Temp%\dotnet\runfile\main-a638fb674794aeab9f6f904090cc07bbd147e13a60051f5fc41a785f90936aa5\publish\release\
13.4 秒後に 成功しました をビルド
すぐにできあがりです。ビルドしたファイルは、固定で %Temp%\dotnet\runfile\
フォルダの下へ作られるようです。
このフォルダを開いてみると、exeとpdbファイルが1つずつあります。とてもシンプルです。exeの依存関係を見てみると、次の通りです。Windowsに入っているDLLと、UCRT(普通のWin10以降なら確実に入っている)だけが依存対象なので、どこでも動きそうですね。
dumpbin /dependents "%Temp%\dotnet\runfile\main-a638fb674794aeab9f6f904090cc07bbd147e13a60051f5fc41a785f90936aa5\publish\release\main.exe"
Microsoft (R) COFF/PE Dumper Version 14.44.35213.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file %Temp%\dotnet\runfile\main-a638fb674794aeab9f6f904090cc07bbd147e13a60051f5fc41a785f90936aa5\publish\release\main.exe
File Type: EXECUTABLE IMAGE
Image has the following dependencies:
ADVAPI32.dll
bcrypt.dll
KERNEL32.dll
ole32.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
このexeファイルを、クリーンなWindows 11環境に持っていて実行すると・・・次のようにコンソール出力がちゃんと表示されて、動きました!(C#で書いたコンソール出力です)
main.exe "C:\Users\User\Desktop\dir"
Target folder: C:\Users\User\Desktop\dir
Moving files from subfolders to the top directory...
Processing: dir2
Moved: dir2\file1.txt -> file1.txt
Deleted: Empty folder dir2
Result:
Number of files moved: 1
Number of folders deleted: 1
Process completed.
まとめ
C#の1ファイルスクリプトを簡単なコマンドでexeにビルドでき、それを .NET ランタイム等の無い環境で実行できました。これなら、バッチファイルの用途をかなり置き換えることも可能だと思います。
C#なら大得意だがバッチファイルは面倒という人がいたら、ぜひ使っていきましょう!