WiFiAnalyzer.psm1
|
# Approved verb wrapper for export vars function Get-WiFiAnalyzerExportVars { [CmdletBinding()] param( [Parameter(Mandatory=$true)]$networks ) # Call the original logic Update-WiFiAnalyzerExportVars -networks $networks return @{ mac = $script:mac computerName = $script:computerName ipAddress = $script:ipAddress connectedSSID = $script:connectedSSID connectedBSSID = $script:connectedBSSID recommendedChannels = $script:recommended scanTime = $script:scanDateTime } } # Helper: Refresh all export variables for terminal usage function Update-WiFiAnalyzerExportVars { param( [Parameter(Mandatory=$true)]$networks ) $computerInfo = Get-ComputerInfoExtras $script:computerName = $computerInfo.ComputerName $script:ipAddress = $computerInfo.IPAddress $script:mac = $computerInfo.MACAddress $connected = Get-ConnectedSSID $script:connectedSSID = $connected.SSID $script:connectedBSSID = $connected.BSSID # Removed unused assignment to ifaceDetails # Ensure $networks is always an array if ($null -eq $networks) { # Error output removed $networks = @() } elseif ($networks -isnot [System.Collections.IEnumerable] -or $networks -is [string]) { $networks = @($networks) } $script:networks = $networks $script:recommended = Get-BestChannel $networks $script:scanDateTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' $script:outputPath = "$PSScriptRoot\WiFiAnalyzerReport.html" # Debug output removed } # Analyze WiFi channel congestion and recommend best channels function Test-WiFiChannelCongestion { $output = netsh wlan show networks mode=bssid | Out-String $channels = @() foreach ($line in $output -split "`r`n") { if ($line -match "Channel\s*:\s*(\d+)") { $channels += [int]$matches[1] } } if ($channels.Count -eq 0) { Write-Output "No WiFi channels detected." return } $grouped = $channels | Group-Object | Sort-Object Count -Descending $mostCongested = $grouped | Select-Object -First 3 $leastCongested = $grouped | Where-Object { $_.Count -eq ($grouped | Select-Object -Last 1).Count } Write-Output "Most Congested Channels:" foreach ($chan in $mostCongested) { Write-Output "Channel $($chan.Name): $($chan.Count) networks" } Write-Output "\nLeast Congested Channels:" foreach ($chan in $leastCongested) { Write-Output "Channel $($chan.Name): $($chan.Count) networks" } } # Utility: Get-SecurityColor function Get-SecurityColor { param( [string]$SecurityType ) if ($SecurityType -match "WPA3") { return @('WPA3', [System.Drawing.Color]::Green) } elseif ($SecurityType -match "WPA2") { return @('WPA2', [System.Drawing.Color]::Blue) } elseif ($SecurityType -match "WPA") { return @('WPA', [System.Drawing.Color]::Orange) } elseif ($SecurityType -match "Open") { return @('Open', [System.Drawing.Color]::Red) } else { return @($SecurityType, [System.Drawing.Color]::Gray) } } # Utility: Get-SignalColor function Get-SignalColor { param( [int]$SignalStrength ) if ($SignalStrength -ge 80) { return @('Excellent', [System.Drawing.Color]::Green) } elseif ($SignalStrength -ge 60) { return @('Good', [System.Drawing.Color]::YellowGreen) } elseif ($SignalStrength -ge 40) { return @('Fair', [System.Drawing.Color]::Orange) } else { return @('Weak', [System.Drawing.Color]::Red) } } # Utility: ConvertTo-NotNull function ConvertTo-NotNull { param( $InputObject, $DefaultValue ) if ($null -ne $InputObject) { return $InputObject } else { return $DefaultValue } } function Get-ComputerInfoExtras { $os = (Get-CimInstance Win32_OperatingSystem).Caption $version = (Get-CimInstance Win32_OperatingSystem).Version $computerName = $env:COMPUTERNAME $ip = (Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true } | Select-Object -ExpandProperty IPAddress)[0] $mac = (Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true } | Select-Object -ExpandProperty MACAddress)[0] return @{ OS = $os; Version = $version; ComputerName = $computerName; IPAddress = $ip; MACAddress = $mac } } function Get-BestChannel { param([Parameter(Mandatory=$true)]$networks) # Ensure input is always an array if ($null -eq $networks) { return @{ '2.4GHz' = ''; '5GHz' = ''; CongestionData = @{} } } if ($networks -isnot [System.Collections.IEnumerable] -or $networks -is [string]) { $networks = @($networks) } elseif ($networks -is [System.Collections.IEnumerable]) { $networks = @($networks) } if (-not $networks -or $networks.Count -eq 0) { return @{ '2.4GHz' = ''; '5GHz' = ''; CongestionData = @{} } } $channels24 = $networks | Where-Object { $_.Channel -le 14 } | ForEach-Object { $_.Channel } $channels5 = $networks | Where-Object { $_.Channel -gt 14 } | ForEach-Object { $_.Channel } $best24 = if ($channels24) { ($channels24 | Group-Object | Sort-Object Count | Select-Object -First 1).Name } else { '' } $best5 = if ($channels5) { ($channels5 | Group-Object | Sort-Object Count | Select-Object -First 1).Name } else { '' } $congestion = Test-ChannelCongestion -networks $networks return @{ '2.4GHz' = $best24; '5GHz' = $best5; CongestionData = $congestion } } # Stub for missing manifest function function Measure-NetworkSpeed { # Returns a dummy speed test result return @{ DownloadMbps = 100; UploadMbps = 50; PingMs = 10 } } if (-not ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq 'System.Windows.Forms' })) { Add-Type -AssemblyName System.Windows.Forms } if (-not ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq 'System.Drawing' })) { Add-Type -AssemblyName System.Drawing } function Get-ConnectedSSID { # Returns info about the currently connected WiFi network $output = netsh wlan show interfaces | Out-String $ssid = $null $bssid = $null foreach ($line in $output -split "`r`n") { # Debug output removed if ($line -match "^\s*SSID\s*:\s*(.+)$") { $ssid = $matches[1].Trim() } # Match 'AP BSSID' field for connected AP if ($line -match "^\s*AP BSSID\s*:\s*(.+)$") { $bssid = $matches[1].Trim() } } return @{ SSID = $ssid; BSSID = $bssid } } function Get-WiFiAdapterDetails { # Returns detailed info for all enabled network adapters $details = @{} $output = netsh wlan show interfaces | Out-String $current = @{} $ifaceName = $null foreach ($line in $output -split "`r`n") { if ($line -match "^\s*Name\s*:\s*(.+)$") { $ifaceName = $matches[1].Trim() } if ($line -match "^\s*Description\s*:\s*(.+)$") { $current.Description = $matches[1].Trim() } if ($line -match "^\s*GUID\s*:\s*(.+)$") { $current.GUID = $matches[1].Trim() } if ($line -match "^\s*Physical address\s*:\s*(.+)$") { $current.MAC = $matches[1].Trim() } if ($line -match "^\s*Interface type\s*:\s*(.+)$") { $current.InterfaceType = $matches[1].Trim() } if ($line -match "^\s*State\s*:\s*(.+)$") { $current.State = $matches[1].Trim() } if ($line -match "^\s*SSID\s*:\s*(.+)$") { $current.SSID = $matches[1].Trim() } if ($line -match "^\s*AP BSSID\s*:\s*(.+)$") { $current.BSSID = $matches[1].Trim() } if ($line -match "^\s*Band\s*:\s*(.+)$") { $current.Band = $matches[1].Trim() } if ($line -match "^\s*Channel\s*:\s*(.+)$") { $current.Channel = $matches[1].Trim() } if ($line -match "^\s*Network type\s*:\s*(.+)$") { $current.NetworkType = $matches[1].Trim() } if ($line -match "^\s*Radio type\s*:\s*(.+)$") { $current.RadioType = $matches[1].Trim() } if ($line -match "^\s*Authentication\s*:\s*(.+)$") { $current.Authentication = $matches[1].Trim() } if ($line -match "^\s*Cipher\s*:\s*(.+)$") { $current.Cipher = $matches[1].Trim() } if ($line -match "^\s*Connection mode\s*:\s*(.+)$") { $current.ConnectionMode = $matches[1].Trim() } if ($line -match "^\s*Receive rate \(Mbps\)\s*:\s*(.+)$") { $current.ReceiveRate = $matches[1].Trim() } if ($line -match "^\s*Transmit rate \(Mbps\)\s*:\s*(.+)$") { $current.TransmitRate = $matches[1].Trim() } if ($line -match "^\s*Signal\s*:\s*(.+)$") { $current.Signal = $matches[1].Trim() } if ($line -match "^\s*Profile\s*:\s*(.+)$") { $current.Profile = $matches[1].Trim() } if ($line -match "^\s*QoS MSCS Configured\s*:\s*(.+)$") { $current.QoSMSCSConfigured = $matches[1].Trim() } if ($line -match "^\s*QoS Map Configured\s*:\s*(.+)$") { $current.QoSMapConfigured = $matches[1].Trim() } if ($line -match "^\s*QoS Map Allowed by Policy\s*:\s*(.+)$") { $current.QoSMapAllowedByPolicy = $matches[1].Trim() } } if ($ifaceName) { $details[$ifaceName] = $current } else { $details["WiFi Adapter"] = @{ Error = "No WiFi interface found via netsh." } } return $details } function Get-MACAddress { # Try to get MAC address of the primary network adapter $adapters = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true } if ($adapters -and $adapters[0].MACAddress) { return $adapters[0].MACAddress } elseif ($adapters) { return $adapters[0].MACAddress } else { return "N/A" } } function Get-WiFiScan { $networks = @() $ssid = "" $security = "" $output = netsh wlan show networks mode=bssid | Out-String $lines = $output -split "`r`n" for ($i = 0; $i -lt $lines.Length; $i++) { $line = $lines[$i].Trim() if ($line -match "^SSID\s+\d+\s*:\s*(.+)$") { $ssid = $matches[1].Trim() $security = "Unknown" } if ($line -match "Authentication\s*:\s*(.+)$") { $security = $matches[1].Trim() } if ($line -match "^BSSID\s+\d+\s*:\s*(.+)$") { $bssid = $matches[1].Trim() $signal = $null $channel = $null $width = $null for ($j = 1; $j -le 8; $j++) { if ($i + $j -ge $lines.Length) { break } $nextLine = $lines[$i + $j].Trim() if ($nextLine -match "^Signal\s*:\s*(\d+)%") { $signal = [int]$matches[1] } elseif ($nextLine -match "^Channel\s*:\s*(\d+)$") { $channel = [int]$matches[1] } elseif ($nextLine -match "^Channel width\s*:\s*(.+)$") { $width = $matches[1].Trim() } } if ($ssid -and $bssid -and $null -ne $signal -and $null -ne $channel) { $networks += [PSCustomObject]@{ SSID = if ($ssid) { $ssid } else { "[Hidden Network]" } BSSID = $bssid Signal = $signal Channel = $channel Security = $security Width = if ($width) { $width } else { "Standard" } Band = if ($channel -gt 14) { "5 GHz" } else { "2.4 GHz" } } } } } return $networks } function Export-WiFiAnalyzerHTMLReport { param( [string]$FilePath, [PSCustomObject[]]$networks, [string]$mac, [hashtable]$recommendedChannels, [string]$computerName, [string]$ipAddress, [hashtable]$userInfo, [string]$connectedSSID, [string]$connectedBSSID, [hashtable]$speedTest, [hashtable]$congestionData, [string]$scanTime = "" ) $userRoomStr = '' if ($null -ne $userInfo -and $userInfo.RoomNumber) { $userRoomStr = [string]$userInfo.RoomNumber } # Defensive: ensure arrays/objects are not null if (-not $networks) { $networks = @() } if (-not $mac) { $mac = "" } if (-not $recommendedChannels) { $recommendedChannels = @{} } if (-not $computerName) { $computerName = "" } if (-not $ipAddress) { $ipAddress = "" } if (-not $userInfo) { $userInfo = @{} } if (-not $connectedSSID) { $connectedSSID = "" } if (-not $connectedBSSID) { $connectedBSSID = "" } if (-not $speedTest) { $speedTest = @{} } if (-not $congestionData) { $congestionData = @{} } $ifaceDetails = $null if ($PSBoundParameters.ContainsKey('ifaceDetails')) { $ifaceDetails = $ifaceDetails } else { $ifaceDetails = @{} } Write-Host "[DEBUG] Export-WiFiAnalyzerHTMLReport called with:" -ForegroundColor Yellow # Debug output removed $ifaceHtml = "" foreach ($key in $ifaceDetails.Keys) { $adapter = $ifaceDetails[$key] if ($adapter -is [hashtable]) { $fields = "" foreach ($field in $adapter.Keys) { $fields += '<strong>' + $field + ':</strong> ' + $adapter[$field] + '<br/>' } $ifaceHtml += "<div class='info-box'><h3>$key</h3><p style='font-size:0.98em;'>$fields</p></div>" } else { $ifaceHtml += "<div class='info-box'><h3>$key</h3><p>$($adapter)</p></div>" } } # Ensure system info fields are always populated $computerNameStr = if ($computerName) { [string]$computerName } elseif ($userInfo -and $userInfo.ComputerName) { [string]$userInfo.ComputerName } else { "N/A" } $ipAddressStr = if ($ipAddress) { [string]$ipAddress } elseif ($userInfo -and $userInfo.IPAddress) { [string]$userInfo.IPAddress } else { "N/A" } $macStr = if ($mac) { [string]$mac } elseif ($userInfo -and $userInfo.MACAddress) { [string]$userInfo.MACAddress } else { "N/A" } $connectedNetworkStr = if ($connectedNetwork) { [string]$connectedNetwork } elseif ($connectedSSID) { [string]$connectedSSID } elseif ($userInfo -and $userInfo.ConnectedNetwork) { [string]$userInfo.ConnectedNetwork } else { "N/A" } # ...existing code for ifaceHtml generation... # Ensure system info fields are always populated $computerNameStr = if ($computerName) { [string]$computerName } elseif ($userInfo -and $userInfo.ComputerName) { [string]$userInfo.ComputerName } else { "N/A" } $ipAddressStr = if ($ipAddress) { [string]$ipAddress } elseif ($userInfo -and $userInfo.IPAddress) { [string]$userInfo.IPAddress } else { "N/A" } $macStr = if ($mac) { [string]$mac } elseif ($userInfo -and $userInfo.MACAddress) { [string]$userInfo.MACAddress } else { "N/A" } # Add raw netsh wlan scan output try { $rawScan = netsh wlan show networks mode=bssid | Out-String # Annotate connected network in raw scan output if ($connectedSSID -and $connectedBSSID) { $scanLines = $rawScan -split "`r?`n" $curSSID = $null for ($i = 0; $i -lt $scanLines.Length; $i++) { if ($scanLines[$i] -match "^SSID\\s+\\d+\\s*:\\s*(.+)$") { $curSSID = $matches[1].Trim() } if ($scanLines[$i] -match "^BSSID\\s+\\d+\\s*:\\s*(.+)$") { $curBSSID = $matches[1].Trim() if ($curSSID -eq $connectedSSID -and $curBSSID -eq $connectedBSSID) { $scanLines[$i] += " <--- Currently Connected" } } } $rawScan = $scanLines -join "`r`n" } $ifaceHtml += "<div class='info-box' style='white-space:pre-wrap;'><h3>Raw WiFi Scan Output</h3><pre style='font-size:0.95em;'>$rawScan</pre></div>" } catch {} # Add congestion analysis section $congestionHtml = "" if ($congestionData -and $congestionData.MostCongested -and $congestionData.LeastCongested) { $congestionHtml += "<div class='section'><h2>WiFi Channel Congestion Analysis</h2>" $congestionHtml += "<div class='info-box'><h3>Most Congested Channels</h3><ul>" foreach ($chan in $congestionData.MostCongested) { $congestionHtml += "<li>Channel $($chan.Name): $($chan.Count) networks</li>" } $congestionHtml += "</ul></div>" $congestionHtml += "<div class='info-box'><h3>Least Congested Channels</h3><ul>" foreach ($chan in $congestionData.LeastCongested) { $congestionHtml += "<li>Channel $($chan.Name): $($chan.Count) networks</li>" } $congestionHtml += "</ul></div></div>" } $networkRows = "" foreach ($network in ($networks | Sort-Object Signal -Descending)) { $signalClass = if ($network.Signal -ge 70) { "signal-strong" } elseif ($network.Signal -ge 40) { "signal-medium" } else { "signal-weak" } $securityClass = if ($network.Security -match "WPA3") { "security-wpa3" } elseif ($network.Security -match "WPA2") { "security-wpa2" } elseif ($network.Security -match "WPA") { "security-wpa" } elseif ($network.Security -match "Open") { "security-open" } else { "" } $bandBadge = if ($network.Band -eq "5 GHz") { "badge-5ghz" } else { "badge-24ghz" } $isConnected = $false if ($connectedSSID -and $connectedBSSID -and $network.SSID -eq $connectedSSID -and $network.BSSID -eq $connectedBSSID) { $isConnected = $true } $rowClass = if ($isConnected) { "connected-network" } else { "" } $networkRows += "<tr class='$rowClass'><td><strong>$($network.SSID)</strong></td><td style='font-family: Courier New, monospace; font-size: 0.9em;'>$($network.BSSID)</td><td class='$signalClass'>$($network.Signal)%</td><td><strong>$($network.Channel)</strong></td><td><span class='badge $bandBadge'>$($network.Band)</span></td><td class='$securityClass'>$($network.Security)</td></tr>" } $speedHtml = "" if ($speedTest -and $speedTest.Success) { $speedHtml = "<div class='section'><h2>Network Performance</h2><div class='info-box'><h3>Average Latency</h3><p>$($speedTest.AverageLatency) $($speedTest.Unit)</p></div></div>" } # Connected Network logic $connectedNetworkStr = if ($connectedSSID -and $connectedSSID -ne "") { [string]$connectedSSID } else { "Not Connected" } # Read HTML template from file $templatePath = Join-Path $PSScriptRoot 'WiFiAnalyzerTemplate.html' $html = Get-Content -Path $templatePath -Raw $scanTimeStr = [string]$scanTime $userNameStr = '' if ($null -ne $userInfo -and $userInfo.Name) { $userNameStr = [string]$userInfo.Name } $userEmailStr = '' if ($null -ne $userInfo -and $userInfo.Email) { $userEmailStr = [string]$userInfo.Email } $userLocationStr = '' if ($null -ne $userInfo -and $userInfo.Building) { $userLocationStr = [string]$userInfo.Building } $notesHtmlStr = [string]$notesHtml $ifaceHtmlStr = [string]$ifaceHtml # Ensure system info fields are always populated $computerNameStr = if ($computerName) { [string]$computerName } elseif ($userInfo -and $userInfo.ComputerName) { [string]$userInfo.ComputerName } else { "N/A" } $ipAddressStr = if ($ipAddress) { [string]$ipAddress } elseif ($userInfo -and $userInfo.IPAddress) { [string]$userInfo.IPAddress } else { "N/A" } $macStr = if ($mac) { [string]$mac } elseif ($userInfo -and $userInfo.MACAddress) { [string]$userInfo.MACAddress } else { "N/A" } $connectedNetworkStr = if ($connectedNetwork) { [string]$connectedNetwork } elseif ($connectedSSID) { [string]$connectedSSID } elseif ($userInfo -and $userInfo.ConnectedNetwork) { [string]$userInfo.ConnectedNetwork } else { "N/A" } $speedHtmlStr = [string]$speedHtml $recommended24Str = '' $recommended5Str = '' if ($null -ne $recommendedChannels) { if ($recommendedChannels.ContainsKey('2.4GHz')) { $recommended24Str = [string]$recommendedChannels['2.4GHz'] } if ($recommendedChannels.ContainsKey('5GHz')) { $recommended5Str = [string]$recommendedChannels['5GHz'] } } $networksCountStr = [string]$networks.Count $networkRowsStr = [string]$networkRows # Debug output removed $html = $html.Replace('__SCAN_DATE__', $scanTimeStr) $html = $html.Replace('__SCAN_TIME__', $scanTimeStr) $html = $html.Replace('__USER_NAME__', $userNameStr) $html = $html.Replace('__USER_EMAIL__', $userEmailStr) $html = $html.Replace('__USER_LOCATION__', $userLocationStr) $html = $html.Replace('__ROOM_NUMBER__', $userRoomStr) $html = $html.Replace('__NOTES_HTML__', $notesHtmlStr) $html = $html.Replace('__IFACE_HTML__', $ifaceHtmlStr) $html = $html.Replace('__CONGESTION_HTML__', $congestionHtml) $html = $html.Replace('__COMPUTER_NAME__', $computerNameStr) $html = $html.Replace('__IP_ADDRESS__', $ipAddressStr) $html = $html.Replace('__MAC_ADDRESS__', $macStr) $html = $html.Replace('__MAC__', $macStr) $html = $html.Replace('__CONNECTED_NETWORK__', $connectedNetworkStr) $html = $html.Replace('__SPEED_HTML__', $speedHtmlStr) $html = $html.Replace('__RECOMMENDED_24GHZ__', $recommended24Str) $html = $html.Replace('__RECOMMENDED_5GHZ__', $recommended5Str) $html = $html.Replace('__NETWORKS_COUNT__', $networksCountStr) $html = $html.Replace('__NETWORK_ROWS__', $networkRowsStr) $safeFilePath = Join-Path $PWD (Split-Path $FilePath -Leaf) $html | Out-File -FilePath $safeFilePath -Encoding UTF8 } function Export-WiFiAnalyzerCSVReport { param( [string]$FilePath, $networks ) if (-not $networks) { $networks = @() } # Add Connected column to CSV $connectedSSID = $global:connectedSSID $connectedBSSID = $global:connectedBSSID $csvRows = @() foreach ($network in $networks) { $isConnected = ($connectedSSID -and $connectedBSSID -and $network.SSID -eq $connectedSSID -and $network.BSSID -eq $connectedBSSID) $row = $network | Select-Object * if ($isConnected) { Add-Member -InputObject $row -MemberType NoteProperty -Name Connected -Value 'Yes' } else { Add-Member -InputObject $row -MemberType NoteProperty -Name Connected -Value '' } $csvRows += $row } $csvRows | Export-Csv -Path $FilePath -NoTypeInformation } <# .SYNOPSIS Exports a WiFi analysis report to HTML or CSV format. #> function Export-WiFiAnalyzerFullReport { [CmdletBinding()] param( [Parameter(Mandatory = $false)] [PSCustomObject[]]$networks = @(), [ValidateSet('HTML', 'CSV')] [string]$OutputFormat = 'HTML', [Parameter(Mandatory = $false)] [string]$OutputPath, [Parameter(Mandatory = $false)] [switch]$SkipReportInfo, [object]$ifaceDetails = $null, [Parameter(Mandatory = $false)] [hashtable]$userInfo = $null, [Parameter(Mandatory = $false)] [string]$mac = "", [Parameter(Mandatory = $false)] [string]$computerName = "", [Parameter(Mandatory = $false)] [string]$ipAddress = "", [Parameter(Mandatory = $false)] $connected = $null, [Parameter(Mandatory = $false)] $speedTest = $null, [Parameter(Mandatory = $false)] $recommended = $null, [Parameter(Mandatory = $false)] [string]$scanTime = "" ) # Removed unused variable assignments to fix warnings if (-not $SkipReportInfo -and $null -eq $userInfo) { Write-Host "Enter report information:" -ForegroundColor Cyan $name = Read-Host "Your Name" $email = Read-Host "Email (optional)" $location = Read-Host "Location (optional)" $roomNumber = Read-Host "Room Number (optional)" $userInfo = @{ Name = $name Email = $email Location = $location RoomNumber = $roomNumber } } elseif ($null -eq $userInfo) { $userInfo = @{ Name = "N/A" Email = "N/A" Location = "N/A" RoomNumber = "N/A" } } if (-not $OutputPath) { $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $extension = if ($OutputFormat -eq 'HTML') { 'html' } else { 'csv' } $desktopPath = [Environment]::GetFolderPath('Desktop') $OutputPath = Join-Path $desktopPath "WiFi_Report_$timestamp.$extension" } # Debug output removed # Ensure exportVars.connectedBSSID is set correctly if (-not $exportVars.connectedBSSID -or $exportVars.connectedBSSID -eq "") { if ($connected -and $connected.BSSID) { $exportVars.connectedBSSID = $connected.BSSID } else { $connInfo = Get-ConnectedSSID if ($connInfo -and $connInfo.BSSID) { $exportVars.connectedBSSID = $connInfo.BSSID } } } if ($OutputFormat -eq 'HTML') { # Debug output removed Export-WiFiAnalyzerHTMLReport -FilePath $OutputPath -networks $networks -mac $mac ` -recommendedChannels $recommended -computerName $computerName ` -ipAddress $ipAddress -userInfo $userInfo ` -connectedSSID $exportVars.connectedSSID -connectedBSSID $exportVars.connectedBSSID ` -speedTest $speedTest -congestionData $recommended.CongestionData -ifaceDetails $ifaceDetails -scanTime $scanTime } else { Export-WiFiAnalyzerCSVReport -FilePath $OutputPath -networks $networks # Output congestion analysis to command line if ($recommended.CongestionData -and $recommended.CongestionData.MostCongested -and $recommended.CongestionData.LeastCongested) { # Debug output removed } # Output raw netsh wlan scan to command line try { $rawScan = netsh wlan show networks mode=bssid | Out-String # Debug output removed } catch {} } # Debug output removed } # ===== COMMAND-LINE FUNCTION ===== <# .SYNOPSIS Runs a complete WiFi analysis and exports results. #> function Start-WiFiAnalyzerAll { [CmdletBinding()] param ( [string]$OutputFormat = "HTML", [string]$OutputPath = "", [switch]$SkipReportInfo ) try { # If no output path specified, create one in user's Documents folder if ([string]::IsNullOrEmpty($OutputPath)) { $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $extension = if ($OutputFormat -eq 'HTML') { 'html' } else { 'csv' } $documentsPath = [Environment]::GetFolderPath('MyDocuments') $OutputPath = Join-Path $documentsPath "WiFi_Report_$timestamp.$extension" } else { # Ensure the directory exists for the specified path $directory = Split-Path -Path $OutputPath -Parent if (-not (Test-Path -Path $directory)) { New-Item -Path $directory -ItemType Directory -Force | Out-Null # Debug output removed } } $networks = Get-WiFiScan if ($null -eq $networks) { $networks = @() } $mac = Get-MACAddress $connected = Get-ConnectedSSID $info = Get-ComputerInfoExtras $computerName = $info.ComputerName $ipAddress = $info.IPAddress $ifaceDetails = $null if (Get-Command Get-WiFiAdapterDetails -ErrorAction SilentlyContinue) { $ifaceDetails = Get-WiFiAdapterDetails } else { $ifaceDetails = @{} } if (-not $networks) { $networks = @() } $recommendations = Get-BestChannel $networks $speedTest = Measure-NetworkSpeed Export-WiFiAnalyzerFullReport -networks $networks -OutputFormat $OutputFormat -OutputPath $OutputPath -SkipReportInfo:$SkipReportInfo -ifaceDetails $ifaceDetails -mac $mac -computerName $computerName -ipAddress $ipAddress -connected $connected -speedTest $speedTest -recommended $recommendations if ($SkipReportInfo) { # Debug output removed Write-Host "5 GHz Band : Channel $($recommendations.'5GHz')" Write-Host "" Write-Host "Signal Strength Legend:" -ForegroundColor Cyan Write-Host " Strong: 70-100% | Medium: 40-69% | Weak: 0-39%" Write-Host "" Write-Host "Security Type Legend:" -ForegroundColor Cyan Write-Host " WPA3: Most Secure | WPA2: Secure | WPA: Less Secure | Open: Not Secure" Write-Host "" } } catch { Write-Error "Start-WiFiAnalyzerAll failed: $_" } } # ===== GUIDED SETUP AND QUICK START FUNCTIONS ===== function Get-UserPreference { $preferencePath = Join-Path $env:APPDATA "WiFiAnalyzer_Preference.txt" if (Test-Path $preferencePath) { return Get-Content $preferencePath -Raw } return $null } function Set-UserPreference { param([string]$preference) $preferencePath = Join-Path $env:APPDATA "WiFiAnalyzer_Preference.txt" $preference | Out-File -FilePath $preferencePath -Force } function Show-StartupChoiceDialog { $form = New-Object System.Windows.Forms.Form $form.Text = "WiFi Analyzer - Welcome" $form.Size = New-Object System.Drawing.Size(500, 420) $form.StartPosition = "CenterScreen" $form.FormBorderStyle = "FixedDialog" $form.MaximizeBox = $false # Ensure the closing braces for the if/else blocks are present if (-not $OutputPath) { $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $extension = if ($OutputFormat -eq 'HTML') { 'html' } else { 'csv' } $OutputPath = Join-Path $PSScriptRoot "WiFi_Report_$timestamp.$extension" } $form.MinimizeBox = $false $form.BackColor = [System.Drawing.Color]::FromArgb(230, 248, 242) # Light accent # Title $title = New-Object System.Windows.Forms.Label $title.Location = New-Object System.Drawing.Point(20, 20) $title.Size = New-Object System.Drawing.Size(460, 40) $title.Text = "Welcome to WiFi Analyzer" $title.Font = New-Object System.Drawing.Font("Segoe UI", 18, [System.Drawing.FontStyle]::Bold) $title.ForeColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $form.Controls.Add($title) # Description $description = New-Object System.Windows.Forms.Label $description.Location = New-Object System.Drawing.Point(20, 70) $description.Size = New-Object System.Drawing.Size(460, 40) $description.Text = "Choose how you'd like to start the WiFi Analyzer:" $description.Font = New-Object System.Drawing.Font("Segoe UI", 10) $form.Controls.Add($description) # Guided Setup Button $btnGuided = New-Object System.Windows.Forms.Button $btnGuided.Location = New-Object System.Drawing.Point(50, 130) $btnGuided.Size = New-Object System.Drawing.Size(400, 60) $btnGuided.Text = "Guided Setup - Learn the features (Recommended for first time)" $btnGuided.Font = New-Object System.Drawing.Font("Segoe UI", 10) $btnGuided.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $btnGuided.ForeColor = [System.Drawing.Color]::White $btnGuided.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $btnGuided.FlatAppearance.BorderSize = 0 $form.Controls.Add($btnGuided) # Quick Start Button $btnQuick = New-Object System.Windows.Forms.Button $btnQuick.Location = New-Object System.Drawing.Point(50, 210) $btnQuick.Size = New-Object System.Drawing.Size(400, 60) $btnQuick.Text = "Quick Start - Jump right in" $btnQuick.Font = New-Object System.Drawing.Font("Segoe UI", 10) $btnQuick.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $btnQuick.ForeColor = [System.Drawing.Color]::White $btnQuick.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $btnQuick.FlatAppearance.BorderSize = 0 $form.Controls.Add($btnQuick) # Remember choice checkbox $checkRemember = New-Object System.Windows.Forms.CheckBox $checkRemember.Location = New-Object System.Drawing.Point(50, 290) $checkRemember.Size = New-Object System.Drawing.Size(400, 30) $checkRemember.Text = "Remember my choice for next time" $checkRemember.Font = New-Object System.Drawing.Font("Segoe UI", 9) $form.Controls.Add($checkRemember) # Cancel Button $btnCancel = New-Object System.Windows.Forms.Button $btnCancel.Location = New-Object System.Drawing.Point(175, 330) $btnCancel.Size = New-Object System.Drawing.Size(150, 35) $btnCancel.Text = "Cancel" $btnCancel.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnCancel.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $btnCancel.ForeColor = [System.Drawing.Color]::White $form.Controls.Add($btnCancel) # Variable to store the choice - needs to be accessible in closures $choice = @{ Value = "Cancel" } $btnGuided.Add_Click({ $choice.Value = "Guided" if ($checkRemember.Checked) { Set-UserPreference "Guided" } $form.Close() }) $btnQuick.Add_Click({ $choice.Value = "Quick" if ($checkRemember.Checked) { Set-UserPreference "Quick" } $form.Close() }) $btnCancel.Add_Click({ $choice.Value = "Cancel" $form.Close() }) [void]$form.ShowDialog() return $choice.Value } function Start-GuidedSetup { try { $form = New-Object System.Windows.Forms.Form $form.Text = "WiFi Analyzer - Guided Setup" $form.Size = New-Object System.Drawing.Size(700, 550) $form.StartPosition = "CenterScreen" $form.BackColor = [System.Drawing.Color]::FromArgb(230, 248, 242) $title = New-Object System.Windows.Forms.Label $title.Location = New-Object System.Drawing.Point(30, 20) $title.Size = New-Object System.Drawing.Size(640, 40) $title.Text = "WiFi Analyzer Features Tour" $title.Font = New-Object System.Drawing.Font("Segoe UI", 18, [System.Drawing.FontStyle]::Bold) $title.ForeColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $form.Controls.Add($title) $infoText = New-Object System.Windows.Forms.RichTextBox $infoText.Location = New-Object System.Drawing.Point(30, 70) $infoText.Size = New-Object System.Drawing.Size(640, 380) $infoText.ReadOnly = $true $infoText.Font = New-Object System.Drawing.Font("Segoe UI", 10) $infoText.BorderStyle = [System.Windows.Forms.BorderStyle]::None $infoText.BackColor = [System.Drawing.Color]::FromArgb(245, 249, 250) $infoText.Text = @" Welcome to WiFi Analyzer! This tool helps you analyze WiFi networks in your area. Here's what you can do: SCAN NETWORKS Click the 'Scan Networks' button to detect all nearby WiFi networks. You'll see signal strength, channels, security types, and more. CHANNEL ANALYSIS The tool automatically recommends the best channels for both 2.4 GHz and 5 GHz bands based on network congestion. SYSTEM INFORMATION View your computer name, IP address, MAC address, and current connection status. EXPORT REPORTS Generate professional HTML or CSV reports with all scan data. Perfect for documentation and troubleshooting. COLOR-CODED RESULTS - Green: Strong signal or secure network - Orange: Medium signal or moderate security - Red: Weak signal or insecure network - Blue: WPA2 security (recommended standard) Ready to start? Click Continue to open the WiFi Analyzer! "@ $form.Controls.Add($infoText) $btnContinue = New-Object System.Windows.Forms.Button $btnContinue.Location = New-Object System.Drawing.Point(250, 465) $btnContinue.Size = New-Object System.Drawing.Size(120, 40) $btnContinue.Text = "Continue" $btnContinue.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold) $btnContinue.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $btnContinue.ForeColor = [System.Drawing.Color]::White $btnContinue.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $btnContinue.FlatAppearance.BorderSize = 0 $btnContinue.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.Controls.Add($btnContinue) $btnCancel = New-Object System.Windows.Forms.Button $btnCancel.Location = New-Object System.Drawing.Point(390, 465) $btnCancel.Size = New-Object System.Drawing.Size(120, 40) $btnCancel.Text = "Cancel" $btnCancel.Font = New-Object System.Drawing.Font("Segoe UI", 10) $btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $form.Controls.Add($btnCancel) $result = $form.ShowDialog() return ($result -eq [System.Windows.Forms.DialogResult]::OK) } catch { [System.Windows.Forms.MessageBox]::Show( "Guided Setup failed: $($_.Exception.Message)", "Guided Setup Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error ) return $false } } function Start-QuickStart { try { $result = [System.Windows.Forms.MessageBox]::Show( "WiFi Analyzer is ready to scan!`n`nClick OK to continue to the main interface.", "Quick Start", [System.Windows.Forms.MessageBoxButtons]::OKCancel, [System.Windows.Forms.MessageBoxIcon]::Information ) return ($result -eq [System.Windows.Forms.DialogResult]::OK) } catch { [System.Windows.Forms.MessageBox]::Show( "Quick Start failed: $($_.Exception.Message)", "Quick Start Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error ) return $false } } function Get-MainWiFiAnalyzerForm { # Create main form $form = New-Object System.Windows.Forms.Form $form.Text = "WiFi Network Analyzer" $form.Size = New-Object System.Drawing.Size(1100, 700) $form.StartPosition = "CenterScreen" $form.BackColor = [System.Drawing.Color]::FromArgb(230, 248, 242) # Title Header Panel $headerPanel = New-Object System.Windows.Forms.Panel $headerPanel.Location = New-Object System.Drawing.Point(0, 0) $headerPanel.Size = New-Object System.Drawing.Size(1100, 80) $headerPanel.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $form.Controls.Add($headerPanel) # Title Label $titleLabel = New-Object System.Windows.Forms.Label $titleLabel.Location = New-Object System.Drawing.Point(20, 15) $titleLabel.Size = New-Object System.Drawing.Size(500, 50) $titleLabel.Text = "WiFi Network Analyzer" $titleLabel.Font = New-Object System.Drawing.Font("Segoe UI", 24, [System.Drawing.FontStyle]::Bold) $titleLabel.ForeColor = [System.Drawing.Color]::White $headerPanel.Controls.Add($titleLabel) # Scan Button $scanButton = New-Object System.Windows.Forms.Button $scanButton.Location = New-Object System.Drawing.Point(40, 100) $scanButton.Size = New-Object System.Drawing.Size(200, 50) $scanButton.Text = "Scan Networks" $scanButton.Font = New-Object System.Drawing.Font("Segoe UI", 12, [System.Drawing.FontStyle]::Bold) $scanButton.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $scanButton.ForeColor = [System.Drawing.Color]::White $scanButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $scanButton.FlatAppearance.BorderSize = 0 $form.Controls.Add($scanButton) # Annotate connected AP in outputBox if ($script:connectedSSID -and $script:connectedBSSID -and $network.SSID -eq $script:connectedSSID -and $network.BSSID -eq $script:connectedBSSID) { $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(255, 248, 176) $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold) $outputBox.AppendText(" <--- Currently Connected") $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold) } $outputBox.AppendText("`r`n") # Export Button $exportButton = New-Object System.Windows.Forms.Button $exportButton.Location = New-Object System.Drawing.Point(260, 100) $exportButton.Size = New-Object System.Drawing.Size(200, 50) $exportButton.Text = "Export Report" $exportButton.Font = New-Object System.Drawing.Font("Segoe UI", 12, [System.Drawing.FontStyle]::Bold) $exportButton.BackColor = $scanButton.BackColor $exportButton.ForeColor = [System.Drawing.Color]::White $exportButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat $exportButton.FlatAppearance.BorderSize = 0 $exportButton.Enabled = $false $form.Controls.Add($exportButton) # Output Box $outputBox = New-Object System.Windows.Forms.RichTextBox $outputBox.Location = New-Object System.Drawing.Point(40, 170) $outputBox.Size = New-Object System.Drawing.Size(1010, 480) $outputBox.Font = New-Object System.Drawing.Font("Segoe UI", 10) $outputBox.ReadOnly = $true $outputBox.BackColor = [System.Drawing.Color]::FromArgb(245, 249, 250) $outputBox.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle $form.Controls.Add($outputBox) # Script-level variables to store scan results $script:networks = @() $script:mac = "" if ($dataGridView) { for ($i = 0; $i -lt $dataGridView.Rows.Count; $i++) { $row = $dataGridView.Rows[$i] $ssid = $row.Cells[0].Value $bssid = $row.Cells[1].Value if ($script:connectedSSID -and $script:connectedBSSID -and $ssid -eq $script:connectedSSID -and $bssid -eq $script:connectedBSSID) { $row.DefaultCellStyle.BackColor = [System.Drawing.Color]::FromArgb(255, 248, 176) $row.DefaultCellStyle.ForeColor = [System.Drawing.Color]::FromArgb(0, 0, 0) $row.DefaultCellStyle.Font = New-Object System.Drawing.Font($dataGridView.Font, [System.Drawing.FontStyle]::Bold) } } } $script:recommended = @{} $script:computerName = "" $script:ipAddress = "" $script:connectedSSID = "" $script:connectedBSSID = "" $script:speedTest = $null $script:congestionData = @{} # Scan button event handler $scanButton.Add_Click({ try { $outputBox.Clear() $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 12, [System.Drawing.FontStyle]::Bold) $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $outputBox.AppendText("Scanning WiFi Networks...`r`n`r`n") $outputBox.Refresh() # Get WiFi networks $script:networks = Get-WiFiScan $computerInfo = Get-ComputerInfoExtras $script:computerName = $computerInfo.ComputerName $script:ipAddress = $computerInfo.IPAddress $script:mac = $computerInfo.MACAddress $connected = Get-ConnectedSSID $script:connectedSSID = $connected.SSID $script:connectedBSSID = $connected.BSSID # Record scan date and time $script:scanDateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss" # Get recommendations $script:recommended = Get-BestChannel -networks $script:networks $script:congestionData = $script:recommended.CongestionData # Test speed (quick test) $script:speedTest = Measure-NetworkSpeed $outputBox.Clear() # Computer Information Section $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold) $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $outputBox.AppendText("System Information`r`n") $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.AppendText("--------------------------------------------------`r`n") $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10) $outputBox.AppendText("Computer Name: $($script:computerName)`r`n") $outputBox.AppendText("IP Address : $($script:ipAddress)`r`n") $outputBox.AppendText("MAC Address : $($script:mac)`r`n") if ($script:connectedSSID) { $outputBox.AppendText("Connected To : $($script:connectedSSID)`r`n") $outputBox.AppendText("BSSID : $($script:connectedBSSID)`r`n") } else { $outputBox.AppendText("Connected To : Not connected to WiFi`r`n") } if ($script:speedTest -and $script:speedTest.Success) { $outputBox.AppendText("Avg Latency : $($script:speedTest.AverageLatency) $($script:speedTest.Unit)`r`n") } $outputBox.AppendText("`r`n") # WiFi Interface Details Section $ifaceDetails = ConvertTo-NotNull (Get-WiFiAdapterDetails) @{} $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold) $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $outputBox.AppendText("WiFi Interface Details`r`n") $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.AppendText("--------------------------------------------------`r`n") $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10) foreach ($key in $ifaceDetails.Keys) { $adapter = $ifaceDetails[$key] if ($adapter -is [hashtable]) { $outputBox.AppendText($key + "`r`n") foreach ($field in $adapter.Keys) { $outputBox.AppendText(" " + $field + ": " + $adapter[$field] + "`r`n") } } else { $outputBox.AppendText($key + " : " + $adapter + "`r`n") } } $outputBox.AppendText("`r`n") # Networks Found Section $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold) $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $outputBox.AppendText("Detected Networks ($($script:networks.Count) Found)`r`n") $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.AppendText("--------------------------------------------------`r`n`r`n") if ($script:networks.Count -eq 0) { $outputBox.SelectionColor = [System.Drawing.Color]::Red $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold) $outputBox.AppendText("No networks found. Make sure WiFi is enabled.`r`n") } else { $sortedNetworks = $script:networks | Sort-Object Signal -Descending foreach ($network in $sortedNetworks) { $signalText, $signalColor = Get-SignalColor $network.Signal $securityText, $securityColor = Get-SecurityColor $network.Security # SSID in bold $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold) $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.AppendText("$($network.SSID)`r`n") # Network details $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9) $outputBox.AppendText(" BSSID: $($network.BSSID) | Channel: $($network.Channel) ($($network.Band))`r`n") # Signal strength with color $outputBox.AppendText(" Signal: ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = $signalColor $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) $outputBox.AppendText("$($network.Signal)% ($signalText)") # Security with color $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9) $outputBox.AppendText(" | Security: ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = $securityColor $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) $outputBox.AppendText($securityText) $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9) $outputBox.AppendText("`r`n`r`n") } } # Channel Recommendations $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold) $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64) $outputBox.AppendText("Channel Recommendations`r`n") $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.AppendText("--------------------------------------------------`r`n") $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10) $outputBox.AppendText("2.4 GHz Band: Channel $($script:recommended.'2.4GHz')`r`n") $outputBox.AppendText("5 GHz Band : Channel $($script:recommended.'5GHz')`r`n`r`n") # Legends $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold) $outputBox.AppendText("Signal Strength Legend:`r`n") $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10) $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Green $outputBox.AppendText("Strong: 70-100% ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.AppendText("| ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Orange $outputBox.AppendText("Medium: 40-69% ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.AppendText("| ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Red $outputBox.AppendText("Weak: 0-39%") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Black $outputBox.AppendText("`r`n`r`n") # Security legend $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold) $outputBox.AppendText("Security Type Legend:`r`n") $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10) $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Green $outputBox.AppendText("WPA3: Most Secure ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Blue $outputBox.AppendText("WPA2: Secure ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Orange $outputBox.AppendText("WPA: Less Secure ") $outputBox.SelectionStart = $outputBox.TextLength $outputBox.SelectionLength = 0 $outputBox.SelectionColor = [System.Drawing.Color]::Red $outputBox.AppendText("Open: Not Secure") $outputBox.SelectionColor = [System.Drawing.Color]::Black # Enable export button $exportButton.Enabled = $script:networks.Count -gt 0 } catch { [System.Windows.Forms.MessageBox]::Show("Error during scan: $($_.Exception.Message)", "Error") } }) # End of scan button event handler # Export button event handler $exportButton.Add_Click({ Write-Host "[DEBUG] Exporting report with system info:" -ForegroundColor Yellow Write-Host " Computer Name: $($script:computerName)" -ForegroundColor Gray Write-Host " IP Address: $($script:ipAddress)" -ForegroundColor Gray Write-Host " MAC Address: $($script:mac)" -ForegroundColor Gray Write-Host " Connected SSID: $($script:connectedSSID)" -ForegroundColor Gray Write-Host " Connected BSSID: $($script:connectedBSSID)" -ForegroundColor Gray try { if ($script:networks.Count -gt 0) { $userInfo = Show-WiFiReportInfoForm if ($userInfo) { # Refresh all system info and recommendations before export $computerInfo = Get-ComputerInfoExtras $script:computerName = $computerInfo.ComputerName $script:ipAddress = $computerInfo.IPAddress $script:mac = $computerInfo.MACAddress $connected = Get-ConnectedSSID $script:connectedSSID = $connected.SSID $script:connectedBSSID = $connected.BSSID $ifaceDetails = ConvertTo-NotNull (Get-WiFiAdapterDetails) @{} $script:recommended = Get-BestChannel $script:networks $outputPath = "$PSScriptRoot\WiFiAnalyzerReport.html" Write-Host "[DEBUG][GUI] Exporting report with refreshed values:" -ForegroundColor Yellow Write-Host " Computer Name: $($script:computerName)" -ForegroundColor Gray Write-Host " IP Address: $($script:ipAddress)" -ForegroundColor Gray Write-Host " MAC Address: $($script:mac)" -ForegroundColor Gray Write-Host " Connected SSID: $($script:connectedSSID)" -ForegroundColor Gray Write-Host " Connected BSSID: $($script:connectedBSSID)" -ForegroundColor Gray Write-Host " Recommended Channels: $($script:recommended | Out-String)" -ForegroundColor Gray Write-Host " Scan Time: $script:scanDateTime" -ForegroundColor Gray Export-WiFiAnalyzerFullReport -networks $script:networks -OutputFormat 'HTML' -OutputPath $outputPath -ifaceDetails $ifaceDetails -userInfo $userInfo -mac $script:mac -computerName $script:computerName -ipAddress $script:ipAddress -connected $connected -recommended $script:recommended -scanTime $script:scanDateTime -SkipReportInfo $result = [System.Windows.Forms.MessageBox]::Show("Report exported successfully. Would you like to quit?", "Export Complete", [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Question) if ($result -eq [System.Windows.Forms.DialogResult]::Yes) { $form.Close() } } } else { [System.Windows.Forms.MessageBox]::Show("Nothing to export. Please run a scan first.", "Export Error") } } catch { [System.Windows.Forms.MessageBox]::Show("Export error: $($_.Exception.Message)", "Error") } }) # End of export button event handler # Show the form [void]$form.ShowDialog() } <# .SYNOPSIS Launches the WiFi Analyzer GUI directly without any startup screens. #> function Start-WiFiAnalyzerDirect { [CmdletBinding()] param() Write-Host "Launching WiFi Analyzer..." -ForegroundColor Cyan Get-MainWiFiAnalyzerForm Write-Host "WiFi Analyzer closed." -ForegroundColor Cyan } <# .SYNOPSIS Starts the WiFi Analyzer application with startup options. #> function Start-WiFiAnalyzer { [CmdletBinding()] param( [switch]$QuickStart, [switch]$SkipPreflightCheck ) Write-Host "WiFi Analyzer Starting..." -ForegroundColor Cyan # Check command line parameters first if ($QuickStart -or $SkipPreflightCheck) { Write-Host "Quick start mode selected" -ForegroundColor Yellow Get-MainWiFiAnalyzerForm return } # Check saved preference $savedPreference = Get-UserPreference if ($savedPreference) { Write-Host "Found saved preference: $savedPreference" -ForegroundColor Yellow switch ($savedPreference.Trim()) { "Guided" { Write-Host "Running guided setup..." -ForegroundColor Green if (Start-GuidedSetup) { Write-Host "Guided setup complete, launching main form..." -ForegroundColor Green Get-MainWiFiAnalyzerForm } else { Write-Host "Guided setup cancelled by user" -ForegroundColor Red } return } "Quick" { Write-Host "Running quick start..." -ForegroundColor Green if (Start-QuickStart) { Write-Host "Quick start complete, launching main form..." -ForegroundColor Green Get-MainWiFiAnalyzerForm } else { Write-Host "Quick start cancelled by user" -ForegroundColor Red } return } } } # No preference saved, show choice dialog Write-Host "No saved preference found, showing choice dialog..." -ForegroundColor Yellow $choice = Show-StartupChoiceDialog Write-Host "User selected: $choice" -ForegroundColor Yellow switch ($choice) { "Guided" { Write-Host "Starting Guided Setup..." -ForegroundColor Green if (Start-GuidedSetup) { Write-Host "Guided setup completed, showing main form..." -ForegroundColor Green Get-MainWiFiAnalyzerForm } else { Write-Host "Guided setup was cancelled" -ForegroundColor Red } } "Quick" { Write-Host "Starting Quick Start..." -ForegroundColor Green if (Start-QuickStart) { Write-Host "Quick start completed, showing main form..." -ForegroundColor Green Get-MainWiFiAnalyzerForm } else { Write-Host "Quick start was cancelled" -ForegroundColor Red } } "Cancel" { Write-Host "User cancelled startup dialog" -ForegroundColor Red } default { Write-Host "Unexpected choice: '$choice', launching main form anyway..." -ForegroundColor Yellow Get-MainWiFiAnalyzerForm } } Write-Host "WiFi Analyzer session ended." -ForegroundColor Cyan } # Aliases Set-Alias -Name Show-WiFiAnalyzerGUI -Value Get-MainWiFiAnalyzerForm Set-Alias -Name WiFi-Analyzer -Value Start-WiFiAnalyzer Set-Alias -Name Scan-WiFi -Value Get-WiFiScan # Note: Do NOT alias Get-WiFiNetworks to Get-WiFiScan - that would shadow # the existing code.. function Show-WiFiReportInfoForm { $form = New-Object System.Windows.Forms.Form $form.Text = "Report Info" $form.Size = New-Object System.Drawing.Size(400, 360) $form.StartPosition = "CenterScreen" $labels = @("Your Name:", "ID Number:", "Email Address:", "Telephone Number:", "Building:", "Room Number:") $textboxes = @() for ($i = 0; $i -lt $labels.Count; $i++) { $label = New-Object System.Windows.Forms.Label $label.Text = $labels[$i] $label.Location = New-Object System.Drawing.Point -ArgumentList 20, (30 + ($i * 40)) $label.Size = New-Object System.Drawing.Size(120, 20) $form.Controls.Add($label) $textbox = New-Object System.Windows.Forms.TextBox $textbox.Location = New-Object System.Drawing.Point -ArgumentList 150, (30 + ($i * 40)) $textbox.Size = New-Object System.Drawing.Size(220, 20) $form.Controls.Add($textbox) $textboxes += $textbox } $okButton = New-Object System.Windows.Forms.Button $okButton.Text = "OK" $okButton.Location = New-Object System.Drawing.Point -ArgumentList 150, 270 $okButton.Size = New-Object System.Drawing.Size(100, 30) $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.AcceptButton = $okButton $form.Controls.Add($okButton) $result = $form.ShowDialog() if ($result -eq [System.Windows.Forms.DialogResult]::OK) { return @{ Name = $textboxes[0].Text ID = $textboxes[1].Text Email = $textboxes[2].Text Phone = $textboxes[3].Text Building = $textboxes[4].Text RoomNumber = $textboxes[5].Text } } else { return $null } } function Test-ChannelCongestion { param( [Parameter(Mandatory = $true)] [PSCustomObject[]]$networks ) if (-not $networks -or $networks.Count -eq 0) { Write-Error "Test-ChannelCongestion: 'networks' parameter must be a non-empty array." return $null } $channelAnalysis = @{} $networks24GHz = $networks | Where-Object { [int]$_.Channel -le 14 } $networks5GHz = $networks | Where-Object { [int]$_.Channel -gt 14 } foreach ($network in $networks24GHz) { $channel = [int]$network.Channel $signal = [int]$network.Signal $startChannel = [Math]::Max(1, $channel - 4) $endChannel = [Math]::Min(14, $channel + 4) for ($i = $startChannel; $i -le $endChannel; $i++) { $distance = [Math]::Abs($i - $channel) $impact = $signal * (1 - ($distance / 5)) if ($channelAnalysis.ContainsKey($i)) { $channelAnalysis[$i] += $impact } else { $channelAnalysis[$i] = $impact } } } foreach ($network in $networks5GHz) { $channel = [int]$network.Channel $signal = [int]$network.Signal if ($channelAnalysis.ContainsKey($channel)) { $channelAnalysis[$channel] += $signal } else { $channelAnalysis[$channel] = $signal } } return $channelAnalysis } # Exported wrapper for manifest compliance function Export-WiFiReport { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [PSCustomObject[]]$networks, [ValidateSet('HTML', 'CSV')] [string]$OutputFormat = 'HTML', [Parameter(Mandatory = $false)] [string]$OutputPath, [Parameter(Mandatory = $false)] [object]$ifaceDetails = $null, [Parameter(Mandatory = $false)] [hashtable]$userInfo = $null, [Parameter(Mandatory = $false)] [switch]$SkipReportInfo ) Export-WiFiAnalyzerFullReport -networks $networks -OutputFormat $OutputFormat -OutputPath $OutputPath -ifaceDetails $ifaceDetails -userInfo $userInfo -SkipReportInfo $SkipReportInfo } |