TL;DR
- 最上位権限でタスクスケジューラに登録したい
- ログオフ(サインアウト)しておいても動いてほしいから
- エクスポートしたXMLファイルをもとに作って、登録すればなんとかいけた
現在作業中のユーザで登録してみる
まずは普通に登録してみます。
// タスクスケジューラの登録解除runProcess(@"/c schtasks.exe /delete /TN SampleTask /F");// タスクスケジューラの登録varcommand="/c schtasks.exe /create /TN SampleTask /TR "+Directory.GetCurrentDirectory()+@"\SampleTask.bat ";// TODO 必要に応じて、ここでcommandに色々な指定を追加する// 登録Processproc=newProcess();proc.StartInfo.FileName=Environment.GetEnvironmentVariable("ComSpec");//"cmd.exe";proc.StartInfo.UseShellExecute=false;proc.StartInfo.RedirectStandardOutput=true;proc.StartInfo.RedirectStandardInput=false;proc.StartInfo.CreateNoWindow=true;proc.StartInfo.Arguments=command;proc.Start();varresults=proc.StandardOutput.ReadToEnd();// TODO 必要ならresultsからログ出力とかproc.WaitForExit();proc.Close();// 完了通知MessageBox.Show("登録しました");
さて。
これだと、ログインしている状態じゃないと動きません。
それでもいいなら、十分です。
XMLを利用して、登録してみる
「いちいち色々な設定を記載して登録するのとか面倒じゃない?」
ということで、一度テンプレートとなるようなXMLを作成してからタスクを登録する方法です。
テンプレートとなるXMLの作成
- 普通にWindowsのタスクスケジューラを起動し、適当なタスクを作成します。
- 作成したタスクを選択して、右クリックなり、画面右なりから「エクスポート」を選択します。
- 作成したタスクを削除します。
登録
XMLをタスクスケジューラに登録します。
といっても、command部分を以下のようにするだけです。
varcommand="/c schtasks.exe /create /XML "+Path.Combine(Environment.CurrentDirectory,"template.xml")+" /TN SampleTask";
仮に、テンプレートを読み込んで編集したい場合があれば、XMLを読み込んだ後、追加したり変更したりします。
XmlDocumentdocument=newXmlDocument();document.Load(inputXmlPath);// テンプレートとなるXMLをロードvartask=document.GetElementsByTagName("Task")[0];DateTimenow=DateTime.Now;// 今日の日付vardate=document.GetElementsByTagName("Date")[0];date.InnerText=now.ToString("yyyy-MM-ddTHH:mm:ss");// Authorvarauthor=document.GetElementsByTagName("Author")[0];author.InnerText=$@"{Environment.UserDomainName}\{Environment.UserName}";// バッチのパスvarcommand=document.GetElementsByTagName("Command")[0];command.InnerText=Directory.GetCurrentDirectory()+@"\SampleTask.bat";// todo などなど適当にXMLに追加したり、変更したりする// 保存document.Save(outputXmlPath);// テンプレートに上書きでもいいが、他の名前で保存しておく(つまり、登録時のパスはoutputXmlPathを使う)
XMLを利用して、SYSTEMユーザで登録してみる
サインアウト時にも動くようにしたいので、登録時のユーザをSYSTEMにしてみます。
"schtasks.exe /create /XML "+Path.Combine(Environment.CurrentDirectory,"sample.xml")+" /TN SampleTask /RU "" /RP ""
これで実行ユーザがSYSTEM(たぶん、最上位)になる。
ただし、ツールを起動したときのアカウントの権限次第ですが、タスクが登録されているかどうかの確認でエラーになります。
ITaskServicetaskservice=null;Booleanexist=false;try{taskservice=newTaskScheduler.TaskScheduler();taskservice.Connect(null,null,null,null);ITaskFoldercontainingFolder=taskservice.GetFolder("\\");// 存在確認containingFolder.GetTask("SampleTask");exist=true;}catch(Exceptionex){// こっちに来るexist=false;}finally{if(taskservice!=null){System.Runtime.InteropServices.Marshal.ReleaseComObject(taskservice);}}returnexist;
タスクが登録されているかどうかを判定する必要がないなら、このままでもOKです。
XMLを利用して、ユーザにIDとパスを入力させつつ登録してみる
色々こねくり回してます。
前提として、エクスポートするタスクの設定は、最低でも以下のようにしています。
まず、バッチファイルをもう一つ作ります。
保存パスを動的に変更したいなら、バッチファイルを動的に作ります。
stringstr="echo off"+Environment.NewLine+"set USR_INPUT_STR="+Environment.NewLine+"set /P USR_INPUT_STR=\"ユーザIDを入力してください: \""+Environment.NewLine+"schtasks /create /XML "+Path.Combine(Environment.CurrentDirectory,"template.xml")+" /TN SampleTask /RU %USR_INPUT_STR% /RP \"\""+Environment.NewLine+"timeout 5 /nobreak";// 最後5秒待っているのは趣味(すぐ閉じないで、結果を見たかったから)stringoutputBatPath=Path.Combine(Environment.CurrentDirectory,@"Register.bat");// 保存先のパスStreamWritersw=newStreamWriter(outputBatPath,false,Encoding.GetEncoding("shift_jis"));// 内容を書き込むsw.Write(str);// 閉じるsw.Close();
次に、Processも少し設定をいじります。
stringoutputBatPath=Path.Combine(Environment.CurrentDirectory,@"Register.bat");// 保存先のパスProcessproc=newProcess();proc.StartInfo.Verb="RunAs";proc.StartInfo.FileName=Environment.GetEnvironmentVariable("ComSpec");;proc.StartInfo.UseShellExecute=true;proc.StartInfo.CreateNoWindow=true;proc.StartInfo.Arguments="/c "+outputBatPath;try{proc.Start();proc.WaitForExit();proc.Close();}catch(System.ComponentModel.Win32Exception){//「ユーザーアカウント制御」ダイアログでキャンセルされたなどによって//起動できなかった時returntrue;}returnfalse;
この方法をとると、ユーザIDとパスワードをユーザに入力させることができます。
とはいえ、逆に管理アカウントのパスワードを知らないとダメだったりするので、他のを使った方が良い場合もあると思います。
とりあえず、私がやりたかったことはこれで実現できたということで。