Home > Software design >  How to set correct User for scheduled Tasks during Installation
How to set correct User for scheduled Tasks during Installation

Time:09-16

I am setting up a scheduled task during deployment using TaskScheduler. At the same time I am using a settings file to store user configuration. Now when the task scheduler runs it doesn't access the settings file because the users don't match.

During installation the setup project runs as system to get writing Permission in the application directory. I am running a custom action to write both, the settings and the scheduled Task yet the users don't match.

How can I ensure that the users match. do I have to create a separate application to make the configuration so that the settings can be in the application scope? This makes no sense to me because these settings will be different per deployment and set by the user and not me.

Edit: Location of the user settings file

string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "ApplicationName");
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
Directory.SetCurrentDirectory(path);

Script Snippet creating the scheduled task

using Microsoft.Win32.TaskScheduler;

...

 if (Interval == null) Interval = TimeSpan.FromHours(1);
 if (Duration == null) Duration = TimeSpan.FromDays(1);

 using(TaskService ts = new TaskService())
 {
     var td = ts.NewTask();

     // attempt to get the correct user, gets system user as if ommitted
     td.Principal.UserId = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
     td.Principal.LogonType = TaskLogonType.InteractiveToken;

     td.Settings.ExecutionTimeLimit = TimeSpan.FromMinutes(5);
     var trigger = new DailyTrigger((short)DaysInterval)
     {
         StartBoundary = DateTime.Today,
         Repetition = new RepetitionPattern(Interval, Duration)
     };
     td.Triggers.Add(trigger);

     string exePath = System.Reflection.Assembly.GetEntryAssembly().Location;

     td.Actions.Add("\""   exePath   "\"", "", Path.GetDirectoryName(exePath));
     ts.RootFolder.RegisterTaskDefinition("myTask", td);
 }

The custom action, so to speak is too big and split on different files accros the project to share here

Edit: Example for setting fields of the settings file

Properties.Settings _s = Properties.Settings.Default; 
_s.ClientIp = Tx_Ip.Text;
_s.ShopID = Tx_ShopId.Text;
_s.Save();

Edit: I have now logged the User, UserPath and AppPath both during Setup and when running through scheduled Task.

Setup

User: NT-AUTORITÄT\SYSTEM 
UserPath: C:\Users\user\AppData\Local\appname 
AppPath: C:\Program Files (x86)\businessname\appname

Scheduled Task

User: NT-AUTORITÄT\SYSTEM
UserPath: C:\Windows\system32\config\systemprofile\AppData\Local\appname
AppPath: C:\Program Files (x86)\businessname\appname

So actually it is the same User but the UserPath is different. As I am Writing the settings during Setup they get saved in the wrong location and later can't get accessed during the scheduled task.

CodePudding user response:

The solution to this problem is using a separate project to perform the custom actions and just use the Application scope for the Settings. This way The configuration can be created during Installation. The settings can only be changed with administrator privileges if the application is deployed to the setups default folder.

Proof of concept Code:

Main Application Project

using System;

namespace MyApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Properties.MyApplication.Default.Setting);
            Console.ReadLine();
        }
    }
}

Custom Action Project

using System;
using System.Configuration;
using System.IO;
using System.Reflection;

namespace WriteAppSettingsTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string exePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "MyApplication.exe");
            Console.WriteLine(exePath);
            Console.ReadLine();

            Configuration cfg = ConfigurationManager.OpenExeConfiguration(exePath);
            ClientSettingsSection section = (ClientSettingsSection)cfg.GetSectionGroup("applicationSettings").Sections["MyApplication.Properties.MyApplication"];

            section.Settings.Get("Setting").Value.ValueXml.InnerText = "Edited Setting";
            section.SectionInformation.ForceSave = true;
            cfg.Save();
        }
    }
}

The main application requires a settings file. For this example I called it "MyApplication.settings". It needs a setting called "Setting". In this example I set the value to "default value".

In the setup project execute the custom action project under the commit custom action. the Installer class property has to be set as false to work like this.

This solution also assumes that both project outputs are located in the same folder

  • Related