You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 08:15:04