¿Cómo elevar los privilegios solo cuando sea necesario?

85

¡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 en sí con privilegios más altos cuando sé que la mayoría de las veces el usuario ni siquiera usará esa función.

Estoy pensando en cierto método mediante 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 solicita un diálogo de UAC o consentimiento. ¿Cómo puedo hacer esto?

Hemant
fuente

Respuestas:

58

No creo que sea posible elevar el proceso que se está ejecutando actualmente. Según tengo entendido, está integrado en Windows Vista que se otorgan privilegios de administrador a un proceso al inicio. Si observa varios programas que utilizan UAC, debería ver que en realidad inician un proceso separado cada vez que se debe realizar una acción administrativa (el Administrador de tareas es uno, Paint.NET es otro, siendo este último una aplicación .NET de hecho ).

La solución típica a este problema es especificar los argumentos de la línea de comandos al iniciar un proceso elevado (la sugerencia de abatishchev es una forma de hacerlo), de modo que el proceso iniciado solo sepa mostrar un determinado cuadro de diálogo y luego salir después de que se haya realizado esta acción. terminado. Por lo tanto, el usuario apenas debería notar que se ha iniciado y luego cerrado un nuevo proceso, y más bien debería aparecer como si se hubiera abierto un nuevo cuadro de diálogo dentro de la misma aplicación (especialmente si ha realizado algún pirateo para crear la ventana principal de la aplicación). proceso elevado hijo del proceso padre). Si no necesita la interfaz de usuario para el acceso elevado, aún mejor.

Para una discusión completa de UAC en Vista, le recomiendo que vea este artículo detallado sobre el tema (los ejemplos de código están en C ++, pero sospecho que necesitará usar WinAPI y P / Invoke para hacer la mayoría de las cosas en C # de todas formas). Con suerte, ahora al menos ve el enfoque correcto a seguir, aunque diseñar un programa compatible con UAC está lejos de ser trivial ...

Noldorin
fuente
4
¿Hay algún cambio con Windows 7 o se mantiene la respuesta "no, usar un nuevo proceso"? Gracias ...
Radim Vansa
2
No hay cambios con Windows 7, me temo, lo siento. (Hasta donde yo sé, soy un usuario / desarrollador habitual en Win7.)
Noldorin
2
Así es exactamente como lo hace el administrador de tareas. Cuando hace clic en el botón para mostrar tareas para todos los usuarios, existe el administrador de tareas actual y luego invoca otro administrador de tareas con derechos de administrador.
Natalie Adams
3
@NathanAdams Técnicamente, primero abre el nuevo administrador de tareas. De lo contrario, ¿qué está haciendo la apertura? :-)
wizzwizz4
16

Como se decía allí :

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

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

abatishchev
fuente
Eso implica abarcar un nuevo proceso. ¿Correcto? Buscaba elevar los privilegios del propio proceso actual.
Hemant
Intente usar Process.GetCurrentProcess ()
abatishchev
27
No puede elevar un proceso que se está ejecutando actualmente.
Jacob Proffitt
1
Esto no es verdad. Puede cambiar el propietario del proceso y establecer los valores de DACL y ACL para el usuario dándoles poderes administrativos ...
Nightforce2
4
@ nightforce2: seguramente esto solo funcionaría, si ya tienes derechos administrativos (es decir, ya estás elevado). De lo contrario, AdjustTokenPrivileges, etc., simplemente fallará, ¿no?
Ben Schwehn
13

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

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

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

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

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

FruitBreak
fuente
1
Práctico para un botón, pero cuando desea lo mismo para un elemento del menú, se encontrará con un lío realmente complicado.
Nyerguds
3
@Todd Puede encontrar el código aquí: https://code.msdn.microsoft.com/windowsapps/CSUACSelfElevation-644673d3
Matthiee
El enlace de la respuesta está muerto y el enlace del comentario apunta a una lista larga de 2608 elementos.
DonBoitnott
Puede encontrarlo aquí
mirh
2

Quizás alguien sea útil con 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);
            }
        }

    }
}
Konstantin S.
fuente
1

Sé que esta es una publicación antigua, pero es en respuesta a cualquier otra persona que se encuentre con la sugerencia de MarcP. La publicación de msdn a la que hizo referencia efectivamente reinicia las aplicaciones en todos los ejemplos de código. Los ejemplos de código utilizan el runasverbo propuesto ya en otras sugerencias.

Descargué el código para asegurarme, 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 administrador elevado.
5. Cierre la aplicación.

SpaceGhost440
fuente
1
¿Puede agregar el enlace de MSDN en cuestión? No puedo encontrar un usuario llamado MarcP.
Alf