PowerShell 技能连载 - 避免使用 Get-EventLog

Get-EventLog 是 Windows PowerShell 中非常受欢迎的 cmdlet。通过仅使用几个简单的参数,它可以从主要的 Windows 事件日志中读取事件日志。然而,这个 cmdlet 使用的技术不仅很慢,而且越来越危险。

Get-EventLog 在查找正确的事件消息时存在困难,所以过去经常得不到有意义的消息。然而,越来越频繁地,Get-EventLog 返回完全无关的错误消息,这可能会触发错误警报。就像这个例子:

1
2
3
4
5
6
PS> Get-EventLog -Source Microsoft-Windows-Kernel-General -Newest 2 -LogName System -InstanceId 1

Index Time EntryType Source InstanceID Message
----- ---- --------- ------ ---------- -------
551590 Jun 01 17:57 Information Microsoft-Windows-Kernel-General 1 Possible detection of CVE: 2023-06-01T15:57:15.025483...
551505 Mai 31 17:57 Information Microsoft-Windows-Kernel-General 1 Possible detection of CVE: 2023-05-31T15:57:13.842816...

CVE 检测是安全问题或入侵的指示器。你可不想成为那个在最后引发混乱的人,结果发现一切只是误报。任何其他工具都会返回相应的事件消息,正如官方替代 Get-EventLog 的工具: Get-WinEvent 也是如此:

1
2
3
4
5
6
7
8
9
10
11
PS> Get-WinEvent -FilterHashtable @{
ProviderName = 'Microsoft-Windows-Kernel-General'
LogName = 'System'
Id = 1
} -MaxEvents 2

ProviderName: Microsoft-Windows-Kernel-General
TimeCreated Id LevelDisplayName Message
----------- -- ---------------- -------
01.06.2023 17:57:15 1 Information The system time has changed to ‎2023‎-‎06‎-‎01T15:57:15.025483100Z from ‎2023‎-‎06‎-‎01T1...
31.05.2023 17:57:13 1 Information The system time has changed to ‎2023‎-‎05‎-‎31T15:57:13.842816200Z from ‎2023‎-‎05‎-‎31T1...

实际上,与 CVE 检测和安全问题不同,系统时间被调整了。

以后在脚本中不要再使用 Get-EventLog(除非你百分之百确定所关心的事件不受其缺点影响),而是要熟悉 Get-WinEvent:它更快、更多功能,并且还可以读取导出的事件文件。

PowerShell 技能连载 - 星座计算器(又称“Sternzeichen”)

想过自动将日期转换成星座吗?这里有一个非常简单的脚本,可以帮你实现这个功能,支持英文和德文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
param (
[Parameter(Mandatory)]
[DateTime]$Date
)

$cutoff = $Date.toString('"0000-"MM-dd')
'Zodiac,Sternzeichen,StartDate
Capricorn,Steinbock,0000-01-20
Aquarius,Wassermann,0000-01-21
Pisces,Fische,0000-02-20
Aries,Widder,0000-03-21
Taurus,Stier,0000-04-21
Gemini,Zwillinge,0000-05-21
Cancer,Krebs,0000-06-22
Leo,Löwe,0000-07-23
Virgo,Jungfrau,0000-08-23
Libra,Waage,0000-09-23
Scorpio,Skorpion,0000-10-23
Sagittarius,Schütze,0000-11-22' |
ConvertFrom-Csv |
Where-Object StartDate -lt $cutoff |
Select-Object -Last 1

PowerShell 技能连载 - 从 DateTime 中生成日期

这里有一种简单通用的方法,可以将 `DateTime`` 信息转换为你所需的 ISO 字符串数据组件。例如,如果你只需要日期和月份,而不关心年份,可以按照以下方式操作:

1
2
PS> (Get-Date).ToString('"0000-"MM-dd')
0000-06-02

(Get-Date) 表示当前日期,但可以替换为任何 `DateTime`` 对象:

1
2
3
4
PS> $anyDate = Get-Date -Date '2024-12-24 19:22:11'

PS> $anyDate.ToString('"0000-"MM-dd')
0000-12-24

假设你需要过去 48 小时内的所有错误和警告,但是从上午 8 点 45 分开始计算。以下是计算方法:

1
2
PS> (Get-Date).AddHours(-48).ToString('yyyy-MM-dd "08:45:00"')
2023-05-31 08:45:00

基本上,您可以使用 ToString() 方法,并使用区分大小写的 .NET DateTime 占位符(例如,’yyyy’ 表示以 4位数字显示的年份)来组合所需的日期和时间字符串表示形式,再加上您自己控制的固定文本。请确保将固定文本放在额外引号中。

PowerShell 技能连载 - PowerShell 脚本未经确认无法运行

当你在 Windows 中右键单击任何 PowerShell 脚本时,上下文菜单会出现“使用 PowerShell 运行”的选项。然而,当你选择这个选项时,可能会看到一个 PowerShell 控制台弹出,询问关于“执行策略”的奇怪问题。让我们明确一点:这与你个人的执行策略设置无关,这些通常控制着 PowerShell 脚本是否可以运行。

相反,上下文菜单命令运行它自己的代码。你可以在 Windows 注册表中查找:

1
2
3
4
$path = 'HKEY_CLASSES_ROOT\SystemFileAssociations\.ps1\Shell\0\Command'
$name = ''
$value = Get-ItemProperty -Path "Registry::$path" -Name $name
$value.'(default)'

而这就是每当您调用它时上下文菜单命令运行的内容:

1
2
3
4
5
if((Get-ExecutionPolicy ) -ne 'AllSigned') 
{
Set-ExecutionPolicy -Scope Process Bypass -Force
}
& '%1'

所以基本上,除非你使用的是超严格的执行策略 “AllSigned“(几乎没有人这样做),否则执行策略会在临时情况下(仅限于此次调用)设置为 “Bypass“,以允许你运行右键单击的脚本文件。实际上,执行策略会稍微放宽一些,使得即使在未定义明确的执行策略的系统上也可以使用上下文菜单命令。

然而,Set-ExecutionPolicy 有向用户询问回复的倾向,在这里可能会导致烦人的提示框出现。用户真的不想每次使用此上下文菜单命令启动某个脚本时都被问到“确定吗?”

要解决这个问题,只需调整所述注册表键中的代码。在调用 Set-ExecutionPolicy 时添加 “-Force“ 参数,这样该 cmdlet 就能够进行调整而无需提问。

PowerShell 技能连载 - 选择最佳的文件格式(第 4 部分)

在之前的部分中,我们回顾了不同的文件类型以持久化数据,并了解了用于读写这些文件的 cmdlets。

今天,让我们将这些知识应用到一个真实的数据文件中,你可以自己创建它(前提是你拥有一台带有 Windows 系统的笔记本电脑,并带有电池供电)。

1
2
$Path = "$env:temp\battery.xml"
powercfg.exe /batteryreport /duration 1 /output $path /xml

运行这行代码后,它会生成一个包含所有电池信息的XML文件,包括设计容量和实际容量,这样你就可以查看电池的状态是否良好。从前面的代码示例中选择适当的代码,读取XML文件的内容:

1
2
3
4
5
# path to XML file:
$Path = "$env:temp\battery.xml"

# read file and convert to XML:
[xml]$xml = Get-Content -Path $Path -Raw -Encoding UTF8

接下来,在您喜爱的编辑器中,通过在$xml中添加“.”来探索XML的对象结构,并查看 IntelliSense 或通过简单地输出变量来查看,这样 PowerShell 会打印下一个级别的属性名称。

通过这种方式,我找到了电池容量信息:

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
PS> $xml

xml xml-stylesheet BatteryReport
--- -------------- -------------
version="1.0" encoding="utf-8" type='text/xsl' href='C:\battery-stylesheet.xsl' BatteryReport

PS> $xml.BatteryReport

xmlns : http://schemas.microsoft.com/battery/2012
ReportInformation : ReportInformation
SystemInformation : SystemInformation
Batteries : Batteries
RuntimeEstimates : RuntimeEstimates
RecentUsage : RecentUsage
History : History
EnergyDrains :

PS> $xml.BatteryReport.Batteries
Battery
-------
Battery

PS> $xml.BatteryReport.Batteries.Battery

Id : DELL XX3T797
Manufacturer : BYD
SerialNumber : 291
ManufactureDate :
Chemistry : LiP
LongTerm : 1
RelativeCapacity : 0
DesignCapacity : 49985
FullChargeCapacity : 32346
CycleCount : 0

现在我们可以将所有部分组合成一个脚本,返回面向对象的电池磨损信息(确保您的系统有电池,否则会出现红色异常):

1
2
3
4
5
6
7
8
9
10
# temp path to XML file:
$Path = "$env:temp\battery$(Get-Date -Format yyyyMMddHHmmssffff).xml"
# generate XML file
powercfg.exe /batteryreport /duration 1 /output $path /xml
# read file and convert to XML:
[xml]$xml = Get-Content -Path $Path -Raw -Encoding UTF8
# remove temporary file:
Remove-Item -Path $Path
# show battery infos:
$xml.BatteryReport.Batteries.Battery

只需非常少的努力,相同的内容可以成为一个有用的新命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
function Get-BatteryCapacity
{
# temp path to XML file:
$Path = "$env:temp\battery$(Get-Date -Format yyyyMMddHHmmssffff).xml"
# generate XML file
powercfg.exe /batteryreport /duration 1 /output $path /xml
# read file and convert to XML:
[xml]$xml = Get-Content -Path $Path -Raw -Encoding UTF8
# remove temporary file:
Remove-Item -Path $Path
# show battery infos:
$xml.BatteryReport.Batteries.Battery
}

现在轻松检查电池磨损:

1
2
3
4
5
6
7
PS> Get-BatteryCapacity | Select-Object Id, Manufacturer, FullChargeCapacity, DesignCapacity

Id Manufacturer FullChargeCapacity DesignCapacity

-- ------------ ------------------ --------------

DELL XX3T797 BYD 32346 49985

使用哈希表,Select-Object 现在甚至可以计算剩余电池容量的百分比(但这是我们今天不会深入探讨的另一个话题):

1
2
3
4
5
PS> Get-BatteryCapacity | Select-Object Id, Manufacturer, FullChargeCapacity, @{N='Remain';E={'{0:P}' -f ($_.FullChargeCapacity/$_.DesignCapacity)}}
Id Manufacturer FullChargeCapacity Remain
-- ------------ ------------------ ------

DELL XX3T797 BYD 32346 64,71 %

PowerShell 技能连载 - 选择最佳的文件格式(第 3 部分)

PowerShell 支持多种文本文件格式,那么保存和读取数据的最佳方法是什么呢?

在本系列的前两部分中,我们提供了一个实用的指南,帮助您根据数据的性质选择最佳文件格式(和适当的 cmdlet)。

当您决定使用 XML 作为数据格式时,您会发现内置的 Export/Import-CliXml cmdlet 是将 您自己的对象 保存到 XML 文件和反向操作的简单方法。但是如果您需要处理来自您自己未创建的源的 XML 数据,该怎么办呢?让我们来看一下名为“Xml”的 cmdlet:ConvertTo-Xml。它可以将任何对象转换为 XML 格式:

1
2
3
4
5
PS> Get-Process -Id $pid | ConvertTo-Xml

xml Objects
--- -------
version="1.0" encoding="utf-8" Objects

结果是XML,只有在将其存储在变量中时才有意义,这样您可以检查XML对象并输出XML字符串表示:

1
2
3
4
5
6
7
8
9
10
PS> $xml = Get-Process -Id $pid | ConvertTo-Xml
PS> $xml.OuterXml
<?xml version="1.0" encoding="utf-8"?><Objects><Object Type="System.Diagnostics.Process"><Property Name="Name"
Type="System.String">powershell_ise</Property><Property Name="SI" Type="System.Int32">1</Property><Property N
ame="Handles" Type="System.Int32">920</Property><Property Name="VM" Type="System.Int64">5597831168</Property><
Property Name="WS" Type="System.Int64">265707520</Property><Property Name="PM" Type="System.Int64">229797888</
Property><Property Name="NPM" Type="System.Int64">53904</Property><Property Name="Path" Type="System.String">C
:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe</Property><Property Name="Company" Type="System.S
tring">Microsoft Corporation</Property><Property Name="CPU" Type="System.Double">3,984375</Property><Property
Name="FileVersion" Type="System.String">10.0.19041.1 (WinBuild.160101.0800)</Property><Property Name="Produc...

虽然没有 Export-Xml 的命令,但你可以轻松地创建自己的 Export-CliXml,将对象持久化到文件中,而无需使用专有的“CliXml”结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# data to be persisted in XML:
$Data = Get-Process | Select-Object -First 10 # let's take 10 random processes,
# can be any data
# destination path for XML file:
$Path = "$env:temp\result.xml"

# take original data
$Data |
# convert each item into an XML object but limit to 2 levels deep
ConvertTo-Xml -Depth 2 |
# pass the string XML representation which is found in property
# OuterXml
Select-Object -ExpandProperty OuterXml |
# save to plain text file with appropriate encoding
Set-Content -Path $Path -Encoding UTF8

notepad $Path

要走相反的路线,将XML转换回对象,没有 ConvertFrom-Xml`` - 因为这个功能已经内置在类型 [Xml]` 中。要将上面的示例文件转换回对象,您可以执行以下操作(假设您使用上面的示例代码创建了result.xml文件):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# path to XML file:
$Path = "$env:temp\result.xml"

# read file and convert to XML:
[xml]$xml = Get-Content -Path $Path -Raw -Encoding UTF8

# dive into the XML object model (which happens to start
# in this case with root properties named "Objects", then
# "Object":
$xml.Objects.Object |
# next, examine each object found here:
ForEach-Object {
# each object describes all serialized properties
# in the form of an array of objects with properties
# "Name" (property name), "Type" (used data type),
# and "#text" (property value).
# One simple way of finding a specific entry
# in this array is to use .Where{}:
$Name = $_.Property.Where{$_.Name -eq 'Name'}.'#text'
$Id = $_.Property.Where{$_.Name -eq 'Id'}.'#text'
$_.Property | Out-GridView -Title "Process $Name (ID $Id)"
}

这段代码可以读取(任何)XML文件并将XML转换为对象。你可以使用这个模板来读取和处理几乎任何XML文件。

话虽如此,要使用这些数据,你需要了解它的内部结构。在我们的示例中,我们”序列化”了10个进程对象。结果发现,Convert-Xml 通过描述所有属性来保存这些对象。上面的代码演示了如何首先获取序列化对象(在 .Objects.Object` 中找到),然后如何读取属性信息(在 .Property` 中作为对象数组,每个属性一个对象)。

PowerShell 技能连载 - 选择最适当的文件格式(第 1 部分)

PowerShell支持各种文本文件格式,那么保存和读取数据的最佳方法是什么呢?

这主要取决于数据的类型,下面是实际指南的第一部分:

  • 一维数据:当数据只有一个维度,例如服务器名称列表时,最好将其保存为纯文本文件。首选的命令是使用“Content”名词的命令:Get-Content 用于读取,Set-Content 用于写入,Add-Content 用于追加。纯文本文件存储字符串数组。注意事项:在保存和读取时,需要使用相同的文本编码,因此最好使用 UTF-8 编码。注意事项#2:如果您想将字符串数组文件内容读取到变量中,添加 -ReadCount 0 参数。这比默认方式快很多倍。
  • 二维数据:列和行形式的数据最好保存为CSV格式。首选的命令是使用“Csv”名词的命令:Export-CsvImport-Csv。CSV 文件存储对象数组。CSV 列名定义了对象属性。注意事项:由于 CSV 基于文本,请确保主动选择良好的文本编码,如 UTF-8。注意事项#2:CSV 文件可以使用许多不同的分隔符,因此要么使用 -Delimiter 来始终定义分隔符,要么使用-UseCulture,如果您希望自动选择的分隔符与其他应用程序在同一系统上匹配,例如,当您计划稍后在 Microsoft Excel 中打开 CSV 文件时。

PowerShell 技能连载 - 测试驱动 PowerShellGet 版本 3

PowerShellGet 是一个模块,包含重要的 cmdlet,比如 Install-Module,因此该模块实际上是下载和安装其他模块的先决条件,即从 powershellgallery.com 下载和安装模块的先决条件。

终于,期待已久的第 3 版该模块作为预览版在 PowerShell Gallery 中可用,有很多理由说明你应该使用这个新版本。

以下是安装步骤:

1
PS> Install-Module -Name PowerShellGet -AllowPrerelease -Scope CurrentUser

你应该更新的一个原因是,你可能再也无法这样做了。很可能你的 Install-Module cmdlet 缺少 -AllowPrerelease 参数,因此无法安装任何预发布模块。对于任何使用语义版本的现代模块都是如此。

悲伤的事实是,PowerShellGet 在 Windows 10/11 映像中的初始版本 1.0.0.1 中被包含进去,并且从那时起从未自动更新。版本 1.0.0.1 现在已经过时,无法在许多情况下正常工作。

为了解决这个问题,你应该先手动强制安装 PowerShellGet 2.x。这将安装你安装 PowerShellGet 3.x 所需的先决条件:

1
PS> Install-Module -Name PowerShellGet -Scope CurrentUser -Force -AllowClobber

运行这行命令并重新启动 PowerShell 后,Install-Module 应该具有 -AllowPrelease 参数,因此现在你可以运行第一个代码行并安装 PowerShellGet 3.x。

最终,PowerShellGet 3 版将希望解决所有这些问题,并为 PowerShell 的模块交换机制提供更强大的支持。

PowerShell 技能连载 - SpeculationControl:使用 PowerShell 检查风险

微软几年前发布了一个模块(最近 3 周更新),您可以使用该模块来检测您的硬件是否容易受到 Spectre 和 Meltdown 威胁的攻击。要尝试这个功能,请从 PowerShell Gallery 安装该模块:

1
Install-Module -Name SpeculationControl -Scope CurrentUser

要运行测试套件并查看结果,请输入以下命令:

1
PS> Get-SpeculationControlSettings

这将显示您的计算机的测试结果,可能类似于以下内容:

For more information about the output below, please refer to https://support.microsoft.com/help/4074629

Speculation control settings for CVE-2017-5715 [branch target injection]

Hardware support for branch target injection mitigation is present: True
Windows OS support for branch target injection mitigation is present: True
Windows OS support for branch target injection mitigation is enabled: True

Speculation control settings for CVE-2017-5754 [rogue data cache load]

Hardware is vulnerable to rogue data cache load: False

Hardware requires kernel VA shadowing: False

Speculation control settings for CVE-2018-3639 [speculative store bypass]

Hardware is vulnerable to speculative store bypass: True
Hardware support for speculative store bypass disable is present: True
Windows OS support for speculative store bypass disable is present: True
Windows OS support for speculative store bypass disable is enabled system-wide: False

Speculation control settings for CVE-2018-3620 [L1 terminal fault]

Hardware is vulnerable to L1 terminal fault: False

Speculation control settings for MDS [microarchitectural data sampling]

Windows OS support for MDS mitigation is present: True
Hardware is vulnerable to MDS: False

Speculation control settings for SBDR [shared buffers data read]

Windows OS support for SBDR mitigation is present: True
Hardware is vulnerable to SBDR: True
Windows OS support for SBDR mitigation is enabled: False

Speculation control settings for FBSDP [fill buffer stale data propagator]

Windows OS support for FBSDP mitigation is present: True
Hardware is vulnerable to FBSDP: True
Windows OS support for FBSDP mitigation is enabled: False

Speculation control settings for PSDP [primary stale data propagator]

Windows OS support for PSDP mitigation is present: True
Hardware is vulnerable to PSDP: True
Windows OS support for PSDP mitigation is enabled: False

Suggested actions

* Follow the guidance for enabling Windows Client support for speculation control 
mitigations described in https://support.microsoft.com/help/4073119


BTIHardwarePresent                  : True
BTIWindowsSupportPresent            : True
BTIWindowsSupportEnabled            : True
BTIDisabledBySystemPolicy           : False
BTIDisabledByNoHardwareSupport      : False
BTIKernelRetpolineEnabled           : False
BTIKernelImportOptimizationEnabled  : True
RdclHardwareProtectedReported       : True
RdclHardwareProtected               : True
KVAShadowRequired                   : False
KVAShadowWindowsSupportPresent      : True
KVAShadowWindowsSupportEnabled      : False
KVAShadowPcidEnabled                : False
SSBDWindowsSupportPresent           : True
SSBDHardwareVulnerable              : True
SSBDHardwarePresent                 : True
SSBDWindowsSupportEnabledSystemWide : False
L1TFHardwareVulnerable              : False
L1TFWindowsSupportPresent           : True
L1TFWindowsSupportEnabled           : False
L1TFInvalidPteBit                   : 0
L1DFlushSupported                   : True
HvL1tfStatusAvailable               : True
HvL1tfProcessorNotAffected          : True
MDSWindowsSupportPresent            : True
MDSHardwareVulnerable               : False
MDSWindowsSupportEnabled            : False
FBClearWindowsSupportPresent        : True
SBDRSSDPHardwareVulnerable          : True
FBSDPHardwareVulnerable             : True
PSDPHardwareVulnerable              : True
FBClearWindowsSupportEnabled        : False


PS>

PowerShell 技能连载 - 获取父级文化

大部分情况下,本地化资源都会标有类似 “en-us” 或 “de-de” 这样的文化名称。如果你想知道这种标识代表什么,只需将其转换为 [System.Globalization.CultureInfo] 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
PS> [System.Globalization.CultureInfo]'en-us'

LCID Name DisplayName
---- ---- -----------
1033 en-US English (United States)



PS> [System.Globalization.CultureInfo]'de-de'

LCID Name DisplayName
---- ---- -----------
1031 de-DE German (Germany)

正如你所见,文化名称非常细致。例如,有 106 个子文化都属于同一个英语基础文化:

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
PS> [System.Globalization.CultureInfo]::GetCultures( [System.Globalization.CultureTypes]::AllCultures) | Where-Object Parent -eq 'en'

LCID Name DisplayName
---- ---- -----------
4096 en-001 English (World)
9225 en-029 English (Caribbean)
4096 en-150 English (Europe)
19465 en-AE English (United Arab Emirates)
4096 en-AG English (Antigua and Barbuda)
4096 en-AI English (Anguilla)
4096 en-AS English (American Samoa)
4096 en-AT English (Austria)
3081 en-AU English (Australia)
4096 en-BB English (Barbados)
4096 en-BE English (Belgium)
4096 en-BI English (Burundi)
4096 en-BM English (Bermuda)
4096 en-BS English (Bahamas)
4096 en-BW English (Botswana)
10249 en-BZ English (Belize)
4105 en-CA English (Canada)
4096 en-CC English (Cocos [Keeling] Islands)
4096 en-CH English (Switzerland)
4096 en-CK English (Cook Islands)
4096 en-CM English (Cameroon)
4096 en-CX English (Christmas Island)
4096 en-CY English (Cyprus)
4096 en-DE English (Germany)
4096 en-DK English (Denmark)
4096 en-DM English (Dominica)
4096 en-ER English (Eritrea)
4096 en-FI English (Finland)
4096 en-FJ English (Fiji)
4096 en-FK English (Falkland Islands)
4096 en-FM English (Micronesia)
2057 en-GB English (United Kingdom)
4096 en-GD English (Grenada)
4096 en-GG English (Guernsey)
4096 en-GH English (Ghana)
4096 en-GI English (Gibraltar)
4096 en-GM English (Gambia)
4096 en-GU English (Guam)
4096 en-GY English (Guyana)
15369 en-HK English (Hong Kong SAR)
14345 en-ID English (Indonesia)
6153 en-IE English (Ireland)
4096 en-IL English (Israel)
4096 en-IM English (Isle of Man)
16393 en-IN English (India)
4096 en-IO English (British Indian Ocean Territory)
4096 en-JE English (Jersey)
8201 en-JM English (Jamaica)
4096 en-KE English (Kenya)
4096 en-KI English (Kiribati)
4096 en-KN English (Saint Kitts and Nevis)
4096 en-KY English (Cayman Islands)
4096 en-LC English (Saint Lucia)
4096 en-LR English (Liberia)
4096 en-LS English (Lesotho)
4096 en-MG English (Madagascar)
4096 en-MH English (Marshall Islands)
4096 en-MO English (Macao SAR)
4096 en-MP English (Northern Mariana Islands)
4096 en-MS English (Montserrat)
4096 en-MT English (Malta)
4096 en-MU English (Mauritius)
4096 en-MW English (Malawi)
17417 en-MY English (Malaysia)
4096 en-NA English (Namibia)
4096 en-NF English (Norfolk Island)
4096 en-NG English (Nigeria)
4096 en-NL English (Netherlands)
4096 en-NR English (Nauru)
4096 en-NU English (Niue)
5129 en-NZ English (New Zealand)
4096 en-PG English (Papua New Guinea)
13321 en-PH English (Republic of the Philippines)
4096 en-PK English (Pakistan)
4096 en-PN English (Pitcairn Islands)
4096 en-PR English (Puerto Rico)
4096 en-PW English (Palau)
4096 en-RW English (Rwanda)
4096 en-SB English (Solomon Islands)
4096 en-SC English (Seychelles)
4096 en-SD English (Sudan)
4096 en-SE English (Sweden)
18441 en-SG English (Singapore)
4096 en-SH English (St Helena, Ascension, Tristan da Cunha)
4096 en-SI English (Slovenia)
4096 en-SL English (Sierra Leone)
4096 en-SS English (South Sudan)
4096 en-SX English (Sint Maarten)
4096 en-SZ English (Swaziland)
4096 en-TC English (Turks and Caicos Islands)
4096 en-TK English (Tokelau)
4096 en-TO English (Tonga)
11273 en-TT English (Trinidad and Tobago)
4096 en-TV English (Tuvalu)
4096 en-TZ English (Tanzania)
4096 en-UG English (Uganda)
4096 en-UM English (US Minor Outlying Islands)
1033 en-US English (United States)
4096 en-VC English (Saint Vincent and the Grenadines)
4096 en-VG English (British Virgin Islands)
4096 en-VI English (US Virgin Islands)
4096 en-VU English (Vanuatu)
4096 en-WS English (Samoa)
7177 en-ZA English (South Africa)
4096 en-ZM English (Zambia)
12297 en-ZW English (Zimbabwe)

如果您的代码最终需要检查给定的资源区域设置是否与您的兴趣相匹配,而不是将资源区域设置与您的用户界面区域设置进行比较,您可能希望获取您的用户界面区域设置和资源的父级区域设置,并查看它们是否匹配。

这样,英国用户(en-GB)也将找到美国的文档(en-us)。同样,瑞士用户(de-ch)将找到德国的资源(de-de)。