{"id":1292,"date":"2014-06-03T10:52:01","date_gmt":"2014-06-03T08:52:01","guid":{"rendered":"http:\/\/hen.co.za\/blog\/?p=1292"},"modified":"2014-06-06T09:27:51","modified_gmt":"2014-06-06T07:27:51","slug":"how-to-build-an-c-application-that-can-relaunch-itself-in-admin-mode-without-uac-prompt","status":"publish","type":"post","link":"https:\/\/hen.co.za\/blog\/2014\/06\/how-to-build-an-c-application-that-can-relaunch-itself-in-admin-mode-without-uac-prompt\/","title":{"rendered":"How to build an C# Application that can relaunch itself in Admin mode &#8211; without UAC prompt"},"content":{"rendered":"<p>Lets start by emphasizing that this is NOT a way to create a hack. In order for this to work you (the user) needs to be an Administrator and access to be able to launch applications in &#8216;Admin mode&#8217; anyway. The first time when the application needs to set up this functionality it needs to run in Admin mode as well (for which you&#8217;ll have to be prompted by UAC). Only after this and for the future the application in &#8216;Non-admin&#8217; mode can then relaunch itself in &#8216;Admin mode&#8217; without showing the UAC prompt.<\/p>\n<p>The &#8216;trick&#8217; (not hack) is to use the built-in Windows Task scheduler that can launch applications with the &#8216;highest&#8217; priority setting. Take note that this also stops you from launching the app with any command line parameters &#8211; but there are other ways an application can &#8216;communicate&#8217; with itself\/another instance of itself e.g. by saving its own settings before launching the second instance and the second instance reading those settings again.<\/p>\n<p>So how can a (C#) application integrate this easily? My first idea was to call the Task scheduler (Schtasks.exe) manually with the required parameters to create a task of launching the app again later in admin mode. The problem part is finding out if the task already exists or not. Then I came across an article that showed how the COM+ library for the Task Scheduler can be used from .Net which make it a whole lot easier to interact.<\/p>\n<h2>Task Scheduler COM+ library<\/h2>\n<p>In your application&#8217;s references add a reference to &#8216;TaskScheduler 1.1 Type Library&#8217; (Interop.TaskScheduler.dll) usually located on &#8216;c:\\Windows\\SysWow64\\taskschd.dll (on 64-bit at least). Then you can add the following type of code in your project:<\/p>\n<h2>Code<\/h2>\n<p>To test if task exists or is running already:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\r\nprivate string myLaunchTaskName = &quot;RunMeAsAdmin&quot;;\r\n\r\nprivate bool LaunchTaskExist()\r\n{\r\n  try\r\n  {\r\n    TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();\r\n    ts.Connect(null, null, null, null);\r\n    if (ts.Connected)\r\n    {\r\n      TaskScheduler.ITaskFolder root = ts.GetFolder(&quot;\\\\&quot;);\r\n      TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);\r\n      if (task != null)\r\n        return true;\r\n    }\r\n  }\r\n  catch { }\r\n  return false;\r\n}\r\nprivate bool TaskAlreadyRunning()\r\n{\r\n  try\r\n  {\r\n    TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();\r\n    ts.Connect(null, null, null, null);\r\n    if (ts.Connected)\r\n    {\r\n      foreach (TaskScheduler.IRunningTask td in ts.GetRunningTasks(0))\r\n      {\r\n        if (td.Name == myLaunchTaskName)\r\n          return true;\r\n      }\r\n    }\r\n  }\r\n  catch { }\r\n  return false;\r\n}\r\n\r\n<\/pre>\n<p>To create the task the first time:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nfunction CreateSelfLaunchTask()\r\n{\r\n  try\r\n  {\r\n    if (AdminModeTools.IsInAdminMode()) \/\/Different library to test if app is in Admin mode\r\n    {\r\n      TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();\r\n      ts.Connect(null, null, null, null);\r\n      if (ts.Connected)\r\n      {\r\n        TaskScheduler.ITaskDefinition task = ts.NewTask(0);\r\n        task.RegistrationInfo.Author = &quot;Me&quot;;\r\n        task.RegistrationInfo.Description = myLaunchTaskName;\r\n        task.Principal.RunLevel = TaskScheduler._TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;\r\n        task.Settings.MultipleInstances = TaskScheduler._TASK_INSTANCES_POLICY.TASK_INSTANCES_IGNORE_NEW;\r\n        TaskScheduler.ITimeTrigger trigger = (TaskScheduler.ITimeTrigger)task.Triggers.Create(TaskScheduler._TASK_TRIGGER_TYPE2.TASK_TRIGGER_TIME);\r\n        trigger.Id = &quot;NoTime&quot;;\r\n        trigger.StartBoundary = &quot;2000-01-01T12:00:00&quot;;\r\n        trigger.StartBoundary = &quot;2000-01-01T12:00:00&quot;;\r\n        TaskScheduler.IExecAction action = (TaskScheduler.IExecAction)task.Actions.Create(TaskScheduler._TASK_ACTION_TYPE.TASK_ACTION_EXEC);\r\n        action.Id = &quot;Run exe&quot;;\r\n        action.Path = System.Reflection.Assembly.GetExecutingAssembly().Location;\r\n        action.WorkingDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);\r\n\r\n        TaskScheduler.ITaskFolder root = ts.GetFolder(&quot;\\\\&quot;);\r\n        TaskScheduler.IRegisteredTask regTask = root.RegisterTaskDefinition(\r\n          myLaunchTaskName,\r\n          task,\r\n          (int)TaskScheduler._TASK_CREATION.TASK_CREATE_OR_UPDATE,\r\n          null,\r\n          null,\r\n          TaskScheduler._TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN);\r\n      }\r\n    }\r\n    else\r\n    {\r\n      MessageBox.Show(&quot;To create the task you must start this program in 'Admin' mode.&quot;, &quot;Error&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n    }\r\n  }\r\n  catch(Exception ex)\r\n  {\r\n    MessageBox.Show(ex.ToString(), &quot;Error&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n  }\r\n}\r\n<\/pre>\n<p>Then to call the task:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nfunction void RunAppAsAdmin()\r\n{\r\n  try\r\n  {\r\n    if (LaunchTaskExist())\r\n    {\r\n      if (!TaskAlreadyRunning())\r\n      {\r\n        TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();\r\n        ts.Connect(null, null, null, null);\r\n        if (ts.Connected)\r\n        {\r\n          TaskScheduler.ITaskFolder root = ts.GetFolder(&quot;\\\\&quot;);\r\n          TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);\r\n          TaskScheduler.IRunningTask runTask = task.Run(null);\r\n        }\r\n      }\r\n      else\r\n      {\r\n        MessageBox.Show(&quot;The task is already running!&quot;, &quot;Error&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n      }\r\n    }\r\n    else\r\n    {\r\n      MessageBox.Show(&quot;The task does not exist yet!&quot;, &quot;Error&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n    }\r\n  }\r\n  catch (Exception ex)\r\n  {\r\n    MessageBox.Show(ex.ToString(), &quot;Error&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n  }\r\n}\r\n<\/pre>\n<p>If for some reason you need to delete the task you can use this:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate void DeleteRunAsAdminTask()\r\n{\r\n    try\r\n    {\r\n        if (AdminModeTools.IsInAdminMode())\r\n        {\r\n            if (LaunchTaskExist())\r\n            {\r\n                TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();\r\n                ts.Connect(null, null, null, null);\r\n                if (ts.Connected)\r\n                {\r\n                    TaskScheduler.ITaskFolder root = ts.GetFolder(&quot;\\\\&quot;);\r\n                    TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);\r\n                    if (task != null)\r\n                    {\r\n                        root.DeleteTask(myLaunchTaskName, 0);\r\n                    }\r\n                }\r\n            }\r\n            else\r\n            {\r\n                MessageBox.Show(&quot;The task does not exist!&quot;, &quot;Error&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n            }\r\n        }\r\n        else\r\n        {\r\n            MessageBox.Show(&quot;To delete the task you must start this program in 'Admin' mode.&quot;, &quot;Error&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n        }\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        MessageBox.Show(ex.ToString(), &quot;Error&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n    }\r\n}\r\n<\/pre>\n<p>With all these &#8216;bits&#8217; you can build an application that can launch itself in &#8216;Admin&#8217; mode. Have fun kidz but not too much!<\/p>\n<p>I&#8217;ve tested this on Windows Vista, 7, 2008\/R2 and 8. I don&#8217;t have access to any XP machines anymore but I doubt it will work on XP (or 2003)&#8230; duhh.. Just remembered XP and 2003 does not have &#8216;Admin&#8217; mode anyway so this does not apply&#8230; silly me.<\/p>\n<p>Update: I now have one of my utilities actually using this code: <a title=\"Service Monitor\" href=\"https:\/\/srvstool.codeplex.com\/\" target=\"_blank\">Service Monitor<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lets start by emphasizing that this is NOT a way to create a hack. In order for this to work you (the user) needs to be an Administrator and access to be able to launch applications in &#8216;Admin mode&#8217; anyway. &hellip;<\/p>\n<p class=\"read-more\"><a href=\"https:\/\/hen.co.za\/blog\/2014\/06\/how-to-build-an-c-application-that-can-relaunch-itself-in-admin-mode-without-uac-prompt\/\">Read more &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,16],"tags":[7,281,8,303,282,283],"class_list":["post-1292","post","type-post","status-publish","format-standard","hentry","category-development","category-reference","tag-net","tag-admin","tag-c","tag-development","tag-mode","tag-task-scheduler"],"_links":{"self":[{"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/posts\/1292","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/comments?post=1292"}],"version-history":[{"count":11,"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/posts\/1292\/revisions"}],"predecessor-version":[{"id":1303,"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/posts\/1292\/revisions\/1303"}],"wp:attachment":[{"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/media?parent=1292"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/categories?post=1292"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hen.co.za\/blog\/wp-json\/wp\/v2\/tags?post=1292"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}