PowerShell 技能连载 - 使用秘密的 $FormatEnumerationLimit 变量

Format-List 缺省以列表的形式显示对象的属性,如果某个属性包含一个数组,该数组将会转换为文本,而且只显示一小部分数组元素。以下是一个例子:

1
2
3
4
5
6
7
PS> Get-Process -Id $Pid | Format-List -Property Name, Modules


Name : powershell_ise
Modules : {System.Diagnostics.ProcessModule (PowerShell_ISE.exe),
System.Diagnostics.ProcessModule (ntdll.dll), System.Diagnostics.ProcessModule
(MSCOREE.DLL), System.Diagnostics.ProcessModule (KERNEL32.dll)...}

这行代码获取 PowerShell 的进程,并且显示它的名称和加载的模块。如您所见,输出的结果并没有显示所有加载的模块。

有一个名为 FormatEnumerationLimit 的神秘变量,控制 Format-List 显示多少个数组元素。

缺省情况下,显示个数限制为 4 个,所以输出结果中最多显示 4 个数组元素。如果将限制值设为 -1,事实上相当于关闭了该限制:

1
2
3
4
5
6
7
PS> $FormatEnumerationLimit
4

PS> $FormatEnumerationLimit = -1

PS> $FormatEnumerationLimit
-1

如果您再次运行相同的命令,Format-List 将显示所有数组元素:

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
PS> Get-Process -Id $Pid | Format-List -Property Name, Modules


Name : powershell_ise
Modules : {System.Diagnostics.ProcessModule (PowerShell_ISE.exe),
System.Diagnostics.ProcessModule (ntdll.dll), System.Diagnostics.ProcessModule
(MSCOREE.DLL), System.Diagnostics.ProcessModule (KERNEL32.dll),
System.Diagnostics.ProcessModule (KERNELBASE.dll), System.Diagnostics.ProcessModule
(ADVAPI32.dll), System.Diagnostics.ProcessModule (msvcrt.dll),
System.Diagnostics.ProcessModule (sechost.dll), System.Diagnostics.ProcessModule
(RPCRT4.dll), System.Diagnostics.ProcessModule (mscoreei.dll),
System.Diagnostics.ProcessModule (SHLWAPI.dll), System.Diagnostics.ProcessModule
(combase.dll), System.Diagnostics.ProcessModule (ucrtbase.dll),
System.Diagnostics.ProcessModule (bcryptPrimitives.dll),
System.Diagnostics.ProcessModule (GDI32.dll), System.Diagnostics.ProcessModule
(gdi32full.dll), System.Diagnostics.ProcessModule (msvcp_win.dll),
System.Diagnostics.ProcessModule (USER32.dll), System.Diagnostics.ProcessModule
(win32u.dll), System.Diagnostics.ProcessModule (IMM32.DLL),
System.Diagnostics.ProcessModule (kernel.appcore.dll), System.Diagnostics.ProcessModule
(VERSION.dll), System.Diagnostics.ProcessModule (clr.dll),
System.Diagnostics.ProcessModule (MSVCR120_CLR0400.dll),
System.Diagnostics.ProcessModule (mscorlib.ni.dll), System.Diagnostics.ProcessModule
(ole32.dll), System.Diagnostics.ProcessModule (uxtheme.dll),
System.Diagnostics.ProcessModule (tiptsf.dll), System.Diagnostics.ProcessModule
(OLEAUT32.dll), System.Diagnostics.ProcessModule (CRYPTSP.dll),
System.Diagnostics.ProcessModule (rsaenh.dll), System.Diagnostics.ProcessModule
(bcrypt.dll), System.Diagnostics.ProcessModule (CRYPTBASE.dll),
(...)

PowerShell 技能连载 - 立刻关闭显示器

如果您想运行一个长时间执行的脚本,何不先关闭显示器,而是傻傻地等着超时以后显示屏保呢?

以下是一个简单的函数,能够立即关闭显示器。只需要移动鼠标或按任意键就可以唤醒:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Set-DisplayOff
{
$code = @"
using System;
using System.Runtime.InteropServices;
public class API
{
[DllImport("user32.dll")]
public static extern
int SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
}
"@
$t = Add-Type -TypeDefinition $code -PassThru
$t::SendMessage(0xffff, 0x0112, 0xf170, 2)
}

PowerShell 技能连载 - 配置网络适配器

以下是一个简单的例子,演示如何向网络适配器分配 IP 地址、网关,和 DNS 服务器。这段脚本列出所有活动的网络适配器。当您选择一项并点击确认,脚本将把硬编码的地址赋给网络适配器。

请注意一下脚本只是模拟改变网络配置。如果您希望真的改变网络设置,请移除 -WhatIf 参数:

1
2
3
4
5
6
7
8
9
10
11
12
$NewIP = '192.168.2.12'
$NewGateway = '192.168.2.2'
$NewDNS = '8.8.8.8'
$Prefix = 24

$adapter = Get-NetAdapter |
Where-Object Status -eq 'Up' |
Out-GridView -Title 'Select Adapter to Configure' -OutputMode Single
$index = $adapter.InterfaceIndex

New-NetIPAddress -InterfaceIndex $index -IPAddress $NewIP -DefaultGateway $NewGateway -PrefixLength $Prefix -AddressFamily IPv4 -WhatIf
Set-DNSClientServerAddress –InterfaceIndex $index –ServerAddresses $NewDNS -whatIf

PowerShell 技能连载 - 免费的 PowerShell 帮助手册

即便是有经验的 PowerShell 用户也会经常忽略 PowerShell 强大的帮助系统,它类似 Linux 中的 man page。您所需要做的只是一次性下载帮助文件。要下载帮助文件,您需要在提升权限的 PowerShell 中运行以下代码:

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

当帮助文件下载完以后,以下是一个很棒的基础列表,展示 PowerShell 语言的几乎所有细节:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PS> Get-Help about* | Select Name, Synopsis

Name Synopsis
---- --------
about_ActivityCommonParameters Describes the parameters that Windows...
about_Aliases Describes how to use alternate names ...
about_Arithmetic_Operators Describes the operators that perform ...
about_Arrays Describes arrays, which are data stru...
about_Assignment_Operators Describes how to use operators to ass...
about_Automatic_Variables Describes variables that store state ...
about_Break Describes a statement you can use to ...
about_Checkpoint-Workflow Describes the Checkpoint-Workflow act...
about_CimSession Describes a CimSession object and the...
about_Classes Describes how you can use classes to ...
about_Command_Precedence Describes how Windows PowerShell dete...
about_Command_Syntax Describes the syntax diagrams that ar...
about_Comment_Based_Help Describes how to write comment-based ...
about_CommonParameters Describes the parameters
...

您甚至可疑用这行代码创建您自己的 PowerShell 帮助查看器:

1
2
3
4
5
6
Get-Help about* |
Select-Object -Property Name, Synopsis |
Out-GridView -Title 'Select Topic' -OutputMode Multiple |
ForEach-Object {
Get-Help -Name $_.Name -ShowWindow
}

当运行这行代码时,PowerShell 将搜索帮助主题并打开一个网格视图。只需要按住 CTRL 并选择所有您想阅读的主题,然后单击确认。选中的主题将会在独立的帮助查看窗口中打开。

PowerShell 技能连载 - 用 PowerShell 管理 Windows 10 的缺省 APP

Windows 10 缺省安装了一系列 APP,而且即使您手动卸载了它们,它们有可能在下一个重大 Windows 10 更新的时候又回来。

PowerShell 也可以移除这些 Windows 10 APP。您可以在任意时候重新运行脚本,来确保要清除的 APP 确实被删除了。例如这行代码将移除 3D Builder APP:

1
PS> Get-AppxPackage *3dbuilder* | Remove-AppxPackage

有许多类似 http://www.thewindowsclub.com/remove-built-windows-10-apps-users-using-powershell-script 的网站,提供许多更多如何移除特定的 Windows 10 APP 的例子。

PowerShell 技能连载 - 使用神奇的脚本块参数

在前一个例子中我们演示了 Rename-ItemNewName 的神奇功能。它可以接受一个新的文件名,也可以接受一个脚本块。脚本块可以用来批量命名大量文件。

我们现在来看看 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
function Test-MagicFunc
{
[CmdletBinding()]
param
(

[Parameter(Mandatory=$true, Position=0, ValueFromPipeline)]
[string]
$Par1,



[Parameter(ValueFromPipelineByPropertyName)]
[string]
$Par2
)


begin
{
Write-Warning "Starting..."
}

process
{
Write-Warning "Processing Par1=$Par1 and Par2=$Par2"
}

end
{
Write-Warning "Ending..."
}
}

您可以把它当作一个传统的独立函数运行:

1
2
3
4
PS>  Test-MagicFunc -Par1 100 -Par2 50
WARNING: Starting...
WARNING: Processing Par1=100 and Par2=50
WARNING: Ending...

您也可以通过管道输出来运行它,并且传入一个固定的第二参数:

1
2
3
4
5
6
7
PS> 1..4 |  Test-MagicFunc -Par2 99
WARNING: Starting...
WARNING: Processing Par1=1 and Par2=99
WARNING: Processing Par1=2 and Par2=99
WARNING: Processing Par1=3 and Par2=99
WARNING: Processing Par1=4 and Par2=99
WARNING: Ending...

但是您也可以对的第二个参数传入一个脚本块,该脚本块引用了从管道收到的对象:

1
2
3
4
5
6
7
PS> 1..4 |  Test-MagicFunc -Par2 { $_ * $_ }
WARNING: Starting...
WARNING: Processing Par1=1 and Par2=1
WARNING: Processing Par1=2 and Par2=4
WARNING: Processing Par1=3 and Par2=9
WARNING: Processing Par1=4 and Par2=16
WARNING: Ending...

事实证明,这个魔法十分简单:Par2 的参数定义显示它可以接受管道输入。它不关心是由属性名输入 (ValueFromPipelineByPropertyName) 还是通过值输入 (ValueFromPipeline)。在这些例子中,当您将一个脚本块传给参数时,PowerShell 将该脚本块当作管道输入值的接口:$_ 引用输入的对象,脚本块可以使用任何需要的代码来计算需要绑定到参数的值。

PowerShell 技能连载 - 批量重命名图片

重命名单个文件可以很容易地用 Rename-Item 实现,但是有些时候 cmdlet 参数可以更聪明地使用,帮您实现批量自动化。

例如,假设您的照片文件夹中有大量的照片:

1
2
$path = [Environment]::GetFolderPath('MyPictures')
Get-ChildItem -Path $path -Filter *.png

如果您想对它们命名,例如在前面加一个序号,您需要设计一个循环,例如这样:

1
2
3
4
5
6
7
8
9
$path = [Environment]::GetFolderPath('MyPictures')
$counter = 0
$files = Get-ChildItem -Path $path -Filter *.png
$files |
ForEach-Object {
$counter++
$newname = '{0} - {1}' -f $counter, $_.Name
Rename-Item -Path $_.FullName -NewName $newname -WhatIf
}

还有一个简单得多的解决方案:-NewName 参数也可以接受一个脚本块。每当一个元素通过管道传给 Rename-Item,脚本块就会执行一次。代码可以简化为:

1
2
3
4
5
6
7
$path = [Environment]::GetFolderPath('MyPictures')
$counter = 0
$files = Get-ChildItem -Path $path -Filter *.png
$files | Rename-Item -NewName {
$script:counter++
'{0} - {1}' -f $counter, $_.Name
} -WhatIf

还有一处重要的区别:Rename-Item 执行的脚本块是在它自己的作用域中运行的,所以如果您希望使用一个递增的计数器,那么需要在变量名之前增加一个 script:,这样变量就作用在脚本作用域上。

警告:在某些 PowerShell 版本中有一个不友好的 bug,重命名文件将改变 Get-ChildItem 的输出,所以如果您直接将 Get-ChildItem 的结果通过管道传给 Rename-Item,您可能会遇到无限死循环,文件会一直被重命名直到文件路径长度超过限制。要安全地使用它,请确保在将变量传给 Rename-Item 之前将 Get-ChildItem 的结果保存到变量中!

PowerShell 技能连载 - PowerShell 陈列架 dba 工具 – 数据库专家 PowerShell 扩展

在前一个技能中我们解释了如何获取 PowerShellGet 并在您的 PowerShell 版本中运行。现在我们来看看 PowerShell 陈列架能够如何方便地扩展 PowerShell 功能。

PowerShell 是一个多用途的自动化语言,而且世界各地的数据库专家已经开始开发一个名为 “dbatools” 的 PowerShell 扩展,它可以从 PowerShell 陈列架免费地下载:

1
PS> Install-Module dbatools -Scope CurrentUser -Force

当安装完之后,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
35
36
PS> Get-Command -Module dbatools

CommandType Name Version Sou
rce
----------- ---- ------- ---
Alias Attach-DbaDatabase 0.9.332 dba
Alias Backup-DbaDatabaseCertificate 0.9.332 dba
Alias Connect-DbaSqlServer 0.9.332 dba
Alias Copy-SqlAgentCategory 0.9.332 dba
Alias Copy-SqlAlert 0.9.332 dba
Alias Copy-SqlAudit 0.9.332 dba
Alias Copy-SqlAuditSpecification 0.9.332 dba
Alias Copy-SqlBackupDevice 0.9.332 dba
Alias Copy-SqlCentralManagementServer 0.9.332 dba
Alias Copy-SqlCredential 0.9.332 dba
Alias Copy-SqlCustomError 0.9.332 dba
Alias Copy-SqlDatabase 0.9.332 dba
Alias Copy-SqlDatabaseAssembly 0.9.332 dba
Alias Copy-SqlDatabaseMail 0.9.332 dba
Alias Copy-SqlDataCollector 0.9.332 dba
Alias Copy-SqlEndpoint 0.9.332 dba
Alias Copy-SqlExtendedEvent 0.9.332 dba
Alias Copy-SqlJob 0.9.332 dba
Alias Copy-SqlJobServer 0.9.332 dba
Alias Copy-SqlLinkedServer 0.9.332 dba
Alias Copy-SqlLogin 0.9.332 dba
Alias Copy-SqlOperator 0.9.332 dba
Alias Copy-SqlPolicyManagement 0.9.332 dba
Alias Copy-SqlProxyAccount 0.9.332 dba
Alias Copy-SqlResourceGovernor 0.9.332 dba
Alias Copy-SqlServerAgent 0.9.332 dba
Alias Copy-SqlServerTrigger 0.9.332 dba
Alias Copy-SqlSharedSchedule 0.9.332 dba
Alias Copy-SqlSpConfigure 0.9.332 dba
Alias Copy-SqlSsisCatalog 0.9.332 dba
...

这个模块的文档齐备,所以您可以使用 Get-Help 查看每个命令的细节和示例代码。同样地,当您用您喜欢的搜索引擎搜索 “PowerShell + dbatools”,可以找到一个有许多示例和教程的,充满活力的社区。

PowerShell 技能连载 - PowerShell 陈列架:探索脚本块日志(第 2 部分)

在前一个技能中我们介绍了免费的 ScriptBlockLoggingAnalyzer,它覆盖了 PowerShell 日志的代码。默认情况下,它只对一小部分命令有效,但如果您启用了所有脚本块的日志,那么您机器上任何人运行的任何代码都会被记录。

以下是操作步骤(只对 Windows PowerShell 有效,请在提升权限的 PowerShell 中运行!):

1
2
3
4
5
6
7
8
9
10
11
12
13
#requires -RunAsAdministrator

# install the module from the Gallery (only required once!)
Install-Module ScriptBlockLoggingAnalyzer -Force

# enable full script block logging
Enable-SBL

# extend the log size
Set-SBLLogSize -MaxSizeMB 100

# clear the log (optional)
Clear-SBLLog

现在起,这台机器上运行的所有 PowerShell 代码都会被记录。要查看记录的代码,请使用以下代码:

1
PS> Get-SBLEvent | Out-GridView

PowerShell 技能连载 - PowerShell 陈列架:探索脚本块日志(第 1 部分)

在前一个技能中我们解释了如何获取 PowerShellGet 并在您的 PowerShell 版本中运行。现在我们来看看 PowerShell 陈列架能够如何方便地扩展 PowerShell 功能。

脚本块日志是 PowerShell 5 以及之后版本的新功能。当 PowerShell 引擎编译(执行)一个命令,它将命令的执行记录到一个内部的日志文件。默认情况下,只记录了少数被认为与安全性相关的命令。通过一个名为 ScriptBlockLoggingAnalyzer 的免费模块,您可以找到 PowerShell 在您机器上记录日志的代码:

1
2
3
4
5
# install the extension module from the Gallery (only required once!)
Install-Module ScriptBlockLoggingAnalyzer -Scope CurrentUser -Force

# show all logged events
Get-SBLEvent | Out-GridView

请注意 ScriptBlockLoggingAnalyzer 当前只适用于 Windows PowerShell。PowerShell Core 使用相同的机制,但是不同的日志。由于 PowerShell Core 中的日志名称还在开发中,所以您需要手工调整模块来适应 PowerShell Core。