談談C# 以管理員方式啟動實現過程

談談C# 以管理員方式啟動實現過程

以管理員方式不只是簡單的啟動一個處理程序,在實際開發過程中遇到的情況可能會複雜得多。

最後更新 2024/3/10 下午10:05
nobody
預計閱讀 5 分鐘
分類
.NET
標籤
.NET C# 管理員

前言

本文由網友(@nobody)投稿,歡迎留言技術討論。

以系統管理員身分不只是簡單的啟動一個處理程序,在實際開發過程中遇到的情況可能會複雜得多。比如使用者打開應用程式就是以系統管理員身分啟動的,那這個時候就不需要再以系統管理員身分自啟;比如使用者是在無人值守的情況下使用,就需要考慮系統管理員提權的提示行為,只有在「不提示,直接提升」的情況下才以系統管理員身分啟動;比如系統管理員啟動方式會進行傳遞,比如應用程式 A 以系統管理員身分啟動,那應用程式 A 啟動應用程式 B 通常情況下,應用程式 B 預設獲取了應用程式 A 的系統管理員權限等。

本文主要介紹在無人值守情況下,以系統管理員身分啟動的實現過程。其他情況,只要進行靈活組合就應該能夠實現。

無人值守的主要特點是應用程式開機自啟、崩潰重啟,程式自動執行。程式中不能有阻斷程式啟動或是執行的操作,比如彈出視窗提示讓使用者確認或是讓使用者輸入帳號密碼。解決無人值守的情況,主要解決思路如下圖:

需要注意的是,如果使用者提權行為非「不提示,直接提升」,而一定要以系統管理員身分啟動,就一定要更改提權行為。可以透過執行「gpedit.msc」→ 電腦設定 →Windows 設定 → 安全性設定 → 本機原則 → 安全性選項 → 使用者帳戶控制: 在管理員核准模式下管理員的提升權限提示行為 來進行更改。

實作步驟

下面為流程中設計的步驟程式碼實作方法:

  1. 判斷目前應用程式是否是以系統管理員身分啟動,程式碼如下:
public static bool IsRunAsAdmin()
{
    WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
    WindowsPrincipal windows = new WindowsPrincipal(windowsIdentity);
    if (windows.IsInRole(WindowsBuiltInRole.Administrator))
    {
        return true;
    }
    return false;
}

注意:此程式碼是判斷使用者是否以系統管理員身分啟動,不是使用者是否是系統管理員。因為雖然使用者是系統管理員,但是啟動應用程式的時候,不一定是以系統管理員身分啟動的。網上搜尋判斷使用者是否為系統管理員,搜尋出來的大部分都是這個程式碼。

  1. 以系統管理員身分啟動,這是最基本的程式碼,程式碼如下:
public static void RunAsAdmin()
{
    ProcessStartInfo startInfo = new ProcessStartInfo();
    //設定以系統管理員身分啟動標記
    startInfo.Verb = "runas";
    //使用 shell 啟動處理程序
    startInfo.UseShellExecute = true;
    startInfo.FileName = Process.GetCurrentProcess().MainModule.FileName;
    Process.Start(startInfo);
}

注意:Verb 是以系統管理員啟動的識別碼,除了設定 Verb,還需要設定 UseShellExecute=true,使用 shell 啟動處理程序,不然啟動時系統管理員權限會進行傳遞,即如果原先的應用程式不是以系統管理員身分啟動的,那麼傳遞以後也不會以系統管理員身分啟動,以系統管理員身分啟動就會失敗。啟動物件還有很多屬性可以設定,讀者可以自行研究。

  1. 判斷目前是否開啟 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;
}
  1. 判斷目前使用者是否在系統管理員權限群組,程式碼如下:
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");
}
  1. 判斷 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 個方法。在實際開發過程中,可能還要考慮以系統管理員身分啟動失敗後無限重啟的問題。方法中也沒考慮例外情況,使用者需要根據自己的需求,做例外處理。

總結

本文主要是根據作者的開發經驗整理的無人值守情況下的實作方式,讀者在開發過程中要根據實際需求進行靈活組裝,或是添加上述沒有的功能或是邏輯。作者相關知識也可能存在盲區,或是邏輯考慮不周的,歡迎指正。

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2026/2/7

AOT使用經驗總結

從專案建立伊始,就應養成良好的習慣,即只要添加了新功能或使用了較新的語法,就及時進行 AOT 發布測試。

繼續閱讀