PowerShell 技能连载 - 安装并试运行 Windows Terminal

Windows Terminal 是一个新的多选项卡的用于基于控制台的外壳程序。它可以通过 Microsoft Store 正式获得,当前需要 Windows 10 1903 或更高版本。

要从 Microsoft Store 安装它,您首先需要注册,这很令人沮丧。如果要匿名安装 Windows Terminal(并且已在上一个技巧中安装Chocolatey),只需从提升的 PowerShell 中运行以下代码:

1
2
3
4
5
6
7
# download installation code
$code = Invoke-WebRequest -Uri 'https://chocolatey.org/install.ps1' -UseBasicParsing
# invoke installation code
Invoke-Expression $code

# install windows terminal
choco install microsoft-windows-terminal -y

一旦 Windows Terminal 安装好,您可以通过 “wt” 命令启动它。

PowerShell 技能连载 - 安装免费的 Chocolatey 包管理器

Chocolatey 是一个软件包管理系统,可以帮助您下​​载和安装软件包。与 PowerShell Gallery 不同,Chocolatey 不仅限于 PowerShell 模块和脚本,还可以安装各种软件,包括 Notepad ++、Acrobat Reader 或 Chrome 浏览器之类的工具。

如果您准备在具有提升至完整管理员权限的 Shell 中运行 Chocolatey,则很简单。尽管有说明如何在没有完全特权的情况下使 Chocolatey 工作,但几乎肯定会遇到问题。

要在 PowerShell 中使用Chocolatey,请下载其安装脚本并运行它。这需要管理员特权:

1
2
3
4
5
# download installation code
$code = Invoke-WebRequest -Uri 'https://chocolatey.org/install.ps1' -UseBasicParsing

# invoke installation code
Invoke-Expression $code

这步之后,您可以在 PowerShell 中使用新的“choco”命令。只需确保在提升权限的 Shell 中运行即可。

可以在此处找到可安装软件包的列表(例如 Acrobat Reader 或 Google Chrome):

https://chocolatey.org/packages

例如,要安装 Chrome 浏览器,请运行以下命令:

1
choco install googlechrome -y

同样,当您从未提升的 PowerShell 中运行“choco”时,您会收到一条警告消息,并且大多数软件包将无法正确安装。

PowerShell 技能连载 - 下载 PowerShell 语言参考(或任意文件)

Invoke-WebRequest 可以轻松下载文件。下面的代码下载由 PowerShell Magazine 发布的PowerShell语言参考,并使用关联的程序将其打开:

1
2
3
4
5
6
7
8
9
10
11
12
13
$url = "https://download.microsoft.com/download/4/3/1/43113f44-548b-4dea-b471-0c2c8578fbf8/powershell_langref_v4.pdf"

# get desktop path
$desktop = [Environment]::GetFolderPath('Desktop')
$destination = "$desktop\langref.pdf"

# enable TLS1.2 for HTTPS connections
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12

# download PDF file
Invoke-WebRequest -Uri $url -OutFile $destination -UseBasicParsing
# open downloaded file in associated program
Invoke-Item -Path $destination

请注意这段代码如何启用 TLS 1.2。是否需要该协议取决于您的连接类型和防火墙。在以上示例中,并不是必须的。对于其它下载链接,可能是必须的。

PowerShell 技能连载 - 在 Windows PowerShell 和 PowerShell Core 中共享模块

许多 PowerShell 用户开始研究 PowerShell 7,并与内置的 Windows PowerShell 并行运行。

两个 PowerShell 版本都在自己的位置维护各自的 PowerShell 模块。因此当您添加新模块(即通过 Install-Module)时,需要分别对两个版本的 PowerShell 执行此操作。

不过 Windows PowerShell 和 PowerShell 7 共享同一个文件夹路径:尽管是 Windows PowerShell 引入了该目录,但 PowerShell 7 也会检查此文件夹并自动加载位于其中的模块:

C:\Program Files\WindowsPowerShell\Modules

要在两个 PowerShell 版本中同时使用某个模块,请确保将模块复制到此文件夹。使用 Install-Module 时,请使用 -Scope AllUsers(或忽略整个参数)。

由于该文件夹影响所有用户,因此该文件夹受到保护,并且您需要管理员权限才能向其中添加模块。

请注意,PowerShell 还会在另外一个路径中查找模块:

C:\Windows\system32\WindowsPowerShell\v1.0\Modules

这是所有 Microsoft 模块所在的位置。该路径也会和 PowerShell 7 共享。

PowerShell 技能连载 - 安装 ActiveDirectory 模块

这是一个对所有处理 Active Directory 的 PowerShell 用户的好消息:在最新的 Windows 10 版本(企业版、专业版)中,Microsoft 提供了 RSAT 工具,因此不需要另外下载。要将使用 AD 的 PowerShell 命令,只需启用 RSAT 功能(请参见下文)。

此外,PowerShell 7 终于原生支持 Active Directory 模块!如果您开始将新的 PowerShell 与Windows PowerShell 并行使用,则现在可以在 PowerShell 7 中使用以前仅在 Windows PowerShell 中工作的所有 AD cmdlet。

在提升权限的 PowerShell 中运行此命令,以查看可用的 RSAT 组件:

1
2
Get-WindowsCapability -Online |
Where-Object Name -like Rsat*

要使用 Active Directory 和组策略 PowerShell 模块,请启用 RSAT 功能

1
2
3
4
Get-WindowsCapability -Online |
Where-Object Name -like Rsat* |
Where-Object State -ne Installed |
Add-WindowsCapability -Online

完成后,Windows PowerShell 中将同时提供 Active DirectoryGroupPolicy PowerShell 模块。在 PowerShell 7 中,只能使用 ActiveDirectory 模块。

1
2
3
4
5
6
7
8
9
10
PS> Get-Module -Name ActiveDirectory, GroupPolicy -ListAvailable


Directory: C:\Windows\system32\WindowsPowerShell\v1.0\Modules


ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 1.0.1.0 ActiveDirectory {Add-ADCentralAccessPolicyMember, Add-ADCom...
Manifest 1.0.0.0 GroupPolicy {Backup-GPO, Block-GPInheritance, Copy-GPO...

PowerShell 技能连载 - 测试等待重启

当 Windows 安装了更新或对操作系统做了相关改变,改变可能需要在重启以后才能生效。当有一个挂起的重启时,操作系统可能不能被完全保护,而且可能无法安装其它软件。

可以通过测试指定的注册表项来确定是否有挂起的重启:

1
2
3
$rebootRequired = Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending"

"Pending reboot: $rebootRequired"

如果 $rebootRequired 的值是 $true,那么就存在一个挂起的重启。

PowerShell 技能连载 - 隐藏启动 PowerShell 脚本

没有内置的方法可以隐藏启动 PowerShell 脚本:即使您运行 powershell.exe 并指定 -WindowStyle Hidden,PowerShell 控制台仍将一闪而过。

要隐藏启动 PowerShell 脚本,可以使用 VBScript:

1
2
3
4
5
6
Set objShell = CreateObject("WScript.Shell")
path = WScript.Arguments(0)

command = "powershell -noprofile -windowstyle hidden -executionpolicy bypass -file """ & path & """"

objShell.Run command,0

将 test.vbs 保存,然后确保以 ANSI 编码保存(用记事本并在另存为对话框的地步下拉列表中选择编码)。VBS 无法处理 UTF8 编码的脚本。当您试图运行这样的脚本时,会得到一个非法字符的异常。

要隐藏启动一个 PowerShell 脚本,可以运行这行命令:

请注意,虽然 wscript.exe 隐藏了 PowerShell 的控制台窗口,但您打开任何 WPF窗口(例如使用 Out-GridView)时,将继续工作并且正常显示。

1
Wscript.exe c:\pathtovbs.vbs c:\pathtoPS1file.ps1

PowerShell 技能连载 - 杀死无响应的进程

Get-Process 返回的进程对象可以判断该进程当前是否正在响应窗口消息,从而是否正在响应用户请求。此行代码返回当前的 PowerShell 进程的 “Responding” 属性:

1
2
3
4
5
PS> Get-Process -Id $Pid | Select-Object *respond*

Responding
----------
True

进程偶尔会变得无响应是很常见的,例如由于高负载和较弱的软件体系结构。当某个进程在较长时间内没有响应时,就会“挂起”,会让用户发疯。

这行代码列出了当前未响应的进程:

1
2
3
4
5
6
7
8
9
PS> Get-Process | Where-Object { !$_.Responding }

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
560 28 21752 580 0.38 18544 1 Calculator
915 65 26660 2528 0.39 14244 1 MicrosoftEdge
488 21 7108 7988 0.09 13400 1 MicrosoftEdgeCP
543 27 16148 520 0.31 21200 1 Time
1132 77 63544 836 1.55 15212 1 WinStore.App

请注意,此列表可能包括已启动但不再使用的 Windows 应用程序。由于属性“正在响应”仅描述当前状态,因此它无法确定进程多长时间未响应。

如果您想汇报(或杀死)一段时间未响应的所有进程,则需要自己进行反复检查并跟踪结果。

下面的代码在网格视图窗口中列出了 3 秒钟没有响应的所有进程。然后,用户可以选择一个或多个要杀死的进程(按住 CTRL 键选择多个进程)。

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
# report processes hanging for more than 3 seconds
$timeout = 3

# use a hash table to keep track of processes
$hash = @{}

# use an endless loop and test processes
do
{
Get-Process |
# look at processes with a window only
Where-Object MainWindowTitle |
ForEach-Object {
# use process ID as key to the hash table
$key = $_.id
# if the process is responding, reset the counter
if ($_.Responding)
{
$hash[$key] = 0
}
# else, increment the counter by one
else
{
$hash[$key]++
}
}

# copy the hash table keys so that the collection can be
# modified
$keys = @($hash.Keys).Clone()

# emit all processes hanging for longer than $timeout seconds
# look at all processes monitored
$keys |
# take the ones not responding for the time specified in $timeout
Where-Object { $hash[$_] -gt $timeout } |
ForEach-Object {
# reset the counter (in case you choose not to kill them)
$hash[$_] = 0
# emit the process for the process ID on record
Get-Process -id $_
} |
# exclude those that already exited
Where-Object { $_.HasExited -eq $false } |
# show properties
Select-Object -Property Id, Name, StartTime, HasExited |
# show hanging processes. The process(es) selected by the user will be killed
Out-GridView -Title "Select apps to kill that are hanging for more than $timeout seconds" -PassThru |
# kill selected processes
Stop-Process -Force

# sleep for a second
Start-Sleep -Seconds 1

} while ($true)

当然,您可以轻松更改代码以生成挂起的进程报表。只需将 Stop-Process 替换为您想要执行的任何操作,即可使用 Add-Content 将流程写入日志文件。要避免一次次地记录相同的进程,您可能想要添加某种黑名单,以跟踪已经记录的进程。

PowerShell 技能连载 - 测试网络连接(第 2 部分)

如果您想测试一台特定的计算机或 URL 是否在线,几十年来一直使用 ping 请求 (ICMP)。最近,许多服务器和防火墙关闭了 ICMP 以减少攻击面。默认情况下,Test-NetConnection 使用 ICMP,因此在不响应 ICMP 的计算机上会失败:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PS> Test-NetConnection -ComputerName microsoft.com
WARNING: Ping to 40.76.4.15 failed with status: TimedOut
WARNING: Ping to 40.112.72.205 failed with status: TimedOut
WARNING: Ping to 13.77.161.179 failed with status: TimedOut
WARNING: Ping to 40.113.200.201 failed with status: TimedOut
WARNING: Ping to 104.215.148.63 failed with status: TimedOut


ComputerName : microsoft.com
RemoteAddress : 40.76.4.15
InterfaceAlias : Ethernet 4
SourceAddress : 192.168.2.108
PingSucceeded : False
PingReplyDetails (RTT) : 0 ms

Test-NetConnection 内置了另一种计算机无法回避的测试:端口测试。端口提供对特定服务的访问,因此端口必须在任何公共服务可用。对于 Web 服务器,可以使用 80 端口,例如:

1
2
3
4
5
6
7
8
9
PS> Test-NetConnection -ComputerName microsoft.com -Port 80


ComputerName : microsoft.com
RemoteAddress : 104.215.148.63
RemotePort : 80
InterfaceAlias : Ethernet 4
SourceAddress : 192.168.2.108
TcpTestSucceeded : True

以下是常用的端口列表:

HTTP: Port 80
HTTPS: Port 443
FTP: Port 21
FTPS/SSH: Port 22
TELNET: Port 23
POP3: Port 110
POP3 SSL: Port 995
IMAP: Port 143
IMAP SSL: Port 993
WMI: Port 135
RDP: Port 3389
DNS: Port 53
DHCP: Port 67, 68
SMB/NetBIOS: 139
NetBIOS over TCP: 445
PowerShell Remoting: 5985
PowerShell Remoting HTTPS: 5986