using QemuVmManager.Services; using QemuVmManager.Models; namespace QemuVmManager.Console; class Program { private static VmManagementService _vmService = null!; static async Task Main(string[] args) { try { _vmService = new VmManagementService(); System.Console.WriteLine("=== QEMU VM Manager ==="); System.Console.WriteLine("Type 'help' for available commands"); System.Console.WriteLine(); await RunInteractiveMode(); } catch (Exception ex) { System.Console.WriteLine($"Error: {ex.Message}"); System.Console.WriteLine("Press any key to exit..."); System.Console.ReadKey(); } } static async Task RunInteractiveMode() { while (true) { try { System.Console.Write("qemu-vm> "); var input = System.Console.ReadLine()?.Trim(); if (string.IsNullOrEmpty(input)) continue; var parts = input.Split(' ', StringSplitOptions.RemoveEmptyEntries); var command = parts[0].ToLower(); var arguments = parts.Skip(1).ToArray(); switch (command) { case "help": ShowHelp(); break; case "list": await ListVms(); break; case "create": await CreateVm(arguments); break; case "start": await StartVm(arguments); break; case "stop": await StopVm(arguments); break; case "pause": await PauseVm(arguments); break; case "resume": await ResumeVm(arguments); break; case "delete": await DeleteVm(arguments); break; case "clone": await CloneVm(arguments); break; case "export": await ExportVm(arguments); break; case "import": await ImportVm(arguments); break; case "status": await ShowVmStatus(arguments); break; case "config": await ShowVmConfig(arguments); break; case "disk": await ManageDisk(arguments); break; case "validate": await ValidateVm(arguments); break; case "diagnose": await DiagnoseSystem(); break; case "monitor": await MonitorPerformance(arguments); break; case "metrics": await ShowMetrics(arguments); break; case "exit": case "quit": System.Console.WriteLine("Goodbye!"); return; default: System.Console.WriteLine($"Unknown command: {command}"); System.Console.WriteLine("Type 'help' for available commands"); break; } } catch (Exception ex) { System.Console.WriteLine($"Error: {ex.Message}"); } System.Console.WriteLine(); } } static void ShowHelp() { System.Console.WriteLine("Available commands:"); System.Console.WriteLine(" list - List all VMs"); System.Console.WriteLine(" create - Create a new VM (interactive)"); System.Console.WriteLine(" start - Start a VM"); System.Console.WriteLine(" stop [--force] - Stop a VM"); System.Console.WriteLine(" pause - Pause a VM"); System.Console.WriteLine(" resume - Resume a VM"); System.Console.WriteLine(" delete - Delete a VM"); System.Console.WriteLine(" clone - Clone a VM"); System.Console.WriteLine(" export - Export VM configuration"); System.Console.WriteLine(" import [name] - Import VM configuration"); System.Console.WriteLine(" status [name] - Show VM status"); System.Console.WriteLine(" config - Show VM configuration"); System.Console.WriteLine(" disk [info|resize|convert] - Manage disk images"); System.Console.WriteLine(" validate - Validate VM disk images"); System.Console.WriteLine(" diagnose - Diagnose system and QEMU installation"); System.Console.WriteLine(" monitor [start|stop|status] - Performance monitoring"); System.Console.WriteLine(" metrics [current|history] - Show performance metrics"); System.Console.WriteLine(" help - Show this help"); System.Console.WriteLine(" exit/quit - Exit the application"); } static Task ListVms() { var configs = _vmService.GetAllVmConfigurations().ToList(); var statuses = _vmService.GetAllVmStatuses().ToDictionary(s => s.Name); if (configs.Count == 0) { System.Console.WriteLine("No VMs configured."); return Task.CompletedTask; } System.Console.WriteLine($"{"Name",-20} {"Status",-10} {"CPU",-8} {"Memory",-10} {"Description"}"); System.Console.WriteLine(new string('-', 80)); foreach (var config in configs) { var status = statuses.GetValueOrDefault(config.Name); var statusText = status?.State.ToString() ?? "Unknown"; var cpuText = $"{config.Cpu.Cores} cores"; var memoryText = $"{config.Memory.Size}{config.Memory.Unit}"; System.Console.WriteLine($"{config.Name,-20} {statusText,-10} {cpuText,-8} {memoryText,-10} {config.Description}"); } return Task.CompletedTask; } static async Task CreateVm(string[] arguments) { string vmName; if (arguments.Length > 0) { vmName = arguments[0]; } else { System.Console.Write("Enter VM name: "); vmName = System.Console.ReadLine()?.Trim() ?? ""; } if (string.IsNullOrEmpty(vmName)) { System.Console.WriteLine("VM name cannot be empty."); return; } var config = new VmConfiguration { Name = vmName, Description = GetUserInput("Description (optional): "), Cpu = new CpuConfiguration { Cores = int.Parse(GetUserInput("CPU cores (2): ", "2")), Model = GetUserInput("CPU model (qemu64): ", "qemu64") }, Memory = new MemoryConfiguration { Size = long.Parse(GetUserInput("Memory size in MB (2048): ", "2048")), Unit = "M" }, Storage = new StorageConfiguration { Disks = new List { new DiskConfiguration { Path = GetUserInput($"Disk path (vm-disks/{vmName}.qcow2): ", $"vm-disks/{vmName}.qcow2"), Size = long.Parse(GetUserInput("Disk size in GB (10): ", "10")), Format = GetUserInput("Disk format (qcow2): ", "qcow2"), Interface = GetUserInput("Disk interface (virtio): ", "virtio"), IsBoot = true } } }, Network = new NetworkConfiguration { Interfaces = new List { new NetworkInterfaceConfiguration { Type = "bridge", Model = "virtio-net-pci", Bridge = GetUserInput("Network bridge (virbr0): ", "virbr0") } } }, Display = new DisplayConfiguration { Type = GetUserInput("Display type (gtk): ", "gtk"), Vga = GetUserInput("VGA type (virtio): ", "virtio") } }; await _vmService.CreateVmAsync(config); System.Console.WriteLine($"VM '{vmName}' created successfully."); } static async Task StartVm(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: start "); return; } var vmName = arguments[0]; var success = await _vmService.StartVmAsync(vmName); if (success) System.Console.WriteLine($"VM '{vmName}' started successfully."); else System.Console.WriteLine($"Failed to start VM '{vmName}'."); } static async Task StopVm(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: stop [--force]"); return; } var vmName = arguments[0]; var force = arguments.Contains("--force"); var success = await _vmService.StopVmAsync(vmName, force); if (success) System.Console.WriteLine($"VM '{vmName}' stopped successfully."); else System.Console.WriteLine($"Failed to stop VM '{vmName}'."); } static async Task PauseVm(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: pause "); return; } var vmName = arguments[0]; var success = await _vmService.PauseVmAsync(vmName); if (success) System.Console.WriteLine($"VM '{vmName}' paused successfully."); else System.Console.WriteLine($"Failed to pause VM '{vmName}'."); } static async Task ResumeVm(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: resume "); return; } var vmName = arguments[0]; var success = await _vmService.ResumeVmAsync(vmName); if (success) System.Console.WriteLine($"VM '{vmName}' resumed successfully."); else System.Console.WriteLine($"Failed to resume VM '{vmName}'."); } static async Task DeleteVm(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: delete "); return; } var vmName = arguments[0]; System.Console.Write($"Are you sure you want to delete VM '{vmName}'? (y/N): "); var confirm = System.Console.ReadLine()?.Trim().ToLower(); if (confirm == "y" || confirm == "yes") { await _vmService.DeleteVmAsync(vmName); System.Console.WriteLine($"VM '{vmName}' deleted successfully."); } else { System.Console.WriteLine("Deletion cancelled."); } } static async Task CloneVm(string[] arguments) { if (arguments.Length < 2) { System.Console.WriteLine("Usage: clone "); return; } var sourceVm = arguments[0]; var targetVm = arguments[1]; var clonedConfig = await _vmService.CloneVmAsync(sourceVm, targetVm); System.Console.WriteLine($"VM '{sourceVm}' cloned to '{targetVm}' successfully."); } static async Task ExportVm(string[] arguments) { if (arguments.Length < 2) { System.Console.WriteLine("Usage: export "); return; } var vmName = arguments[0]; var exportPath = arguments[1]; var exportedPath = await _vmService.ExportVmConfigurationAsync(vmName, exportPath); System.Console.WriteLine($"VM '{vmName}' exported to '{exportedPath}' successfully."); } static async Task ImportVm(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: import [new-name]"); return; } var importPath = arguments[0]; var newName = arguments.Length > 1 ? arguments[1] : null; var importedConfig = await _vmService.ImportVmConfigurationAsync(importPath, newName); System.Console.WriteLine($"VM '{importedConfig.Name}' imported successfully."); } static Task ShowVmStatus(string[] arguments) { if (arguments.Length == 0) { // Show all VM statuses var statuses = _vmService.GetAllVmStatuses(); if (!statuses.Any()) { System.Console.WriteLine("No VMs found."); return Task.CompletedTask; } System.Console.WriteLine($"{"Name",-20} {"Status",-10} {"PID",-8} {"Started",-20} {"Error"}"); System.Console.WriteLine(new string('-', 80)); foreach (var status in statuses) { var pidText = status.ProcessId > 0 ? status.ProcessId.ToString() : "-"; var startedText = status.StartedAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? "-"; var errorText = status.ErrorMessage ?? ""; System.Console.WriteLine($"{status.Name,-20} {status.State,-10} {pidText,-8} {startedText,-20} {errorText}"); } } else { // Show specific VM status var vmName = arguments[0]; var status = _vmService.GetVmStatus(vmName); if (status == null) { System.Console.WriteLine($"VM '{vmName}' not found."); return Task.CompletedTask; } System.Console.WriteLine($"VM: {status.Name}"); System.Console.WriteLine($"Status: {status.State}"); System.Console.WriteLine($"Process ID: {status.ProcessId}"); System.Console.WriteLine($"Started: {status.StartedAt}"); System.Console.WriteLine($"Stopped: {status.StoppedAt}"); if (status.ResourceUsage != null) { System.Console.WriteLine($"CPU Usage: {status.ResourceUsage.CpuUsage:F1}%"); System.Console.WriteLine($"Memory Usage: {status.ResourceUsage.MemoryUsage} MB"); } if (!string.IsNullOrEmpty(status.ErrorMessage)) { System.Console.WriteLine($"Error: {status.ErrorMessage}"); } } return Task.CompletedTask; } static Task ShowVmConfig(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: config "); return Task.CompletedTask; } var vmName = arguments[0]; var config = _vmService.GetVmConfiguration(vmName); if (config == null) { System.Console.WriteLine($"VM '{vmName}' not found."); return Task.CompletedTask; } System.Console.WriteLine($"VM Configuration: {config.Name}"); System.Console.WriteLine($"Description: {config.Description}"); System.Console.WriteLine($"Created: {config.Created}"); System.Console.WriteLine($"Modified: {config.LastModified}"); System.Console.WriteLine(); System.Console.WriteLine("CPU Configuration:"); System.Console.WriteLine($" Cores: {config.Cpu.Cores}"); System.Console.WriteLine($" Model: {config.Cpu.Model}"); System.Console.WriteLine($" KVM: {config.Cpu.EnableKvm}"); System.Console.WriteLine(); System.Console.WriteLine("Memory Configuration:"); System.Console.WriteLine($" Size: {config.Memory.Size}{config.Memory.Unit}"); System.Console.WriteLine(); System.Console.WriteLine("Storage Configuration:"); foreach (var disk in config.Storage.Disks) { System.Console.WriteLine($" Disk: {disk.Path}"); System.Console.WriteLine($" Size: {disk.Size} GB"); System.Console.WriteLine($" Format: {disk.Format}"); System.Console.WriteLine($" Interface: {disk.Interface}"); System.Console.WriteLine($" Boot: {disk.IsBoot}"); } if (!string.IsNullOrEmpty(config.Storage.Cdrom)) { System.Console.WriteLine($" CD-ROM: {config.Storage.Cdrom}"); } System.Console.WriteLine(); System.Console.WriteLine("Network Configuration:"); foreach (var nic in config.Network.Interfaces) { System.Console.WriteLine($" Interface: {nic.Model}"); System.Console.WriteLine($" Type: {nic.Type}"); System.Console.WriteLine($" Bridge: {nic.Bridge}"); if (!string.IsNullOrEmpty(nic.Mac)) { System.Console.WriteLine($" MAC: {nic.Mac}"); } } System.Console.WriteLine(); System.Console.WriteLine("Display Configuration:"); System.Console.WriteLine($" Type: {config.Display.Type}"); System.Console.WriteLine($" VGA: {config.Display.Vga}"); System.Console.WriteLine($" SPICE: {config.Display.EnableSpice}"); if (config.Display.EnableSpice) { System.Console.WriteLine($" SPICE Port: {config.Display.SpicePort}"); } return Task.CompletedTask; } static async Task ManageDisk(string[] arguments) { if (arguments.Length < 1) { System.Console.WriteLine("Usage: disk [info|resize|convert]"); return; } var vmName = arguments[0]; var action = arguments.Length > 1 ? arguments[1].ToLower() : "info"; switch (action) { case "info": await ShowDiskInfo(vmName); break; case "resize": await ResizeDisk(vmName, arguments.Skip(2).ToArray()); break; case "convert": await ConvertDisk(vmName, arguments.Skip(2).ToArray()); break; default: System.Console.WriteLine($"Unknown disk action: {action}"); System.Console.WriteLine("Available actions: info, resize, convert"); break; } } static async Task ShowDiskInfo(string vmName) { try { var config = _vmService.GetVmConfiguration(vmName); if (config == null) { System.Console.WriteLine($"VM '{vmName}' not found."); return; } System.Console.WriteLine($"Disk Information for VM: {vmName}"); System.Console.WriteLine(new string('-', 50)); for (int i = 0; i < config.Storage.Disks.Count; i++) { var disk = config.Storage.Disks[i]; System.Console.WriteLine($"Disk {i}:"); System.Console.WriteLine($" Path: {disk.Path}"); System.Console.WriteLine($" Format: {disk.Format}"); System.Console.WriteLine($" Size: {disk.Size} GB"); System.Console.WriteLine($" Interface: {disk.Interface}"); System.Console.WriteLine($" Boot: {disk.IsBoot}"); var diskInfo = await _vmService.GetDiskInfoAsync(vmName, i); if (diskInfo.Exists) { System.Console.WriteLine($" Virtual Size: {diskInfo.VirtualSize}"); System.Console.WriteLine($" Disk Size: {diskInfo.DiskSize}"); System.Console.WriteLine($" Format: {diskInfo.Format}"); } else { System.Console.WriteLine(" Status: Not found"); } System.Console.WriteLine(); } } catch (Exception ex) { System.Console.WriteLine($"Error: {ex.Message}"); } } static async Task ResizeDisk(string vmName, string[] arguments) { if (arguments.Length < 2) { System.Console.WriteLine("Usage: disk resize "); return; } try { var diskIndex = int.Parse(arguments[0]); var newSizeGB = long.Parse(arguments[1]); var success = await _vmService.ResizeDiskAsync(vmName, diskIndex, newSizeGB); if (success) { System.Console.WriteLine($"Disk {diskIndex} resized to {newSizeGB} GB successfully."); } else { System.Console.WriteLine("Failed to resize disk."); } } catch (Exception ex) { System.Console.WriteLine($"Error: {ex.Message}"); } } static async Task ConvertDisk(string vmName, string[] arguments) { if (arguments.Length < 2) { System.Console.WriteLine("Usage: disk convert "); System.Console.WriteLine("Available formats: qcow2, raw, vmdk, vdi, vhd"); return; } try { var diskIndex = int.Parse(arguments[0]); var newFormat = arguments[1]; var success = await _vmService.ConvertDiskAsync(vmName, diskIndex, newFormat); if (success) { System.Console.WriteLine($"Disk {diskIndex} converted to {newFormat} format successfully."); } else { System.Console.WriteLine("Failed to convert disk."); } } catch (Exception ex) { System.Console.WriteLine($"Error: {ex.Message}"); } } static async Task ValidateVm(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: validate "); return; } var vmName = arguments[0]; try { var isValid = _vmService.ValidateDiskImages(vmName); if (isValid) { System.Console.WriteLine($"VM '{vmName}' disk images are valid."); } else { System.Console.WriteLine($"VM '{vmName}' has invalid disk images."); System.Console.WriteLine("Use 'disk info' to check disk status."); } } catch (Exception ex) { System.Console.WriteLine($"Error: {ex.Message}"); } } static async Task DiagnoseSystem() { System.Console.WriteLine("=== System Diagnosis ==="); System.Console.WriteLine(); // Check .NET version System.Console.WriteLine("1. .NET Runtime:"); System.Console.WriteLine($" Version: {Environment.Version}"); System.Console.WriteLine($" OS: {Environment.OSVersion}"); System.Console.WriteLine($" Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}"); System.Console.WriteLine(); // Check QEMU installation and virtualization System.Console.WriteLine("2. QEMU Installation:"); try { var processManager = new QemuVmManager.Core.QemuProcessManager(); var isInstalled = processManager.IsQemuInstalled(); var version = processManager.GetQemuVersion(); var accelerators = processManager.GetQemuAccelerators(); var virtualizationEnabled = processManager.IsVirtualizationEnabled(); var availableVirtualization = processManager.GetAvailableVirtualization(); System.Console.WriteLine($" Installed: {(isInstalled ? "Yes" : "No")}"); System.Console.WriteLine($" Version: {version}"); System.Console.WriteLine($" Available Accelerators:"); foreach (var line in accelerators.Split('\n', StringSplitOptions.RemoveEmptyEntries)) { System.Console.WriteLine($" {line.Trim()}"); } System.Console.WriteLine($" Virtualization Enabled in BIOS: {(virtualizationEnabled ? "Yes" : "No")}"); System.Console.WriteLine($" Available Virtualization: {availableVirtualization}"); if (!isInstalled) { System.Console.WriteLine(" ❌ QEMU is not installed or not found in PATH"); System.Console.WriteLine(" Please install QEMU and ensure it's available in your system PATH"); System.Console.WriteLine(" Windows: Download from https://qemu.weilnetz.de/"); System.Console.WriteLine(" Linux: sudo apt-get install qemu-system-x86_64"); System.Console.WriteLine(" macOS: brew install qemu"); } else if (!virtualizationEnabled) { System.Console.WriteLine(" ⚠️ Virtualization is not enabled in BIOS/UEFI"); System.Console.WriteLine(" Please enable VT-x (Intel) or AMD-V (AMD) in your BIOS settings"); System.Console.WriteLine(" This will significantly improve VM performance"); } else if (availableVirtualization == VirtualizationType.TCG) { System.Console.WriteLine(" ⚠️ Only software emulation (TCG) is available"); System.Console.WriteLine(" Hardware virtualization is not available or not properly configured"); System.Console.WriteLine(" This may be due to:"); System.Console.WriteLine(" - QEMU build not supporting hardware acceleration"); System.Console.WriteLine(" - Missing virtualization drivers"); System.Console.WriteLine(" - Hyper-V or other virtualization software conflicts"); } else { System.Console.WriteLine($" ✅ Hardware virtualization ({availableVirtualization}) is available"); } } catch (Exception ex) { System.Console.WriteLine($" ❌ Error checking QEMU: {ex.Message}"); } System.Console.WriteLine(); // Check disk manager System.Console.WriteLine("3. Disk Manager:"); try { var diskManager = new QemuVmManager.Core.DiskManager(); System.Console.WriteLine(" ✅ Disk manager initialized successfully"); } catch (Exception ex) { System.Console.WriteLine($" ❌ Error initializing disk manager: {ex.Message}"); } System.Console.WriteLine(); // Check VM configurations System.Console.WriteLine("4. VM Configurations:"); try { var configs = _vmService.GetAllVmConfigurations().ToList(); System.Console.WriteLine($" Found {configs.Count} VM configuration(s)"); foreach (var config in configs) { System.Console.WriteLine($" - {config.Name}: {config.Description}"); // Check disk images foreach (var disk in config.Storage.Disks) { var exists = File.Exists(disk.Path); System.Console.WriteLine($" Disk: {disk.Path} - {(exists ? "✅ Exists" : "❌ Missing")}"); } } } catch (Exception ex) { System.Console.WriteLine($" ❌ Error checking VM configurations: {ex.Message}"); } System.Console.WriteLine(); // Check running VMs System.Console.WriteLine("5. Running VMs:"); try { var statuses = _vmService.GetAllVmStatuses().ToList(); var runningVms = statuses.Where(s => s.State == QemuVmManager.Models.VmState.Running).ToList(); System.Console.WriteLine($" Running: {runningVms.Count}"); foreach (var vm in runningVms) { System.Console.WriteLine($" - {vm.Name} (PID: {vm.ProcessId})"); } } catch (Exception ex) { System.Console.WriteLine($" ❌ Error checking running VMs: {ex.Message}"); } System.Console.WriteLine(); System.Console.WriteLine("=== Diagnosis Complete ==="); } static string GetUserInput(string prompt, string defaultValue = "") { System.Console.Write(prompt); var input = System.Console.ReadLine()?.Trim(); return string.IsNullOrEmpty(input) ? defaultValue : input; } static async Task MonitorPerformance(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: monitor [start|stop|status]"); return; } var vmName = arguments[0]; var action = arguments.Length > 1 ? arguments[1].ToLower() : "status"; try { switch (action) { case "start": await _vmService.StartPerformanceMonitoringAsync(vmName); System.Console.WriteLine($"Performance monitoring started for VM '{vmName}'"); break; case "stop": _vmService.StopPerformanceMonitoring(vmName); System.Console.WriteLine($"Performance monitoring stopped for VM '{vmName}'"); break; case "status": default: var isMonitoring = _vmService.IsPerformanceMonitoringActive(vmName); System.Console.WriteLine($"Performance monitoring for VM '{vmName}': {(isMonitoring ? "Active" : "Inactive")}"); break; } } catch (Exception ex) { System.Console.WriteLine($"Error: {ex.Message}"); } } static async Task ShowMetrics(string[] arguments) { if (arguments.Length == 0) { System.Console.WriteLine("Usage: metrics [current|history]"); return; } var vmName = arguments[0]; var type = arguments.Length > 1 ? arguments[1].ToLower() : "current"; try { switch (type) { case "current": var currentMetrics = await _vmService.GetVmPerformanceMetricsAsync(vmName); DisplayPerformanceMetrics(currentMetrics, "Current"); break; case "history": var history = await _vmService.GetPerformanceHistoryAsync(vmName, 20); System.Console.WriteLine($"Performance History for VM '{vmName}' (Last {history.Count} samples):"); System.Console.WriteLine(); foreach (var metrics in history.TakeLast(10)) { DisplayPerformanceMetrics(metrics, metrics.Timestamp.ToString("HH:mm:ss")); } break; default: System.Console.WriteLine("Invalid metrics type. Use 'current' or 'history'"); break; } } catch (Exception ex) { System.Console.WriteLine($"Error: {ex.Message}"); } } static void DisplayPerformanceMetrics(VmPerformanceMetrics metrics, string label) { System.Console.WriteLine($"=== {label} Performance Metrics ==="); System.Console.WriteLine($"Timestamp: {metrics.Timestamp:yyyy-MM-dd HH:mm:ss}"); System.Console.WriteLine($"Process ID: {metrics.ProcessId}"); System.Console.WriteLine(); System.Console.WriteLine("CPU Usage:"); System.Console.WriteLine($" VM CPU: {metrics.CpuUsagePercent:F2}%"); System.Console.WriteLine($" System CPU: {metrics.SystemCpuUsagePercent:F2}%"); System.Console.WriteLine(); System.Console.WriteLine("Memory Usage:"); System.Console.WriteLine($" Working Set: {metrics.MemoryUsageMB:N0} MB"); System.Console.WriteLine($" Private Memory: {metrics.PrivateMemoryMB:N0} MB"); System.Console.WriteLine($" Virtual Memory: {metrics.VirtualMemoryMB:N0} MB"); System.Console.WriteLine(); System.Console.WriteLine("Process Info:"); System.Console.WriteLine($" Threads: {metrics.ThreadCount}"); System.Console.WriteLine($" Handles: {metrics.HandleCount}"); System.Console.WriteLine(); } }