PowerShell 技能连载 - 遮罩输入框(第 2 部分)

永远不要将纯文本输入框用于保密信息和密码——用户输入的文本可能被记录和利用。请始终使用遮罩输入框。这是使用参数的一种简单方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
param
(
[Parameter(Mandatory)]
[SecureString]
# asking secret using masked input box
$secret
)

# internally, get back plain text
$data = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret)
$plain =[Runtime.InteropServices.Marshal]::PtrToStringAuto($data)

Write-Host "You secret: $plain" -ForegroundColor Yellow

只需将数据类型 [SecureString] 用于您的参数,这样将将其强制添加一个带遮罩的输入框。

PowerShell 技能连载 - 遮罩输入框(第 1 部分)

永远不要将纯文本输入框用于保密信息和密码——用户输入的文本可能被记录和利用。请始终使用遮罩输入框。这是用户提示的一种简单方法:

1
2
3
4
5
6
7
8
# asking secret using masked input box
$secret = Read-Host "Enter secret" -AsSecureString

# internally, get back plain text
$data = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret)
$plain =[Runtime.InteropServices.Marshal]::PtrToStringAuto($data)

Write-Host "You secret: $plain" -ForegroundColor Yellow

PowerShell 技能连载 - 查找 MSI 产品代码(第 2 部分)

在 Windows 10 及以上版本,查找 MSI 软件包及其产品代码不再需要 WMI 查询。相反,您可以使用 Get-Package 来替代:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Get-Package |
Select-Object -Property Name, @{
Name='ProductCode'
Expression={
$code = $_.Metadata["ProductCode"]
if ([string]::IsNullOrWhiteSpace($code) -eq $false)
{
$code
}
else
{
'N/A'
}
}
} |
Format-List

PowerShell 技能连载 - 查找 MSI 产品代码(第 1 部分)

如果您需要已安装的 MSI 软件包及其产品代码列表,则可以使用 WMI 查询信息。以下操作可能需要几秒钟:

1
2
Get-CimInstance -ClassName Win32_Product |
Select-Object -Property Name, @{Name='ProductCode'; Expression={$_.IdentifyingNumber}}

PowerShell 技能连载 - 存取 Windows 凭据管理器

如果您需要访问 Windows 凭据管理器存储的凭据(已保存的密码),则 “CredentialManager” 模块可能有所帮助。运行此代码下载并安装它:

1
Install-Module -Name CredentialManager -Scope CurrentUser

安装该模块后,您可以列出其提供的新命令:

1
2
3
4
5
6
7
8
PS> Get-Command -Module CredentialManager

CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Get-StoredCredential 2.0 CredentialManager
Cmdlet Get-StrongPassword 2.0 CredentialManager
Cmdlet New-StoredCredential 2.0 CredentialManager
Cmdlet Remove-StoredCredential 2.0 CredentialManager

Get-StoredCredential 获取存储的凭据。并且 New-StoredCredential 可以与凭据管理器一起存储凭据:
获得存储的存储凭据。 而且,新存储者可以为您与凭据管理器一起存储凭据:

1
New-StoredCredential -Target MyCred -Credentials (Get-Credential) -Type Generic -Persist LocalMachine

现在,当脚本需要访问存储的凭据时,请像这样使用 Get-StoredCredential

1
2
3
4
$cred = Get-StoredCredential -Target MyCred
# show clear text information
$cred.UserName
$cred.GetNetworkCredential().Password

Windows 凭据管理器安全地为本地用户存储凭据。只有最初保存凭据的用户才能检索它。

PowerShell 技能连载 - 使用 HTML 来创建 PDF 报告(第 3 部分)

HTML 方便地将数据格式化为输出报告。在这个最后的部分中,我们将介绍如何将最终 HTML 报告转换为 PDF,以便轻松地将其传递给同事和团队成员。

以下是我们在第二部分介绍的脚本:

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
$path = "$env:temp\report.html"

# get data from any cmdlet you wish
$data = Get-Service | Sort-Object -Property Status, Name

# helper function to convert arrays to string lists
function Convert-ArrayToStringList
{
param
(
[Parameter(Mandatory, ValueFromPipeline)]
$PipelineObject
)
process
{
$Property = $PipelineObject.psobject.Properties |
Where-Object { $_.Value -is [Array] } |
Select-Object -ExpandProperty Name

foreach ($item in $Property)
{
$PipelineObject.$item = $PipelineObject.$item -join ','


}

return $PipelineObject
}
}


# compose style sheet
$stylesheet = "
<style>
body { background-color:#AAEEEE;
font-family:Monospace;
font-size:10pt; }
table,td, th { border:1px solid blue;}
th { color:#00008B;
background-color:#EEEEAA;
font-size: 12pt;}
table { margin-left:30px; }
h2 {
font-family:Tahoma;
color:#6D7B8D;
}
h1{color:#DC143C;}
h5{color:#DC143C;}
</style>
"

# output to HTML
$data |
# make sure you use Select-Object to copy the objects
Select-Object -Property * |
Convert-ArrayToStringList |
ConvertTo-Html -Title Report -Head $stylesheet |
Set-Content -Path $path -Encoding UTF8

Invoke-Item -Path $path

结果是位于 $Path 中指定的文件位置中的 HTML 报告。现在,缺少的是将 HTML 文件转换为 PDF 文件的方法。

有很多方法可以实现这一目标,但最方便的方法是使用 Chrome 浏览器。但是,要进行转换,首先需要安装 Chrome 浏览器(如果尚未安装)。

这是获取现有 HTML 文件并将其转换为 PDF 的最终代码:

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
# path to existing HTML file
$path = "$env:temp\report.html"

# determine installation path for Chrome
$Chrome = ${env:ProgramFiles(x86)}, $env:ProgramFiles |
ForEach-Object { "$_\Google\Chrome\Application\chrome.exe" } |
Where-Object { Test-Path -Path $_ -PathType Leaf } |
Select-Object -First 1

if ($Chrome.Count -ne 1) { throw "Chrome not installed." }

# compose destination path by changing file extension to PDF
$destinationPath = [System.IO.Path]::ChangeExtension($Path, '.pdf')

# doing the conversion
& $Chrome --headless --print-to-pdf="$destinationPath" "$Path"

# (this is async so it may take a moment for the PDF to be created)
do
{
Write-Host '.' -NoNewline
Start-Sleep -Seconds 1
} Until (Test-Path -Path $destinationPath)

Invoke-Item -Path $destinationPath

PowerShell 技能连载 - 使用 HTML 来创建 PDF 报告(第 2 部分)

HTML 是一种将数据格式化为输出报告的简单方法。在第二部分中,我们说明了如何将包含数组的属性转换为字符串列表。数组无法正确显示为文本,因此此问题适用于 HTML 报告和将数据导出到 CSV。

请看:下面的代码将您的所有服务生成 HTML 报告,这是我们在第一部分结束时停下的地方:

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
$path = "$env:temp\report.html"

# get data from any cmdlet you wish
$data = Get-Service | Sort-Object -Property Status, Name

# compose style sheet
$stylesheet = "
<style>
body { background-color:#AAEEEE;
font-family:Monospace;
font-size:10pt; }
table,td, th { border:1px solid blue;}
th { color:#00008B;
background-color:#EEEEAA;
font-size: 12pt;}
table { margin-left:30px; }
h2 {
font-family:Tahoma;
color:#6D7B8D;
}
h1{color:#DC143C;}
h5{color:#DC143C;}
</style>
"

# output to HTML
$data | ConvertTo-Html -Title Report -Head $stylesheet | Set-Content -Path $path -Encoding UTF8

Invoke-Item -Path $path

当您查看报告时,您会注意到某些列包含数据类型而不是数据,即 RequiredServicesDependentServices。 原因是因为这些属性包含数组。要正确显示属性内容,您需要首先将数组转换为字符串列表。

这是一个自动检测包含数组的属性并用字符串列表代替这些属性的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Convert-ArrayToStringList
{
param
(
[Parameter(Mandatory, ValueFromPipeline)]
$PipelineObject
)
process
{
$Property = $PipelineObject.psobject.Properties |
Where-Object { $_.Value -is [Array] } |
Select-Object -ExpandProperty Name

foreach ($item in $Property)
{
$PipelineObject.$item = $PipelineObject.$item -join ','
}

return $PipelineObject
}
}

为此,您首先必须通过 Select-Object 获取可以操纵的对象的副本。Convert-ArrayToStringList 也对创建 CSV 导出非常有帮助。下面的代码将服务列表创建为 CSV 文件,并确保所有属性都是可读的,然后将 CSV 文件加载到 Microsoft Excel 中:

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

Get-Service |
Select-Object -Property * |
Convert-ArrayToStringList |
Export-Csv -NoTypeInformation -Encoding UTF8 -Path $Path -UseCulture

Start-Process -FilePath excel -ArgumentList $Path

这是一个完整的脚本,能创建一个具有所有可读属性的服务报告:

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
$path = "$env:temp\report.html"

# get data from any cmdlet you wish
$data = Get-Service | Sort-Object -Property Status, Name

# helper function to convert arrays to string lists
function Convert-ArrayToStringList
{
param
(
[Parameter(Mandatory, ValueFromPipeline)]
$PipelineObject
)
process
{
$Property = $PipelineObject.psobject.Properties |
Where-Object { $_.Value -is [Array] } |
Select-Object -ExpandProperty Name

foreach ($item in $Property)
{
$PipelineObject.$item = $PipelineObject.$item -join ','


}

return $PipelineObject
}
}


# compose style sheet
$stylesheet = "
<style>
body { background-color:#AAEEEE;
font-family:Monospace;
font-size:10pt; }
table,td, th { border:1px solid blue;}
th { color:#00008B;
background-color:#EEEEAA;
font-size: 12pt;}
table { margin-left:30px; }
h2 {
font-family:Tahoma;
color:#6D7B8D;
}
h1{color:#DC143C;}
h5{color:#DC143C;}
</style>
"

# output to HTML
$data |
# make sure you use Select-Object to copy the objects
Select-Object -Property * |
Convert-ArrayToStringList |
ConvertTo-Html -Title Report -Head $stylesheet |
Set-Content -Path $path -Encoding UTF8

Invoke-Item -Path $path

PowerShell 技能连载 - 使用 HTML 来创建 PDF 报告(第 1 部分)

可以通过 HTML 轻松地将格式化的数据转换成输出报告。在这个三部分的系列中,我们首先说明您如何撰写 HTML 报告,然后展示一种将这些 HTML 报告转换为 PDF 文档的简单方法。

PowerShell 中有一个 ConvertTo-Html cmdlet,可以轻松将输出保存到 HTML 表格:

1
2
3
4
5
6
7
8
9
$path = "$env:temp\report.html"

# get data from any cmdlet you wish
$data = Get-Service | Sort-Object -Property Status, Name

# output to HTML
$data | ConvertTo-Html | Set-Content -Path $path -Encoding UTF8

Invoke-Item -Path $path

最终的报告可能仍然很丑陋,但是添加 HTML 样式表可以轻松美化报告并添加您的公司设计:

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
$path = "$env:temp\report.html"

# get data from any cmdlet you wish
$data = Get-Service | Sort-Object -Property Status, Name

# compose style sheet
$stylesheet = "
<style>
body { background-color:#AAEEEE;
font-family:Monospace;
font-size:10pt; }
table,td, th { border:1px solid blue;}
th { color:#00008B;
background-color:#EEEEAA;
font-size: 12pt;}
table { margin-left:30px; }
h2 {
font-family:Tahoma;
color:#6D7B8D;
}
h1{color:#DC143C;}
h5{color:#DC143C;}
</style>
"

# output to HTML
$data | ConvertTo-Html -Title Report -Head $stylesheet | Set-Content -Path $path -Encoding UTF8

Invoke-Item -Path $path

PowerShell 技能连载 - 更新帮助

如果您有时使用 Get-Help 和本地帮助,则应该偶尔运行 Update-Help 以更新本地帮助文件。在 Windows PowerShell 上,这需要本地管理特权,因为帮助文件存储在受保护的 Windows 文件夹中:

1
PS> Update-Help -UICulture en-us -Force

在 PowerShell 7 上,Update-Help 现在有一个附加的参数 -Scope CurrentUser,因此您也可以在没有管理员特权的情况下更新本地帮助。

更新本地帮助很重要,因为每当您运行它时,它都会动态地查看机器上存在的 PowerShell 模块,并仅下载关于它们的帮助。如果以后添加更多模块,则不要忘记再次运行更新——还可以下载新模块的帮助文件——前提是该模块尚未发布它们。

请注意,Update-Module 可能会在结束时发出红色错误消息。不用担心:通常,它仅是由几个没有帮助的模块引起的。错误消息并未表明整个更新过程有问题。

PowerShell 技能连载 - 利用用户配置文件的优势

当 PowerShell 启动时,它会自动查找一个特殊的自动启动脚本。默认情况下该脚本不存在,并且对于每个 PowerShell 环境是不同的。$profile 变量体现它的路径。这是在我机器的 Windows PowerShell 控制台环境中的路径:

1
C:\Users\tobias\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

可以快速地检测这个文件是否存在,如果不存在的话,用 PowerShell 创建它:

1
2
3
4
5
6
7
$exists = Test-Path -Path $profile
if ($exists -eq $false)
{
$null = New-Item -Path $profile -ItemType File -Force
}

notepad $profile

有了这样的自启动脚本后,您可以在您的每个 PowerShell 会话中添加各种有用的东西。例如,创建一个较短的命令行提示符:

1
2
3
4
5
function prompt
{
'PS> '
$host.UI.RawUI.WindowTitle = Get-Location
}

或通过简化的登录使生活更轻松:

1
2
3
4
5
6
7
8
9
10
function in365
{
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName 'youremailhere'
}

function out365
{
Disconnect-ExchangeOnline -Confirm:$false
}

只需确保您保存更改以及执行策略允许脚本运行即可。