using System.Net; using System.Text; using System.Xml.Linq; namespace AmtScanner.Api.Services; public interface IAmtPowerService { Task GetPowerStateAsync(string ip, string username, string password); Task PowerOnAsync(string ip, string username, string password); Task PowerOffAsync(string ip, string username, string password); Task ResetAsync(string ip, string username, string password); Task PowerCycleAsync(string ip, string username, string password); Task HardPowerOffAsync(string ip, string username, string password); Task HardResetAsync(string ip, string username, string password); } public class AmtPowerState { public int PowerState { get; set; } public string PowerStateText { get; set; } = string.Empty; } public class AmtPowerService : IAmtPowerService { private readonly ILogger _logger; private const int AMT_PORT = 16992; // 电源状态枚举 private static readonly Dictionary PowerStateMap = new() { { 1, "其他" }, { 2, "开机" }, { 3, "轻度睡眠" }, { 4, "深度睡眠" }, { 5, "软关机循环" }, { 6, "硬关机" }, { 7, "休眠" }, { 8, "软关机" }, { 9, "硬关机循环" }, { 10, "主总线复位" }, { 11, "诊断中断" }, { 12, "优雅关机" }, { 14, "优雅重启" }, { 15, "从省电模式唤醒" } }; public AmtPowerService(ILogger logger) { _logger = logger; } public async Task GetPowerStateAsync(string ip, string username, string password) { try { // 获取 CIM_AssociatedPowerManagementService var soapEnvelope = BuildGetPowerStateRequest(ip, AMT_PORT); var response = await SendWsmanRequestAsync(ip, AMT_PORT, username, password, soapEnvelope); if (response == null) { _logger.LogWarning("无法获取电源状态"); return null; } return ParsePowerState(response); } catch (Exception ex) { _logger.LogError(ex, "获取电源状态失败: {Ip}", ip); return null; } } public async Task PowerOnAsync(string ip, string username, string password) { return await ChangePowerStateAsync(ip, username, password, 2, "开机"); } public async Task PowerOffAsync(string ip, string username, string password) { // 使用 12 (GracefulOff) 优雅关机,让操作系统正常关闭 // 8 (SoftOff) 是硬关机,会直接断电导致 AMT 掉线 return await ChangePowerStateAsync(ip, username, password, 12, "关机"); } public async Task ResetAsync(string ip, string username, string password) { // 使用 14 (GracefulReset) 优雅重启 // 10 (MasterBusReset) 是硬重启 return await ChangePowerStateAsync(ip, username, password, 14, "重启"); } public async Task PowerCycleAsync(string ip, string username, string password) { // 5 (SoftPowerCycle) 电源循环 - 这个会断电再上电 return await ChangePowerStateAsync(ip, username, password, 5, "电源循环"); } public async Task HardPowerOffAsync(string ip, string username, string password) { // 8 (SoftOff) 硬关机 - 直接断电 return await ChangePowerStateAsync(ip, username, password, 8, "强制关机"); } public async Task HardResetAsync(string ip, string username, string password) { // 10 (MasterBusReset) 硬重启 return await ChangePowerStateAsync(ip, username, password, 10, "强制重启"); } private async Task ChangePowerStateAsync(string ip, string username, string password, int powerState, string actionName) { try { var soapEnvelope = BuildChangePowerStateRequest(ip, AMT_PORT, powerState); var response = await SendWsmanRequestAsync(ip, AMT_PORT, username, password, soapEnvelope); if (response == null) { _logger.LogWarning("{Action}请求无响应", actionName); return false; } // 检查返回值 var doc = XDocument.Parse(response); var returnValue = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "ReturnValue")?.Value; if (returnValue == "0") { _logger.LogInformation("{Action}成功: {Ip}", actionName, ip); return true; } _logger.LogWarning("{Action}失败,返回值: {ReturnValue}", actionName, returnValue); return false; } catch (Exception ex) { _logger.LogError(ex, "{Action}失败: {Ip}", actionName, ip); return false; } } private async Task SendWsmanRequestAsync(string ip, int port, string username, string password, string soapEnvelope) { var url = $"http://{ip}:{port}/wsman"; var handler = new HttpClientHandler { Credentials = new CredentialCache { { new Uri($"http://{ip}:{port}"), "Digest", new NetworkCredential(username, password) } }, PreAuthenticate = false }; using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(5) }; var content = new StringContent(soapEnvelope, Encoding.UTF8, "application/soap+xml"); try { var response = await client.PostAsync(url, content); var responseContent = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { return responseContent; } _logger.LogWarning("WS-Management 请求失败: {StatusCode}", response.StatusCode); return null; } catch (Exception ex) { _logger.LogWarning("HTTP 请求异常: {Message}", ex.Message); return null; } } private static string BuildGetPowerStateRequest(string ip, int port) { var toAddress = $"http://{ip}:{port}/wsman"; var messageId = $"uuid:{Guid.NewGuid()}"; // 获取 CIM_AssociatedPowerManagementService return $@" {toAddress} http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_AssociatedPowerManagementService http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://schemas.xmlsoap.org/ws/2004/09/transfer/Get 153600 {messageId} PT60.000S "; } private static string BuildChangePowerStateRequest(string ip, int port, int powerState) { var toAddress = $"http://{ip}:{port}/wsman"; var messageId = $"uuid:{Guid.NewGuid()}"; return $@" {toAddress} http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService/RequestPowerStateChange 153600 {messageId} PT60.000S Intel(r) AMT Power Management Service {powerState} http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem ManagedSystem "; } private AmtPowerState? ParsePowerState(string xmlResponse) { try { var doc = XDocument.Parse(xmlResponse); var powerStateElement = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "PowerState"); if (powerStateElement == null) { return null; } var powerState = int.Parse(powerStateElement.Value); var powerStateText = PowerStateMap.TryGetValue(powerState, out var text) ? text : "未知"; return new AmtPowerState { PowerState = powerState, PowerStateText = powerStateText }; } catch (Exception ex) { _logger.LogError(ex, "解析电源状态失败"); return null; } } }