Windows で cron 的なナニか

タスクスケジューラ。以上。

このネタ、少しは大作っぽいのになる気配がしてたけど全然だった、ので、書くか迷ったけど、個人的メモとしてはとっときたいので一応、と思って。

最初に頭で書いた通り「タスクスケジューラ。以上。」以外のナニモノでもないことはやる前から知ってたんだけど、なんとなく億劫になっててこれまで手を出してこなかったのよね。たぶん Windows 9x (別名「壊れたオモチャ」)の頃には手も足も出なかった記憶をいまだにトラウマとして抱えてるからだと思う。

Unix の cron/crontab が簡単でクールだ、なんて言わない。慣れれば簡単だ、というだけであって、別にクールじゃない。マニュアルもしっかりしてるし情報もすぐに見つかるから誰も文句言わず使ってるだけの話。だから Windows のこれがどんなであってもあまり驚かない…、と心構えたところでさて…。

今回は昨日のネタで書いた「あるサイトの動的ページを定期的にお取り寄せしたい」が動機。なので、スクリプトは既に Unix もどきシェルスクリプトで書いてある:

1 #! /bin/sh
2 cd "`dirname $0`"
3 
4 dt=`date +'%Y%m%d%H%M%S'`
5 wget --no-check-certificate \
6     --output-document="${dt}_"'topanime.php@type=airing' \
7     'https://myanimelist.net/topanime.php?type=airing'

「アニメ」からわかるかもしんないけどこれ、海外ではメジャーなアニメ評価サイト。これの「オンエアー中のアニメのランキング」ね。このサイトってアーカイブ的なものがなさげで、「推移」がわからんのよね。なのでちょっとしばらく観察したくなってな。

Unix の cron にはなく Windows のタスクスケジュール固有の「ありそうな懸念」は、「サービス化してないプログラムでもいいの?」てことだったが、これは問題なかった。どんなもんでもスケジューラに乗っけられる。(Windows の「サービス」は非常に特殊かつ特別扱いが激しく、なおかつ「サービス」プログラムを作るのは相当難儀。)

それと「黒いよー」(恐怖の DOS 窓)問題があるにはあるけれど、ワタシは気にならないので、「問題なし」とする。

Unix の cron でも Windows のタスクスケジュールでも共通の「注意点」は結局はこれ:

  1. プログラム(スクリプト)の置き場問題
  2. プログラム(スクリプト)の出力の吐き場問題
  3. プログラム(スクリプト)の標準出力・標準エラー出力を返せ問題
  4. プログラム(スクリプト)に問題があった場合にそれがすぐにわかるか問題
  5. プログラム(スクリプト)の権限問題

2. についてはワタシはスクリプトの先頭でスクリプトのある場所に cd することで措置してる。3.、4. は Unix の cron の場合、デフォルトで勝手にメールで飛んでくるので却って気にしなくて良かったりするのだが、どうか? 5. は Unix はある意味シンプルだが Windows のこれはどうか?

まず StackOverflow でコマンドラインから指定する方法を見つけた。あぁ、今スクリプトを目の前にしてる(つまりコマンドラインでスクリプトがある場所にいる)ならまずはこれが楽だね:

例によって MSYS の bash プロンプトから。
1 [me@host: MAL]$ schtasks -Create -SC DAILY -TN "get_topanime_airing" -TR "sh.exe `pwd -W`/get_topanime_airing.sh"

pwd の出力を使うことで「1. スクリプトの置き場問題」を解決してるのはわかるよね? でこれが「うまくいったぜベイベー」かどうかは実はわかってない。別の理由でうまくいかなかった後でやり直したのはこう:

例によって MSYS の bash プロンプトから。
1 [me@host: MAL]$ schtasks -Create -SC DAILY -TN "get_topanime_airing" -TR "c:\MinGW\msys\1.0\bin\sh.exe `pwd -W`/get_topanime_airing.sh"

違いはわかるよね? sh.exe をフルパスで指定してる。こういうのは Windows 固有ではなくて、Unix でも同じ問題は起こる、が、「パス区切りをスラッシュにするとアウト」ということだけは確認した。なんだよもう…。バックスラッシュにしないとなんだかとてつもなくヘンちくりんな解釈がなされる。

でこういうの、「作れたぜやったね!」で済ませる輩は阿呆である。すぐさまセットで「問い合わせ」と「削除」を学習せねば:

例によって MSYS の bash プロンプトから。
1 [me@host: MAL]$ schtasks -QUERY | less
2 [me@host: MAL]$ schtasks -DELETE -TN "get_topanime_airing" -F

削除は「-F」付けないと多分ダメ。(おそらく「有無」「有効無効」というステータスが別々なために、有効になってれば消せない、という仕様だと思う。)

てわけで上で「うまくいった」ヤツが動き、「うまくいかなかったヤツ」が動かなかった結果としては:

  • 3. プログラム(スクリプト)の標準出力・標準エラー出力を返せ問題 → これはどうしようもない。どうにかしたければ自力でログりたまえよ、が結論。
  • 4. プログラム(スクリプト)に問題があった場合にそれがすぐにわかるか問題 → これくらいかと。イベントログにはそれらしいのは吐かれてなかったし、C:\Windows\Tasks\SchedLgU.txt は期待するリッチなものではなかった。
  • 5. プログラム(スクリプト)の権限問題 → 今のワタシのニーズでは問題なし。つまりオレがログインしてるときだけオレさま権限で動けばよろしい、てことなら何もせずともおけ。

さて、あとは schtasks を喰らい尽くすだけだぜぃ…、と、でも、いう、と、おもったかぁ!! あまいよね!

-Create のヘルプ
  1 [me@host: MAL]$ schtasks -Create -?
  2 
  3 SCHTASKS /Create [/S システム [/U ユーザー名 [/P [パスワード]]]]
  4     [/RU ユーザー名 [/RP パスワード]] /SC スケジュール [/MO 修飾子] [/D 日]
  5     [/M 月] [/I アイドル時間] /TN タスク名 /TR 実行タスク [/ST 開始時刻]
  6     [/RI 間隔] [ {/ET 終了時刻 | /DU 継続時間} [/K] [/XML xml ファイル] [/V1]]
  7     [/SD 開始日] [/ED 終了日] [/IT | /NP] [/Z] [/F]
  8 
  9 説明:
 10     管理者がローカルまたはリモートのシステム上にスケジュール タスク
 11      を作成します。 
 12 
 13 パラメーター一覧:
 14     /S   システム      接続先のリモート システムを指定します。システム 
 15                        パラメーターを省略すると、既定値によりローカル システム
 16                        になります。
 17 
 18     /U   ユーザー名    SchTasks.exe が実行されるユーザー コンテキストを
 19                        指定します。
 20 
 21     /P   [パスワード]  与えられたユーザーのコンテキストのパスワードを指定し
 22                        ます。省略すると入力が促されます。
 23 
 24     /RU  ユーザー名    タスクの実行に使う実行ユーザー アカウント
 25                        (ユーザー コンテキスト) を指定します。システム
 26                        アカウントの有効な値は ""、"NT AUTHORITY\SYSTEM"、
 27                        または "SYSTEM" です。
 28                        v2 タスクには、"NT AUTHORITY\LOCALSERVICE" と
 29                        "NT AUTHORITY\NETWORKSERVICE" も 3 つすべての
 30                        3 つすべてに対して既知の SID と同じく利用できます。
 31 
 32     /RP  [パスワード]  実行ユーザーのパスワードを指定します。
 33                        パスワードを要求するには、値は "*" または
 34                        空である必要があります。システム アカウントではこの
 35                        パスワードは無視されます。/RU または /XML スイッチの
 36                        いずれかと組み合わせる必要があります。
 37 
 38     /SC   スケジュール スケジュールの頻度を指定します。
 39                        有効なスケジュールの種類は MINUTE、HOURLY、DAILY、
 40                        WEEKLY、MONTHLY、ONCE、ONSTART、ONLOGON、ONIDLE、
 41                        ONEVENT です。
 42 
 43     /MO  修飾子        スケジュールの種類を詳細に指定して、スケジュールの頻度
 44                        に関してより細かな制御を行います。有効な値は、下の
 45                        "修飾子" の節に記述されています。
 46 
 47     /D    日           タスクを実行する曜日を指定します。 有効な
 48                        値は、MON、TUE、WED、THU、FRI、SAT および SUN です。
 49                        毎月の指定 (MONTHLY) の場合は、日を 1 から 31 の
 50                        間で指定します。ワイルドカード "*" を使うとすべての日を
 51                        指定できます。
 52 
 53     /M   月            月を指定します。既定の日は月の最初の日になります。
 54                        有効な値は、JAN、FEB、MAR、APR、MAY、JUN、JUL、
 55                        AUG、SEP、OCT、NOV および DEC です。ワイルド カード
 56                        "*" を使うとすべての月が指定できます。
 57 
 58     /I  アイドル時間   待機するアイドル時間を指定します。このアイドル時間の
 59                        待機後にスケジュールされた ONIDLE のタスクが実行され
 60                        ます。
 61                        有効な範囲は、1 から 999 分です。
 62 
 63     /TN   タスク名     このスケジュール タスクを一意に識別するための
 64                        名前を指定します。
 65 
 66     /TR   実行タスク   スケジュールされた時刻に実行するプログラムのパスおよび
 67                        ファイル名を指定します。
 68                        例: C:\windows\system32\calc.exe
 69 
 70     /ST   開始時刻     タスクを実行する開始時刻を指定します。時刻は
 71                        HH:mm の形式 (24 時間形式) です。たとえば、
 72                        午後 2 時 30 分の場合は14:30 と指定します。/ST 
 73                        が指定されていない場合の既定値は現在の時刻です。
 74                        このオプションは /SC ONCE と併用する必要があります。
 75 
 76     /RI   間隔         繰り返す間隔を分で指定します。これは
 77                        次のスケジュールの種類には適用できません: MINUTE、
 78                        HOURLY、ONSTART、ONLOGON、ONIDLE、ONEVENT。
 79                        有効な範囲: 1 - 599940 分。
 80 
 81                        /ET または /DU が指定されている場合、既定値は
 82                        10 分になります。
 83 
 84     /ET   終了時刻     タスクの実行を終了する時刻を指定します。時刻の形式は
 85                        HH:mm (24 時間形式) です。たとえば、午後 2 時 50 分
 86                        の場合は 14:50 と指定します。次のスケジュールの種類には
 87                        適用できません: ONSTART、ONLOGON、ONIDLE、ONEVENT。
 88 
 89     /DU   継続時間     タスクを実行する継続時間を指定します。時間は
 90                        HH:mm の形式です。これは /ET と共には適用され
 91                        ません。また、次のスケジュールの種類には適用されません:
 92                        ONSTART、ONLOGON、ONIDLE、ONEVENT。
 93                        /V1 タスクの場合、/RIが指定されると、既定値は
 94                        1 時間になります。
 95 
 96     /K                 終了時刻または継続時間にタスクを終了します。 
 97                        これは次のスケジュールの種類には適用されません: ONSTART、
 98                        ONLOGON、ONIDLE、ONEVENT。/ET または /DU を
 99                        指定する必要があります。
100 
101     /SD   開始日       タスクを実行する最初の日を指定します。 形式は
102                        yyyy/mm/dd です。既定値は現在の日付です。
103                        これは次のスケジュールの種類には適用されません: ONCE、
104                        ONSTART、ONLOGON、ONIDLE、ONEVENT。
105 
106     /ED   終了日       タスクを実行する最後の日を指定してください。形式は
107                        yyyy/mm/dd です。これは次のスケジュールの種類には適用
108                        されません: ONCE、ONSTART、ONLOGON、ONIDLE、ONEVENT。
109 
110     /EC   チャネル名   OnEvent トリガーに対するイベントのチャネルを指定します。
111 
112     /IT                ジョブの実行時に /RU ユーザーが現在ログオンしている
113                        場合にのみ、タスクが対話的に実行されるようにします。
114                        このタスクは、ユーザーがログインしている場合にのみ実行
115                        します。
116 
117     /NP                パスワードは保存されません。タスクは特定のユーザー
118                        として非対話的に実行されます。
119                        ローカル リソースしか使用できません。
120 
121     /Z                 最後の実行後で削除するタスクをマークします。
122 
123     /XML  XMLファイル  ファイル内で指定されているタスク XML からタスクを作成し
124                        ます。
125                        タスク XML に既にプリンシパルが含まれている場合は、
126                        /RU および /RP スイッチ、または /RP 単体と組み合わ
127                        せることができます。
128 
129     /V1                Vista 以前のプラットフォームで表示するタスクを作成
130                        します。/XML との互換性はありません。
131 
132     /F                 指定したタスクが既に存在する場合、タスクを強制的に作
133                        成し、警告を抑制します。
134 
135     /RL   レベル       ジョブの実行レベルを設定します。有効な値は
136                        LIMITED と HIGHEST です。既定値は LIMITED です。
137 
138     /DELAY 遅延時間    トリガーの開始後から、タスクが実行するまでの待機
139                        時間を指定します。時間の形式は mmmm:ss です。
140                        このオプションは ONSTART、ONLOGON、ONEVENT の
141                        種類のスケジュールにのみ有効です。
142 
143     /?                 このヘルプを表示します。
144 
145 修飾子: /MO スイッチでスケジュールの各種類に利用できる値:
146     MINUTE:  1 から 1439 (分)
147     HOURLY:  1 から 23 (時)
148     DAILY:   1 から 365 (日)
149     WEEKLY:  1 から 52 (週)
150     ONCE:    修飾子なし
151     ONSTART: 修飾子なし
152     ONLOGON: 修飾子なし
153     ONIDLE:  修飾子なし
154     MONTHLY: 1 から 12 (月) または
155              FIRST、SECOND、THIRD、FOURTH、LAST、LASTDAY
156 
157     ONEVENT:  XPath イベントのクエリ文字列。
158 例:
159     ==> ユーザー "runasuser" の下で 1 時間ごとに notepad.exe を実行する
160         スケジュール タスク "doc" をリモート コンピューター "ABC" に作成します。
161 
162         SCHTASKS /Create /S ABC /U user /P password /RU runasuser
163                  /RP runaspassword /SC HOURLY /TN doc /TR notepad 
164 
165     ==> リモート コンピューター "ABC" にスケジュール タスク "accountant" 
166         を作成し、開始日と終了日の間、指定された開始時刻から終了時刻の
167         間で 5 分ごとに calc.exe を実行します。
168 
169         SCHTASKS /Create /S ABC /U domain\user /P password /SC MINUTE
170                  /MO 5 /TN accountant /TR calc.exe /ST 12:00 /ET 14:00
171                  /SD 06/06/2006 /ED 06/06/2006 /RU 実行ユーザー
172                  /RP ユーザーパスワード
173 
174     ==> スケジュール タスク "gametime" を作成し、毎月第一日曜日
175         にフリーセルを実行します。
176 
177         SCHTASKS /Create /SC MONTHLY /MO first /D SUN /TN gametime 
178                  /TR c:\windows\system32\freecell
179 
180     ==> リモート コンピューター "ABC" にスケジュール タスク "report" 
181         を作成し、毎週 notepad.exe を実行します。
182 
183         SCHTASKS /Create /S ABC /U user /P password /RU runasuser
184                  /RP runaspassword /SC WEEKLY /TN report /TR notepad.exe
185 
186     ==> リモート コンピューター "ABC" スケジュール タスク 
187         "logtracker" を作成し、指定の開始時刻から 5 分ごとに 
188         notepad.exe を実行します。/RP パスワードの入力を促され
189         ます。
190 
191         SCHTASKS /Create /S ABC /U domain\user /P password /SC MINUTE
192                  /MO 5 /TN logtracker 
193                  /TR c:\windows\system32\notepad.exe /ST 18:30
194                  /RU runasuser /RP
195 
196     ==> スケジュール タスク "gaming" を作成して freecell.exe を毎日 
197         12:00 に開始し、自動的に 14:00 に終了するようにします。
198 
199         SCHTASKS /Create /SC DAILY /TN ゲーム /TR c:\freecell /ST 12:00
200                  /ET 14:00 /K
201     ==> スケジュール タスク "EventLog" を作成し、システム チャネルで
202         イベント 101 が発行された場合は常に wevtvwr.msc wo を実行します。
203 
204         SCHTASKS /Create /TN EventLog /TR wevtvwr.msc /SC ONEVENT
205                  /EC System /MO *[System/EventID=101] 
206     ==> ファイル パスにスペースを含める場合は、CMD.EXE に対する引用符 1 組と、
207         合計 2 セット使用します。CDM の外側の引用符には二重引用符を使用する
208         必要があります。内側の引用符には一重引用符、またはエスケープした
209         二重引用符を使用できます:
210         SCHTASKS /Create 
211            /tr "'c:\program files\internet explorer\iexplorer.exe' 
212            \"c:\log data\today.xml\"" ... 

いや、使いこなす気にはなれん。最初に一発手っ取り早く基礎版だけ放り込むのにはいいけど、こうまで柔軟で複雑だと、「コマンドラインだからラクチン」という気分にはナレマセヌ。

そもそもすぐに出来る例が「HOURLY」が最小単位で、それ以上は「ハゲしくアドバンスト」なのよな、ツラいわ。だってこういうのってさぁ、「まずはお試して 3分後に動けやヲラァ」ってやってみたいでせう。それをすぐにさ、出来る?

てわけで、「コントロールパネル → 管理ツール → タスクスケジューラ」するのがいいと思う、素直に。

スケジューリングに関して crontab が持つのと同程度の自由度があるのかどうかが、初見で伝わりにくいんだけれど、上画像の「繰り返し間隔」が編集可能なプルダウンになってて、多分 crontab でやるのと同程度の柔軟性があるとみた。あと個人的にまさしく「有効期限」が欲しかったんで、これがあるだけでとても高評価。ええではないの。

えーっとこんくらいで書きたかったことは書いた、かな、多分。まぁ誰の役にも立たんとは思う。というかもっとキレイにまとめてるサイトはきっとたくさんあるに違いない。