WindowsでPowerShellスクリプトを自動起動させるときにウィンドウを表示させない方法
ツイートしたら結構反響があったのでメモしておきます。
Windows難しすぎるだろ、なんでスタートアップ時にターミナル画面を出現させずにバックグラウンドでスクリプトを実行させておくぐらいのことに四苦八苦してるんだよ
— エヌユル (@ncaq) 2023年10月3日
GNU/Linuxならsystemdのサービス作るか.profileあたりで適当に起動すれば終わりの話だぞ
常駐してほしいソフトウェアを書きました
最近、 ncaq/anti-idle: If it determines that the system has been idle for a certain period of time, it will attempt to release it. というソフトウェアを作りました。
これは一定時間(現状2分)マウスカーソルの動きがなければ適当にちょっと動かして戻すという、色々な意味でくだらないソフトウェアです。
本体でやっていることは非常に単純で、ポインタの位置を保存して、 2分間sleepして、保存したポインタと現在のポインタが同じなら雑に動かすというだけです。
2分ごとに少し動かすだけでもだいたい目標は達成されているのですが、本当にポインタを使う作業をしている時に微妙に動かされて操作ミスしたら嫌だなと思ったので、一応保存して比較しています。
作った後にこの程度のものは誰かが書いているよなと気がついて調べたら、案の定いろんなもので書かれていました。まあそれは良いことにします。
どうせ殆どChatGPTとCopilotがプログラム書きましたし。 WindowsのAPIには詳しくないのでこういうのは助かりますね。
PowerShellの自動起動がめんどくさい
メインのプログラムは単純なので、こんなものはPowerShellで十分だろうと思って採用しました。
さてこのスクリプトをログイン時に自動実行するのはどうすれば良いでしょう。
流石にそれぐらいは知っていて、
shell:startup
フォルダにショートカットを置いておけば良いです。
しかしそれではPowerShellが実行されるウィンドウが表示されてしまいます。自分の環境ではWindows Terminalのタブになります。
PCを起動している間はずっと実行しているソフトウェアなので、 Windows Terminalを終了させたりした時に巻き添えで終了したら嫌です。
単体で実行させるとしても無駄なウィンドウが一つずっと表示され続けているのも嫌です。
powershell.exe -WindowStyle Hidden -File ".\AntiIdle.ps1"
のように-WindowStyle Hidden
を指定しても変わらずウィンドウは表示されてしまいました。
タスクスケジューラは使いたくないです
タスクスケジューラはなるべく使いたくないですね。システム権限を一切使わずに動くプログラムなので、ユーザディレクトリ以下にファイルを置くだけで自動起動を設定したいです。ファイルがあるかどうかだけ見て有効になっているかサッと確認したいというのもあります。
VBScriptを経由して解決
色々試してみたところ、
- VBScript
- Windows Script Host
- Batch file
- PowerShell
のように連鎖して起動させたらウィンドウが表示されなくなりました。
vbsで、
CreateObject("Wscript.Shell").Run ".\AntiIdle.bat", 0, True
のようにBatch Fileを起動させます。
batでは、
@echo off
powershell.exe -WindowStyle Hidden -File ".\AntiIdle.ps1"
のようにPowerShellを起動させます。
多分Batch fileはいらないとは思います。最初Batch fileからの起動でどうにかならないかなと思ってた名残です。
VBScriptから直接PowerShellを起動させて良いと思います。試してないですが。
VBScriptもBatch fileもPowerShellと同じだろとutf-8-bom
にしてはいけません。文字コードはASCIIでeditorconfig上ではlatin1
にでもしておきましょう。
PowerShellのスクリプトを書く時の諸注意 - ncaq
You could have a
powershellw.exe
which would be a GUI application that doesn't show a console window. Same as whatjavaw.exe
andpythonw.exe
do.https://github.com/PowerShell/PowerShell/issues/3028#issuecomment-311142372
で提案されていたように、
PowerShellにもコンソールを起動しないpowershellw.exe
が存在すれば楽になるんですが。
何故ターミナルを開かないスクリプトを自動起動するだけでVBScriptを経由するようなバカバカしいことをしないといけないのでしょうか。
conhostでも良いらしい
conhost --headless powershell.exe -nop -win hidden -noni -f "C:.ps1"
— おーい (@OiOi_012) 2023年10月4日
これでどうでしょうか。手元の環境ではwindowは表示されません。
によるとconhostを指定する形でも良いらしいですね。 VBScriptを経由する方法でなんとかなった後に知ったので試していませんが。
F#使えば良かった
最初から常駐してウィンドウを持たないプログラムをWindowsで書くならF#やC#を使ったほうが丸かったんじゃないかなと思いました。
PowerShellにbashやzshのような単純なシェル機能を期待するのが間違いだったということですね。
Windowsホスト側にまともな開発環境を用意してなかったので、
System.Windows.Forms
とかWin32とか使っているとWSL側で開発するの面倒くさいのではという気持ちが勝ってしまいました。多分自動実行のいざこざの方が面倒くさかったと思います。
この程度のほぼAPIを呼び出すだけのプログラムでパフォーマンスを気にする必要は多分ありませんが、一応どちらもJITコンパイルされるとは言え静的型がついている言語の方が安全かつ軽量そうですし。
将来的に例えばタスクバーに起動時にはアイコン表示させるとかの機能拡張をするなら、絶対にF#とかで書いたほうが良いでしょうしね。
VBScriptは非推奨になるのでこの方法も非推奨
こんな記事を書いた数日後にVBScriptが非推奨になるという発表が行われました。「VBScript」は非推奨に、将来のWindowsリリースで削除 - 窓の杜
いやまあ確かに色々とひどい言語なのはVBA案件やってた時によく知ってますし、こんなものをメンテナンスしたくないのも分かります。なので削除するのはそれはそうなんですが、何故かこういう時に使うことになるんですよね。モダンな代替手段を用意して欲しい。
conhostなどを使うパターンにするか、 F#で書き直すかしますか。