PowerShell 技能连载 - 翻译数据

哈希表和字典是完美的查找表:每当您的原始数据包含难以理解的数字或命令返回仅为数值返回值时,哈希表可以将这些数字转换为友好的文本。

由于您可以自由地向哈希表添加任何键,因此要翻译的数字也不必是连续的数字范围。

以下是一个示例,从 WMI 查询操作系统信息,然后将您的 Windows SKU 从数字转换为描述性文本:

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
# get any info, i.e. some WMI information about your OS
$info = Get-CimInstance -ClassName Win32_OperatingSystem
# it may include information that is cryptically encoded as some number:
$rawData = $info.OperatingSystemSKU
# by using a hash table, you can easily translate the numbers to text:
$translation = @{
0 = 'UNDEFINED'
1 = 'ULTIMATE'
2 = 'HOME_BASIC'
3 = 'HOME_PREMIUM'
4 = 'ENTERPRISE'
5 = 'HOME_BASIC_N'
6 = 'BUSINESS'
7 = 'STANDARD_SERVER'
8 = 'DATACENTER_SERVER'
9 = 'SMALLBUSINESS_SERVER'
10 = 'ENTERPRISE_SERVER'
11 = 'STARTER'
12 = 'DATACENTER_SERVER_CORE'
13 = 'STANDARD_SERVER_CORE'
14 = 'ENTERPRISE_SERVER_CORE'
15 = 'ENTERPRISE_SERVER_IA64'
16 = 'BUSINESS_N'
17 = 'WEB_SERVER'
18 = 'CLUSTER_SERVER'
19 = 'HOME_SERVER'
20 = 'STORAGE_EXPRESS_SERVER'
21 = 'STORAGE_STANDARD_SERVER'
22 = 'STORAGE_WORKGROUP_SERVER'
23 = 'STORAGE_ENTERPRISE_SERVER'
24 = 'SERVER_FOR_SMALLBUSINESS'
25 = 'SMALLBUSINESS_SERVER_PREMIUM'
26 = 'HOME_PREMIUM_N'
27 = 'ENTERPRISE_N'
28 = 'ULTIMATE_N'
29 = 'WEB_SERVER_CORE'
30 = 'MEDIUMBUSINESS_SERVER_MANAGEMENT'
31 = 'MEDIUMBUSINESS_SERVER_SECURITY'
32 = 'MEDIUMBUSINESS_SERVER_MESSAGING'
33 = 'SERVER_FOUNDATION'
34 = 'HOME_PREMIUM_SERVER'
35 = 'SERVER_FOR_SMALLBUSINESS_V'
36 = 'STANDARD_SERVER_V'
37 = 'DATACENTER_SERVER_V'
38 = 'ENTERPRISE_SERVER_V'
39 = 'DATACENTER_SERVER_CORE_V'
40 = 'STANDARD_SERVER_CORE_V'
41 = 'ENTERPRISE_SERVER_CORE_V'
42 = 'HYPERV'
43 = 'STORAGE_EXPRESS_SERVER_CORE'
44 = 'STORAGE_STANDARD_SERVER_CORE'
45 = 'STORAGE_WORKGROUP_SERVER_CORE'
46 = 'STORAGE_ENTERPRISE_SERVER_CORE'
47 = 'STARTER_N'
48 = 'PROFESSIONAL'
49 = 'PROFESSIONAL_N'
50 = 'SB_SOLUTION_SERVER'
51 = 'SERVER_FOR_SB_SOLUTIONS'
52 = 'STANDARD_SERVER_SOLUTIONS'
53 = 'STANDARD_SERVER_SOLUTIONS_CORE'
54 = 'SB_SOLUTION_SERVER_EM'
55 = 'SERVER_FOR_SB_SOLUTIONS_EM'
56 = 'SOLUTION_EMBEDDEDSERVER'
57 = 'SOLUTION_EMBEDDEDSERVER_CORE'
58 = 'PROFESSIONAL_EMBEDDED'
59 = 'ESSENTIALBUSINESS_SERVER_MGMT'
60 = 'ESSENTIALBUSINESS_SERVER_ADDL'
61 = 'ESSENTIALBUSINESS_SERVER_MGMTSVC'
62 = 'ESSENTIALBUSINESS_SERVER_ADDLSVC'
63 = 'SMALLBUSINESS_SERVER_PREMIUM_CORE'
64 = 'CLUSTER_SERVER_V'
65 = 'EMBEDDED'
66 = 'STARTER_E'
67 = 'HOME_BASIC_E'
68 = 'HOME_PREMIUM_E'
69 = 'PROFESSIONAL_E'
70 = 'ENTERPRISE_E'
71 = 'ULTIMATE_E'
72 = 'ENTERPRISE_EVALUATION'
76 = 'MULTIPOINT_STANDARD_SERVER'
77 = 'MULTIPOINT_PREMIUM_SERVER'
79 = 'STANDARD_EVALUATION_SERVER'
80 = 'DATACENTER_EVALUATION_SERVER'
84 = 'ENTERPRISE_N_EVALUATION'
85 = 'EMBEDDED_AUTOMOTIVE'
86 = 'EMBEDDED_INDUSTRY_A'
87 = 'THINPC'
88 = 'EMBEDDED_A'
89 = 'EMBEDDED_INDUSTRY'
90 = 'EMBEDDED_E'
91 = 'EMBEDDED_INDUSTRY_E'
92 = 'EMBEDDED_INDUSTRY_A_E'
95 = 'STORAGE_WORKGROUP_EVALUATION_SERVE'
96 = 'STORAGE_STANDARD_EVALUATION_SERVER'
97 = 'CORE_ARM'
98 = 'CORE_N'
99 = 'CORE_COUNTRYSPECIFIC'
100 = 'CORE_SINGLELANGUAGE'
101 = 'CORE'
103 = 'PROFESSIONAL_WMC'
105 = 'EMBEDDED_INDUSTRY_EVAL'
106 = 'EMBEDDED_INDUSTRY_E_EVAL'
107 = 'EMBEDDED_EVAL'
108 = 'EMBEDDED_E_EVAL'
109 = 'NANO_SERVER'
110 = 'CLOUD_STORAGE_SERVER'
111 = 'CORE_CONNECTED'
112 = 'PROFESSIONAL_STUDENT'
113 = 'CORE_CONNECTED_N'
114 = 'PROFESSIONAL_STUDENT_N'
115 = 'CORE_CONNECTED_SINGLELANGUAGE'
116 = 'CORE_CONNECTED_COUNTRYSPECIFIC'
117 = 'CONNECTED_CAR'
118 = 'INDUSTRY_HANDHELD'
119 = 'PPI_PRO'
120 = 'ARM64_SERVER'
121 = 'EDUCATION'
122 = 'EDUCATION_N'
123 = 'IOTUAP'
124 = 'CLOUD_HOST_INFRASTRUCTURE_SERVER'
125 = 'ENTERPRISE_S'
126 = 'ENTERPRISE_S_N'
127 = 'PROFESSIONAL_S'
128 = 'PROFESSIONAL_S_N'
129 = 'ENTERPRISE_S_EVALUATION'
130 = 'ENTERPRISE_S_N_EVALUATION'
135 = 'HOLOGRAPHIC'
138 = 'PRO_SINGLE_LANGUAGE'
139 = 'PRO_CHINA'
140 = 'ENTERPRISE_SUBSCRIPTION'
141 = 'ENTERPRISE_SUBSCRIPTION_N'
143 = 'DATACENTER_NANO_SERVER'
144 = 'STANDARD_NANO_SERVER'
145 = 'DATACENTER_A_SERVER_CORE'
146 = 'STANDARD_A_SERVER_CORE'
147 = 'DATACENTER_WS_SERVER_CORE'
148 = 'STANDARD_WS_SERVER_CORE'
149 = 'UTILITY_VM'
159 = 'DATACENTER_EVALUATION_SERVER_CORE'
160 = 'STANDARD_EVALUATION_SERVER_CORE'
161 = 'PRO_WORKSTATION'
162 = 'PRO_WORKSTATION_N'
164 = 'PRO_FOR_EDUCATION'
165 = 'PRO_FOR_EDUCATION_N'
168 = 'AZURE_SERVER_CORE'
169 = 'AZURE_NANO_SERVER'
171 = 'ENTERPRISEG'
172 = 'ENTERPRISEGN'
175 = 'SERVERRDSH'
178 = 'CLOUD'
179 = 'CLOUDN'
180 = 'HUBOS'
182 = 'ONECOREUPDATEOS'
183 = 'CLOUDE'
184 = 'ANDROMEDA'
185 = 'IOTOS'
186 = 'CLOUDEN'
}
# use the raw data as key to the hash table
# AND MAKE SURE you convert numeric data to [int]!
# (WMI returns unusual data types like [byte] and [UInt16],
# and hash table keys are type-aware)
$translation[$rawData -as [int]]

这个基本的概念适用于所有类型的翻译。以下是一个示例,可以将 ping.exe 提供的返回值进行翻译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$translation = @{
0 = 'SUCCESS'
1 = 'FAILURE'
2 = 'ERROR'
}

1..255 | ForEach-Object {
# create the IP address to ping
# make sure you adjust this to your segment!
$ip = "192.168.2.$_"
# execute ping.exe and disregard the text output
ping -n 1 -w 500 $ip > $null
# instead return the translated return value found in $LASTEXITCODE
[PSCustomObject]@{
IpAddress = $ip
Status = $translation[$LASTEXITCODE]
}
}

以下是执行结果:

IpAddress   Status
---------   ------
192.168.2.1 SUCCESS
192.168.2.2 FAILURE
192.168.2.3 FAILURE
192.168.2.4 FAILURE
192.168.2.5 FAILURE
192.168.2.6 FAILURE
...

PowerShell 技能连载 - 自动化操作 Defender 杀毒软件(第 2 部分)

在 Windows 上,PowerShell 带有用于自动化内置防病毒引擎 “Defender” 的 cmdlet。在第二部分中,让我们看看如何找出在您的计算机上活动的防病毒设置:

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
PS C:\> Get-MpPreference


AllowDatagramProcessingOnWinServer : False
AllowNetworkProtectionDownLevel : False
AllowNetworkProtectionOnWinServer : False
AllowSwitchToAsyncInspection : False
AttackSurfaceReductionOnlyExclusions : {N/A: Must be and administrator to view exclusions}
AttackSurfaceReductionRules_Actions :
AttackSurfaceReductionRules_Ids :
CheckForSignaturesBeforeRunningScan : False
CloudBlockLevel : 1
CloudExtendedTimeout : 1
ComputerID : 7AB83555-0B97-47C7-A67C-8778E4757F65
ControlledFolderAccessAllowedApplications : {N/A: Must be and administrator to view exclusions}
ControlledFolderAccessProtectedFolders :
DefinitionUpdatesChannel : 0
DisableArchiveScanning : False
DisableAutoExclusions : False
DisableBehaviorMonitoring : False
DisableBlockAtFirstSeen : False
DisableCatchupFullScan : True
DisableCatchupQuickScan : True
DisableCpuThrottleOnIdleScans : True
DisableDatagramProcessing : False
DisableDnsOverTcpParsing : False
DisableDnsParsing : False
DisableEmailScanning : True
DisableFtpParsing : False
DisableGradualRelease : False
DisableHttpParsing : False
DisableInboundConnectionFiltering : False
DisableIOAVProtection : False
DisableNetworkProtectionPerfTelemetry : False
DisablePrivacyMode : False
DisableRdpParsing : False
DisableRealtimeMonitoring : False
DisableRemovableDriveScanning : True
DisableRestorePoint : True
DisableScanningMappedNetworkDrivesForFullScan : True
DisableScanningNetworkFiles : False
DisableScriptScanning : False
DisableSmtpParsing : False
DisableSshParsing : False
DisableTlsParsing : False
EnableControlledFolderAccess : 0
EnableDnsSinkhole : True
EnableFileHashComputation : False
EnableFullScanOnBatteryPower : False
EnableLowCpuPriority : False
EnableNetworkProtection : 0
EngineUpdatesChannel : 0
ExclusionExtension : {N/A: Must be and administrator to view exclusions}
ExclusionIpAddress : {N/A: Must be and administrator to view exclusions}
ExclusionPath : {N/A: Must be and administrator to view exclusions}
ExclusionProcess : {N/A: Must be and administrator to view exclusions}
ForceUseProxyOnly : False
HighThreatDefaultAction : 0
IntelTDTEnabled : True
LowThreatDefaultAction : 0
MAPSReporting : 2
MeteredConnectionUpdates : False
ModerateThreatDefaultAction : 0
PlatformUpdatesChannel : 0
ProxyBypass :
ProxyPacUrl :
ProxyServer :
PUAProtection : 1
QuarantinePurgeItemsAfterDelay : 90
RandomizeScheduleTaskTimes : True
RealTimeScanDirection : 0
RemediationScheduleDay : 0
RemediationScheduleTime : 02:00:00
ReportDynamicSignatureDroppedEvent : False
ReportingAdditionalActionTimeOut : 10080
ReportingCriticalFailureTimeOut : 10080
ReportingNonCriticalTimeOut : 1440
ScanAvgCPULoadFactor : 50
ScanOnlyIfIdleEnabled : True
ScanParameters : 1
ScanPurgeItemsAfterDelay : 10
ScanScheduleDay : 0
ScanScheduleOffset : 120
ScanScheduleQuickScanTime : 00:00:00
ScanScheduleTime : 02:00:00
SchedulerRandomizationTime : 4
ServiceHealthReportInterval : 60
SevereThreatDefaultAction : 0
SharedSignaturesPath :
SignatureAuGracePeriod : 0
SignatureBlobFileSharesSources :
SignatureBlobUpdateInterval : 60
SignatureDefinitionUpdateFileSharesSources :
SignatureDisableUpdateOnStartupWithoutEngine : False
SignatureFallbackOrder : MicrosoftUpdateServer|MMPC
SignatureFirstAuGracePeriod : 120
SignatureScheduleDay : 8
SignatureScheduleTime : 01:45:00
SignatureUpdateCatchupInterval : 1
SignatureUpdateInterval : 0
SubmitSamplesConsent : 1
ThreatIDDefaultAction_Actions : {6}
ThreatIDDefaultAction_Ids : {311978}
ThrottleForScheduledScanOnly : True
TrustLabelProtectionStatus : 0
UILockdown : False
UnknownThreatDefaultAction : 0
PSComputerName :

从结果中可以看到,一些设置是受保护的,需要管理员权限才能查询。

如果您想更改防病毒软件设置,只需使用 Set-MpPreference 命令。

当然,您可以使用 Select-Object 命令过滤返回的信息以回答特定问题,但如果您想根据值过滤信息怎么办?比如说,您需要一份当前关闭的所有功能的列表?

以下是一种聪明的方法,使用底层的 PSObject 列出所有属性的名称,然后根据它们的值进行过滤:

1
2
3
4
5
$preference = Get-MpPreference
[PSObject]$psObject = $preference.PSObject
$psObject.Properties | Where-Object {
$_.Value -is [bool] -and $_.Value -eq $true
} | Select-Object -ExpandProperty Name

同样,下面的代码列出了所有当前已禁用的属性(值为 $false):

1
2
3
4
5
$preference = Get-MpPreference
[PSObject]$psObject = $preference.PSObject
$psObject.Properties | Where-Object {
$_.Value -is [bool] -and $_.Value -eq $false
} | Select-Object -ExpandProperty Name

由于上述方法可以根据任何属性值进行过滤,因此您可以轻松地调整它,例如只转储包含小于 500 的 [byte] 属性:

1
2
3
4
5
$preference = Get-MpPreference
[PSObject]$psObject = $preference.PSObject
$psObject.Properties | Where-Object {
$_.Value -is [byte] -and $_.Value -lt 500
} | Select-Object -Property Name, Value

以下是执行结果:

Name                         Value
----                         -----
CloudBlockLevel                  1
DefinitionUpdatesChannel         0
EnableControlledFolderAccess     0
EnableNetworkProtection          0
EngineUpdatesChannel             0
HighThreatDefaultAction          0
LowThreatDefaultAction           0
MAPSReporting                    2
ModerateThreatDefaultAction      0
PlatformUpdatesChannel           0
PUAProtection                    1
RealTimeScanDirection            0
RemediationScheduleDay           0
ScanAvgCPULoadFactor            50
ScanParameters                   1
ScanScheduleDay                  0
SevereThreatDefaultAction        0
SignatureScheduleDay             8
SubmitSamplesConsent             1
UnknownThreatDefaultAction       0

现在,我们总结一下:通过将代码封装在函数中,您使代码可以重复使用,自动添加可扩展性(在上面的示例中,我们现在可以在同一个调用中转换一个或数千个字符串),并且您的生产脚本代码变得更短,可以集中精力完成真正想要实现的任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PS C:\> Get-Command -Module ConfigDefender

CommandType Name Version Source
----------- ---- ------- ------
Function Add-MpPreference 1.0 ConfigDefender
Function Get-MpComputerStatus 1.0 ConfigDefender
Function Get-MpPreference 1.0 ConfigDefender
Function Get-MpThreat 1.0 ConfigDefender
Function Get-MpThreatCatalog 1.0 ConfigDefender
Function Get-MpThreatDetection 1.0 ConfigDefender
Function Remove-MpPreference 1.0 ConfigDefender
Function Remove-MpThreat 1.0 ConfigDefender
Function Set-MpPreference 1.0 ConfigDefender
Function Start-MpRollback 1.0 ConfigDefender
Function Start-MpScan 1.0 ConfigDefender
Function Start-MpWDOScan 1.0 ConfigDefender
Function Update-MpSignature 1.0 ConfigDefender

PowerShell 技能连载 - 自动化操作 Defender 杀毒软件(第 1 部分)

在 Windows 上,PowerShell 带有用于自动化操作内置防病毒引擎 “Defender” 的 cmdlet。

如果您想自动更新签名,请尝试以下操作:

1
PS C:\> Update-MpSignature

如果您在计划任务的脚本中运行此命令,则现在可以完全控制。无需管理员特权。

同样,PowerShell 可以仅使用一个命令随时启动快速扫描:

1
PS C:\> Start-MpScan -ScanType QuickScan

扫描进度显示为 PowerShell 进度条,无需打开烦人的对话框。

如果您想知道您最近面临的最新威胁,请让 Defender 输出其威胁分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
PS C:\> Get-MpThreat

CategoryID : 27
DidThreatExecute : False
IsActive : True
Resources :
RollupStatus : 1
SchemaVersion : 1.0.0.0
SeverityID : 1
ThreatID : 311978
ThreatName : PUADlManager:Win32/DownloadSponsor
TypeID : 0
PSComputerName :

PowerShell 技能连载 - 将波长转换为 RGB

PowerShell 是一种通用脚本语言,因此您可以使用它来完成各种任务。以下是一个将光波长转换为相应 RGB 颜色值的函数:

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
function Convert-WavelengthToRgb
{
# derived from http://www.physics.sfasu.edu/astro/color/spectra.html

param
(
[Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
[ValidateRange(380,780)]
[int]
$Wavelength,

[double]
$Gamma = 0.8,

[int]
[ValidateRange(1,255)]
$Intensity = 255,

[switch]
$AdjustHumanSensitivity
)

process
{
#from: https://www.codedrome.com/exploring-the-visible-spectrum-in-python/
$factor = 0

$result = [PSCustomObject]@{
Wavelength = $Wavelength
R = 0
G = 0
B = 0
}

switch($Wavelength)
{

{ $_ -lt 420 } {
$result.R = -($_ - 440) / 60
$result.B = 1
$factor = 0.3 + 0.7 * ($_ - 380) / 40
break
}

{ $_ -lt 440 } {
$result.R = -($_ - 440) / 60
$result.B = 1
$factor = 1
break
}

{ $_ -lt 490 } {
$result.G = ($_ - 440) / 50
$result.B = 1
$factor = 1
break
}

{ $_ -lt 510 } {
$result.B = -($_ - 510) / 20
$result.G = 1
$factor = 1
break
}

{ $_ -lt 580 } {
$result.R = ($_ - 510) / 70
$result.G = 1
$factor = 1
break
}

{ $_ -lt 645 } {
$result.G = -($_ - 645) / 65
$result.R = 1
$factor = 1
break
}
{ $_ -le 700 } {
$result.R = 1
$factor = 1
break
}


{ $_ -le 780 } {
$result.R = 1
$factor = 0.3 + 0.7 * (780 - $_) / 80
break
}
}

if ($AdjustHumanSensitivity.IsPresent -eq $false) { $factor = 1 }

$result.R = [Math]::Pow( ($result.R * $factor), $gamma) * $Intensity -as [int]
$result.G = [Math]::Pow( ($result.G * $factor), $gamma) * $Intensity -as [int]
$result.B = [Math]::Pow( ($result.B * $factor), $gamma) * $Intensity -as [int]

return $result
}
}

现在,将整个可见光谱转换为相应的 RGB 值就变得简单了:

1
2
3
4
5
# Calculate RGB values for the visible light spectrum (wavelengths)

380..780 |
Convert-WavelengthToRgb |
Out-GridView -Title 'Without Correction'

由于人眼对不同颜色的敏感度不同,该函数甚至可以考虑此敏感度并自动应用校正:

1
2
3
380..780 |
Convert-WavelengthToRgb -AdjustHumanSensitivity |
Out-GridView -Title 'With Correction'

PowerShell 技能连载 - 自动化操作 Defender 杀毒软件(第 1 部分)

在 Windows 上,PowerShell 带有用于自动化操作内置防病毒引擎 “Defender” 的 cmdlet。

如果您想自动更新签名,请尝试以下操作:

1
PS C:\> Update-MpSignature

如果您在计划任务的脚本中运行此命令,则现在可以完全控制。无需管理员特权。

同样,PowerShell 可以仅使用一个命令随时启动快速扫描:

1
PS C:\> Start-MpScan -ScanType QuickScan

扫描进度显示为 PowerShell 进度条,无需打开烦人的对话框。

如果您想知道您最近面临的最新威胁,请让 Defender 输出其威胁分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
PS C:\> Get-MpThreat

CategoryID : 27
DidThreatExecute : False
IsActive : True
Resources :
RollupStatus : 1
SchemaVersion : 1.0.0.0
SeverityID : 1
ThreatID : 311978
ThreatName : PUADlManager:Win32/DownloadSponsor
TypeID : 0
PSComputerName :

PowerShell 技能连载 - 存储任何加密的文本

假设您的脚本需要敏感输入,例如数据库的连接字符串或其他文本信息。

管理此类机密信息的一种方法是将它们存储为 [SecureString],并安全地序列化此信息到 XML。以下是此部分的操作:

1
2
3
4
5
6
7
8
$Path = "$env:temp\safeconnectionstring.test"


[ordered]@{
Con1 = 'secret1' | ConvertTo-SecureString -AsPlainText -Force
Con2 = 'secret2' | ConvertTo-SecureString -AsPlainText -Force
Con3 = 'secret3' | ConvertTo-SecureString -AsPlainText -Force
} | Export-Clixml -Path $Path

它将三段机密信息存储到一个哈希表中,将其转换为安全字符串,然后安全地将它们导出到 XML。机密的关键是运行此脚本的用户和机器,因此只有此人(在同一台计算机上)才能稍后读取信息。

如果您不想将机密信息存储在任何地方,您还可以交互式地输入它们:

1
2
3
4
5
6
7
8
$Path = "$env:temp\safeconnectionstring.test"


[ordered]@{
Con1 = Read-Host -Prompt Secret1 -AsSecureString
Con2 = Read-Host -Prompt Secret1 -AsSecureString
Con3 = Read-Host -Prompt Secret1 -AsSecureString
} | Export-Clixml -Path $Path

Now, when it is time to use the secrets, you need a way to convert secure strings back to plain text. This is what this script does:
现在,当需要使用这些机密信息时,您需要一种将安全字符串转换回纯文本的方法。此脚本的操作:

1
2
3
4
5
6
7
$hash = Import-Clixml -Path $Path
# important: MUST cast $keys to [string[]] or else you cannot modify the hash
# in the loop:
[string[]]$keys = $hash.Keys
$keys | ForEach-Object {
$hash[$_] = [PSCredential]::new('xyz', $hash[$_]).GetNetworkCredential().Password
}

结果($hash)是一个哈希表,其中包含以纯文本形式保存的机密信息,因此在此示例中,您可以通过三个键“con1”、“con2”和“con3”访问这三个机密信息:

1
2
3
4
5
6
7
8
PS> $hash.Con1
secret1

PS> $hash.Con2
secret2

PS> $hash.Con3
secret3

PowerShell 技能连载 - 使用合适的数据类型(第 2 部分)

第 1 部分中我们介绍了将数据转换为更适合的 .NET 数据类型后数据的可用性如何提高。

如果无法为数据找到现有的数据类型以为其提供结构,也可以创建自己的数据类型。

假设您需要处理名称。这是一个名为 [TeamMember] 的自定义数据类型,可以为名称添加结构:

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
class TeamMember
{
[string]$FirstName
[string]$LastName


TeamMember([string]$Name)
{
# case correct text
$newName = [cultureinfo]::InvariantCulture.TextInfo.ToTitleCase($Name)
# automatically find delimiter character
$delimiter = $newName.ToCharArray() -match '[,. ]' | Select-Object -First 1

# no delimiter?
if ($delimiter.Count -eq 0)
{
$this.LastName = $Name
return
}

$array = $newName.Split($delimiter)

# based on found delimiter
switch -Regex ($delimiter)
{
# dot or space:
'[.\s]' {
$this.FirstName = $array[0]
$this.LastName = $array[1]
}
# comma
'\,' {
$this.FirstName = $array[1]
$this.LastName = $array[0]
}
# invalid
default {
$this.LastName = $Name
}
}
}
}

运行此代码后,定义了名为 [TeamMember] 的新数据类型。现在可以将包含名称的字符串简单地转换为结构化数据类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PS> [TeamMember]'tobias weltner'

FirstName LastName
--------- --------
Tobias Weltner



PS> [TeamMember]'tobias.weltner'

FirstName LastName
--------- --------
Tobias Weltner



PS> [TeamMember]'weltner,tobias'

FirstName LastName
--------- --------
Tobias Weltner

还有个额外的好处,即自动纠正大小写,或者说,您的类可以包含任何您喜欢的魔法。当您后来使用该类型时,您不再需要担心它。

更好的是,当将此类型分配给变量时,它将自动将任何名称转换为新结构,即使在以后的赋值中也是如此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PS> [TeamMember]$name = 'Tobias Weltner'

PS> $name

FirstName LastName
--------- --------
Tobias Weltner


PS> $name = 'kloVER,kaRL'

PS> $name

FirstName LastName
--------- --------
Karl Klover

自定义类的自动转换的秘密在于其构造函数。当构造函数接受一个 [string] 类型的参数时,它可以自动将任何字符串转换为新结构。

类的构造函数和类名相同,并且输入参数为 [string]

1
2
3
4
TeamMember([string]$Name)
{
...
}

PowerShell 技能连载 - 使用合适的数据类型(第 1 部分)

Windows 是一个 API 驱动的操作系统,而 PowerShell 也是如此。与其他使用纯文本作为基础元素并让用户通过 grep 和正则表达式来结构化数据的 shell 相比,PowerShell(和底层的 .NET 框架)提供了一组丰富的数据类型,您可以从中选择最适合的来完美地存储数据。

默认情况下,PowerShell 仅使用基本数据类型,例如[string](文本),[int](数字),[double](浮点数),[datetime](日期和时间)和[bool](真和假)。

You however can pick any other data type that you find more suitable:
但是,您可以选择任何其他您认为更合适的数据类型:

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
PS> [System.IO.FileInfo]'c:\test\somefile.txt'

Mode LastWriteTime Length Name
---- ------------- ------ ----
darhsl 01.01.1601 01:00 () somefile.txt



PS> [System.IO.FileInfo]'c:\test\somefile.txt' | Select-Object -Property *


Mode : darhsl
VersionInfo :
BaseName : somefile
Target :
LinkType :
Name : somefile.txt
Length :
DirectoryName : c:\test
Directory : c:\test
IsReadOnly : True
Exists : False
FullName : c:\test\somefile.txt
Extension : .txt
CreationTime : 01.01.1601 01:00:00
CreationTimeUtc : 01.01.1601 00:00:00
LastAccessTime : 01.01.1601 01:00:00
LastAccessTimeUtc : 01.01.1601 00:00:00
LastWriteTime : 01.01.1601 01:00:00
LastWriteTimeUtc : 01.01.1601 00:00:00
Attributes : -1

通过将通用数据类型(如字符串)转换为更适当的数据类型,访问单个信息变得更加容易。例如,如果您想解析文件路径,通过将字符串转换为[System.Io.FileInfo],您可以轻松地拆分路径并提取驱动器、父文件夹、文件名、没有扩展名的文件名或扩展名:

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
PS> $path = [System.IO.FileInfo]'c:\test\somefile.txt'

PS> $path.DirectoryName
c:\test

PS> $path.FullName
c:\test\somefile.txt

PS> $path.Name
somefile.txt

PS> $path.BaseName
somefile

PS> $path.Extension
.txt

PS> $path.Directory.Parent

Mode LastWriteTime Length Name
---- ------------- ------ ----
d--hs- 15.02.2023 17:33 c:\



PS> $path.Directory.Parent.Name
c:\

PowerShell 技能连载 - 研究 ConfirmImpact(第 2 部分:脚本作者视角)

在前面的部分中,已经解释了 PowerShell 将 $ConfirmPreference 自动变量作为其风险缓解系统的一部分使用:每当一个 PowerShell 命令自身的 “ConfirmImpact“ 高于或等于 $ConfirmPreference 中的设置时,PowerShell 将显示自动确认对话框。

作为函数或脚本作者,您可以使用属性 CmdletBinding() 设置函数或脚本的“影响级别”:

1
2
3
4
5
6
7
8
9
10
11
12
function Remove-Something
{
[CmdletBinding(ConfirmImpact='Medium')]
param
(
[Parameter(Mandatory)]
[string]
$Name
)

"You entered $Name"
}

示例函数 Remove-Something 已将其 ConfirmImpact 声明为 “Medium“,因此当您运行它时,如果 $ConfirmPreference 设置为 “Medium“ 以上的级别,PowerShell 将触发自动确认。

二进制 cmdlet 也是一样。要找出二进制 cmdlet 的确认影响,您可以使用以下函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
filter Get-ConfirmInfo
{
param
(
[Parameter(Mandatory,ValueFromPipeline)]
[string]
$CommandName
)

$CommandInfo = Get-Command -Name $CommandName
[System.Management.Automation.CommandMetaData]::new($CommandInfo) |
Select-Object -Property Name, ConfirmImpact, SupportsShouldProcess
}

当您提交命令名称时,它将显示命令作者定义的 ConfirmImpact,以及命令是否支持模拟开关,例如 -WhatIf(在这个情况下,SupportsShouldProcess 显示 $true)。

1
2
3
4
5
6
7
PS> 'Get-Random', 'Remove-Item', 'Stop-Process' | Get-ConfirmInfo

Name ConfirmImpact SupportsShouldProcess
---- ------------- ---------------------
Get-Random Medium False
Remove-Item Medium True
Stop-Process Medium True

由于 Get-ConfirmInfo 支持管道,因此您甚至可以检查您的 PowerShell 命令集并搜索高影响级别的命令:

1
2
3
4
5
6
7
8
9
10
11
12
PS> Get-Command -Verb Remove | Get-ConfirmInfo | Where-Object ConfirmImpact -eq High

Name ConfirmImpact SupportsShouldProcess
---- ------------- ---------------------
Remove-CIAccessControlRule High True
Remove-CIVApp High True
Remove-CIVAppNetwork High True
Remove-CIVAppTemplate High True
Remove-BCDataCacheExtension High True
Remove-ClusterAffinityRule High True
Remove-ClusterFaultDomain High True
(...)

PowerShell 技能连载 - 研究 ConfirmImpact(第 1 部分:用户视角)

在 PowerShell 中,默认情况下,$ConfimPreference 变量设置为 “High“。这个设置控制什么?

1
2
PS> $ConfirmPreference
High

任何 PowerShell 命令(二进制 cmdlet 或函数)都可以设置自己的 “ConfirmImpact“:允许的值为 NoneLowMediumHighConfirmImpact 是一个评估 cmdlet 效果的关键性程度。

默认情况下,当 $ConfirmImpact 设置为 “High“ 时,PowerShell 将在你运行设置了 ConfirmImpactHigh 的cmdlet 或函数时自动要求确认(所以你只会在运行像 AD 账户这样不能轻易恢复的东西的 cmdlets 时看到确认对话框弹出)。

作为用户,您可以调整这个风险缓解系统。如果你在一个十分敏感的生产系统上工作,你可能想把 $ConfirmPreference 降低到 Medium 或甚至 Low,以在运行 PowerShell 命令或脚本时获得更多的确认。当设置为 “Low“时,即使创建一个新文件夹也会触发自动确认:

1
2
3
4
5
6
7
8
9
10
PS> $ConfirmPreference = 'Low'

PS> New-Item -Path c:\testfolder

Confirm
Are you sure you want to perform this action?
Performing the operation "Create File" on target "Destination:
C:\testfolder".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

同样地,如果你想运行一个脚本而不被自动确认对话框打断,你可以把 $ConfirmPreference 设置为 “None“,从而关闭这个风险缓解系统。这比为脚本中可能触发确认的每个命令添加 -Confirm:$false 参数来手动覆盖自动确认要高效得多。

$ConfirmPreference 的任何更改都会在关闭当前 PowerShell 会话时恢复为默认值。它们不会自动持久化。如果您想永久更改这些设置,请创建一个配置文件脚本并将所有永久更改添加到这个脚本中。当 PowerShell 启动时,它会自动启动。

这样的配置文件脚本的路径可以在这里找到:

1
2
PS> $profile.CurrentUserAllHosts
C:\Users\USERNAME\OneDrive\Documents\WindowsPowerShell\profile.ps1