前言
本文由網友(@nobody)投稿,歡迎留言技術討論。
以管理員方式不只是簡單的啟動一個進程,在實際開發過程中遇到的情況可能會複雜的多。比如用戶打開應用程式就是以管理員方式啟動的,那這個時候就不需要再以管理員方式自啟;比如用戶是在無人值守的情況下使用,就需要考慮管理員提權的提示行為,只有在”不提示,直接提升“的情況下才以管理員方式啟動;比如管理員啟動方式會進行傳遞,比如應用 a 以管理員方式啟動,那應用 a 啟動應用 b 通常情況下,應用 b 默認獲取了應用 a 的管理員權限等。
本文主要居間在無人值守情況下,以管理員方式啟動的實現過程。其他情況,只要進行靈活組合就應該能夠實現。
無人值守的主要特點是應用程式開機自啟、崩潰重啟,程式自動執行。程式中不能有阻斷程式啟動或是執行的操作,比如彈窗提示讓用戶確認或是讓用戶輸入帳號密碼。解決無人值守的情況,主要解決思路如下圖:

需要注意的是,如果用戶提權行為非”不提示,直接提升“,而一定要以管理員方式啟動,就一定要更改提權行為。可以通過運行”gpedit.msc“→ 計算機配置 →windows 設置 → 安全設置 → 本地策略 → 安全選項 → 用戶帳戶控制: 在管理審批模式下管理員的提升提示行為 來進行更改。
實現步驟
下面為流程中設計的步驟代碼實現方法:
- 判斷當前應用程式是否是以管理員方式啟動,代碼如下:
public static bool IsRunAsAdmin()
{
WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal windows = new WindowsPrincipal(windowsIdentity);
if (windows.IsInRole(WindowsBuiltInRole.Administrator))
{
return true;
}
return false;
}
note:此代碼是判斷用戶是否以管理員方式啟動,不是用戶是否是管理員。因為雖然用戶是管理員,但是啟動應用程式的時候,不一定是以管理員方式啟動的。網上搜索判斷用戶是否管理員,搜索出來的大部分都是這個代碼。
- 以管理員方式啟動, 這個是最基本的代碼,代碼如下:
public static void RunAsAdmin()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
//设置以管理员方式启动标记
startInfo.Verb = "runas";
//使用shell启动进程
startInfo.UseShellExecute = true;
startInfo.FileName = Process.GetCurrentProcess().MainModule.FileName;
Process.Start(startInfo);
}
note:verb 是以管理員啟動的標識,除了設置 verb,還需要設置 useshellexecute=true,使用 shell 啟動進程,不然啟動時管理員權限會進行傳遞,即如果原先的應用程式不是以管理員方式啟動的,那麼傳遞以後也不會以管理員方式啟動,以管理員方式啟動就會失敗。啟動對象還有很多屬性可以設置,讀者可以自行研究。
- 判斷當前是否開啟 uac(用戶帳號控制),關閉 uac 表示當前用戶有管理員權限,代碼如下:
public static bool IsUACEnabled()
{
//注册表项
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", false);
if (key != null)
{
//获取子键EnableLUA的值,1表示开启了UAC
object value = key.GetValue("EnableLUA");
if (value != null && value.ToString() == "1")
{
return true;
}
}
return false;
}
- 判斷當前用戶是否在管理員權限組,代碼如下:
public static bool IsInAdminGroup()
{
WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
var claims = windowsPrincipal.Claims;
//声明集合中有用户组的信息,S-1-5-32-544代表管理员组
return claims.Any(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid" && c.Value == "S-1-5-32-544");
}
- 判斷 uac 管理員提升權限提示行為,這裡需要判斷行為是否為“不提示,直接提升”,代碼如下:
public static bool IsUpPermissionWithOutTip()
{
//注册表项
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", false);
if (key != null)
{
//获取子键ConsentPromptBehaviorAdmin的值,0表示开启了不提示直接提升,就不会造成阻断
object value = key.GetValue("ConsentPromptBehaviorAdmin");
if (value != null && value.ToString() == "0")
{
return true;
}
}
return false;
}
上述是根據主要流程提取出的 5 個方法。在實際開發過程中。可能還要考慮以管理員方式啟動失敗後無限重啟的問題。方法中也沒考慮異常情況,用戶需要根據自己的需求,做異常處理。
總結
本文主要是根據作者的開發經驗整理的無人值守情況下的實現方式,讀者在開發過程中要根據實際需求進行靈活組裝,或是添加上述沒有的功能或是邏輯。作者相關知識也可能存在盲區,或是邏輯考慮不周的,歡迎指正。