サーバー関連の作業のあるあるですが、Linuxだと簡単なのにWindows だと動かないということが時々発生します。
先日もWindows Serverの作業で同様の事象がは発生したので、今回はその解決方法を寄稿したと思います。
タスクスケジューラでPowerShellが動かない?!リターンコード2147942401の解決方法とは?
さて、今回遭遇したのは以下のような状況です。
- 手動によるバッチ実行はエラーなく実行可能
- タスクスケジューラでPowerShellを実行するとPowerShell が起動はしているものの、バッチ用のPowerShellは実行されない
- 全く同じ設定でも、バッチを問題なく実行できる環境もある
- 切り分け環境を含め、サーバーは全てWindows Server 2016
- アカウントも管理者権限で切り分け用のサーバも設定は同じ
- PowerShellの実行ポリシーがBypassでも、タスクスケジューラではPowerShellのバッチは実行されない
- リターンコードとして2147942401が返される
といった感じです。
同じPowerShellのバッチにも関わらず、動く環境と動かない環境があることが、問題解決に時間が掛かった理由です。
正直「どうやったら動くのか・・・」という感じでした。
同じような状況の方で、同じエラーで困り果ててこのページにたどり着いた方は、以下の手順をそれぞれお試しいただくと最短で事象の解決が出来るはずですので是非と試し下さい。
タスクの作成
では早速、タスクを作成してみましょう。
まずはタスクスケジューラを起動します。
タスクバーの検索ウィンドウか、『Windows ボタン+s』を実行し、task、タスク、タスク スケジューラと入力し、タスク スケジューラを選択します。
タスク スケジューラが起動したら、『タスク スケジューラライブラリー』を右クリックし『タスクの作成』を選択します。
タスクの作成時では5つのタブが有り、それぞれ以下のような設定を行います。
設定する内容は、
- 5分毎にスクリプトを実行
- 24時間/365日、継続して実行
です。
バッチなので当然と言えば当然の設定ですね。
では、設定をしていきますが、設定したタスクは後から編集も可能です。
『全般』の設定
『全般』のタブでは、以下の3か所を設定します。
- 名前
- 最上位の特権で実行する
『トリガー』の設定
『トリガー』のタブでは、トリガーを実行するスケジュールを設定します。
初めてタスクを設定する場合には『新規』を選択します。
今回設定する内容は以下の通りです。
あなたが設定した内容に合わせてください。
- 開始時間を設定(現在時間より先の時間を設定します)
- 繰り返し間隔は『5分間』、継続時間は『無期限』に設定
設定したら『OK』を選択します。
『操作』の設定
『操作』のタブでは、トリガーを実行するスケジュールを設定します。
今回テスト用に用意したサンプルバッチは以下の通りです。
Cドライブ以下にtaskディレクトリがあり、その中にバッチのtask.ps1とtask.ps1に呼び出されるPsExec.exeが有ります。
C:\task>tree /f
フォルダー パスの一覧
ボリューム シリアル番号は 0000008C 8A96:999A です
C:.
PsExec.exe
task.ps1
サブフォルダーは存在しません
今回の設定では以下のように設定を行います。
プログラム/スクリプト | %Systemroot%\System32\WindowsPowerShell\v1.0\powershell.exe |
引数の追加(オプション) | -ExecutionPolicy Bypass “C:\task\task.ps1” |
開始(オプション) | C:\task |
- プログラム/スクリプトは、PowerShellを実行させるためPowerShell.exeを指定
- 引数の追加オプションは、PowerShellの実行ポリシーと実行するPowerShell(ps1)を指定
- 開始は、バッチが保存されているディレクトリを指定
PowerShellの実行ポリシーについては後ほど解説します。
設定したら『OK』を選択し『操作』については完了します。
『条件』の設定
『条件』のタブでは、タスクの実行条件を設定します。
今回は、以下のチェックボックスを外します。
- コンピューターをAC電源で使用している場合のみタスクを開始する
サーバー環境ではそもそも不要な設定なのですが、このAC電源の設定が入っていることでタスクの実行が安定しないこともあるようなので、念のためチェックボックスを外します。
『設定』の設定
『設定』のタブでは、タスクの動作に影響する追加設定を設定します。
今回は何も設定しませんので、そのまま『OK』を選択してタスクの設定が完了です
リターンコードの出力(ログの出力)設定
タスクを設定したらリターンコードの出力が確認できるように、ログの設定を行います。
デフォルトではオフのため、タスクの実行時にリターンコードの確認ができません。
- 全てのタスク履歴を有効にする
を選択すると『履歴(無効)』が 『履歴』の表示となり、 タスクの実行時のログが確認できるようになります。
タスクが動作しているかを確認する
タスクスケジューラの設定が完了したら、時刻通りにタスクが実行されているのかを必ず確認しましょう。
以下はスケジュール前でまだダスクが実行されていない状態のため、前回の実行時間が『1999/11/30 0:00:00 タスクはまだ実行されていません。(0x41303)』と表示されています。
タスクスケジューラのコードについてはMicrosoft社に説明があり、今回の場合では41303で検索するとヒットします。
PowerShell 実行ポリシーとは?
PowerShell の実行ポリシーは、PowerShell が構成ファイルを読み込み、スクリプトを実行する際の条件を制御する安全性機能で悪意のあるスクリプトの実行を防止に役立ちます。
デフォルトでは、RemoteSignedに設定されています。
確認方法は、PowerShellを起動し Get-ExecutionPolicyコマンドで確認ができます。
PS C:\Users\Administrator> Get-ExecutionPolicy
RemoteSigned
詳細はMicrosoft社のページで確認ができますが、簡単に纏めると以下となります。
スクリプトの実行可・不可を含め、タスクスケジューラでスクリプトを実行するにはこれらの実行ポリシーを理解しておく必要がありますが、確実にタスク動作させるにはBypassを指定すると良いでしょう。
ポリシー | 内容 | 実行 |
AllSigned | 信頼済みまたは信頼できないものとして分類されていない発行元からのスクリプトを実行する前に、プロンプトを表示 | スクリプトの実行が可能 |
Bypass | 何もブロックされず、警告やプロンプトは表示されない | スクリプトの実行が可能 |
RemoteSigned | ローカルコンピューター上に記述され、インターネットからダウンロードされないスクリプトに対してデジタル署名は不要 | スクリプトの実行が可能 |
Restricted | すべてのスクリプトファイルの実行を禁止 | 個々のコマンドを許可されるが、スクリプトの実行は許可されない |
Unrestricted | ローカルイントラネットゾーンからのものではないスクリプトと構成ファイルを実行する前にユーザーに警告 | 署名されていないスクリプトを実行可能 |
事象解決までに実施した切り分け方法は?
筆者が上手くタスクが実行できなかった部分は以下の3つです。
- 全般:ユーザーがログオンしている時のみ実行する
- 操作:引数の追加(オプション)にPowerShellの実行ポリシーを設定しない
- 操作:開始(オプション)にディレクトリを設定しない
特に2.の引数の追加(オプション)は、PowerShellの実行ポリシー入力せずにバッチ用のPowerShellを指定していただけでしたが、これでタスクスケジューラによるバッチが正しく動く環境もあります。
タスクスケジューラによるバッチが動かない環境では、設定した時刻になるとPowerShell自体は実行されているようですが、結果としてリターンコードとして2147942401が返されました。
解決までに数日を要したので、急ぎの案件の場合だと困ってしまいますね。
WindowsタスクスケジューラはMicrosoftのQ&Aではサポートされていない
筆者もハマったので調べてみると、タスクスケジューラ関連でトラブルを抱えている人は多く、しかもMicrosoft社のコミュニティではQ&A対象外とのことです。
今回ご紹介した対応でも解決できない場合には、正規にチケットを利用して有料のサポートに問い合わせしてみるのも良いかもしれません。
まとめ
ITエンジニアの仕事をしていると、Unix/Linuxではcron(クーロン)、Windowsではタスクスケジューラで定時にジョブを実行させる作業は頻繁に発生します。
まだ試したことがない方は、本記事が参考になれば幸いです。