Windowsの定期タスクから黒いコマンドウィンドウを消す
スケジュールタスクが発火のたびに出すコンソール窓を、管理者権限なし・ログと終了コードを保ったまま消す手順。wscript.exe経由の中継VBS、検証手順、適用してよいジョブの見極め、落とし穴の一覧まで。
約2.2万トークンの節約 (API料金換算で約33円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「Windowsの定期タスクから黒いコマンドウィンドウを消す」は、業務自動化カテゴリのAI指示書(MDファイル)です。スケジュールタスクが発火のたびに出すコンソール窓を、管理者権限なし・ログと終了コードを保ったまま消す手順。wscript.exe経由の中継VBS、検証手順、適用してよいジョブの見極め、落とし穴の一覧まで。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約2.2万トークン(API料金換算で約33円)・85%のトークンを節約できます。
- カテゴリ
- 業務自動化
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約2.6万トークン
- この巻物使用時
- 約4,000トークン
- 節約量
- 約2.2万トークン (約33円)
- 更新日
- 2026-08-28
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/windows/raw を読み込んで、この指示書どおりに実装して"
中身
Windows の定期タスクから「黒いコマンドウィンドウ」を消す
毎時・毎朝走るスケジュールタスクが、発火のたびに一瞬〜数十秒コンソール窓を出して作業を邪魔する問題を、管理者権限なし・ログを失わず・終了コードも保ったまま解決する手順。
前提と原因
Windows のスケジュールタスクは LogonType=Interactive(=「ユーザーがログオンしているときのみ実行」)だと、node.exe / powershell.exe / *.cmd を起動するたびにコンソール窓を必ず表示する。タスクの「表示しない(Hidden)」設定はタスク一覧での表示可否であって窓を隠す設定ではないので、チェックしても効かない。
正攻法は Principal を S4U(「ユーザーがログオンしているかどうかにかかわらず実行」)へ変えることだが、これは実行に管理者権限(SeTcbPrivilege)が要る。標準ユーザー権限では次のように必ず失敗する。
$p = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType S4U -RunLevel Limited
Set-ScheduledTask -TaskName '<TASK_NAME>' -Principal $p
# => Set-ScheduledTask: アクセスが拒否されました。
-WindowStyle Hidden を PowerShell に渡す方法も、プロセス起動直後に窓が生成されてから隠れるため一瞬フラッシュする。
解決策: コンソールホストを持たない wscript.exe から起動する
wscript.exe は GUI サブシステムのアプリなのでコンソールを一切作らない。そこから中継用の VBScript で本体を起動すれば、窓はゼロになる。
1. 中継スクリプトを置く(<repo>/tools/run-hidden.vbs)
' run-hidden.vbs -- run a command with NO console window at all.
' Usage (as a scheduled task action):
' Execute : C:\Windows\System32\wscript.exe
' Arguments : //nologo "<...>\tools\run-hidden.vbs" "<exe>" "<arg1>" "<arg2>" ...
' ASCII only on purpose: JP-locale script hosts mis-decode non-BOM UTF-8.
Option Explicit
Dim args, i, inner, exePath, baseName, logDir, logPath, shell, fso, rc, full
Set args = WScript.Arguments
If args.Count < 1 Then
WScript.Quit 2
End If
Set fso = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
exePath = args(0)
baseName = fso.GetBaseName(exePath)
If args.Count >= 2 Then
' Prefer the script name over the interpreter name for the log file.
baseName = fso.GetBaseName(args(1))
End If
logDir = shell.ExpandEnvironmentStrings("%USERPROFILE%") & "\.claude\logs"
If Not fso.FolderExists(logDir) Then
On Error Resume Next
fso.CreateFolder logDir
On Error Goto 0
End If
logPath = logDir & "\" & baseName & ".log"
' Rotate at ~1 MB so the log cannot grow without bound.
On Error Resume Next
If fso.FileExists(logPath) Then
If fso.GetFile(logPath).Size > 1048576 Then
If fso.FileExists(logPath & ".1") Then fso.DeleteFile logPath & ".1", True
fso.MoveFile logPath, logPath & ".1"
End If
End If
On Error Goto 0
inner = ""
For i = 0 To args.Count - 1
inner = inner & """" & args(i) & """"
If i < args.Count - 1 Then inner = inner & " "
Next
' cmd /s /c "<...>" always strips exactly the outer quotes, which keeps the
' quoting of the inner command intact regardless of spaces in paths.
full = "cmd.exe /d /s /c " & """" & inner & " >> """ & logPath & """ 2>&1" & """"
' 0 = hidden window, True = wait so the exit code can be propagated.
rc = shell.Run(full, 0, True)
WScript.Quit rc
設計上のポイント(省くと後で必ず困る):
- stdout/stderr を必ずログへ落とす。窓を消すと同時に出力も消えるため、リダイレクトを中継側に組み込まないと障害が無言化する。1MB ローテートまで入れておく。
- 終了コードを透過する(
shell.Run(..., True)で待ってWScript.Quit rc)。これがないとタスクのLastTaskResultが常に 0 になり、失敗を検知できなくなる。 cmd /d /s /c "…"で包む。/sを付けると「最初と最後の引用符だけを剥がす」挙動が確定するので、パスに空白や日本語が入っても内側の引用が壊れない。- VBS 本文は ASCII のみ。日本語ロケールの Windows Script Host は BOM なし UTF-8 を誤デコードする。
2. タスクのアクションを差し替える(管理者権限不要)
$repo = '<REPO_PATH>'
$vbs = Join-Path $repo 'tools\run-hidden.vbs'
$node = (Get-Command node).Source
$script = Join-Path $repo 'tools\<YOUR_SCRIPT>.mjs'
$arg = '//nologo "{0}" "{1}" "{2}" --limit 50' -f $vbs, $node, $script
$a = New-ScheduledTaskAction -Execute "$env:SystemRoot\System32\wscript.exe" -Argument $arg -WorkingDirectory $repo
Set-ScheduledTask -TaskName '<TASK_NAME>' -Action $a
Set-ScheduledTask -Action は自分が作ったタスクなら標準ユーザー権限で通る(-Principal の変更だけが管理者権限を要求する)。
3. 登録スクリプト側も同時に直す
タスクを作る register-*.ps1 を直さないと、次に再登録した瞬間に窓が復活する。New-ScheduledTaskAction の -Execute を wscript.exe に、-Argument を //nologo "<vbs>" "<exe>" "<args>" に変えておく。
検証(沈黙を合格と誤読しないために)
- 無害なプローブで経路を確かめる(本番スクリプトは副作用があるので使わない):
Set-Content .\probe.mjs 'console.log("out ok " + process.cwd()); console.error("err ok"); process.exit(7);' -Encoding ASCII
$p = Start-Process 'C:\Windows\System32\wscript.exe' -ArgumentList '//nologo','"<...>\run-hidden.vbs"','"C:\Program Files\nodejs\node.exe"','".\probe.mjs"' -Wait -PassThru
$p.ExitCode # => 7 なら終了コード透過OK
Get-Content "$env:USERPROFILE\.claude\logs\probe.log" # => out/err 両方入っていればOK
- パスに空白・日本語が入るケースを1回通す(引用崩れはここで出る)。
- タスクを
Start-ScheduledTaskで実走し、Get-ScheduledTaskInfoのLastTaskResultとログ内容の両方を見る。窓が出なかったことだけを確認して終わらない。
適用してよいジョブ / だめなジョブ
- 適用してよい: 純 CLI の定期ジョブ(node / python / PowerShell スクリプト、HTTP を叩くだけの取込・集計・通知)。
- 適用しない: ブラウザや GUI を実際に画面へ出す必要があるジョブ。ただし「スクリプトが Chrome を起動する」だけなら中継してよい(隠れるのは中継の窓だけで、子の GUI は通常どおり表示される)。
- 名前で判断しない。
.cmdの中身を読んで、GUI が必要かどうかを確かめてから決める。
よく踏む落とし穴
| 症状 | 原因 | 対処 |
|---|---|---|
Set-ScheduledTask が Access Denied | 対象タスクが管理者権限で作られている | Start-Process powershell -Verb RunAs(UAC 1クリック)で実行。-Wait を付けずに起動し、あとからタスク状態をポーリングすれば自動化側が固まらない |
| 窓は消えたが失敗に気付けない | 出力のリダイレクトを入れていない | 中継側で必ずログへ追記する(本手順に同梱) |
LastTaskResult が常に 0 | 中継が子を待たずに終了している | shell.Run(..., True) + WScript.Quit rc |
| VBS が構文エラー | 日本語コメント + BOM なし UTF-8 | VBS は ASCII のみで書く |
| 再登録したら窓が戻った | 登録スクリプトを直していない | register-*.ps1 を同じコミットで直す |
| タスクの削除・無効化が AI エージェント側でブロックされる | 破壊的操作のガード | 迂回せず、ダブルクリックで実行できる .cmd(ASCII のみ、失敗時に「管理者として実行」を案内する分岐入り)を用意して人に渡す。消す前に Export-ScheduledTask で XML バックアップ |
参考: 窓を出しているタスクの棚卸し
Get-ScheduledTask | Where-Object {
$_.TaskPath -eq '\' -and $_.State -ne 'Disabled' -and $_.Principal.LogonType -eq 'Interactive'
} | Select-Object TaskName,
@{n='Exe';e={Split-Path $_.Actions.Execute -Leaf}},
@{n='Start';e={$_.Triggers[0].StartBoundary}} | Format-Table -AutoSize
Exe が wscript.exe 以外(node.exe / powershell.exe / *.cmd / *.bat)のものが窓を出す候補。時刻を見て「日中に発火するもの」だけを直せば、夜間ジョブはそのまま残せる。
よくある質問
+「Windowsの定期タスクから黒いコマンドウィンドウを消す」とは何ですか?
スケジュールタスクが発火のたびに出すコンソール窓を、管理者権限なし・ログと終了コードを保ったまま消す手順。wscript.exe経由の中継VBS、検証手順、適用してよいジョブの見極め、落とし穴の一覧まで。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約2.6万トークンかかりますが、この巻物を使えば約4,000トークンで済みます。差し引き約2.2万トークン(API料金換算で約33円)・85%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
Google Meet 自動参加&動画配信Bot 開発指示書
指定した時刻に Google Meet へ自動参加し、動画を再生しながら画面共有する Bot を、Claude Code に一発で作らせる開発指示 MD。朝会の定例動画配信・ウェビナーの自動放送に。
受信メール添付を案件フォルダへ自動取込するパイプライン
メールを読むアプリとドライブに書くアプリが別、という現実的な構成で顧客メールの添付を案件フォルダへ無人保存する設計。権限追加を避ける理由、実行時間制限下の予算3本立て、二重の重複防止、base64url/行数上限/変換判定などの実装罠、案件と顧客のマッチング、名寄せは候補提示+人の承認にする型まで。
Gmail 自動仕分け&返信ドラフト生成MD
受信メールを AI が分類 (要返信/情報/営業/スパム) してラベル付けし、要返信メールには返信ドラフトまで自動生成する仕組みを作らせる指示書。DWD (ドメイン全体委任) 設定手順込み。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア