#Requires -Version 5.1 [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$IPRange, [Parameter(Mandatory = $false)] [string]$Username = "", [Parameter(Mandatory = $false)] [string]$Password = "", [Parameter(Mandatory = $false)] [string]$SNMPCommunity = "public", [ValidateSet("v1", "v2c", "v3")] [string]$SNMPVersion = "v2c", [ValidateSet("SSH", "SNMP", "Telnet", "Both", "All")] [string]$Method = "All", [string]$OutputPath = $PSScriptRoot, [ValidateRange(1, 100)] [int]$MaxThreads = 20, [int]$SSHPort = 22, [int]$Timeout = 5 ) Set-StrictMode -Version Latest $ErrorActionPreference = "SilentlyContinue" function Write-Header { param([string]$t); Write-Host "`n$('-'*60)" -ForegroundColor DarkCyan; Write-Host " $t" -ForegroundColor Cyan; Write-Host "$('-'*60)" -ForegroundColor DarkCyan } function Write-Step { param([string]$t); Write-Host " [>] $t" -ForegroundColor Yellow } function Write-OK { param([string]$t); Write-Host " [+] $t" -ForegroundColor Green } function Write-Fail { param([string]$t); Write-Host " [-] $t" -ForegroundColor Red } function Write-Info { param([string]$t); Write-Host " [i] $t" -ForegroundColor Gray } function Test-Dependencies { Write-Header "Bagimlilik Kontrolu" $missing = @() if (-not (Get-Module -ListAvailable -Name Posh-SSH)) { Write-Fail "Posh-SSH bulunamadi"; $missing += "Posh-SSH" } else { Write-OK "Posh-SSH mevcut" } $script:SnmpLibAvailable = $false $dll = Join-Path $PSScriptRoot "lib\SharpSnmpLib.dll" if (Test-Path $dll) { Add-Type -Path $dll -ErrorAction SilentlyContinue $script:SnmpLibAvailable = $true Write-OK "SharpSnmpLib.dll mevcut" } else { Write-Info "SharpSnmpLib.dll yok - yerlesik UDP SNMP kullanilacak" } if ($missing.Count -gt 0) { Write-Host "`n Eksik: Install-Module Posh-SSH -Scope CurrentUser -Force" -ForegroundColor Magenta $ans = Read-Host " Simdi kurulsun mu? (E/H)" if ($ans -match '^[Ee]') { foreach ($m in $missing) { Write-Step "$m kuruluyor..." Install-Module -Name $m -Scope CurrentUser -Force -AllowClobber Write-OK "$m kuruldu" } } } } function Resolve-IPRange { param([string]$Range) $ips = [System.Collections.Generic.List[string]]::new() if ($Range -match '^(\d{1,3}(?:\.\d{1,3}){3})/(\d{1,2})$') { $bytes = [System.Net.IPAddress]::Parse($Matches[1]).GetAddressBytes() [array]::Reverse($bytes) $ipInt = [System.BitConverter]::ToUInt32($bytes, 0) $prefix = [int]$Matches[2] $mask = [uint32]([math]::Pow(2, 32) - [math]::Pow(2, 32 - $prefix)) $net = $ipInt -band $mask $count = [math]::Pow(2, 32 - $prefix) for ($i = 1; $i -lt ($count - 1); $i++) { $b = [System.BitConverter]::GetBytes([uint32]($net + $i)); [array]::Reverse($b) $ips.Add(([System.Net.IPAddress]::new($b)).ToString()) } } elseif ($Range -match '^(\d{1,3}(?:\.\d{1,3}){3})-(\d{1,3}(?:\.\d{1,3}){3})$') { $sb = [System.Net.IPAddress]::Parse($Matches[1]).GetAddressBytes(); [array]::Reverse($sb) $eb = [System.Net.IPAddress]::Parse($Matches[2]).GetAddressBytes(); [array]::Reverse($eb) $s = [System.BitConverter]::ToUInt32($sb, 0); $e = [System.BitConverter]::ToUInt32($eb, 0) for ($i = $s; $i -le $e; $i++) { $b = [System.BitConverter]::GetBytes([uint32]$i); [array]::Reverse($b) $ips.Add(([System.Net.IPAddress]::new($b)).ToString()) } } elseif ($Range -match '^\d{1,3}(?:\.\d{1,3}){3}$') { $ips.Add($Range) } else { throw "Gecersiz IP formati: $Range" } return $ips } function Get-AliveHosts { param([System.Collections.Generic.List[string]]$IPs) Write-Header "Canli Host Taramasi (Ping)" Write-Info "Toplam $($IPs.Count) IP taranacak..." $pool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads) $pool.Open() $jobs = [System.Collections.Generic.List[hashtable]]::new() foreach ($ip in $IPs) { $ps = [powershell]::Create() $ps.RunspacePool = $pool [void]$ps.AddScript({ param($ip, $t) try { $ping = [System.Net.NetworkInformation.Ping]::new() $r = $ping.Send($ip, $t * 1000) if ($r.Status -eq 'Success') { return $ip } } catch { } return $null }).AddArgument($ip).AddArgument($Timeout) $jobs.Add(@{ PS = $ps; Handle = $ps.BeginInvoke() }) } $alive = [System.Collections.Generic.List[string]]::new() foreach ($j in $jobs) { $result = $j.PS.EndInvoke($j.Handle) if ($result) { $alive.Add($result) } $j.PS.Dispose() } $pool.Close(); $pool.Dispose() Write-OK "$($alive.Count) canli host bulundu" return ($alive | Sort-Object { [System.Version]$_ }) } function Invoke-SNMPQuery { param([string]$IP, [string]$Community, [string]$OID) $parts = $OID.TrimStart('.').Split('.') | ForEach-Object { [int]$_ } function eLen([int]$n) { if ($n -lt 128) { return [byte[]]@($n) } $bl = [System.Collections.Generic.List[byte]]::new(); $tmp = $n while ($tmp -gt 0) { $bl.Insert(0, [byte]($tmp -band 0xFF)); $tmp = $tmp -shr 8 } return [byte[]](@([byte](0x80 + $bl.Count)) + $bl) } function eInt([int]$v) { $bl = [System.Collections.Generic.List[byte]]::new(); $tmp = $v do { $bl.Insert(0, [byte]($tmp -band 0xFF)); $tmp = $tmp -shr 8 }while ($tmp -gt 0) if ($bl[0] -band 0x80) { $bl.Insert(0, [byte]0) } return [byte[]](@([byte]0x02) + (eLen $bl.Count) + $bl) } function eOID([int[]]$p) { $enc = [System.Collections.Generic.List[byte]]::new() $enc.Add([byte](40 * $p[0] + $p[1])) for ($i = 2; $i -lt $p.Count; $i++) { $v = $p[$i] if ($v -lt 128) { $enc.Add([byte]$v) } else { $sub = [System.Collections.Generic.List[byte]]::new() while ($v -gt 0) { $sub.Insert(0, [byte]($v -band 0x7F)); $v = $v -shr 7 } for ($j = 0; $j -lt $sub.Count - 1; $j++) { $sub[$j] = [byte]($sub[$j] -bor 0x80) } foreach ($b in $sub) { $enc.Add($b) } } } return [byte[]](@([byte]0x06) + (eLen $enc.Count) + $enc) } try { $oidB = [byte[]](eOID $parts) $nul = [byte[]]@(0x05, 0x00) $vb = [byte[]](@([byte]0x30) + (eLen($oidB.Count + $nul.Count)) + $oidB + $nul) $vbl = [byte[]](@([byte]0x30) + (eLen $vb.Count) + $vb) $cb = [System.Text.Encoding]::ASCII.GetBytes($Community) $cf = [byte[]](@([byte]0x04) + (eLen $cb.Count) + $cb) $ver = eInt 1; $rid = eInt(Get-Random -Min 1 -Max 99999); $es = eInt 0; $ei = eInt 0 $pdu = [byte[]](@([byte]0xA0) + (eLen($rid.Count + $es.Count + $ei.Count + $vbl.Count)) + $rid + $es + $ei + $vbl) $msg = [byte[]]($ver + $cf + $pdu) $pkt = [byte[]](@([byte]0x30) + (eLen $msg.Count) + $msg) $udp = [System.Net.Sockets.UdpClient]::new() $udp.Client.ReceiveTimeout = 2000 $ep = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Parse($IP), 161) [void]$udp.Send($pkt, $pkt.Count, $ep) $rem = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any, 0) $resp = $udp.Receive([ref]$rem); $udp.Close() $skip = $true for ($i = 0; $i -lt $resp.Count - 2; $i++) { if ($resp[$i] -eq 0x04 -and $resp[$i + 1] -gt 0 -and $resp[$i + 1] -lt 200) { $len = $resp[$i + 1]; $st = $i + 2 if (($st + $len) -le $resp.Count) { if ($skip) { $skip = $false; $i = $st + $len - 1; continue } $val = [System.Text.Encoding]::ASCII.GetString($resp, $st, $len).Trim() if ($val -match '\S') { return $val } } } } } catch { } return $null } function Get-Vendor { param([string]$d) if (-not $d) { return "Bilinmiyor" } $dl = $d.ToLower() if ($dl -match "cisco|sg[1-5]\d{2}|cbs\d{3}|catalyst|nexus") { return "Cisco" } if ($dl -match "hp|hewlett|procurve|aruba") { return "HP/Aruba" } if ($dl -match "ubiquiti|unifi|edgeswitch") { return "Ubiquiti" } if ($dl -match "mikrotik") { return "MikroTik" } if ($dl -match "huawei") { return "Huawei" } if ($dl -match "tp-link|tplink") { return "TP-Link" } if ($dl -match "juniper") { return "Juniper" } if ($dl -match "dell|force10") { return "Dell" } if ($dl -match "netgear") { return "Netgear" } if ($dl -match "zyxel") { return "ZyXEL" } if ($dl -match "dlink|d-link") { return "D-Link" } return "Bilinmiyor" } function Get-Model { param([string]$desc, [string]$vendor) if (-not $desc) { return "Bilinmiyor" } switch ($vendor) { "Cisco" { if ($desc -match '(?i)(Catalyst\s*[\w-]+)') { return $Matches[1].Trim() } if ($desc -match '(?i)\b(C\d{4}[A-Za-z0-9-]*|SG[1-5]\d{2}[A-Za-z0-9-]*|CBS\d{3}[A-Za-z0-9-]*|Nexus\s*[\w-]+|N\d{4}[A-Za-z0-9-]*)\b') { return $Matches[1].Trim() } if ($desc -match '(?i)Cisco\s+(?!IOS\b)([\w-]+)') { return $Matches[1].Trim() } } "HP/Aruba" { if ($desc -match 'HP\s+([\w\s-]+?)(?:\s*,|\s*Switch|\s*$)') { return $Matches[1].Trim() } } "Ubiquiti" { if ($desc -match 'EdgeSwitch\s+([\w-]+)') { return "EdgeSwitch $($Matches[1])" } if ($desc -match 'UniFi\s+([\w-]+)') { return "UniFi $($Matches[1])" } } "Huawei" { if ($desc -match 'Huawei\s+([\w-]+)') { return $Matches[1] } } "TP-Link" { if ($desc -match '(TL-[\w-]+)') { return $Matches[1] } } } if ($desc -cmatch '\b([A-Z]{1,5}[\w-]{2,15})\b') { $m = $Matches[1] if ($m -notmatch '(?i)^(User|Password|System|Switch|Terminal|Length|Screen|Display|Show|Version|Login|Name|Host|Line|Console|Ethernet|Vlan|Port|Interface)$') { return $m } } return "Bilinmiyor" } function Get-DeviceViaSNMP { param([string]$IP, [string]$Community) $info = [PSCustomObject]@{IP = "$IP"; Hostname = ""; Vendor = "Bilinmiyor"; Model = "Bilinmiyor"; SysDescr = ""; SysContact = ""; SysLocation = ""; FirmwareVer = ""; Method = "SNMP"; Status = "Basarisiz"; Error = "" } try { $sysDescr = Invoke-SNMPQuery $IP $Community "1.3.6.1.2.1.1.1.0" $sysName = Invoke-SNMPQuery $IP $Community "1.3.6.1.2.1.1.5.0" $sysContact = Invoke-SNMPQuery $IP $Community "1.3.6.1.2.1.1.4.0" $sysLocation = Invoke-SNMPQuery $IP $Community "1.3.6.1.2.1.1.6.0" if ($sysDescr -or $sysName) { $info.SysDescr = "$sysDescr"; $info.Hostname = "$sysName" $info.SysContact = "$sysContact"; $info.SysLocation = "$sysLocation" $info.Vendor = Get-Vendor $sysDescr $m = Get-Model $sysDescr $info.Vendor if ($info.Hostname -and $m -eq $info.Hostname) { $info.Model = "Bilinmiyor" } else { $info.Model = $m } $info.Status = "Basarili" } else { $info.Error = "SNMP yanit vermedi" } } catch { $info.Error = "$($_.Exception.Message)" } return $info } function Get-DeviceViaSSH { param([string]$IP, [string]$User, [string]$Pass, [int]$Port) $info = [PSCustomObject]@{IP = "$IP"; Hostname = ""; Vendor = "Bilinmiyor"; Model = "Bilinmiyor"; SysDescr = ""; SysContact = ""; SysLocation = ""; FirmwareVer = ""; Method = "SSH"; Status = "Basarisiz"; Error = "" } if (-not (Get-Module -ListAvailable -Name Posh-SSH)) { $info.Error = "Posh-SSH yuklu degil"; return $info } Import-Module Posh-SSH -ErrorAction SilentlyContinue try { $secPass = ConvertTo-SecureString $Pass -AsPlainText -Force $cred = [System.Management.Automation.PSCredential]::new($User, $secPass) $session = New-SSHSession -ComputerName $IP -Credential $cred -Port $Port -AcceptKey -ConnectionTimeout($Timeout * 1000) -ErrorAction Stop if (-not $session) { $info.Error = "SSH oturumu acilamadi"; return $info } $stream = $session.Session.CreateShellStream("xterm", 80, 24, 800, 600, 1024) Start-Sleep -Milliseconds 1500; $banner = $stream.Read() $vendor = "Unknown" if ($banner -match "Cisco") { $vendor = "Cisco" } elseif ($banner -match "HP|ProCurve|Aruba") { $vendor = "HP/Aruba" } elseif ($banner -match "Ubiquiti|EdgeOS") { $vendor = "Ubiquiti" } elseif ($banner -match "MikroTik") { $vendor = "MikroTik" } elseif ($banner -match "Huawei") { $vendor = "Huawei" } $cmds = switch ($vendor) { "Cisco" { @("terminal length 0", "show version", "show running-config | include hostname") } "HP/Aruba" { @("no page", "show system information", "show version") } "Ubiquiti" { @("show version", "show system") } "MikroTik" { @("/system identity print", "/system resource print", "/system routerboard print") } "Huawei" { @("screen-length 0 temporary", "display version", "display sysname") } default { @("show version", "show system", "uname -a") } } $out = "" foreach ($cmd in $cmds) { $stream.WriteLine($cmd); Start-Sleep -Milliseconds 800; $out += $stream.Read() } if ($out) { $cleanOut = $out -replace '\x1B\[[0-9;?]*[a-zA-Z]', '' $info.SysDescr = (($cleanOut -split "`n" | Select-Object -First 3) -join " ").Trim() if ($cleanOut -match '(?im)(?:hostname|sysname)[:\s]+([^\r\n]+)') { $info.Hostname = $Matches[1].Trim() } else { $pMatches = [regex]::Matches($cleanOut, '[<\[]*([A-Za-z0-9_-]{3,})[#>\]]') if ($pMatches.Count -gt 0) { $info.Hostname = $pMatches[$pMatches.Count - 1].Groups[1].Value.Trim() } } $info.Vendor = if ($vendor -ne "Unknown") { $vendor }else { Get-Vendor $cleanOut } $m = Get-Model $cleanOut $info.Vendor if ($info.Hostname -and $m -eq $info.Hostname) { $info.Model = "Bilinmiyor" } else { $info.Model = $m } if ($cleanOut -match '(?i)Version[:\s]+([\d\.A-Za-z\(\)]+)') { $info.FirmwareVer = $Matches[1] } $info.Status = "Basarili" } } catch { $info.Error = "$($_.Exception.Message)" } return $info } function Get-DeviceViaTelnet { param([string]$IP, [string]$User, [string]$Pass, [int]$Port = 23) $info = [PSCustomObject]@{IP = "$IP"; Hostname = ""; Vendor = "Bilinmiyor"; Model = "Bilinmiyor"; SysDescr = ""; SysContact = ""; SysLocation = ""; FirmwareVer = ""; Method = "Telnet"; Status = "Basarisiz"; Error = "" } try { $tcp = [System.Net.Sockets.TcpClient]::new() $res = $tcp.BeginConnect($IP, $Port, $null, $null) $wait = $res.AsyncWaitHandle.WaitOne(3000) if (-not $wait -or -not $tcp.Connected) { $info.Error = "Port kapali veya zaman asimi"; return $info } $tcp.EndConnect($res) $stream = $tcp.GetStream() $reader = [System.IO.StreamReader]::new($stream, [System.Text.Encoding]::ASCII) $writer = [System.IO.StreamWriter]::new($stream, [System.Text.Encoding]::ASCII) $writer.AutoFlush = $true $sb = [System.Text.StringBuilder]::new() $start = [datetime]::UtcNow $loggedIn = $false while (([datetime]::UtcNow - $start).TotalSeconds -lt 5) { if ($stream.DataAvailable) { while ($stream.DataAvailable) { [void]$sb.Append([char]$stream.ReadByte()) } $out = $sb.ToString() if ($out -match "(?i)username:|login:") { $writer.WriteLine($User); Start-Sleep -Milliseconds 500; $sb.Clear() } elseif ($out -match "(?i)password:") { $writer.WriteLine($Pass); Start-Sleep -Milliseconds 500; $sb.Clear() } elseif ($out -match ">|#") { $loggedIn = $true; break } } else { Start-Sleep -Milliseconds 200 } } if (-not $loggedIn) { $writer.WriteLine(""); Start-Sleep -Milliseconds 500 } $cmds = @("terminal length 0", "screen-length 0 temporary", "no page", "show version", "show system", "display version") foreach ($cmd in $cmds) { $writer.WriteLine($cmd); Start-Sleep -Milliseconds 500 while ($stream.DataAvailable) { [void]$sb.Append([char]$stream.ReadByte()) } } $tcp.Close() $fullOut = $sb.ToString() if ($fullOut -match '\S') { $cleanOut = $fullOut -replace '\x1B\[[0-9;?]*[a-zA-Z]', '' $info.SysDescr = (($cleanOut -split "`n" | Select-Object -First 3) -join " ").Trim() if ($cleanOut -match '(?im)(?:hostname|sysname)[:\s]+([^\r\n]+)') { $info.Hostname = $Matches[1].Trim() } else { $pMatches = [regex]::Matches($cleanOut, '[<\[]*([A-Za-z0-9_-]{3,})[#>\]]') if ($pMatches.Count -gt 0) { $info.Hostname = $pMatches[$pMatches.Count - 1].Groups[1].Value.Trim() } } $info.Vendor = Get-Vendor $cleanOut $m = Get-Model $cleanOut $info.Vendor if ($info.Hostname -and $m -eq $info.Hostname) { $info.Model = "Bilinmiyor" } else { $info.Model = $m } if ($cleanOut -match '(?i)Version[:\s]+([\d\.A-Za-z\(\)]+)') { $info.FirmwareVer = $Matches[1] } $info.Status = "Basarili" } } catch { $info.Error = "$($_.Exception.Message)" } return $info } function Get-DNS { param([string]$IP) try { return([System.Net.Dns]::GetHostEntry($IP)).HostName }catch { return "" } } function Merge-Info { param($ssh, $telnet, $snmp, [string]$ip) $m = [PSCustomObject]@{IP = "$ip"; Hostname = ""; DNSName = (Get-DNS $ip); Vendor = "Bilinmiyor"; Model = "Bilinmiyor"; FirmwareVer = ""; SysLocation = ""; SysContact = ""; SSHStatus = "Atlandi"; TelnetStatus = "Atlandi"; SNMPStatus = "Atlandi"; SysDescr = "" } if ($snmp) { $m.SNMPStatus = $snmp.Status; if ($snmp.Status -eq "Basarili") { $m.Hostname = $snmp.Hostname; $m.Vendor = $snmp.Vendor; $m.Model = $snmp.Model; $m.SysLocation = $snmp.SysLocation; $m.SysContact = $snmp.SysContact; $m.SysDescr = $snmp.SysDescr } } if ($telnet) { $m.TelnetStatus = $telnet.Status; if ($telnet.Status -eq "Basarili") { if (-not $m.Hostname) { $m.Hostname = $telnet.Hostname }; if ($m.Vendor -eq "Bilinmiyor") { $m.Vendor = $telnet.Vendor }; if ($m.Model -eq "Bilinmiyor") { $m.Model = $telnet.Model }; if (-not $m.FirmwareVer) { $m.FirmwareVer = $telnet.FirmwareVer } } } if ($ssh) { $m.SSHStatus = $ssh.Status; if ($ssh.Status -eq "Basarili") { if (-not $m.Hostname) { $m.Hostname = $ssh.Hostname }; if ($m.Vendor -eq "Bilinmiyor") { $m.Vendor = $ssh.Vendor }; if ($m.Model -eq "Bilinmiyor") { $m.Model = $ssh.Model }; if (-not $m.FirmwareVer) { $m.FirmwareVer = $ssh.FirmwareVer } } } if ((-not $m.Hostname) -and $m.DNSName) { $m.Hostname = $m.DNSName } return $m } function Export-ToCSV { param($res, [string]$path) $ts = Get-Date -Format "yyyyMMdd_HHmmss"; $out = Join-Path $path "SwitchDiscovery_$ts.csv" $res | Select-Object IP, Hostname, DNSName, Vendor, Model, FirmwareVer, SysLocation, SysContact, SSHStatus, TelnetStatus, SNMPStatus, SysDescr | Export-Csv -Path $out -NoTypeInformation -Encoding UTF8 Write-OK "CSV: $out"; return $out } function Export-ToHTML { param($res, [string]$path) $ts = Get-Date -Format "yyyyMMdd_HHmmss"; $outPath = Join-Path $path "SwitchDiscovery_$ts.html" $genDate = Get-Date -Format "dd.MM.yyyy HH:mm:ss" $total = $res.Count $sshOK = ($res | Where-Object { $_.SSHStatus -eq "Basarili" }).Count $telnetOK = ($res | Where-Object { $_.TelnetStatus -eq "Basarili" }).Count $snmpOK = ($res | Where-Object { $_.SNMPStatus -eq "Basarili" }).Count $sb = [System.Text.StringBuilder]::new() foreach ($r in $res) { $s1 = if ($r.SSHStatus -eq "Basarili") { 'SSH OK' }elseif ($r.SSHStatus -eq "Atlandi") { 'SSH -' }else { 'SSH X' } $s3 = if ($r.TelnetStatus -eq "Basarili") { 'TELNET OK' }elseif ($r.TelnetStatus -eq "Atlandi") { 'TELNET -' }else { 'TELNET X' } $s2 = if ($r.SNMPStatus -eq "Basarili") { 'SNMP OK' }elseif ($r.SNMPStatus -eq "Atlandi") { 'SNMP -' }else { 'SNMP X' } [void]$sb.Append("
$($r.IP)| IP | Hostname | Marka | Model | Firmware | Konum | Durum |
|---|