PowerShell 技能连载 - 识别位置和公共 IP
下面的示例返回您的公共 IP 地址和位置:
1 | PS> Invoke-RestMethod -Uri 'ipinfo.io/json' |
下面的示例返回您的公共 IP 地址和位置:
1 | PS> Invoke-RestMethod -Uri 'ipinfo.io/json' |
通常,当您检查网络连接时,您只能看到远程访问者使用的IP地址。IP 地址通常没有通过 DNS 解析,因此您实际上并不知道谁连接了您的计算机。
如果您想找出谁拥有未知 IP 地址,可以使用免费的 RESTful 网络服务。此行代码将显示指定 IP 地址的所有权:
1 | PS> Invoke-RestMethod -Uri 'http://ipinfo.io/51.107.59.180/json' |
将此命令与其他命令结合使用,可以找出与您的计算机进行通信的人员。例如,Get-NetTcpConnection
列出了您的网络连接,现在您可以查找谁是您所连接的 IP 地址背后的所有者。
在下面的示例中,Get-NetTcpConnection
返回所有当前活动的 HTTPS 连接(端口443)。远程 IP 被自动解析,因此您可以知道哪个软件正在保持连接,以及该软件正在与谁通信:
1 | $Process = @{ |
下面是一个实际示例:让我们转储本地管理员组。您可以按名称或不区分文化的 SID 来访问组:
RemoteAuthority RemoteAddress OwningProcess Process
--------------- ------------- ------------- -------
AS8075 Microsoft Corporation (Amsterdam) 52.114.74.221 14204 C:\Users\tobia\AppData\Local\Microsoft\Teams\current\Teams.exe
AS8075 Microsoft Corporation (Hampden Sydney) 52.114.133.169 13736 C:\Users\tobia\AppData\Local\Microsoft\Teams\current\Teams.exe
AS36459 GitHub, Inc. (Ashburn) 140.82.113.26 21588 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
AS8068 Microsoft Corporation (Redmond) 13.107.42.12 9432 C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE
AS8075 Microsoft Corporation (Zürich) 51.107.59.180 14484 C:\Program Files\PowerShell\7\pwsh.exe
AS8068 Microsoft Corporation (Redmond) 13.107.42.12 9432 C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE
AS8075 Microsoft Corporation (San Antonio) 52.113.206.137 13736 C:\Users\tobia\AppData\Local\Microsoft\Teams\current\Teams.exe
AS8075 Microsoft Corporation (Paris) 51.103.5.186 12752 C:\Users\tobia\AppData\Local\Microsoft\OneDrive\OneDrive.exe
有趣吧?
在上一个技巧中,我们介绍了 Get-NetTCPConnection
cmdlet,它是 Windows 系统上 netstat.exe 网络实用程序的更好替代方案,但是此命令仅限于 Windows,并且需要大量其他代码才能将原始信息转化为有用的信息。解析的主机名和进程名。
netstat.exe 的最兼容替代方案是基于 .NET Core 的解决方案,无论 PowerShell 在哪里运行,它都可以跨平台使用。
只需自己获取开源的 GetNetStat
模块 (https://github.com/TobiasPSP/GetNetStat),它使用 .NET Core 代码来获取连接信息:
1 | PS> Install-Module -Name GetNetStat -Scope CurrentUser |
安装模块后,将有一个名为 Get-NetStat
的新命令。现在,列出打开的连接非常简单,现在您可以在 Windows PowerShell 和 PowerShell 7 中通过并行处理来解析主机名和进程名。
这个简单的命令列出了到 HTTPS(端口 443)的所有打开的连接,并解析主机名:
1 | PS> Get-NetStat -RemotePort 443 -State Established -Resolve | Select-Object -Property RemoteIp, Pid, PidName |
在上一个技巧中,我们介绍了 Get-NetTCPConnection
cmdlet,它是 Windows 系统上网络实用程序 netstat.exe 的更好替代方法,并且通过一些技巧,您甚至可以解析 IP 地址和进程 ID。但是,这会大大降低命令的速度,因为 DNS 查找可能会花费一些时间,尤其是在网络超时的情况下。
让我们研究一下新的 PowerShell 7 并行处理功能如何加快处理速度。
以下是具有传统顺序处理的原始代码,该代码转储所有连接到端口 443 并解析主机名和进程(缓慢):
1 | $Process = @{ |
这是一种利用 PowerShell 7 中新的“并行循环”功能的方法(快速):
1 | # get all connections to port 443 (HTTPS) |
如您所见,第二种方法比以前快得多,并且是 PowerShell 7 中新的“并行循环”的好用例。
但是,不利的一面是,该代码现在的兼容性更低,只能在 Windows 系统上运行,并且只能在 PowerShell 7 中运行。在本系列的最后一部分中,我们将展示一个更简单的解决方案,该解决方案可以在所有版本的 PowerShell 上运行。
在上一个技巧中,我们介绍了 Get-NetTCPConnection
cmdlet,它是 Windows 系统上 netstat.exe 网络实用程序的更好替代方案。它可以列出打开的端口和连接,我们以列出所有与 HTTPS(端口443)的连接的示例作为总结:
1 | PS> Get-NetTCPConnection -RemotePort 443 -State Established |
该列表本身并不是很有用,因为它不能解析 IP 地址,也不会告诉您哪些程序保持着连接。但是,借助一点 PowerShell 魔术,您可以解决以下问题:
1 | $Process = @{ |
Select-Object
选择要显示的对象。它支持“计算属性”。 $Process
定义了一个名为 “Process
“ 的计算属性:它采用原始的 OwningProcess
属性,并通过 Get-Process
处理它的进程 ID,以获取应用程序的路径。
$HostName
中也会发生同样的情况:在此,用 .NET 的 GetHostEntry()
方法解析 IP 并返回解析的主机名。现在的结果如下所示:
Host OwningProcess Process
---- ------------- -------
13.107.6.171 9432 C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE
1drv.ms 9432 C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE
lb-140-82-113-26-iad.github.com 21588 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
1drv.ms 9432 C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE
52.113.206.137 13736 C:\Users\tobia\AppData\Local\Microsoft\Teams\current\Teams.exe
51.103.5.186 12752 C:\Users\tobia\AppData\Local\Microsoft\OneDrive\OneDrive.exe
不过这样做的成本可能很高,因为解析 IP 地址可能会花费很长时间,尤其是在查询超时时。在下一部分中,我们将介绍并行处理以加快处理速度。
在 Windows 系统上,netstat.exe 是一个有用的实用程序,用于检查打开的端口和侦听器。但是,该工具仅返回文本,具有隐式参数,并且无法跨平台使用。
在 Windows 系统上,可以使用名为 Get-NetTCPConnection
的新 PowerShell cmdlet,该 cmdlet 模仿 netstat.exe 中的许多功能。例如,您可以列出任何软件(浏览器)当前打开的所有 HTTPS 连接(端口443):
1 | PS> Get-NetTCPConnection -RemotePort 443 -State Established |
不幸的是,Get-NetTCPConnection
有严格的限制。例如,它无法解析 IP 地址或进程 ID,因此您无法轻松发现所连接的服务器名称以及维护连接的程序。并且仅在 Windows 系统上可用。
在接下来的部分中,让我们一一消除这些限制。
PowerShell 7 附带了一个名为 Get-Uptime
的新 cmdlet。它返回一个 timepan 对象,该对象具有自上次重新引导以来已过去的时间:
1 | PS> Get-Uptime |
提交 -Since
参数时,它将返回上次重新启动的日期。
Get-Uptime
在 Windows PowerShell 中不可用,但是自行创建此命令很简单。运行以下代码在 Windows PowerShell 中创建自己的 Get-Uptime
命令:
1 | function Get-Uptime |
通过连接类型转换的结果,您可以轻松创建字母列表:
1 | PS> [Char[]](65..90) |
从此列表中,您可以生成正在使用的驱动器号的列表:
1 | PS> [Char[]](65..90) | Where-Object { Test-Path "${_}:\" } |
同样,要查找空闲的(未使用的)驱动器号,请尝试以下操作:
1 | PS> [Char[]](65..90) | Where-Object { (Test-Path "${_}:\") -eq $false } |
Web 服务类型很多,PowerShell 可以使用 Invoke-RestMethod
访问其中的许多服务。这是一个快速入门,可帮助您起步。
这是最简单的形式,Web 服务就是上面带有结构化数据的网页。您可以在浏览器中使用相同的 URL 来查看数据。PowerShell 使用 Invoke-RestMethod
检索数据。这为您提供了最新的 PowerShell 团队博客:
1 | Invoke-RestMethod -Uri https://blogs.msdn.microsoft.com/powershell/feed/ | |
像上面的那种简单的 REST Web 服务可以接受参数。这些参数可以作为 URL 的一部分提交。这是一个可以接受任何数字并返回有关该数字的部分意义信息的 Web 服务。下次您被邀请参加 25 周年纪念日时,您可能想查询一些有关数字 25 的有趣信息:
1 | PS> Invoke-RestMethod http://numbersapi.com/25 |
其他 Web 服务通过不可见的 POST 数据传入用户数据(类似于网站上的表单数据)。它们可能还需要会话状态、cookie 和/或登录。
这是最后一个例子:
1 | # https://4bes.nl/2020/08/23/calling-a-rest-api-from-powershell/ |
哈希表类似于您要发送到 Web 服务的参数。它们将转换为 JSON 格式。由 Web 服务确定接受用户输入的格式。然后,使用 POST方法将数据传输到 Web 服务。
如果您为向指定名字的厨师发送一个请求,则会从 Web 服务中获取一条通知,告知您正在准备食品。确保更改 Cook 和 Meal 的数据。
如您所见,Invoke-RestMethod
使用了两次。第一次调用获取会话状态和 cookie,并将其存储在使用 -SessionVariable
参数定义的 $cookie
变量中。
第二个调用通过 -WebSession
参数提交会话状态。这样,Web 服务可以保留每次调用之间的状态并清楚地标识您。
当函数调用自身时,称为“递归”。当脚本想要遍历文件系统的一部分时,您会经常看到这种技术:一个函数处理文件夹内容,当它遇到子文件夹时,它会调用自身。
递归的功能很强大,但是却很难调试,并且有潜在的危险。因为当您犯错时,您将陷入无休止的循环。此外,递归深度过高时,始终存在堆栈溢出的风险。
许多通常需要递归的任务也可以通过使用“队列”来设计:当您的代码遇到新任务时,无需再次调用自身,而是将新任务放在队列中,一旦完成初始任务,开始解决队列中的任务。
感谢 Lee Holmes,这是一个遍历整个驱动器 C:\ 但不使用递归的简单示例。相反,您可以看到正在使用的队列:
1 | # get a new queue |
以下是 UMU 提供的,不用递归实现本任务的方法:
1 | [IO.Directory]::EnumerateFiles('path', '*', 1) |