579 lines
30 KiB
PowerShell
579 lines
30 KiB
PowerShell
#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") { '<span class="ok">SSH OK</span>' }elseif ($r.SSHStatus -eq "Atlandi") { '<span class="sk">SSH -</span>' }else { '<span class="fl">SSH X</span>' }
|
|
$s3 = if ($r.TelnetStatus -eq "Basarili") { '<span class="ok">TELNET OK</span>' }elseif ($r.TelnetStatus -eq "Atlandi") { '<span class="sk">TELNET -</span>' }else { '<span class="fl">TELNET X</span>' }
|
|
$s2 = if ($r.SNMPStatus -eq "Basarili") { '<span class="ok">SNMP OK</span>' }elseif ($r.SNMPStatus -eq "Atlandi") { '<span class="sk">SNMP -</span>' }else { '<span class="fl">SNMP X</span>' }
|
|
[void]$sb.Append("<tr><td><code>$($r.IP)</code></td><td><b>$($r.Hostname)</b><br><small>$($r.DNSName)</small></td><td>$($r.Vendor)</td><td>$($r.Model)</td><td><small>$($r.FirmwareVer)</small></td><td><small>$($r.SysLocation)</small></td><td>$s1 $s3 $s2</td></tr>`n")
|
|
}
|
|
$lines = [System.Collections.Generic.List[string]]::new()
|
|
$lines.Add('<!DOCTYPE html><html lang="tr"><head><meta charset="UTF-8"><title>Switch Discovery</title><style>')
|
|
$lines.Add('*{box-sizing:border-box;margin:0;padding:0}body{font-family:Segoe UI,sans-serif;background:#0f1117;color:#e2e8f0;padding:2rem}')
|
|
$lines.Add('h1{font-size:1.5rem;color:#63b3ed;margin-bottom:.25rem}.meta{font-size:.8rem;color:#718096;margin-bottom:1.5rem}')
|
|
$lines.Add('.stats{display:flex;gap:1rem;margin-bottom:1.5rem;flex-wrap:wrap}.stat{background:#1a202c;border:1px solid #2d3748;border-radius:8px;padding:.75rem 1.25rem}')
|
|
$lines.Add('.val{font-size:1.4rem;font-weight:700;color:#68d391}.lbl{font-size:.75rem;color:#718096}')
|
|
$lines.Add('table{width:100%;border-collapse:collapse;font-size:.85rem}thead tr{background:#1a202c}')
|
|
$lines.Add('th{padding:.75rem 1rem;text-align:left;color:#63b3ed;border-bottom:2px solid #2d3748}')
|
|
$lines.Add('td{padding:.6rem 1rem;border-bottom:1px solid #1e2533;vertical-align:middle}tr:hover td{background:#1a202c}')
|
|
$lines.Add('code{background:#2d3748;padding:2px 6px;border-radius:4px;color:#90cdf4}small{color:#718096}')
|
|
$lines.Add('span{display:inline-block;padding:2px 7px;border-radius:4px;font-size:.7rem;font-weight:600;margin:1px}')
|
|
$lines.Add('.ok{background:#1c4532;color:#68d391}.fl{background:#4a1515;color:#fc8181}.sk{background:#2d3748;color:#718096}')
|
|
$lines.Add('input{background:#1a202c;border:1px solid #2d3748;color:#e2e8f0;padding:6px 10px;border-radius:6px;width:280px;font-size:.85rem}.fb{margin-bottom:1rem}')
|
|
$lines.Add('</style></head><body><h1>Network Switch Discovery Raporu</h1>')
|
|
$lines.Add("<div class=`"meta`">Olusturulma: $genDate | IP: $IPRange | Yontem: $Method</div>")
|
|
$lines.Add("<div class=`"stats`"><div class=`"stat`"><div class=`"val`">$total</div><div class=`"lbl`">Toplam</div></div><div class=`"stat`"><div class=`"val`">$sshOK</div><div class=`"lbl`">SSH Basarili</div></div><div class=`"stat`"><div class=`"val`">$telnetOK</div><div class=`"lbl`">Telnet Basarili</div></div><div class=`"stat`"><div class=`"val`">$snmpOK</div><div class=`"lbl`">SNMP Basarili</div></div></div>")
|
|
$lines.Add('<div class="fb"><input id="s" oninput="f()" placeholder="Filtrele..."></div>')
|
|
$lines.Add('<table id="t"><thead><tr><th>IP</th><th>Hostname</th><th>Marka</th><th>Model</th><th>Firmware</th><th>Konum</th><th>Durum</th></tr></thead><tbody>')
|
|
$lines.Add($sb.ToString())
|
|
$lines.Add('</tbody></table><script>function f(){var q=document.getElementById("s").value.toLowerCase();document.querySelectorAll("#t tbody tr").forEach(function(r){r.style.display=r.textContent.toLowerCase().includes(q)?"":"none"})}</script></body></html>')
|
|
[System.IO.File]::WriteAllLines($outPath, $lines, [System.Text.UTF8Encoding]::new($false))
|
|
Write-OK "HTML: $outPath"; return $outPath
|
|
}
|
|
|
|
# ================================================================ ANA AKIS
|
|
Clear-Host
|
|
Write-Host " =====================================================" -ForegroundColor Cyan
|
|
Write-Host " Network Switch Discovery Tool v1.2" -ForegroundColor Cyan
|
|
Write-Host " SSH + SNMP | Cisco / HP / Ubiquiti / Huawei / TP-Link" -ForegroundColor Cyan
|
|
Write-Host " =====================================================" -ForegroundColor Cyan
|
|
|
|
if ($Method -ne "SNMP" -and -not $Password) {
|
|
if (-not $Username) { $Username = Read-Host " SSH Kullanici adi" }
|
|
$sp = Read-Host " SSH Sifre" -AsSecureString
|
|
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sp))
|
|
}
|
|
|
|
Test-Dependencies
|
|
|
|
Write-Header "IP Araligi Cozumleniyor"
|
|
Write-Step "Aralik: $IPRange"
|
|
$allIPs = Resolve-IPRange -Range $IPRange
|
|
Write-OK "$($allIPs.Count) IP belirlendi"
|
|
|
|
$aliveHosts = Get-AliveHosts -IPs $allIPs
|
|
if ($aliveHosts.Count -eq 0) { Write-Fail "Canli host yok."; exit 1 }
|
|
|
|
Write-Header "Cihaz Bilgisi Toplama"
|
|
Write-Info "Yontem: $Method | Canli: $($aliveHosts.Count)"
|
|
|
|
$scriptRoot = $PSScriptRoot
|
|
$pool2 = [runspacefactory]::CreateRunspacePool(1, $MaxThreads)
|
|
$pool2.Open()
|
|
$jobs2 = [System.Collections.Generic.List[hashtable]]::new()
|
|
|
|
$funcDefs = "
|
|
function Invoke-SNMPQuery { ${function:Invoke-SNMPQuery} }
|
|
function Get-Vendor { ${function:Get-Vendor} }
|
|
function Get-Model { ${function:Get-Model} }
|
|
function Get-DeviceViaSNMP { ${function:Get-DeviceViaSNMP} }
|
|
function Get-DeviceViaSSH { ${function:Get-DeviceViaSSH} }
|
|
function Get-DeviceViaTelnet { ${function:Get-DeviceViaTelnet} }
|
|
function Get-DNS { ${function:Get-DNS} }
|
|
function Merge-Info { ${function:Merge-Info} }
|
|
"
|
|
|
|
$discoverScript = [scriptblock]::Create('
|
|
param($ip,$method,$user,$pass,$comm,$port,$tout)
|
|
' + $funcDefs + '
|
|
$sshR=$null; $snmpR=$null; $telR=$null
|
|
if($method -in @("SSH","Both","All")) { $sshR = Get-DeviceViaSSH $ip $user $pass $port }
|
|
if($method -in @("Telnet","Both","All")) { $telR = Get-DeviceViaTelnet $ip $user $pass 23 }
|
|
if($method -in @("SNMP","Both","All")) { $snmpR = Get-DeviceViaSNMP $ip $comm }
|
|
return (Merge-Info $sshR $telR $snmpR $ip)
|
|
')
|
|
|
|
foreach ($ip in $aliveHosts) {
|
|
$ps = [powershell]::Create()
|
|
$ps.RunspacePool = $pool2
|
|
[void]$ps.AddScript($discoverScript).AddArgument($ip).AddArgument($Method).AddArgument($Username).AddArgument($Password).AddArgument($SNMPCommunity).AddArgument($SSHPort).AddArgument($Timeout)
|
|
$jobs2.Add(@{ PS = $ps; Handle = $ps.BeginInvoke(); IP = $ip; Done = $false })
|
|
}
|
|
|
|
$allResults = [System.Collections.Generic.List[object]]::new()
|
|
$total = $jobs2.Count
|
|
$done = 0
|
|
$startTime = [datetime]::UtcNow
|
|
$lastPrint = [datetime]::MinValue # konsol satirlari icin debounce
|
|
|
|
Write-Host ""
|
|
|
|
while ($done -lt $total) {
|
|
# O an islenen IP'leri goster
|
|
if (([datetime]::UtcNow - $lastPrint).TotalSeconds -ge 1) {
|
|
$runningIPs = $jobs2 | Where-Object { -not $_.Done } | Select-Object -ExpandProperty IP
|
|
$runningStr = ($runningIPs | Select-Object -First 3) -join ", "
|
|
if ($runningIPs.Count -gt 3) { $runningStr += " ve $($runningIPs.Count - 3) daha..." }
|
|
|
|
$pct = if ($total -gt 0) { [math]::Round($done / $total * 100) } else { 0 }
|
|
Write-Progress `
|
|
-Activity "Switch kesfi - $done/$total tamamlandi" `
|
|
-Status ("Islenen cihazlar: $runningStr") `
|
|
-PercentComplete $pct
|
|
|
|
$lastPrint = [datetime]::UtcNow
|
|
}
|
|
|
|
foreach ($j in $jobs2) {
|
|
if ($j.Done) { continue }
|
|
if ($j.Handle.IsCompleted) {
|
|
$r = $j.PS.EndInvoke($j.Handle)
|
|
$j.PS.Dispose()
|
|
$j.Done = $true
|
|
$done++
|
|
|
|
$rObj = $null
|
|
if ($r -and $r.Count -gt 0) { $rObj = $r[0] }
|
|
|
|
# Bulunan cihaz bilgisini al
|
|
$foundIP = $j.IP
|
|
$vendor = if ($rObj -and $rObj.Vendor -and $rObj.Vendor -ne "Bilinmiyor") { $rObj.Vendor } else { "?" }
|
|
$model = if ($rObj -and $rObj.Model -and $rObj.Model -ne "Bilinmiyor") { $rObj.Model } else { "" }
|
|
$hostname = if ($rObj -and $rObj.Hostname -and $rObj.Hostname -ne "") { $rObj.Hostname } else { "" }
|
|
$sshStat = if ($rObj -and $rObj.SSHStatus) { $rObj.SSHStatus } else { "Atlandi" }
|
|
$telStat = if ($rObj -and $rObj.TelnetStatus) { $rObj.TelnetStatus } else { "Atlandi" }
|
|
$snmpStat = if ($rObj -and $rObj.SNMPStatus) { $rObj.SNMPStatus } else { "Atlandi" }
|
|
|
|
if ($rObj) { $allResults.Add($rObj) }
|
|
|
|
# --- ETA hesabi
|
|
$elapsed = ([datetime]::UtcNow - $startTime).TotalSeconds
|
|
$avgPerJob = if ($done -gt 0) { $elapsed / $done } else { 0 }
|
|
$remaining = $total - $done
|
|
$etaSec = [math]::Round($avgPerJob * $remaining)
|
|
$etaStr = if ($etaSec -gt 3600) { "{0}s {1}d {2}sn" -f [math]::Floor($etaSec / 3600), [math]::Floor(($etaSec % 3600) / 60), ($etaSec % 60) }
|
|
elseif ($etaSec -gt 60) { "{0}d {1}sn" -f [math]::Floor($etaSec / 60), ($etaSec % 60) }
|
|
else { "${etaSec}sn" }
|
|
|
|
# --- Renk secimi
|
|
$lineColor = if ($sshStat -eq "Basarili" -or $snmpStat -eq "Basarili" -or $telStat -eq "Basarili") { "Green" } else { "DarkGray" }
|
|
|
|
# --- Konsola yazdir
|
|
$pctDone = [math]::Round($done / $total * 100)
|
|
$bar = ("#" * [math]::Floor($pctDone / 5)).PadRight(20)
|
|
$hostPart = if ($hostname) { " ($hostname)" } else { "" }
|
|
$modPart = if ($model) { " $model" } else { "" }
|
|
|
|
Write-Host (" [{0,3}%] [{1}] {2}/{3} {4,-16}{5}{6}{7} | Kalan ~{8}" -f `
|
|
$pctDone, $bar, $done, $total,
|
|
$foundIP, $hostPart, " $vendor", $modPart,
|
|
$etaStr) -ForegroundColor $lineColor
|
|
}
|
|
}
|
|
if ($done -lt $total) { Start-Sleep -Milliseconds 200 }
|
|
}
|
|
|
|
$pool2.Close(); $pool2.Dispose()
|
|
Write-Progress -Activity "Switch kesfi..." -Completed
|
|
|
|
# Ozet satiri
|
|
$elapsed = [math]::Round(([datetime]::UtcNow - $startTime).TotalSeconds)
|
|
$sshFound = ($allResults | Where-Object { $_.SSHStatus -eq "Basarili" }).Count
|
|
$telFound = ($allResults | Where-Object { $_.TelnetStatus -eq "Basarili" }).Count
|
|
$snmpFound = ($allResults | Where-Object { $_.SNMPStatus -eq "Basarili" }).Count
|
|
Write-Host ""
|
|
Write-Host (" Tamamlandi: {0} cihaz taranadi | SSH:{1} Telnet:{2} SNMP:{3} Sure:{4}sn" -f $total, $sshFound, $telFound, $snmpFound, $elapsed) -ForegroundColor Cyan
|
|
|
|
$sorted = $allResults | Sort-Object { [System.Version]$_.IP }
|
|
|
|
Write-Header "Kesif Sonuclari"
|
|
$sorted | Format-Table -AutoSize -Property IP, Hostname, Vendor, Model, FirmwareVer, SSHStatus, TelnetStatus, SNMPStatus
|
|
|
|
Write-Header "Disari Aktarma"
|
|
$csv = Export-ToCSV $sorted $OutputPath
|
|
$html = Export-ToHTML $sorted $OutputPath
|
|
|
|
Write-Header "Tamamlandi"
|
|
Write-OK "Toplam: $($sorted.Count) cihaz"
|
|
|
|
$ans = Read-Host "`n HTML raporu acilsin mi? (E/H)"
|
|
if ($ans -match '^[Ee]') { Start-Process $html }
|