Elevando o privilégio do processo programaticamente?

147

Estou tentando instalar um serviço usando o InstallUtil.exe, mas invocado Process.Start. Aqui está o código:

ProcessStartInfo startInfo = new ProcessStartInfo (m_strInstallUtil, strExePath);
System.Diagnostics.Process.Start (startInfo);

onde m_strInstallUtilé o caminho completo e exe para "InstallUtil.exe" e strExePathé o caminho / nome completo para o meu serviço.

A execução da sintaxe da linha de comando em um prompt de comando elevado funciona; a execução do meu aplicativo (usando o código acima) não. Suponho que estou lidando com algum problema de elevação de processo, então como eu executaria meu processo em um estado elevado? Preciso olhar ShellExecutepara isso?

Isso é tudo no Windows Vista. Estou executando o processo no depurador VS2008 elevado ao privilégio de administrador.

Eu também tentei configurar, startInfo.Verb = "runas";mas não parecia resolver o problema.

Scott Marlowe
fonte
Depois de adicionar startInfo.UseShellExecute = true;, além disso startInfo.Verb = "runas";, funcionou bem para mim.
Matt

Respostas:

172

Você pode indicar que o novo processo deve ser iniciado com permissões elevadas, definindo a propriedade Verb do seu objeto startInfo como 'runas', da seguinte maneira:

startInfo.Verb = "runas";

Isso fará com que o Windows se comporte como se o processo tivesse sido iniciado no Explorer com o comando de menu "Executar como Administrador".

Isso significa que o prompt do UAC será exibido e precisará ser reconhecido pelo usuário: se isso for indesejável (por exemplo, porque isso aconteceria no meio de um processo demorado), você precisará executar todo o processo do host com permissões elevadas por Criar e incorporar um UAC (Manifesto de aplicativo) para exigir o nível de execução 'maximumAvailable': isso fará com que o prompt do UAC apareça assim que o aplicativo for iniciado e fará com que todos os processos filhos sejam executados com permissões elevadas sem aviso adicional .

Editar: vejo que você acabou de editar sua pergunta para declarar que "runas" não funcionaram para você. Isso é realmente estranho, como deveria (e faz por mim em vários aplicativos de produção). Exigir que o processo pai seja executado com direitos elevados incorporando o manifesto definitivamente deve funcionar.

mdb
fonte
9
"runas" também não funcionou para mim. Pode ser que ele só funcione com o UAC desativado?
Dirk Vollmar
18
@LukePuplett eu agradeceria a eles. É uma ótima maneira de reduzir a instalação do kit raiz, sem realmente segregar completamente as funções do usuário.
Colton
6
@ Sparksis, mas também há outro ponto de vista. As pessoas que sabem como defender seu sistema operacional sabem como fazê-lo sem o UAC. E usuários fictícios, que não sabem o que é defesa, estão clicando em 'SIM' toda vez que vêem a janela do UAC. Também nada pode impedir maus-hackers-Virus-escritores de usar exploits para ignorá-lo;) Então, eu concordo com LukePuplett =)
Jet
24
Parece que você deve definir startInfo.ShellExecute=truetambém para que isso funcione ... também não consegui fazer esse método funcionar com arquivos executáveis ​​que estão em um compartilhamento de rede (é necessário copiá-los para o diretório temporário local antes de executar). ..
TCC
7
@ Jet Desculpe, mas essa é a mentalidade errada. Toda vez que uma caixa de diálogo do UAC é exibida durante a instalação, há uma falha no sistema. O valor é quando você vê uma caixa do UAC sem executar algo que exija elevação. Não importa o quão profissional você - qualquer um de nós - pense que estamos em nossos PCs, você não pode bloquear magicamente zero dias / downloads drive-by (por exemplo, um recente no site oficial do Prêmio Nobel). Se você navegasse até esse site e recebesse um prompt do UAC, saberia que havia algo errado. Com o UAC desativado, você nunca saberia que acabou de ingressar em uma botnet. O custo do aviso prévio é ter que clicar em Sim ocasionalmente
Básico
46

Este código reúne tudo isso e reinicia o aplicativo wpf atual com admin privs:

if (IsAdministrator() == false)
{
    // Restart program and run as admin
    var exeName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
    ProcessStartInfo startInfo = new ProcessStartInfo(exeName);
    startInfo.Verb = "runas";
    System.Diagnostics.Process.Start(startInfo);
    Application.Current.Shutdown();
    return;
}

private static bool IsAdministrator()
{
    WindowsIdentity identity = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal(identity);
    return principal.IsInRole(WindowsBuiltInRole.Administrator);
}


// To run as admin, alter exe manifest file after building.
// Or create shortcut with "as admin" checked.
// Or ShellExecute(C# Process.Start) can elevate - use verb "runas".
// Or an elevate vbs script can launch programs as admin.
// (does not work: "runas /user:admin" from cmd-line prompts for admin pass)

Atualização: a maneira de manifesto do aplicativo é preferida:

Clique com o botão direito do mouse no projeto no visual studio, adicione um novo arquivo de manifesto do aplicativo, altere o arquivo para que você exija o administrador definido como mostrado acima.

Um problema com a maneira original: se você colocar o código de reinicialização no app.xaml.cs OnStartup, ele ainda poderá iniciar a janela principal brevemente, mesmo que o desligamento tenha sido chamado. Minha janela principal explodiu se init app.xaml.cs não foi executado e, em determinadas condições de corrida, ele faria isso.

Curtis Yallop
fonte
Veja abaixo as melhorias.
precisa saber é o seguinte
requireAdministrator não funcionou no meu caso. Então eu tive que fazer do seu jeito. Isso resolveu meu problema! obrigado. Mas eu tive que definir o aplicativo de instância única como false.
Chris19 /
Isso funcionou para mim. Também passei o original string[] argspara o processo reaparecido.
DotNetPadawan
7
[PrincipalPermission(SecurityAction.Demand, Role = @"BUILTIN\Administrators")]

Isso será feito sem o UAC - não é necessário iniciar um novo processo. Se o usuário em execução for membro do grupo Admin, como no meu caso.

hB0
fonte
3
Usando este código, recebo um erro de permissão: "Falha na solicitação de permissão da entidade de segurança". :(
Leonardo
Talvez "Se o usuário em execução for membro do Admin" *
hB0
1
interessante - isso pode ir em qualquer método, não apenas um método de ação (Eu até tentei no método definido em uma página ASPX)
Simon_Weaver
1

Você deve usar a representação para elevar o estado.

WindowsIdentity identity = new WindowsIdentity(accessToken);
WindowsImpersonationContext context = identity.Impersonate();

Não se esqueça de desfazer o contexto representado quando terminar.

Vijesh VP
fonte
28
Você não disse como obter o accessToken. O LogonUser fornecerá o contexto de segurança restrito de um usuário quando o UAC estiver ativado.
cwa 30/03
Se você estiver usando o VSTS, poderá obter um token de acesso pessoal nas configurações do portal da web. (Procure o ícone de configurações ao lado da imagem do usuário.) MSDocs
Su Llewellyn