0

I've developed a small C# software that interfaces with a piece of hardware that will always be connected to the pc. Since this software requires administrative privileges and I want it to start as the PC starts, I'm evaluating what's the best way to deploy it.

The ideal would be to create an installer that takes care of disabling the UAC prompt for that specific software during its installation, so that everytime that specific software starts I won't receive any UAC prompt. Would this be possible? What are the possible alternatives?

xanz
  • 221
  • 3
  • 10
  • 2
    Have you considered running it as a Windows service? – HABO Jun 21 '16 at 00:05
  • What exactly do you need admin rights for? – Yegor Jun 21 '16 at 06:41
  • @ Yegor I need admin rights to read some hardware information, like temperatures. @HABO How do I exactly make it run as a windows service? I mean, typically services are sofware without a GUI, this is just a winform application, how can I run it as a service? Sorry maybe it's a stupid question, but I've never done such a thing – xanz Jun 21 '16 at 08:02
  • 1
    Your question didn't mention the GUI aspect. You could use a Windows service to interface with The Device and provide appropriate services to a Windows application that would not require elevated privileges. Some hunting for `windows service gui` will provide some insights. – HABO Jun 21 '16 at 12:49

2 Answers2

0

You can't create a setup that installs an application in such a way that an interactive app requires admin privilege but does not prompt for it. The install is separate from the app.

Assuming you build an MSI-based Windows Installer setup:

The install almost certainly requires admin privileges to install, and the tool you use to build the MSI will let you say that, and the install will prompt for elevation.

The way you build an app that runs elevated is to have a manifest that requests elevation when it starts.

If you literally want your code to run when the machine starts then it must be installed as a service. Practically all other methods (the Run registry key, the Startup folder in Program menu etc) are called when a user logs in (NOT when the system starts). If you need a UI to do something with the device then you'll need a Windows UI app that talks to the service (because services cannot interact with the desktop).

PhilDW
  • 20,260
  • 1
  • 18
  • 28
0

I find the answer for run a application with admin permission at startup.

Basically I just created a task with run level Highest and your trigger is on Logon.

I found the code in vb in this repository: https://bitbucket.org/trparky/start_program_at_startup_without_uac

Sub addTask(taskName As String, taskDescription As String, taskEXEPath As String, taskParameters As String)
        taskName = taskName.Trim
        taskDescription = taskDescription.Trim
        taskEXEPath = taskEXEPath.Trim
        taskParameters = taskParameters.Trim

        If Not IO.File.Exists(taskEXEPath) Then
            MsgBox("Executable path not found.", MsgBoxStyle.Critical, Me.Text)
            Exit Sub
        End If

        Dim taskService As TaskService = New TaskService()
        Dim newTask As TaskDefinition = taskService.NewTask

        newTask.RegistrationInfo.Description = taskDescription

        If chkEnabled.Checked Then newTask.Triggers.Add(New LogonTrigger)

        Dim exeFileInfo As New FileInfo(taskEXEPath)

        newTask.Actions.Add(New ExecAction(Chr(34) & taskEXEPath & Chr(34), taskParameters, exeFileInfo.DirectoryName))

        newTask.Principal.RunLevel = TaskRunLevel.Highest
        newTask.Settings.Compatibility = TaskCompatibility.V2_1
        newTask.Settings.AllowDemandStart = True
        newTask.Settings.DisallowStartIfOnBatteries = False
        newTask.Settings.RunOnlyIfIdle = False
        newTask.Settings.StopIfGoingOnBatteries = False
        newTask.Settings.AllowHardTerminate = False
        newTask.Settings.UseUnifiedSchedulingEngine = True
        newTask.Settings.ExecutionTimeLimit = Nothing
        newTask.Settings.Priority = ProcessPriorityClass.Normal
        newTask.Principal.LogonType = TaskLogonType.InteractiveToken

        taskService.RootFolder.SubFolders(strTaskFolderName).RegisterTaskDefinition(taskName, newTask)

        newTask.Dispose()
        taskService.Dispose()
        newTask = Nothing
        taskService = Nothing
    End Sub

So all I did was translated this code to c# and make tests

using Microsoft.Win32.TaskScheduler;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CreateTaskTest
{
    class Program
    {
        static void Main(string[] args)
        {
            addTask();
            //deleteTask();
        }

        static void addTask()
        {
            // Get the service on the local machine
            using (TaskService ts = new TaskService())
            {
                // Create a new task definition and assign properties
                TaskDefinition newTask = ts.NewTask();
                newTask.RegistrationInfo.Description = "Rondinelli Morais Create Task";

                newTask.Triggers.Add(new LogonTrigger());

                newTask.Actions.Add(new ExecAction("C:\\Windows\\regedit.exe"));

                newTask.Principal.RunLevel = TaskRunLevel.Highest;
                newTask.Principal.LogonType = TaskLogonType.InteractiveToken;

                newTask.Settings.Compatibility = TaskCompatibility.V2_1;
                newTask.Settings.AllowDemandStart = true;
                newTask.Settings.DisallowStartIfOnBatteries = false;
                newTask.Settings.RunOnlyIfIdle = false;
                newTask.Settings.StopIfGoingOnBatteries = false;
                newTask.Settings.AllowHardTerminate = false;
                newTask.Settings.UseUnifiedSchedulingEngine = true;
                newTask.Settings.Priority = System.Diagnostics.ProcessPriorityClass.Normal;

                // Register the task in the root folder
                ts.RootFolder.RegisterTaskDefinition(@"Test", newTask);

                newTask.Dispose();
                ts.Dispose();
            }
        }

        static void deleteTask()
        {
            using (TaskService ts = new TaskService())
            {

                var tasks = ts.FindAllTasks(new System.Text.RegularExpressions.Regex(@"Test"));

                foreach(var task in tasks){
                    ts.RootFolder.DeleteTask(task.Name);
                }
            }
        }
    }
}

I'm using regedit.exe on exemple because this program required admin permission for run.

Create the task, make logoff and login again and you will see the regedit open after logon.

OBS: To create or delete task you have run visual studio as administrator, or put this code in the install process of your program

Let me know if this worked for someone