最近在配置一台Windows Server 2008 R2的服务器,本来想装上个VNC的,不过想想Windows自带有远程桌面,就没必要这么麻烦了,于是开启了远程桌面访问,并且在TMG防火墙规则中配置了RDP(Terminal Services) Server规则,一切都很顺利,当路由器上映射完3389端口后,客户端成功访问并且连接!
可是过了一段时间发现,远程连接被断开,局域网连接仍然可以,外网死活都连接不上,于是查阅了TMG防火墙日志,发现有段大量不同IP尝试连接3389的记录,并且被TMG侦测为FLOOD攻击,所以拒绝了所有的外网请求,看来不能用默认的3389端口了,所以要更改默认的远程端口,具体怎么改,其实在Windows XP时代我就尝试着找可以改动的图形化界面,可是一直找不到最后还是修改注册表才更改成功。貌似现在在Win2008时代依旧不能找到图形化修改界面,看来又要修改注册表了。主要修改以下两条注册表信息的PortNamber值:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp\
为了避免以后再遇到这类问题,我觉得有必要写个脚本来解决。我们知道在VBScript中修改注册表有两种方式,第一种是使用组件WScript.Shell的RegWrite方法,遗憾的是这种方式常常会使杀毒软件误认为是病毒,因为有段时间WScript.Shell在网页挂马技术上很是流行,导致现在很多安全软件都封杀或者重点监控这个ActvieX组件。第二种是使用WMI方式,这个是我比较推荐的,下面的脚本将说明这些问题。
在提供脚本之前,大家可以到微软的脚本中心参考一下WMI操作注册表的一些方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | ' Author : WangYe ' For more information please visit http://wangye.org/ Option Explicit Const AppTitle = "Modify RDP Port Number" Const StatusOk = 0 Const StatusInvalidPortNumber = -1 Const StatusSetRDPPortNumberFailed = -2 Const StatusSetTDSPortNumberFailed = -3 Const L_Invalid_PortNumber_Text = "ERROR : Invalid port number." Const L_User_Cancelled_Text = "User cancelled." Const HKEY_LOCAL_MACHINE = &H80000002 Const RDPTcpPath =_ "SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" Const TDSTcpPath =_ "SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp\" Class RDPTS Private strComputer Private Registry Private Sub Class_Initialize() strComputer = "." Set Registry = GetObject(_ "winmgmts:{impersonationLevel=impersonate}!\\" &_ strComputer & "\root\default:StdRegProv") End Sub Private Sub Class_Terminate() Set Registry = Nothing End Sub Function isPortAlreadyExists(portnum) ' 判断端口是否冲突(尚未实现) isPortAlreadyExists = False End Function Public Function getPortNumber(lowerbound, upperbound) If lowerbound < 4 Then lowerbound = 4 If upperbound > 65534 Then upperbound = 65535 Do Randomize getPortNumber = Int(_ (upperbound - lowerbound + 1)_ * Rnd + lowerbound) Loop Until getPortNumber<>3389_ And (Not isPortAlreadyExists(getPortNumber)) End Function Public Function isPortValid(portnum) isPortValid = False If Not IsNumeric(portnum) Then Exit Function End If If portnum < 4 Then Exit Function End If If portnum > 65534 Then Exit Function End If isPortValid = True End Function Public Function getRDPTcpPortNumber() Registry.GetDWORDValue HKEY_LOCAL_MACHINE,_ RDPTcpPath,"PortNumber",getRDPTcpPortNumber End Function Public Function getTDSTcpPortNumber() Registry.GetDWORDValue HKEY_LOCAL_MACHINE,_ TDSTcpPath,"PortNumber",getTDSTcpPortNumber End Function Public Function setRDPTcpPortNumber(portnum) On Error Resume Next setRDPTcpPortNumber = True Registry.SetDWORDValue HKEY_LOCAL_MACHINE,_ RDPTcpPath,"PortNumber",portnum If Err Then Err.Clear : setRDPTcpPortNumber = False End Function Public Function setTDSTcpPortNumber(portnum) On Error Resume Next setTDSTcpPortNumber = True Registry.SetDWORDValue HKEY_LOCAL_MACHINE,_ TDSTcpPath,"PortNumber",portnum If Err Then Err.Clear : setTDSTcpPortNumber = False End Function Public Function addFirewallPolicy(portnum, name, state) Dim netfw, policy, port, ports Set netfw = WScript.CreateObject("HNetCfg.FwMgr") Set policy = netfw.LocalPolicy.CurrentProfile Set port = WScript.CreateObject("HNetCfg.FwOpenPort") port.Port = portnum port.Name = name port.Enabled = state Set ports = policy.GloballyOpenPorts addFirewallPolicy = ports.Add(port) Set ports = Nothing Set port = Nothing Set policy = Nothing Set netfw = Nothing End Function End Class Function VBMain() VBMain = StatusOk Dim RDS, portnum, source Set RDS = New RDPTS portnum = RDS.getPortNumber(3390, 65530) source = InputBox("Original port number detected:" & vbCrLf &_ "RDP-TCP(" & RDS.getRDPTcpPortNumber() &_ "), TDS-TCP(" & RDS.getTDSTcpPortNumber() &_ ")" & vbCrLf & vbCrLf &_ "Please Enter the new port number" & vbCrLf &_ "for RDP(Terminal Services) Server", _ AppTitle, portnum) If source = "" Then WScript.Echo L_User_Cancelled_Text Exit Function End If If Not RDS.isPortValid(source) Then WScript.Echo L_Invalid_PortNumber_Text VBMain = StatusInvalidPortNumber Exit Function End If portnum = source If MsgBox("Pending changes : " & vbCrLf & vbCrLf &_ "RDP-TCP ` " & RDS.getRDPTcpPortNumber() &_ " -> " & portnum & " `" & vbCrLf &_ "TDS-TCP ` " & RDS.getTDSTcpPortNumber() &_ " -> " & portnum & " `" & vbCrLf & vbCrLf &_ "Are you sure?", vbOKCancel, AppTitle) = vbCancel Then WSH.Echo "Cancelled, No changes occured." Exit Function End If If Not RDS.setRDPTcpPortNumber(portnum) Then WSH.Echo "Set RDP-TCP port number `" &_ RDS.getRDPTcpPortNumber() & "` to `" &_ portnum & "` failed!" VBMain = StatusSetRDPPortNumberFailed Exit Function End If If Not RDS.setTDSTcpPortNumber(portnum) Then WSH.Echo "Set TDS-TCP port number `" &_ RDS.getTDSTcpPortNumber() & "` to `" &_ portnum & "` failed!" VBMain = StatusSetTDSPortNumberFailed Exit Function End If If MsgBox("Do you want add port `" & portnum &_ "` to Windows Firewall policy?", vbOKCancel, AppTitle) = vbOK Then Do source = InputBox("Enter the name for this new policy",_ AppTitle, "RDP(Terminal Services)") If source="" Then If MsgBox("Policy name required, Do you want quit Add Policy?",_ vbOKCancel, AppTitle) = VbOK Then Exit Do End If End If Loop Until source<>"" If source<>"" Then RDS.addFirewallPolicy portnum, source, 1 End If End If WScript.Echo "All done successfully!" Set RDS = Nothing End Function Call WScript.Quit(VBMain()) |
好了,上面就是全部脚本,为了兼容不带中文的外文操作系统,我这里一些提示信息使用的是英语,很简单的词汇,想必大家应该能看懂的吧。isPortAlreadyExists这个函数尚未完成,是判断端口是否被其他程序占用的,实在找不到好的办法判断,这里先空着吧。对了,我们修改完端口,可能有必要将新端口加入到Windows防火墙规则中,当然如果你关闭了Windows防火墙,这一步就可以省略,不过你可能要修改其他现有防火墙的访问规则了。不能像我一样,有一次就是远程装完ISA防火墙,结果把自己关在外面了,安装前没有配置好规则惹的祸啊。
最后,打包好的脚本(RDP-ChangePorts.zip):-)