在企業環境中,系統管理員常需遠端管理電腦,包含重新開機、關機、查詢狀態等。本文示範使用 C# 透過 WMI (Windows Management Instrumentation) 呼叫 `Win32_OperatingSystem.Reboot()` 方法實現遠端重開機,涵蓋連線認證、錯誤處理、權限需求等實務細節。
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();
}
}
# 以管理員身分執行 PowerShell
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
netsh advfirewall firewall set rule group="Windows Management Instrumentation (WMI)" new enable=yes
# 或手動開放 TCP 135, 445, 動態埠範圍 (通常 49152-65535)
# 登錄機碼允許本地帳號遠端管理
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
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);
}
}
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;
}
// 使用 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 錯誤 | 說明 | 解決方向 |
|---|---|---|---|
| 0 | Success | 成功 | - |
| 2 | Access Denied | 權限不足 | 檢查帳號是否為管理員、DCOM 權限、UAC 設定 |
| 8 | Out of Memory | 記憶體不足 | 目標機資源不足 |
| 21 | Invalid Parameter | 參數錯誤 | 檢查 WQL 查詢、方法參數 |
| 0x800706BA | RPC_S_SERVER_UNAVAILABLE | RPC 伺服器不可用 | 防火牆、WMI 服務未啟動、網路不通 |
| 0x80070005 | E_ACCESSDENIED | 存取被拒 | 認證錯誤、LocalAccountTokenFilterPolicy |
透過 WMI `Win32_OperatingSystem.Reboot()` 實現遠端重開機是經典且有效的方法。關鍵成功因素在於:目標機器防火牆/DCOM/UAC 正確設定、呼叫端具備管理員權限與 SeShutdownPrivilege、網路連通性正常。現代環境建議優先評估 WinRM/PowerShell Remoting,僅開放 TCP 5985/5986 即可,管理更簡單且安全性更高。實務部署時務必建立完整的權限管控與稽核機制。