PowerShell编写TCP/UDP端口扫描器时switch语句运行异常求助
问题原因
- 核心逻辑缺失:switch的1、2分支仅完成了扫描函数的定义与语法提示输出,未实现接收扫描目标、端口参数并调用函数执行的逻辑,函数定义完成后无后续操作,因此选择对应选项后无扫描动作直接结束。
- 命名不匹配:UDP分支的帮助提示写的是
test-port-udp,但实际定义的函数名为port-scan-udp,手动调用也会报错。 - 隐性错误:TCP扫描逻辑中如果
TcpClient初始化失败,后续访问$tcp.client.connected会触发空引用异常;CSV导出未指定编码容易出现乱码。
修复方案
在每个选项分支的函数定义后,增加读取用户输入参数、校验参数合法性、调用对应扫描函数的逻辑即可,同时修正命名不匹配、空引用等问题。
完整可运行代码
Write-Host "Port Scanner" function Show-Menu { param ( [string]$Title = '功能选项' ) Clear-Host Write-Host "================ $Title ================" Write-Host "1: 按 '1' 进行TCP端口扫描" Write-Host "2: 按 '2' 进行UDP端口扫描" Write-Host "Q: 按 'Q' 退出程序" } do { Show-Menu $selection = Read-Host "请选择功能" switch ($selection) { '1' { Write-Host "===== TCP端口扫描 =====" Function Scan-Port { Param([string]$computername=$env:computername, [array]$ports=@("21","22","23","25","80","443","3389") ) #关闭错误提示 $ErrorActionPreference = "SilentlyContinue" #进度条配置 $activity="端口扫描中" $status="正在扫描 $computername" $i=0 foreach ($port in $ports){ $i++ Write-Progress -Activity $activity -status $status ` -currentoperation "扫描端口: $port" -percentcomplete (($i/$ports.count)*100) #构造返回对象 $obj=New-Object PSObject $obj | Add-Member -MemberType Noteproperty -name "主机名" -value $computername.ToUpper() $obj | Add-Member -MemberType Noteproperty -name "端口" -value $port #优化TCP连接逻辑,避免空引用错误 $tcp = New-Object System.Net.Sockets.TcpClient $connectResult = $tcp.BeginConnect($computername, $port, $null, $null) $waitResult = $connectResult.AsyncWaitHandle.WaitOne(1000, $false) #1秒超时 if ($waitResult -and $tcp.Connected) { $obj | Add-Member -MemberType Noteproperty -name "端口是否开放" -value $True [string]$rep=$tcp.Client.RemoteEndPoint [string]$ip=$rep.substring(0,$rep.indexof(":")) } else { $obj | Add-Member -MemberType Noteproperty -name "端口是否开放" -value $False } Write-Output $obj $obj | Export-Csv -Append -path '.\PortScanResults.csv' -Delimiter ";" -Force -Encoding UTF8 #关闭连接 if ($tcp.Connected) { $tcp.Client.Disconnect($False) } $tcp.Close() } #end foreach Write-Progress -Activity $activity -status "扫描完成" -Completed } #end function #新增参数输入与函数调用逻辑 $computername = Read-Host "请输入要扫描的设备名(留空默认扫描本机)" if ([string]::IsNullOrWhiteSpace($computername)) { $computername = $env:computername } $portInput = Read-Host "请输入要扫描的端口,多个端口用逗号分隔(留空默认扫描21,22,23,25,80,443,3389)" $ports = if (![string]::IsNullOrWhiteSpace($portInput)) { $portInput -split ',', [StringSplitOptions]::RemoveEmptyEntries | ForEach-Object { $_.Trim() } } else { @("21","22","23","25","80","443","3389") } Write-Host "`n开始扫描,请稍候..." Scan-Port -computername $computername -ports $ports Write-Host "`n扫描完成,结果已保存到当前目录的PortScanResults.csv文件" } '2' { Write-Host "===== UDP端口扫描 =====" Function port-scan-udp { param($hosts,$ports) $out = ".\scanresults.txt" foreach($p in [array]$ports) { foreach($h in [array]$hosts) { $x = (Get-Content $out -EA SilentlyContinue | Select-String "^$h,udp,$p,") if ($x) { Get-Content $out | Select-String "^$h,udp,$p," continue } $msg = "$h,udp,$p," $u = New-Object System.Net.Sockets.UdpClient $u.Client.ReceiveTimeout = 500 $u.Connect($h,$p) #发送1字节测试包 [void]$u.Send(1,1) $l = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any,0) $r = "被过滤" try { if ($u.Receive([ref]$l)) { #收到返回包,端口开放 $r = "开放" } } catch { if ($Error[0].ToString() -match "failed to respond") { #未收到返回包,检测是否能ping通目标 if ((Get-CimInstance win32_pingstatus -Filter "address = '$h' and Timeout=1000 and ResolveAddressNames=false").StatusCode -eq 0) { #能ping通,说明端口开放 $r = "开放" } } elseif ($Error[0].ToString() -match "forcibly closed") { #收到ICMP端口不可达,端口关闭 $r = "关闭" } } $u.Close() $msg += $r Write-Host $msg $msg | Out-File -FilePath $out -Append -Encoding UTF8 } } } #新增参数输入与函数调用逻辑 $hostInput = Read-Host "请输入要扫描的目标主机,多个主机用逗号分隔" $portInput = Read-Host "请输入要扫描的UDP端口,多个端口用逗号分隔" $hosts = $hostInput -split ',', [StringSplitOptions]::RemoveEmptyEntries | ForEach-Object { $_.Trim() } $ports = $portInput -split ',', [StringSplitOptions]::RemoveEmptyEntries | ForEach-Object { $_.Trim() } if ($hosts.Count -eq 0 -or $ports.Count -eq 0) { Write-Host "错误:主机和端口不能为空" } else { Write-Host "`n开始扫描,请稍候..." port-scan-udp -hosts $hosts -ports $ports Write-Host "`n扫描完成,结果已保存到当前目录的scanresults.txt文件" } } } Write-Host "`n按回车键返回菜单..." Read-Host } until ($selection -eq 'q')
内容的提问来源于stack exchange,提问作者yalink
相关产品推荐
相关产品推荐

