タスクスケジューラ PCログオン時に「1日1回だけ」実行させるサンプル

Windows全般
スポンサーリンク

Windowsのタスクスケジューラを使って、「1日に1回だけ」PCログオン時に処理を実行させる方法を紹介します。これは、タスクスケジューラのタスクと、PowerShellスクリプトを使って実現します。このスクリプトはダウンロード可能です。タスクスケジューラ設定は1からやると面倒なので、インポート用XMLを用意しています。取り込み方法から設定の編集まで、一連の流れを解説しているので、必要な方は参考にしてみて下さい。

やりたいこと

毎日PCにログオンしたときにバッチを実行したい。

ただし、1日1回だけにしたいんだよ。

日中にPCを再起動しても、その日すでに実行済みなら実行させたくないんだ。

タスクスケジューラを使って上の要件を実現する方法を考えてみます。

概要

この例では、タスクスケジューラとPowerShellスクリプトを使います。

タスクスケジューラのタスクで、ログオン時にPowerShellスクリプトを呼び出し、本日まだ実行していない場合のみバッチやプログラムを起動させます。「PCログオン時」だけだと、PCを起動しっぱなしの場合に実行されないので、8時にもスクリプトを実行させます。

スクリプト不要の方式もあるが…

スクリプトを使わずに、タスクスケジューラの設定だけで実現する方式もあります。しかし検証した限りでは、期待したタイミングで実行されないケースが散見され、動作が安定しませんでした後述)。
そのため、確実に動作するスクリプト方式がベターだろうという結論に至りました。

サンプルタスクのダウンロード

タスクスケジューラの設定を一から行うと面倒なので、サンプルタスクファイルを用意しました。以下からダウンロードできます(要ZIP解凍)。

サンプルタスクの条件
  • 次のタイミングでPowerShellスクリプトを実行する。
    • PCのログオン時
    • 毎日 AM8:00
  • PowerShellスクリプトでは、本日まだ未実行の場合のみ「イベントビューアー」を起動(呼び出すプログラムは仮のもの。編集して使うことを想定)
  • ログオン中のWindowsユーザー権限で実行(ログオフ状態では実行しない)
  • 「管理者として実行」はしない(最上位の特権は使用しない)
  • その他の詳細条件
    • 指定日時にスリープ中の場合、スリープを自動解除して実行
    • 電源コンセント接続状態は不問(AC電源/バッテリモードのどちらでも実行)

タスクのインポート方法

タスクのインポート

まず、前項でダウンロードしたファイルを解凍し、「Script」フォルダをCドライブ直下に置きます。(別のパスに置く場合は、後述の「PowerShellスクリプトの場所を編集する」でタスク設定を編集する必要があります)

次に、タスクスケジューラを起動します(起動方法)。

タスクスケジューラの画面で、右側の操作ウィンドウで「タスクのインポート」をクリックします。(もしくは、メニューの[操作]>[タスクのインポート]でもOK)

ダイアログで、上でダウンロードしたXMLファイルを指定します。(解凍してできたScriptフォルダ内にあります)

下の画面で、赤枠部分にタスクの名前を分かりやすいように設定します(そのままでもいいですが、名前だけは何故か後で変更できません)。ここで実行日時などを修正してもいいですが、次項で改めて解説しますので、とりあえず「OK」ボタンを押します。

下のように「タスクスケジューラ ライブラリ」という位置に、新しいタスクが追加されれば、タスクのインポートは完了です。なお、タスクが表示されていない場合、メニューの[操作]>[最新の情報に更新]などで、表示を更新して下さい。

「作成者」は気にしないで

サンプルファイルをインポートすると、タスクの「作成者」が「COMPUTER1\user1」などと表示されます。これは変更できませんが、動作に影響はありません。

設定の変更方法

インポートしたタスクの実行日時やプログラムを変更するには、タスクスケジューラの「タスクスケジューラライブラリ」に追加されているタスク(表示されていない場合は、画面表示を更新)を右クリックして「プロパティ」を選択します。

以下、変更したい内容ごとに操作方法を紹介します。

実行するバッチ・プログラムを変更する(必須)

PowerShellスクリプトを編集し、ログオン時に呼び出したいプログラムを指定します。サンプルでは仮の設定として、イベントビューアーを呼び出すようになっています。

スクリプトを編集するには、Scriptフォルダ内の「launcher.ps1」ファイルをメモ帳などで開き、1行目を編集します。

例えばログオン時にバッチファイル「C:\Script\sample.bat」を実行させたい場合は、1行目を次のようにします。

$path = "C:\Script\sample.bat"

編集したら上書き保存します。

PowerShellスクリプトの場所を編集する

サンプルの設定では、PowerShellスクリプト(launcher.ps1)はC:/Script フォルダにある想定です。スクリプトを別の場所に置いた場合は、タスクの設定を変更します。

この操作は、スクリプトのパスが「C:/Script/launcher.ps1」の場合不要です

タスクのプロパティで[操作]タブを表示します。下の「プログラムの開始」をダブルクリックします。

編集画面が開きます。下のように、赤枠部分の「”C:/Script/launcher.ps1”」の部分を、正しいスクリプトのパスに変更します(それ以外の部分はそのままとします)。

実行タイミングを変更する

サンプルでは、PCログオン時だけでなく、毎日AM8:00にもスクリプトを実行させるようにしています(スクリプトで実行判定するため、AM8:00より前にログオンしても、1日に2回実行されることはありません)。これは、PCログオン時だけの設定だと、PCが起動しっぱなしの場合にバッチやプログラムが実行されないためです。

AM8:00以外の時間に変更したい場合は、[トリガー]タブを表示します。「毎日」のトリガーをダブルクリックします。

詳細設定画面が開きます。下の赤枠の部分を編集すればOKです。

なお、純粋にログオン時のみ実行させたい場合は、2つあるトリガー設定のうち「毎日」の方を削除します。

「管理者として実行」させる

実行するバッチやプログラムによっては、実行する際に右クリックで「管理者として実行」を選ばないと正しく動作しないものがあります。その場合は、下図のように[全般]タブで「最上位の特権で実行する」のチェックをONにします。

こうすることで、まずPowerShellスクリプトが「管理者として実行」され、次にスクリプトから呼び出されるバッチやプログラムが「管理者として実行」されます。

セキュリティのことを全く考えなくてよければ、全てONにしておく方が楽ですが、それはお勧めできません。基本はOFFとして、それで正常に動作できない場合のみONにするが良いでしょう。

テスト実行

タスクが正しく実行されるかを確認するには、下のようにタスクを右クリックして「実行する」を選び、何度かテスト実行してみます。

設定に問題がなければ、1回目は目的のバッチやプログラムが実行され、2回目以降は(本日すでに実行済みのため)何も起こらないはずです。

本日既に実行したかどうかは、スクリプトと同じ場所に作成されるファイル「launcher.ps1.log」(下図)中の前回実行日付で判別されます。このファイルを削除すると、過去1回も実行されていないと扱われます。なので、本日未実行の想定でテストする場合はこのファイルを削除しておきます。

なお、実行時にPowerShellプロンプト画面が一瞬表示されます。実行時に「-WindowStyle Hidden」を指定しているにも関わらず、画面が表示されるのは仕様のようです。実害はないと思うので目を瞑って下さい。

スクリプト単体で実行したときのエラー

タスクスケジューラからではなく、PowerShellスクリプト単体で実行すると、以下のエラーが表示される場合があります。

これは、初期状態のPowerShellの実行ポリシーでは、スクリプトファイルの実行を許可していないためです。許可させるには「Set-ExecutionPolicy」コマンドレットでポリシー設定を変更する必要があります。

サンプルでは、タスクスケジューラからPowerShellスクリプトを実行する際に、引数でポリシーを指定しています。そのため、タスクスケジューラから実行する場合は問題ないはずです。

PowerShell スクリプトの中身

サンプルのPowerShellスクリプトの中身は、次のようになっています。

$path = "C:\WINDOWS\system32\eventvwr.msc"
#       ↑ここを編集して実行するプログラムのパスを指定
#        (バッチファイルを実行する例: $path = "C:\Script\sample.bat" )

Set-Location (Split-Path -Parent $MyInvocation.MyCommand.Path)

$format = "yyyy/MM/dd"
$now = Get-Date -Format $format
$log_path = $MyInvocation.MyCommand.path + ".log"

$is_run = $false
$ErrorActionPreference = "silentlycontinue"

try{

    $last_run_time = [DateTime]::ParseExact((Get-Content $log_path), $format, $null)
    $span =  (Get-Date) - $last_run_time

    #前回実行と現在の日付差が1以上ならプログラムを実行する
    if ($span.Days -ge 1){
        $is_run = $true
    }
}catch{
    #前回実行時を取得できなかった場合(ログファイルが無い or 正しい日時でない)も、プログラムを実行する
    $is_run = $true
}
$ErrorActionPreference = "continue"

if($is_run ){
    Invoke-Item $path
    Write-Output $now | Out-File $log_path
}

別の方式 (スクリプト不要だが確実でない)

ここからは参考情報です。スクリプトを使わずにタスクスケジューラの設定だけで実現する方式も紹介しておきます。

ただし、こちらの方式は動作が安定しません。検証した限りでは、期待したタイミングで実行されないケースが散見されました。そのため「実行されないことがあってもいいから、スクリプトを使わないお手軽な方式がいい」というケースだけ、参考にどうぞ。

別方式の設定方法

まず、タスクジューラのタスク設定で、[設定]タブの「スケジュールされた時刻にタスクを開始できなかった場合は、すぐにタスクを実行する」をONにします。

他の項目は、下の通りです。ログオンしているユーザーでAM8:00に実行するようにします。

この場合、朝8時にPCにログインされていれば、その時間に実行されます。そうでない場合は、次回PC起動の10分後くらいに実行しようとします。

ちなみに、例えば3日間PCの電源OFFだった場合、未実行タスクが3回分溜まっていますが、再実行されるのは1回だけです。

これなら、冒頭の要件を満たせるように見えます。しかし問題はここからです。

別方式の問題点

問題は、未実行タスクの再実行の挙動が不可思議な点です。

まず、この例のように「ユーザーがログオンしているときのみ実行する」の場合、PC起動後10分以上ログオンせずにいると、未実行タスクが再実行されません

じゃあ、PC起動後すぐにログオンすれば大丈夫かというと、そうでもありません。筆者が検証したところでは、PC起動後すぐログオンして10分以上待っても再実行されないケースが見られました。これは「ユーザーがログオンしているかどうかにかからわず実行する」にしても同様でした。

そして「なぜ再実行されないんだ?」と思いタスクスケジューラの設定を確認していると、突然再実行されたりしました。

この不思議な再実行メカニズムを解明し、PCのログオンタイミングに注意すれば、実用に耐えうるかもしれません。しかしその対策をするより、スクリプトを使った方がシンプルだという結論に至りました。

この方式が有効なのは、ソフトウェアのアップデートチェックのような、毎回確実に実行されなくても支障がないタスクに限定されそうです。

参考:タスクスケジューラ関連記事

そのほか、タスクスケジューラの使用例や、起こりがちなトラブルの対処方法、その他知っておくと便利なことなどを以下の記事にまとめています。併せてご覧下さい。

おわりに

今回の記事は以上です。

当サイトでは、ITインフラ関連の知識やノウハウをメインに紹介しています。下の関連記事にも役立つ情報があるかもしれませんので、ぜひご覧下さい。

また、知識やノウハウを効率的に学ぶ方法として、Udemy の「ながらセミナーもおすすめです。三日坊主にならず、普段の生活の中でスキルアップする方法です。これについては下の記事で紹介していますので、良ければご覧下さい。

もとだて
もとだて

最後まで読んでいただき、ありがとうございました。

フィードバック

コメント

タイトルとURLをコピーしました