# Test SSDP/UPnP discovery for Yealink phones param( [string]$IP = "172.16.1.29", [int]$DiscoveryTimeout = 5 ) # --- Test 1: SSDP M-SEARCH broadcast --- Write-Host "=== Test 1: SSDP M-SEARCH (broadcast) ===" -ForegroundColor Yellow Write-Host " Sending M-SEARCH to 239.255.255.250:1900..." -ForegroundColor DarkGray $ssdpMessage = @" M-SEARCH * HTTP/1.1 HOST: 239.255.255.250:1900 MAN: "ssdp:discover" MX: 3 ST: ssdp:all "@ $ssdpBytes = [System.Text.Encoding]::ASCII.GetBytes($ssdpMessage.Replace("`n", "`r`n")) $udpClient = New-Object System.Net.Sockets.UdpClient $udpClient.Client.ReceiveTimeout = ($DiscoveryTimeout * 1000) $udpClient.Client.SetSocketOption([System.Net.Sockets.SocketOptionLevel]::Socket, [System.Net.Sockets.SocketOptionName]::ReuseAddress, $true) $multicastEp = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Parse("239.255.255.250"), 1900) $udpClient.Send($ssdpBytes, $ssdpBytes.Length, $multicastEp) | Out-Null $responses = @() $sw = [System.Diagnostics.Stopwatch]::StartNew() while ($sw.Elapsed.TotalSeconds -lt $DiscoveryTimeout) { try { $remoteEp = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0) $data = $udpClient.Receive([ref]$remoteEp) $response = [System.Text.Encoding]::ASCII.GetString($data) $sourceIp = $remoteEp.Address.ToString() if ($response -match 'yealink|Yealink|YEALINK|SIP-T') { Write-Host " [YEALINK] Response from $sourceIp" -ForegroundColor Green Write-Host $response -ForegroundColor Cyan $responses += @{ IP = $sourceIp; Response = $response } } elseif ($sourceIp -eq $IP) { Write-Host " Response from TARGET $sourceIp" -ForegroundColor Green Write-Host $response -ForegroundColor Cyan $responses += @{ IP = $sourceIp; Response = $response } } } catch [System.Net.Sockets.SocketException] { break # Timeout } } $udpClient.Close() Write-Host " Received $($responses.Count) Yealink/target responses" -ForegroundColor DarkGray # --- Test 2: Direct SSDP to the phone's IP --- Write-Host "" Write-Host "=== Test 2: Direct SSDP M-SEARCH to $IP ===" -ForegroundColor Yellow $udpClient2 = New-Object System.Net.Sockets.UdpClient $udpClient2.Client.ReceiveTimeout = 3000 $directEp = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Parse($IP), 1900) $udpClient2.Send($ssdpBytes, $ssdpBytes.Length, $directEp) | Out-Null try { $remoteEp2 = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0) $data2 = $udpClient2.Receive([ref]$remoteEp2) $response2 = [System.Text.Encoding]::ASCII.GetString($data2) Write-Host " Response from $($remoteEp2.Address):" -ForegroundColor Green Write-Host $response2 -ForegroundColor Cyan } catch { Write-Host " No response (timeout)" -ForegroundColor DarkYellow } $udpClient2.Close() # --- Test 3: Try fetching UPnP device description if we got a LOCATION header --- Write-Host "" Write-Host "=== Test 3: UPnP device description URLs ===" -ForegroundColor Yellow # Try common UPnP description URLs $descUrls = @( "http://${IP}:1900/description.xml", "http://${IP}/description.xml", "http://${IP}:49152/description.xml", "http://${IP}:5060/description.xml", "http://${IP}/DeviceDescription.xml", "http://${IP}/upnp/description.xml" ) # Also extract LOCATION from any SSDP responses foreach ($r in $responses) { if ($r.Response -match 'LOCATION:\s*(http[^\s\r\n]+)') { $loc = $Matches[1].Trim() if ($descUrls -notcontains $loc) { $descUrls = @($loc) + $descUrls } } } [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } [System.Net.ServicePointManager]::Expect100Continue = $false # Enable unsafe header parsing $netAssembly = [System.Reflection.Assembly]::GetAssembly([System.Net.Configuration.SettingsSection]) if ($netAssembly) { $settingsType = $netAssembly.GetType("System.Net.Configuration.SettingsSectionInternal") if ($settingsType) { $bf = [System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::GetProperty -bor [System.Reflection.BindingFlags]::NonPublic $instance = $settingsType.InvokeMember("Section", $bf, $null, $null, @()) if ($instance) { $field = $settingsType.GetField("useUnsafeHeaderParsing", [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance) if ($field) { $field.SetValue($instance, $true) } } } } foreach ($url in $descUrls) { Write-Host " Trying: $url" -ForegroundColor DarkGray -NoNewline try { $req = [System.Net.HttpWebRequest]::Create($url) $req.Timeout = 3000 $req.UserAgent = "UPnP/1.0" $resp = $req.GetResponse() $reader = New-Object System.IO.StreamReader($resp.GetResponseStream()) $body = $reader.ReadToEnd() $reader.Close() $resp.Close() Write-Host " -> OK ($($body.Length) chars)" -ForegroundColor Green Write-Host $body -ForegroundColor Cyan # Save if it looks like XML device description if ($body -match 'serialNumber|modelName|manufacturer') { Write-Host "" Write-Host " [FOUND] Device description with useful fields!" -ForegroundColor Green $body | Out-File "C:\temp\yealink_upnp.xml" -Encoding UTF8 } } catch { Write-Host " -> FAIL" -ForegroundColor Red } } # --- Test 4: Try SNMP if available --- Write-Host "" Write-Host "=== Test 4: SNMP probe (community: public) ===" -ForegroundColor Yellow Write-Host " Trying SNMPv2c GET on common OIDs..." -ForegroundColor DarkGray # Build a simple SNMPv2c GET request for sysDescr (1.3.6.1.2.1.1.1.0) # This is a minimal hand-crafted SNMP packet $snmpGet = [byte[]]@( 0x30, 0x29, # SEQUENCE, length 41 0x02, 0x01, 0x01, # INTEGER: version = 1 (SNMPv2c) 0x04, 0x06, # OCTET STRING: community 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, # "public" 0xA0, 0x1C, # GET-REQUEST, length 28 0x02, 0x04, 0x01, 0x02, 0x03, 0x04, # request-id 0x02, 0x01, 0x00, # error-status: 0 0x02, 0x01, 0x00, # error-index: 0 0x30, 0x0E, # varbind list 0x30, 0x0C, # varbind 0x06, 0x08, # OID 0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, # 1.3.6.1.2.1.1.1.0 (sysDescr) 0x05, 0x00 # NULL ) try { $snmpClient = New-Object System.Net.Sockets.UdpClient $snmpClient.Client.ReceiveTimeout = 3000 $snmpEp = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Parse($IP), 161) $snmpClient.Send($snmpGet, $snmpGet.Length, $snmpEp) | Out-Null $snmpRemote = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0) $snmpData = $snmpClient.Receive([ref]$snmpRemote) $snmpResponse = [System.Text.Encoding]::ASCII.GetString($snmpData) Write-Host " SNMP response received ($($snmpData.Length) bytes)" -ForegroundColor Green # Try to extract readable text from the response $readable = ($snmpData | ForEach-Object { if ($_ -ge 32 -and $_ -le 126) { [char]$_ } else { "." } }) -join "" Write-Host " Readable: $readable" -ForegroundColor Cyan $snmpClient.Close() } catch { Write-Host " No SNMP response (timeout or blocked)" -ForegroundColor DarkYellow }