package device import ( "fmt" "network-topology-discovery/pkg/models" "strings" ) // WindowsParser Windows Server解析器 type WindowsParser struct { BaseParser } // GetCommands 获取Windows命令列表 func (p *WindowsParser) GetCommands() []string { return []string{ "hostname", "systeminfo | findstr /B /C:\"OS Name\" /C:\"OS Version\"", "Get-NetAdapter | Select-Object Name, InterfaceDescription, Status, MacAddress, LinkSpeed | Format-List", "Get-NetIPAddress | Where-Object AddressFamily -eq IPv4 | Select-Object InterfaceAlias, IPAddress, PrefixLength | Format-List", "systeminfo | findstr /B /C:\"System Boot Time\"", } } // Parse 解析Windows输出 func (p *WindowsParser) Parse(device *models.Device, outputs []string) error { if len(outputs) < 5 { return fmt.Errorf("insufficient command outputs") } device.Hostname = strings.TrimSpace(outputs[0]) device.OSVersion = p.parseOSVersion(outputs[1]) device.Uptime = p.parseUptime(outputs[4]) device.Interfaces = p.parseInterfaces(outputs[2], outputs[3]) return nil } func (p *WindowsParser) parseOSVersion(output string) string { lines := strings.Split(output, "\n") var osInfo []string for _, line := range lines { if strings.Contains(line, "OS Name") || strings.Contains(line, "OS Version") { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { osInfo = append(osInfo, strings.TrimSpace(parts[1])) } } } return strings.Join(osInfo, ", ") } func (p *WindowsParser) parseUptime(output string) string { if strings.Contains(output, "System Boot Time") { parts := strings.SplitN(output, ":", 2) if len(parts) == 2 { return strings.TrimSpace(parts[1]) } } return output } func (p *WindowsParser) parseInterfaces(adapterOutput, ipOutput string) []models.Interface { var interfaces []models.Interface // 解析网卡信息 adapters := p.parseNetAdapters(adapterOutput) // 解析IP信息 ipMap := p.parseIPAddresses(ipOutput) // 合并信息 for _, adapter := range adapters { iface := adapter if ipInfo, ok := ipMap[adapter.Name]; ok { iface.IP = ipInfo.IP iface.Mask = ipInfo.Mask } interfaces = append(interfaces, iface) } return interfaces } func (p *WindowsParser) parseNetAdapters(output string) []models.Interface { var interfaces []models.Interface var currentInterface *models.Interface lines := strings.Split(output, "\n") for _, line := range lines { line = strings.TrimSpace(line) if line == "" { continue } if strings.Contains(line, "Name") && strings.Contains(line, ":") { if currentInterface != nil { interfaces = append(interfaces, *currentInterface) } parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { currentInterface = &models.Interface{ Name: strings.TrimSpace(parts[1]), } } } if currentInterface != nil { if strings.Contains(line, "InterfaceDescription") { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { currentInterface.Description = strings.TrimSpace(parts[1]) } } if strings.Contains(line, "Status") { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { status := strings.TrimSpace(parts[1]) if status == "Up" { currentInterface.Status = "up" } else { currentInterface.Status = "down" } } } if strings.Contains(line, "MacAddress") { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { currentInterface.MAC = strings.TrimSpace(parts[1]) } } if strings.Contains(line, "LinkSpeed") { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { currentInterface.Speed = strings.TrimSpace(parts[1]) } } } } if currentInterface != nil { interfaces = append(interfaces, *currentInterface) } return interfaces } type ipInfo struct { IP string Mask string } func (p *WindowsParser) parseIPAddresses(output string) map[string]ipInfo { ipMap := make(map[string]ipInfo) var currentAlias string lines := strings.Split(output, "\n") for _, line := range lines { line = strings.TrimSpace(line) if line == "" { continue } if strings.Contains(line, "InterfaceAlias") { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { currentAlias = strings.TrimSpace(parts[1]) } } if strings.Contains(line, "IPAddress") && currentAlias != "" { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { if _, ok := ipMap[currentAlias]; !ok { ipMap[currentAlias] = ipInfo{} } info := ipMap[currentAlias] info.IP = strings.TrimSpace(parts[1]) ipMap[currentAlias] = info } } if strings.Contains(line, "PrefixLength") && currentAlias != "" { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { if _, ok := ipMap[currentAlias]; !ok { ipMap[currentAlias] = ipInfo{} } info := ipMap[currentAlias] info.Mask = strings.TrimSpace(parts[1]) ipMap[currentAlias] = info } } } return ipMap }