Ilk Commit

This commit is contained in:
2026-05-06 10:43:38 +03:00
commit 2275c078eb
8 changed files with 7731 additions and 0 deletions

134
Install-Dependencies.ps1 Normal file
View File

@@ -0,0 +1,134 @@
#Requires -Version 5.1
Set-StrictMode -Version Latest
function wStep { param([string]$t); Write-Host " [>] $t" -ForegroundColor Yellow }
function wOK { param([string]$t); Write-Host " [+] $t" -ForegroundColor Green }
function wFail { param([string]$t); Write-Host " [-] $t" -ForegroundColor Red }
function wInfo { param([string]$t); Write-Host " [i] $t" -ForegroundColor Gray }
Clear-Host
Write-Host " ================================================" -ForegroundColor Cyan
Write-Host " NetworkSwitchDiscovery - Kurulum Sihirbazi" -ForegroundColor Cyan
Write-Host " ================================================" -ForegroundColor Cyan
Write-Host ""
# 1. PowerShell versiyonu
wStep "PowerShell versiyonu..."
if ($PSVersionTable.PSVersion.Major -lt 5) {
wFail "PowerShell 5.1+ gerekli. Mevcut: $($PSVersionTable.PSVersion)"; exit 1
}
wOK "PowerShell $($PSVersionTable.PSVersion) - Uyumlu"
# 2. ExecutionPolicy
wStep "ExecutionPolicy kontrol..."
$pol = Get-ExecutionPolicy -Scope CurrentUser
if ($pol -in @("Restricted","AllSigned")) {
wInfo "Policy $pol - RemoteSigned olarak degistiriliyor..."
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
wOK "ExecutionPolicy: RemoteSigned"
} else {
wOK "ExecutionPolicy: $pol (uygun)"
}
# 3. Klasor yapisi
wStep "Klasor yapisi..."
$libDir = Join-Path $PSScriptRoot "lib"
if (-not (Test-Path $libDir)) {
New-Item -ItemType Directory -Path $libDir | Out-Null
wOK "lib\ olusturuldu"
} else {
wOK "lib\ mevcut"
}
# 4. NuGet
wStep "NuGet provider..."
$nuget = Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue
if (-not $nuget -or $nuget.Version -lt [version]"2.8.5.201") {
wInfo "NuGet kuruluyor..."
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force | Out-Null
wOK "NuGet kuruldu"
} else {
wOK "NuGet: $($nuget.Version)"
}
# 5. PSGallery
wStep "PSGallery trust..."
$gal = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue
if ($gal -and $gal.InstallationPolicy -ne "Trusted") {
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
wOK "PSGallery: Trusted"
} else {
wOK "PSGallery: Trusted (zaten)"
}
# 6. Posh-SSH
wStep "Posh-SSH..."
$posh = Get-Module -ListAvailable -Name Posh-SSH | Select-Object -First 1
if (-not $posh) {
wInfo "Posh-SSH bulunamadi, kuruluyor..."
try {
Install-Module -Name Posh-SSH -Scope CurrentUser -Force -AllowClobber
wOK "Posh-SSH kuruldu"
} catch {
wFail "Posh-SSH kurulamadi: $($_.Exception.Message)"
wInfo "Manuel: Install-Module Posh-SSH -Scope CurrentUser -Force"
}
} else {
wOK "Posh-SSH v$($posh.Version) mevcut"
}
# 7. ThreadJob (PS 5.1 icin)
wStep "ThreadJob (PS 5.1 icin)..."
if ($PSVersionTable.PSVersion.Major -ge 7) {
wOK "PS 7+ - ThreadJob gereksiz, RunspacePool kullaniliyor"
} else {
$tj = Get-Module -ListAvailable -Name ThreadJob | Select-Object -First 1
if (-not $tj) {
wInfo "ThreadJob bulunamadi, kuruluyor..."
try {
Install-Module -Name ThreadJob -Scope CurrentUser -Force
wOK "ThreadJob kuruldu"
} catch {
wInfo "ThreadJob kurulamadi (opsiyonel): $($_.Exception.Message)"
}
} else {
wOK "ThreadJob v$($tj.Version) mevcut"
}
}
# 8. SharpSnmpLib (opsiyonel)
wStep "SharpSnmpLib.dll (opsiyonel)..."
$dll = Join-Path $PSScriptRoot "lib\SharpSnmpLib.dll"
if (Test-Path $dll) {
wOK "SharpSnmpLib.dll mevcut"
} else {
wInfo "SharpSnmpLib.dll yok - yerlesik UDP SNMP (v1/v2c) kullanilacak"
wInfo "v3 icin: https://www.nuget.org/packages/SharpSnmpLib"
wInfo "Indirip lib\ klasorune kopyalayin"
}
# 9. Script dosyalari
wStep "Script dosyalari..."
$ok = $true
foreach ($f in @("Invoke-SwitchDiscovery.ps1","Start-SwitchDiscovery.ps1")) {
$p = Join-Path $PSScriptRoot $f
if (Test-Path $p) { wOK "$f mevcut" }
else { wFail "$f EKSIK!"; $ok = $false }
}
Write-Host ""
Write-Host " ================================================" -ForegroundColor Cyan
if ($ok) {
Write-Host " Kurulum TAMAMLANDI!" -ForegroundColor Green
Write-Host ""
Write-Host " Baslangic:" -ForegroundColor White
Write-Host " .\Start-SwitchDiscovery.ps1" -ForegroundColor Cyan
Write-Host ""
Write-Host " Veya dogrudan:" -ForegroundColor White
Write-Host " .\Invoke-SwitchDiscovery.ps1 -IPRange '192.168.1.0/24' -Username admin" -ForegroundColor Cyan
} else {
Write-Host " UYARI: Bazi dosyalar eksik!" -ForegroundColor Yellow
}
Write-Host " ================================================" -ForegroundColor Cyan
Write-Host ""
Read-Host " Cikmak icin Enter"

578
Invoke-SwitchDiscovery.ps1 Normal file
View File

@@ -0,0 +1,578 @@
#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 }

245
README.md Normal file
View File

@@ -0,0 +1,245 @@
# 🔍 Network Switch Discovery Tool
PowerShell tabanlı, SSH + SNMP destekli, çoklu marka ağ switch keşif aracı.
Cisco, HP/Aruba, Ubiquiti/UniFi, Huawei, TP-Link ve diğer markaları otomatik olarak tespit eder.
---
## 📁 Dosya Yapısı
```
NetworkSwitchDiscovery\
├── Start-SwitchDiscovery.ps1 ← İnteraktif menü (buradan başla)
├── Invoke-SwitchDiscovery.ps1 ← Ana keşif motoru
├── discovery_config.json ← Otomatik kaydedilen ayarlar (ilk çalıştırmada oluşur)
├── lib\
│ └── SharpSnmpLib.dll ← (İsteğe bağlı) Gelişmiş SNMP desteği
└── README.md
```
---
## ⚙️ Gereksinimler
| Gereksinim | Açıklama |
|---|---|
| PowerShell 5.1+ | Windows 10/11 ile birlikte gelir |
| [Posh-SSH](https://github.com/darkoperator/Posh-SSH) | SSH bağlantısı için (otomatik kurulum menüde mevcut) |
| .NET Framework 4.7+ | SNMP UDP soketi için |
| SharpSnmpLib.dll | İsteğe bağlı, gelişmiş SNMP v3 desteği için |
---
## 🚀 Hızlı Başlangıç
### 1. PowerShell'i Yönetici Olarak Aç
```powershell
# Execution Policy (bir kez gerekli)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
### 2. Menüyü Başlat
```powershell
cd C:\Tools\NetworkSwitchDiscovery
.\Start-SwitchDiscovery.ps1
```
### 3. Veya Doğrudan Parametreli Çalıştır
```powershell
# CIDR aralığı, SSH + SNMP birlikte
.\Invoke-SwitchDiscovery.ps1 -IPRange "192.168.1.0/24" -Username admin -Method Both
# Sadece SNMP, farklı community
.\Invoke-SwitchDiscovery.ps1 -IPRange "10.0.0.1-10.0.0.50" -Method SNMP -SNMPCommunity private
# Tek IP, sadece SSH
.\Invoke-SwitchDiscovery.ps1 -IPRange "172.16.0.1" -Username admin -Password "sifre123" -Method SSH
```
---
## 📋 Parametreler
| Parametre | Varsayılan | Açıklama |
|---|---|---|
| `-IPRange` | *(zorunlu)* | CIDR, tire veya tekil IP |
| `-Username` | — | SSH kullanıcı adı |
| `-Password` | — | SSH şifre (girilmezse güvenli prompt açılır) |
| `-SNMPCommunity` | `public` | SNMP community string |
| `-SNMPVersion` | `v2c` | v1, v2c veya v3 |
| `-Method` | `Both` | SSH, SNMP veya Both |
| `-OutputPath` | Script dizini | CSV/HTML çıktı klasörü |
| `-MaxThreads` | `20` | Paralel tarama thread sayısı |
| `-SSHPort` | `22` | SSH port numarası |
| `-Timeout` | `5` | Bağlantı zaman aşımı (saniye) |
---
## 🏷️ Desteklenen Markalar ve SSH Komutları
### Cisco IOS / IOS-XE
```
terminal length 0
show version
show running-config | include hostname
```
Tespit: Banner'da `Cisco` ifadesi veya SNMP sysDescr
### HP / Aruba ProCurve
```
no page
show system information
show version
```
Tespit: `HP`, `ProCurve`, `Aruba` ifadeleri
### Ubiquiti EdgeSwitch / UniFi
```
show version
show system
```
Tespit: `Ubiquiti`, `EdgeOS`, `UniFi` ifadeleri
### MikroTik RouterOS
```
/system identity print
/system resource print
/system routerboard print
```
Tespit: `MikroTik` ifadesi
### Huawei VRP
```
screen-length 0 temporary
display version
display sysname
```
Tespit: `Huawei` ifadesi
### TP-Link / Diğer
```
show version
show system
```
Tespit: `TL-`, model kodu deseni
---
## 📡 SNMP OID Referansı
| OID | Açıklama |
|---|---|
| `1.3.6.1.2.1.1.1.0` | sysDescr — Cihaz tam açıklaması |
| `1.3.6.1.2.1.1.5.0` | sysName — Hostname |
| `1.3.6.1.2.1.1.4.0` | sysContact — İletişim bilgisi |
| `1.3.6.1.2.1.1.6.0` | sysLocation — Fiziksel konum |
| `1.3.6.1.2.1.1.3.0` | sysUpTime — Çalışma süresi |
SNMP community string varsayılan olarak `public` kullanılır.
Cihazda SNMP devre dışıysa veya community yanlışsa SNMP sütunu `Başarısız` gösterir.
---
## 📤 Çıktı Dosyaları
Her tarama sonunda iki dosya oluşturulur:
### CSV (`SwitchDiscovery_YYYYMMDD_HHmmss.csv`)
Excel veya başka araçlarda açılabilir, UTF-8 kodlamalı.
| Alan | Açıklama |
|---|---|
| IP | Cihaz IP adresi |
| Hostname | Switch hostname (SNMP/SSH'dan) |
| DNSName | DNS çözümlemesi |
| Vendor | Tespit edilen marka |
| Model | Cihaz modeli |
| FirmwareVer | IOS/Firmware versiyonu |
| SysLocation | SNMP konum bilgisi |
| SysContact | SNMP iletişim bilgisi |
| Uptime | Cihaz çalışma süresi |
| SSHStatus | Başarılı / Başarısız / Atlandı |
| SNMPStatus | Başarılı / Başarısız / Atlandı |
| SysDescr | Ham sysDescr verisi |
### HTML (`SwitchDiscovery_YYYYMMDD_HHmmss.html`)
Tarayıcıda açılan interaktif rapor:
- Anlık arama/filtreleme
- Marka renkli rozet gösterimi
- SSH/SNMP durum badgeleri
- Özet istatistik kartları
---
## 💡 Pratik Kullanım Örnekleri
```powershell
# Tüm /24 ağı tara, sonucu masaüstüne kaydet
.\Invoke-SwitchDiscovery.ps1 `
-IPRange "192.168.10.0/24" `
-Username netadmin `
-SNMPCommunity mycompany `
-Method Both `
-OutputPath "$env:USERPROFILE\Desktop" `
-MaxThreads 30
# Birden fazla switch IP'si — tire formatıyla
.\Invoke-SwitchDiscovery.ps1 `
-IPRange "10.1.1.1-10.1.1.20" `
-Username cisco `
-Method SSH `
-SSHPort 2222
# Sadece SNMP, hızlı envanter
.\Invoke-SwitchDiscovery.ps1 `
-IPRange "172.20.0.0/22" `
-Method SNMP `
-SNMPCommunity readonly `
-MaxThreads 50 `
-Timeout 3
```
---
## 🔧 Sorun Giderme
| Sorun | Çözüm |
|---|---|
| `Posh-SSH bulunamadı` | Menüden [8] seçerek otomatik kurulum yap |
| SSH bağlantı hatası | Firewall port 22'yi açık, cihazda SSH aktif mi kontrol et |
| SNMP yanıt vermiyor | Community string'i doğrula, cihazda SNMP v2c aktif mi kontrol et |
| `execution policy` hatası | `Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` çalıştır |
| Thread hatası | `-MaxThreads` değerini düşür (örn. 5) |
| Şifre prompt açılmıyor | `-Password` parametresini doğrudan ver |
---
## 🔒 Güvenlik Notları
- Şifreler `discovery_config.json` dosyasına **kaydedilmez**, her oturumda sorulur.
- SSH host anahtarları `Posh-SSH` tarafından otomatik kabul edilir (`-AcceptKey`).
Üretim ortamında host key doğrulama etkinleştirilmesi önerilir.
- SNMP v1/v2c community string düz metin iletilir. Mümkünse SNMP v3 kullan.
- Tarama yalnızca yetkili ağlarda yapılmalıdır.
---
## 📦 İsteğe Bağlı: SharpSnmpLib Kurulumu (Gelişmiş SNMP)
```powershell
# NuGet ile indir
Install-Package SharpSnmpLib -Destination .\lib
# Veya dotnet CLI
dotnet add package SharpSnmpLib
# Ardından bin\Debug\net*\SharpSnmpLib.dll dosyasını .\lib\ klasörüne kopyala
```
SharpSnmpLib olmadan araç yerleşik UDP SNMP implementasyonu kullanır (v1/v2c destekli).
---
*Mustafa Özkaya — NetworkSwitchDiscovery v1.0*

232
Start-SwitchDiscovery.ps1 Normal file
View File

@@ -0,0 +1,232 @@
#Requires -Version 5.1
Set-StrictMode -Version Latest
$ErrorActionPreference = "SilentlyContinue"
$configFile = Join-Path $PSScriptRoot "discovery_config.json"
function Write-Banner {
Clear-Host
Write-Host " ======================================================" -ForegroundColor Cyan
Write-Host " Network Switch Discovery Tool v1.1" -ForegroundColor Cyan
Write-Host " SSH + SNMP | Cisco / HP / Ubiquiti / Huawei / TP-Link" -ForegroundColor Cyan
Write-Host " ======================================================" -ForegroundColor Cyan
Write-Host ""
}
function Write-Menu {
param([hashtable]$c)
Write-Host " Mevcut Ayarlar:" -ForegroundColor DarkGray
Write-Host (" | IP Aralik : " + $c.IPRange) -ForegroundColor Gray
Write-Host (" | Kullanici : " + $c.Username) -ForegroundColor Gray
Write-Host (" | Yontem : " + $c.Method) -ForegroundColor Gray
Write-Host (" | SNMP Comm. : " + $c.SNMPCommunity) -ForegroundColor Gray
Write-Host (" | SSH Port : " + $c.SSHPort) -ForegroundColor Gray
Write-Host (" | Max Thread : " + $c.MaxThreads) -ForegroundColor Gray
Write-Host (" | Timeout (s) : " + $c.Timeout) -ForegroundColor Gray
Write-Host ""
Write-Host " +------------------------------------------+" -ForegroundColor Cyan
Write-Host " | [1] Taramayi Baslat |" -ForegroundColor White
Write-Host " | [2] IP Araligini Degistir |" -ForegroundColor White
Write-Host " | [3] SSH Kimlik Bilgilerini Gir |" -ForegroundColor White
Write-Host " | [4] SNMP Ayarlarini Duzenle |" -ForegroundColor White
Write-Host " | [5] Gelismis Ayarlar |" -ForegroundColor White
Write-Host " | [6] Yontemi Degistir (SSH/SNMP/Both) |" -ForegroundColor White
Write-Host " | [7] Profil Kaydet / Yukle |" -ForegroundColor White
Write-Host " | [8] Bagimlilik Kontrol/Kur |" -ForegroundColor White
Write-Host " | [Q] Cikis |" -ForegroundColor DarkGray
Write-Host " +------------------------------------------+" -ForegroundColor Cyan
Write-Host ""
}
function rInput {
param([string]$p,[string]$d="")
$disp = if ($d) { "$p [$d]" } else { $p }
Write-Host " $disp : " -ForegroundColor Yellow -NoNewline
$v = Read-Host
if ([string]::IsNullOrWhiteSpace($v)) { return $d }
return $v
}
function rSecret {
param([string]$p)
Write-Host " $p : " -ForegroundColor Yellow -NoNewline
$s = Read-Host -AsSecureString
return [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($s))
}
function Get-DefaultConfig {
return @{
IPRange="192.168.1.0/24"; Username="admin"; Password=""
SNMPCommunity="public"; SNMPVersion="v2c"; Method="Both"
OutputPath=$PSScriptRoot; MaxThreads=20; SSHPort=22; Timeout=5
Profiles=@{}
}
}
function Load-Config {
if (Test-Path $configFile) {
try {
$j = Get-Content $configFile -Raw | ConvertFrom-Json
$cfg = Get-DefaultConfig
foreach ($k in @("IPRange","Username","SNMPCommunity","SNMPVersion","Method","OutputPath","MaxThreads","SSHPort","Timeout")) {
if ($j.PSObject.Properties.Name -contains $k) { $cfg[$k] = $j.$k }
}
return $cfg
} catch { }
}
return Get-DefaultConfig
}
function Save-Config {
param([hashtable]$c)
$s = $c.Clone(); $s.Password = ""
$s | ConvertTo-Json -Depth 5 | Out-File $configFile -Encoding UTF8
}
function Set-IPRange {
param([hashtable]$c)
Write-Host "`n Format ornekleri:" -ForegroundColor DarkGray
Write-Host " CIDR : 192.168.1.0/24" -ForegroundColor DarkGray
Write-Host " Tire : 10.0.0.1-10.0.0.50" -ForegroundColor DarkGray
Write-Host " Tekil: 172.16.0.1" -ForegroundColor DarkGray
$c.IPRange = rInput "Yeni IP araligi" $c.IPRange
}
function Set-SSH {
param([hashtable]$c)
$c.Username = rInput "SSH Kullanici adi" $c.Username
$c.Password = rSecret "SSH Sifre (gizli)"
Write-Host " [+] SSH bilgileri guncellendi" -ForegroundColor Green
}
function Set-SNMP {
param([hashtable]$c)
$c.SNMPCommunity = rInput "Community string" $c.SNMPCommunity
Write-Host " Versiyon: [1] v1 [2] v2c [3] v3" -ForegroundColor Yellow
$v = rInput "Secim" "2"
$c.SNMPVersion = switch ($v) { "1"{"v1"} "3"{"v3"} default{"v2c"} }
}
function Set-Advanced {
param([hashtable]$c)
$c.MaxThreads = [int](rInput "Thread sayisi (1-100)" $c.MaxThreads)
$c.SSHPort = [int](rInput "SSH port" $c.SSHPort)
$c.Timeout = [int](rInput "Timeout (saniye)" $c.Timeout)
$c.OutputPath = rInput "Cikti dizini" $c.OutputPath
}
function Set-Method {
param([hashtable]$c)
Write-Host " [1] SSH [2] SNMP [3] Both" -ForegroundColor Gray
$m = rInput "Yontem" "3"
$c.Method = switch ($m) { "1"{"SSH"} "2"{"SNMP"} default{"Both"} }
Write-Host " [+] Yontem: $($c.Method)" -ForegroundColor Green
}
function Manage-Profiles {
param([hashtable]$c)
Write-Host " [1] Kaydet [2] Yukle [3] Listele" -ForegroundColor Gray
$sel = rInput "Secim" "1"
switch ($sel) {
"1" {
$n = rInput "Profil adi"
if ($n) {
if (-not $c.Profiles) { $c.Profiles = @{} }
$c.Profiles[$n] = @{
IPRange=$c.IPRange; Username=$c.Username
SNMPCommunity=$c.SNMPCommunity; Method=$c.Method
SNMPVersion=$c.SNMPVersion; SSHPort=$c.SSHPort; MaxThreads=$c.MaxThreads
}
Save-Config $c
Write-Host " [+] Profil '$n' kaydedildi" -ForegroundColor Green
}
}
"2" {
if ($c.Profiles -and $c.Profiles.Count -gt 0) {
$keys = @($c.Profiles.Keys)
for ($i=0;$i -lt $keys.Count;$i++) { Write-Host " [$($i+1)] $($keys[$i])" -ForegroundColor Gray }
$idx = [int](rInput "Profil no") - 1
if ($idx -ge 0 -and $idx -lt $keys.Count) {
$p = $c.Profiles[$keys[$idx]]
foreach ($k in $p.PSObject.Properties.Name) { $c[$k]=$p.$k }
Write-Host " [+] Yuklendi: $($keys[$idx])" -ForegroundColor Green
}
} else { Write-Host " Kayitli profil yok" -ForegroundColor DarkYellow }
}
"3" {
if ($c.Profiles -and $c.Profiles.Count -gt 0) {
$c.Profiles.Keys | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray }
} else { Write-Host " Profil yok" -ForegroundColor DarkGray }
}
}
}
function Install-Deps {
Write-Host "`n Kontrol ediliyor..." -ForegroundColor Yellow
if (Get-Module -ListAvailable -Name Posh-SSH) {
Write-Host " [+] Posh-SSH kurulu" -ForegroundColor Green
} else {
Write-Host " [-] Posh-SSH eksik" -ForegroundColor Red
$a = rInput "Kurulsun mu? (E/H)" "E"
if ($a -match '^[Ee]') {
Install-Module Posh-SSH -Scope CurrentUser -Force -AllowClobber
Write-Host " [+] Posh-SSH kuruldu" -ForegroundColor Green
}
}
if (Get-Module -ListAvailable -Name ThreadJob) {
Write-Host " [+] ThreadJob kurulu" -ForegroundColor Green
} else {
Write-Host " [!] ThreadJob eksik, kuruluyor..." -ForegroundColor Yellow
Install-Module ThreadJob -Scope CurrentUser -Force
Write-Host " [+] ThreadJob kuruldu" -ForegroundColor Green
}
$dll = Join-Path $PSScriptRoot "lib\SharpSnmpLib.dll"
if (Test-Path $dll) { Write-Host " [+] SharpSnmpLib.dll mevcut" -ForegroundColor Green }
else { Write-Host " [i] SharpSnmpLib.dll yok - yerlesik SNMP UDP kullanilir" -ForegroundColor Gray }
Read-Host "`n Devam icin Enter"
}
function Start-Discovery {
param([hashtable]$c)
if (-not $c.Password -and $c.Method -ne "SNMP") {
$c.Password = rSecret "SSH Sifre"
}
$script = Join-Path $PSScriptRoot "Invoke-SwitchDiscovery.ps1"
if (-not (Test-Path $script)) {
Write-Host " [-] Invoke-SwitchDiscovery.ps1 bulunamadi: $script" -ForegroundColor Red
Read-Host " Enter"; return
}
& $script `
-IPRange $c.IPRange `
-Username $c.Username `
-Password $c.Password `
-SNMPCommunity $c.SNMPCommunity `
-SNMPVersion $c.SNMPVersion `
-Method $c.Method `
-OutputPath $c.OutputPath `
-MaxThreads $c.MaxThreads `
-SSHPort $c.SSHPort `
-Timeout $c.Timeout
Read-Host "`n Menuye donmek icin Enter"
}
# === ANA DONGU ===========================================================
$cfg = Load-Config
while ($true) {
Write-Banner
Write-Menu -c $cfg
Write-Host " Seciminiz: " -ForegroundColor White -NoNewline
$ch = Read-Host
switch ($ch.Trim().ToUpper()) {
"1" { Start-Discovery $cfg }
"2" { Set-IPRange $cfg; Save-Config $cfg }
"3" { Set-SSH $cfg; Save-Config $cfg }
"4" { Set-SNMP $cfg; Save-Config $cfg }
"5" { Set-Advanced $cfg; Save-Config $cfg }
"6" { Set-Method $cfg; Save-Config $cfg }
"7" { Manage-Profiles $cfg }
"8" { Install-Deps }
"Q" { Write-Host "`n Gule gule!`n" -ForegroundColor Cyan; exit 0 }
default { Write-Host " [!] Gecersiz secim" -ForegroundColor Red; Start-Sleep 1 }
}
}

1
lib/README.txt Normal file
View File

@@ -0,0 +1 @@
SharpSnmpLib.dll dosyasini buraya kopyalayin

BIN
lib/SharpSnmpLib.dll Normal file

Binary file not shown.

BIN
lib/SharpSnmpLib.pdb Normal file

Binary file not shown.

6541
lib/SharpSnmpLib.xml Normal file

File diff suppressed because it is too large Load Diff