¿Cómo se elevan los privilegios solo cuando es necesario?

¡Esta pregunta se aplica a Windows Vista!

Tengo una aplicación que normalmente funciona sin privilegios administrativos. Hay una actividad que necesita privilegios administrativos pero no quiero iniciar la aplicación con mayores privilegios cuando sé que la mayoría de las veces el usuario ni siquiera está usando esa característica.

Estoy pensando en cierto método por el cual puedo elevar los privilegios de la aplicación en algún evento (como presionar un botón). Ejemplo:

Si el usuario hace clic en este botón, se le solicitará el diálogo o el consentimiento de UAC. ¿Cómo puedo hacer esto?

No creo que sea posible elevar el proceso actualmente en ejecución. Está integrado en Windows Vista que los privilegios de administrador se otorgan a un proceso al inicio, según tengo entendido. Si observa varios progtwigs que utilizan UAC, debería ver que en realidad lanzan un proceso por separado cada vez que se necesita realizar una acción administrativa (el Administrador de tareas es uno, Paint.NET es otro, el último es una aplicación .NET de hecho )

La solución típica a este problema es especificar argumentos de línea de comando cuando se inicia un proceso elevado (la sugerencia de abatishchev es una forma de hacerlo), de modo que el proceso lanzado solo sabe mostrar un cuadro de diálogo determinado y luego salir después de que se haya realizado esta acción terminado. Por lo tanto, apenas debe ser notorio para el usuario que un nuevo proceso ha sido lanzado y luego salido, y más bien parecería como si se hubiera abierto un nuevo cuadro de diálogo dentro de la misma aplicación (especialmente si usted tiene hackers para hacer la ventana principal del proceso elevado un hijo del proceso principal). Si no necesita UI para el acceso elevado, aún mejor.

Para una discusión completa de UAC en Vista, te recomiendo que veas este artículo completo sobre el tema (los ejemplos de código están en C ++, pero sospecho que necesitarás usar WinAPI y P / Invoke para hacer la mayoría de las cosas en C # de todas formas). Afortunadamente, al menos ahora verá el enfoque correcto, aunque diseñar un progtwig compatible con UAC no es nada trivial …

Como se dijo allí :

Process.StartInfo.UseShellExecute = true; Process.StartInfo.Verb = "runas"; 

ejecutará el proceso como administrador para hacer lo que necesite con el registro, pero regrese a su aplicación con los privilegios normales.

El siguiente artículo KB 981778 de MSDN describe cómo ‘autoelevar’ una aplicación:

http://support.microsoft.com/kb/981778

Contiene muestras descargables en Visual C ++, Visual C #, Visual Basic.NET.

Este enfoque evita la necesidad de iniciar un proceso por separado, pero de hecho es la aplicación original la que se reinicia y se ejecuta como un usuario elevado. Sin embargo, esto puede ser muy útil en algunos contextos en los que no es práctico duplicar el código en un archivo ejecutable por separado.

Para eliminar la elevación, debe salir de la aplicación.

Necesita un moniker UAC y el código para ejecutar elevado como un objeto COM.

Ver esta pregunta

Documentación en MSDN.

Sé que esta es una publicación anterior, pero esto es en respuesta a cualquier otra persona que se encuentre con la sugerencia de MarcP. La publicación msdn a la que hace referencia reinicia las aplicaciones en todos los ejemplos de código. Los ejemplos de código usan el verbo runas propuesto ya en otras sugerencias.

Descargué el código para estar seguro, pero esto es del artículo original de msdn:

4. Haga clic en Sí para aprobar la elevación. Luego, la aplicación original se reinicia y se ejecuta como un administrador elevado.
5. Cierre la aplicación.

Tal vez alguien sea útil este simple ejemplo:

 using System; using System.Linq; using System.Reflection; using System.Diagnostics; using System.Security.Principal; using System.Windows.Forms; namespace WindowsFormsApp1 { internal static class Program { private class Form1 : Form { internal Form1() { var button = new Button{ Dock = DockStyle.Fill }; button.Click += (sender, args) => RunAsAdmin(); Controls.Add(button); ElevatedAction(); } } [STAThread] internal static void Main(string[] arguments) { if (arguments?.Contains("/run_elevated_action") == true) { ElevatedAction(); return; } Application.Run(new Form1()); } private static void RunAsAdmin() { var path = Assembly.GetExecutingAssembly().Location; using (var process = Process.Start(new ProcessStartInfo(path, "/run_elevated_action") { Verb = "runas" })) { process?.WaitForExit(); } } private static void ElevatedAction() { MessageBox.Show($@"IsElevated: {IsElevated()}"); } private static bool IsElevated() { using (var identity = WindowsIdentity.GetCurrent()) { var principal = new WindowsPrincipal(identity); return principal.IsInRole(WindowsBuiltInRole.Administrator); } } } }