Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

windows-automation-ops

Three small tools for running unattended automation on a Windows machine that a human also uses.

「人間も使っているWindows機」で無人自動化を回すための小道具3本。

English日本語


English

Running scheduled jobs on a server is easy. Running them on the desktop somebody is working — or gaming — on is a different problem: windows pop up over what they are doing, resources leak until the machine stops responding, and when something goes wrong you have no idea what the machine looked like at the time.

These are the three things that fixed it here.

Tool Problem it solves
run-hidden.vbs Scheduled tasks flashing a console window every time they fire
browser-watchdog.ps1 Leaked automation browsers, and no data when the machine freezes
screenshot.ps1 Seeing what is on screen without clicking anything — including windows that are covered

run-hidden.vbs

Ten scheduled tasks launching node.exe meant ten console windows popping over whatever was in the foreground, at every interval. The usual advice — Task Scheduler's Hidden checkbox — does not hide a console app, and "Run whether user is logged on or not" hides it only by running in a different session, which breaks anything that needs the desktop.

wscript.exe has no console of its own. Launch through it.

Program   : wscript.exe
Arguments : //nologo "C:\tools\run-hidden.vbs" "C:\Program Files\nodejs\node.exe" "job.mjs" --flag

It waits for the child and returns the real exit code, so Task Scheduler's Last Run Result stays meaningful. Most VBS snippets you find for this fire-and-forget and always report 0x0 — a task that fails silently while reporting success is worse than one that never ran.

Arguments containing spaces are re-quoted, because WScript.Arguments has already stripped the quotes you wrote in the task action and C:\Program Files\... would otherwise split in half.


browser-watchdog.ps1

Samples GDI objects, USER objects, total handles, process counts, automation-browser working set and free physical memory every 15 seconds into a CSV, and optionally kills automation browsers that have been alive too long.

The motivating incident: the desktop became input-unresponsive three times in half an hour. The event log showed no bugcheck, no application crash, no memory-exhaustion event and no GPU/TDR event — but two unrelated services failed to start with 30-second timeouts right before the first reboot. That pattern says handle or desktop-heap exhaustion, not a crash. And you cannot check after the fact, because a reboot takes the numbers with it.

The honest epilogue: once the data existed, it disproved the handle theory (a parked browser sat at GDI 1,180 / USER 2,231 against a warning threshold of 8,000) and pointed at a focus-stealing poll loop instead. That is the whole value proposition — measure before you believe your own theory about a freeze.

# sample only, no killing - start here
powershell -ExecutionPolicy Bypass -File .\browser-watchdog.ps1 -ReapAfterMinutes 0

# with reaping, scoped to one project path
powershell -ExecutionPolicy Bypass -File .\browser-watchdog.ps1 -ScopeMarker my-automation-project

Safety. A browser is only considered "automation-launched" if its command line contains --remote-debugging-port, --enable-automation, ms-playwright, or your -ScopeMarker path fragment. Your everyday Chrome and Edge match none of these. Browsers stamped with a keep-flag (--pwguard-keep by default — see playwright-launch-guard) are never reaped, because those are deliberately parked with work in progress. Run with -ReapAfterMinutes 0 first and read the CSV to confirm the classification on your machine before you let it kill anything.


screenshot.ps1

Captures a named window or a monitor to PNG. Read-only: it never clicks, types, or moves focus.

.\screenshot.ps1                            # every monitor
.\screenshot.ps1 -Window 'Store Connect'    # matching window only
.\screenshot.ps1 -Monitor 1 -Out C:\tmp\a.png

The useful part is PrintWindow with PW_RENDERFULLCONTENT, which asks the window to redraw itself into our device context. A window that is covered by another one still captures correctly. Graphics.CopyFromScreen cannot do this — it only reads pixels physically on screen, so an overlapping chat window ends up in the shot instead of the thing you wanted. (Yes, we shipped that version first.)

Not every app implements PrintWindow properly, so the result is checked against a sparse pixel grid: if every sample is identical the capture failed, and it falls back to a screen copy and says so in the output.

Why this matters for automation: many sites forbid automated access in their terms, which rules out driving them with Playwright. Reading pixels off your own monitor touches none of their servers and is exactly what a human does with the Print Screen key. When you have to hand a step back to a person, being able to see the screen — instead of asking them to describe it — removes an entire round trip.

Requirements: Windows PowerShell 5.1+ (System.Drawing / System.Windows.Forms). No modules to install.

Note on encoding: both .ps1 files are deliberately ASCII-only. Windows PowerShell 5.1 reads a BOM-less UTF-8 script as cp932 and throws parse errors that point at the wrong line entirely. If you add comments in Japanese, save as UTF-8 with BOM.


日本語

サーバでバッチを回すのは簡単ですが、本人が作業やゲームをしている同じデスクトップで無人自動化を回すのは別問題です。実行のたびに窓が前面に出る、リソースが漏れて最終的にPCが固まる、そして固まった時にその瞬間の状態を示すデータが何も残らない

ここで実際に効いた3本です。

run-hidden.vbs — タスクスケジューラのコンソール窓を消す

node.exe を起動するタスクが10本あると、実行のたびに10回コンソール窓が前面に出ます。タスクスケジューラの「非表示」チェックはコンソールアプリには効かず、「ユーザーがログオンしているかどうかにかかわらず実行」は別セッションで走るのでデスクトップが要る処理が壊れます。

wscript.exe は自前のコンソールを持たないので、これを噛ませます。

プログラム : wscript.exe
引数       : //nologo "C:\tools\run-hidden.vbs" "C:\Program Files\nodejs\node.exe" "job.mjs" --flag

子プロセスを待って終了コードを返すので、タスクスケジューラの「前回の実行結果」が正しい値になります。ネットにある同種のVBSは投げっぱなしで常に 0x0 を返すものが大半ですが、失敗しているのに成功と報告するタスクは、動いていないタスクより有害です。

browser-watchdog.ps1 — 固まる前の数字を残す

15秒ごとに GDIオブジェクト / USERオブジェクト / 全ハンドル数 / プロセス数 / 自動化ブラウザのワーキングセット / 空き物理メモリをCSVに記録し、必要なら長時間放置された自動化ブラウザを回収します。

きっかけは、30分の間に3回デスクトップが入力を受け付けなくなり再起動が必要になった件です。イベントログには BSODもアプリのクラッシュもメモリ枯渇もGPU/TDRも記録がなく、代わりに1回目の直前に無関係な2サービスが30秒タイムアウトで起動失敗していました。これは「クラッシュ」ではなくハンドル/デスクトップヒープ枯渇の典型です。しかし再起動すると数字は消えるので、事後には確認できません。

正直な後日談として、データが取れた結果 ハンドル枯渇説は否定されました(常駐ブラウザ1台で GDI 1,180 / USER 2,231・警告閾値8,000)。真犯人は別のフォーカス奪還ループでした。フリーズの原因は、自分の仮説を信じる前に実測すること — このツールの価値はそこにあります。

🔴 安全性: 「自動化ブラウザ」と判定するのはコマンドラインに --remote-debugging-port / --enable-automation / ms-playwright / 指定した -ScopeMarker を含むものだけで、本人常用のChrome/Edgeは一切該当しません。keep フラグ付き(既定 --pwguard-keep)のものは「送信待ちで意図的に残してある窓」なので絶対に殺しません。まず -ReapAfterMinutes 0 で走らせてCSVを読み、自分の環境での判定が正しいことを確認してから回収を有効にしてください。

screenshot.ps1 — 触らずに画面を見る

指定ウィンドウまたはモニタをPNGで保存します。読み取り専用。クリックも入力もフォーカス移動も一切しません。

肝は PrintWindow + PW_RENDERFULLCONTENT で、ウィンドウ自身に再描画させるため 他のウィンドウに隠れていても正しく撮れますGraphics.CopyFromScreen は画面上の実ピクセルしか読めないので、手前にチャット窓が被っているとそれが写ります(最初にその版を作って踏みました)。

PrintWindow を正しく実装していないアプリもあるため、まばらなピクセル格子で結果を検査し、全サンプルが同一なら失敗と判定して画面コピーにフォールバックし、その旨を出力します。

これが自動化で効く理由: 自動的手段でのアクセスを規約で禁じているサイトは多く、その場合 Playwright での操作はできません。一方、自分のモニタのピクセルを読む行為は相手のサーバに一切触れず、人間が Print Screen キーを押すのと同じです。本人に操作を引き継ぐ場面で「今どうなっているか説明してください」の往復が丸ごと消えます。

要件: Windows PowerShell 5.1 以上。追加モジュール不要。

文字コード注意: .ps1 2本は意図的に ASCIIのみです。Windows PowerShell 5.1 は BOM無しUTF-8 を cp932 として読み、まったく無関係な行を指すパースエラーを出します。日本語コメントを足す場合は **UTF-8(BOM付き)**で保存してください。


MIT License. Built by AI Jidoka Lab (Taku)https://setlog-app.github.io/ai-jidoka-lab/

About

Three tools for unattended automation on a Windows box a human also uses: hidden scheduled tasks, a resource watchdog, and occlusion-safe screenshots.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages