首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 透過 WMI 遠端重新開機電腦完整指南

     編輯:關於C語言

前言

在企業環境中,系統管理員常需遠端管理電腦,包含重新開機、關機、查詢狀態等。本文示範使用 C# 透過 WMI (Windows Management Instrumentation) 呼叫 `Win32_OperatingSystem.Reboot()` 方法實現遠端重開機,涵蓋連線認證、錯誤處理、權限需求等實務細節。

核心原理

  • WMI 遠端連線:透過 `ManagementScope` 連接遠端電腦的 `root\cimv2` 命名空間
  • 認證機制:`ConnectionOptions` 指定使用者名稱/密碼(需目標機器管理員權限)
  • 目標類別:`Win32_OperatingSystem` 代表作業系統實例
  • 方法呼叫:`InvokeMethod("Reboot", null)` 觸發重開機

完整實作程式碼

using System;
using System.Management;
using System.Net.NetworkInformation;

public class RemoteRebootManager
{
    /// 
    /// 遠端重新開機
    /// 
    /// 目標電腦 IP 或主機名稱
    /// 管理員帳號 (格式: DOMAIN\user 或 user)
    /// 密碼
    /// 是否成功送出重開機指令
    public bool RebootRemoteMachine(string targetIp, string username, string password)
    {
        // 1. 先測試網路連通性
        if (!TestConnection(targetIp))
        {
            Console.WriteLine($"無法連線至 {targetIp}");
            return false;
        }

        ConnectionOptions options = new ConnectionOptions
        {
            Username = username,
            Password = password,
            Impersonation = ImpersonationLevel.Impersonate,
            Authentication = AuthenticationLevel.PacketPrivacy,
            EnablePrivileges = true, // 重要:啟用 SeShutdownPrivilege
            Timeout = TimeSpan.FromSeconds(30)
        };

        // 2. 建立管理範圍
        string scopePath = $@"\\{targetIp}\root\cimv2";
        ManagementScope scope = new ManagementScope(scopePath, options);
        
        try
        {
            scope.Connect(); // 測試連線
            Console.WriteLine($"WMI 連線成功: {targetIp}");
        }
        catch (UnauthorizedAccessException)
        {
            Console.WriteLine("認證失敗:帳號密碼錯誤或權限不足");
            return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"WMI 連線錯誤: {ex.Message}");
            return false;
        }

        // 3. 查詢作業系統實例
        ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
        using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
        {
            try
            {
                foreach (ManagementObject os in searcher.Get())
                {
                    // 4. 呼叫 Reboot 方法
                    // 參數陣列:null 表示使用預設值
                    ManagementBaseObject outParams = os.InvokeMethod("Reboot", null, null);
                    
                    // 檢查回傳值 (0 = 成功)
                    uint returnValue = (uint)(outParams.Properties["ReturnValue"]?.Value ?? 1);
                    
                    if (returnValue == 0)
                    {
                        Console.WriteLine($"重開機指令已送出,目標: {targetIp}");
                        return true;
                    }
                    else
                    {
                        Console.WriteLine($"重開機失敗,錯誤碼: {returnValue}");
                        return false;
                    }
                }
            }
            catch (ManagementException ex)
            {
                Console.WriteLine($"WMI 方法呼叫失敗: {ex.Message}");
                return false;
            }
        }
        
        Console.WriteLine("找不到作業系統實例");
        return false;
    }

    private bool TestConnection(string host)
    {
        try
        {
            using (Ping ping = new Ping())
            {
                PingReply reply = ping.Send(host, 3000);
                return reply.Status == IPStatus.Success;
            }
        }
        catch
        {
            return false;
        }
    }
}

// 使用範例
class Program
{
    static void Main()
    {
        var manager = new RemoteRebootManager();
        
        // 目標資訊(實務上應從安全設定檔讀取,不可硬編碼)
        string targetIp = "192.168.1.100";
        string username = "Administrator"; // 或 "DOMAIN\Admin"
        string password = "YourSecurePassword";
        
        Console.WriteLine($"準備遠端重開機: {targetIp}");
        bool success = manager.RebootRemoteMachine(targetIp, username, password);
        
        if (success)
            Console.WriteLine("操作成功完成");
        else
            Console.WriteLine("操作失敗,請檢查日誌");
            
        Console.ReadKey();
    }
}

必要條件與前置設定

目標電腦設定 (被控端)

  1. 啟用 WMI 遠端存取:
    # 以管理員身分執行 PowerShell
    Enable-PSRemoting -Force
    Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
  2. 防火牆開放 WMI 連接埠:
    netsh advfirewall firewall set rule group="Windows Management Instrumentation (WMI)" new enable=yes
    # 或手動開放 TCP 135, 445, 動態埠範圍 (通常 49152-65535)
  3. DCOM 權限設定:
    • 執行 `dcomcnfg` → 元件服務 → 電腦 → 我的電腦 → 內容 → COM 安全性
    • 「啟動及啟動權限」與「存取權限」加入目標使用者/群組,給予「遠端啟動」、「遠端存取」權限
  4. UAC 遠端權杖(非網域環境):
    # 登錄機碼允許本地帳號遠端管理
    reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f

呼叫端權限需求

  • 目標帳號必須是目標電腦的 Administrators 群組成員
  • 需具備 SeShutdownPrivilege (關機/重開機權限),`EnablePrivileges = true` 會自動嘗試啟用
  • 網域環境建議使用服務帳號,非網域需同步帳號密碼或建立相同帳號

進階功能擴充

1. 支援關機、登出、鎖定等操作

public enum RemoteAction
{
    Reboot,      // 重新開機
    Shutdown,    // 關機
    LogOff,      // 登出
    PowerOff     // 切斷電源
}

public bool ExecuteRemoteAction(string targetIp, string user, string pass, RemoteAction action)
{
    // ... 連線程式碼相同 ...
    
    string methodName = action switch
    {
        RemoteAction.Reboot => "Reboot",
        RemoteAction.Shutdown => "Shutdown",      // Win32_OperatingSystem.Shutdown()
        RemoteAction.LogOff => "Win32Shutdown",   // 需不同參數
        RemoteAction.PowerOff => "Win32Shutdown", // 需參數 8 (PowerOff) + 4 (Force)
        _ => throw new ArgumentException()
    };
    
    // Win32Shutdown 參數說明:
    // 0=LogOff, 4=Force, 1=Shutdown, 2=Reboot, 8=PowerOff
    // 組合範例:Force Shutdown = 1+4=5, Force Reboot = 2+4=6
    object[] methodParams = action switch
    {
        RemoteAction.LogOff => new object[] { 0 },      // LogOff
        RemoteAction.Shutdown => new object[] { 5 },    // Force Shutdown
        RemoteAction.PowerOff => new object[] { 12 },   // Force PowerOff (8+4)
        _ => null
    };
    
    foreach (ManagementObject os in searcher.Get())
    {
        os.InvokeMethod(methodName, methodParams, null);
    }
}

2. 非同步批次處理多台電腦


public async Task> RebootMultipleAsync(
    IEnumerable targets, string user, string pass)
{
    var results = new Dictionary();
    var semaphore = new SemaphoreSlim(10); // 限制並發 10
    
    var tasks = targets.Select(async ip =>
    {
        await semaphore.WaitAsync();
        try
        {
            bool ok = RebootRemoteMachine(ip, user, pass);
            results[ip] = ok;
        }
        finally
        {
            semaphore.Release();
        }
    });
    
    await Task.WhenAll(tasks);
    return results;
}

3. 替代方案:PSRemoting / WinRM


// 使用 PowerShell Remoting (WinRM) 更現代、防火牆友善
using System.Management.Automation;
using System.Management.Automation.Runspaces;

public void RebootViaWinRM(string target, string user, string pass)
{
    var credential = new PSCredential(user, ToSecureString(pass));
    var connectionInfo = new WSManConnectionInfo(
        false, target, 5985, "/wsman", "https://schemas.microsoft.com/powershell/Microsoft.PowerShell", credential);
    
    using (var runspace = RunspaceFactory.CreateRunspace(connectionInfo))
    {
        runspace.Open();
        using (var pipeline = runspace.CreatePipeline())
        {
            pipeline.Commands.AddScript("Restart-Computer -Force");
            pipeline.Invoke();
        }
    }
}

常見錯誤代碼對照表

錯誤碼Win32 錯誤說明解決方向
0Success成功-
2Access Denied權限不足檢查帳號是否為管理員、DCOM 權限、UAC 設定
8Out of Memory記憶體不足目標機資源不足
21Invalid Parameter參數錯誤檢查 WQL 查詢、方法參數
0x800706BARPC_S_SERVER_UNAVAILABLERPC 伺服器不可用防火牆、WMI 服務未啟動、網路不通
0x80070005E_ACCESSDENIED存取被拒認證錯誤、LocalAccountTokenFilterPolicy

安全性最佳實踐

  • 不要硬編碼密碼:使用 Windows Credential Manager、Azure Key Vault、環境變數或加密設定檔
  • 最小權限原則:建立專用服務帳號,僅授予必要權限
  • 審計日誌:記錄操作時間、操作人、目標電腦、結果
  • 確認機制:執行前要求二次確認,避免誤操作
  • 加密通訊:`AuthenticationLevel.PacketPrivacy` 確保傳輸加密

總結

透過 WMI `Win32_OperatingSystem.Reboot()` 實現遠端重開機是經典且有效的方法。關鍵成功因素在於:目標機器防火牆/DCOM/UAC 正確設定、呼叫端具備管理員權限與 SeShutdownPrivilege、網路連通性正常。現代環境建議優先評估 WinRM/PowerShell Remoting,僅開放 TCP 5985/5986 即可,管理更簡單且安全性更高。實務部署時務必建立完整的權限管控與稽核機制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved