PowerShell 技能连载 - 处理长文件路径

以前,当路径长于 256 字符时,Windows 文件系统有时会变得缓慢。在 PowerShell Gallery 有一个 module,增加了一系列 cmdlet,可以快速搜索文件系统,并且支持任意长度的路径。

如果您使用 PowerShell 5 或安装了 PowerShellGet(www.powershellgallery.com),那么您可以从 PowerShell Gallery 中下载和安装 “PSAlphaFS” module:

1
Install-Module -Name PSAlphaFS -Scope CurrentUser

不幸的是,这些 cmdlet 似乎需要完整的管理员特权,而对普通用户会抛出异常。如果您是管理员,您可以以这种方式查找长路径的文件:

1
2
Get-LongChildItem -Path c:\windows -Recurse -File |
Where-Object { $_.FullName.Length -gt 250 }

PowerShell 技能连载 - 检测字符代码 0

有些时候,字符串适用 “\0“ 作为分隔符。不像其它大多数分隔符,这个分隔符并不显示在文本输出中,但仍然可以用于分割文本。

PowerShell 可以处理包含字符代码 0 的字符串。它用反斜杠后跟着数字 0 来表示。请注意文本需要放在双引号之内,才能将反斜杠序列转换为字节 0。

以下是一个演示如何分割 \0 分割的文本的例子:

1
2
3
4
5
6
# create a sample text
$text = "Part 1`0Part 2`0Part 3"
# delimiter does not show in output...
$text
# ...but can be used to split:
$text -split "`0"

PowerShell 技能连载 - 自动定义函数的别名

您也许知道 PowerShell 支持命令的别名。但是您是否知道也可以在函数定义内部为 PowerShell 函数定义别名(PowerShell 4 引入的功能)呢?让我们来看看:

1
2
3
4
5
6
7
8
function Get-AlcoholicBeverage
{
[Alias('Beer','Drink')]
[CmdletBinding()]
param()

"Here is your beer."
}

这个函数的“正式”名称是 Get-AlcoholicBeverage,但是这个函数也可以通过 “Beer“ 和 “Drink“ 别名来引用。在函数定义时,PowerShell 自动增加了这些别名:

1
2
3
4
CommandType     Name
----------- ----
Alias Beer -> Get-AlcoholicBeverage
Alias Drink -> Get-AlcoholicBeverage

PowerShell 技能连载 - 检查操作系统版本

以下是一个简单快速的检查操作系统版本的方法:

1
2
3
4
5
6
PS C:\> [Environment]::OSVersion


Platform ServicePack Version VersionString
-------- ----------- ------- -------------
Win32NT 10.0.14393.0 Microsoft Windows NT 10.0.14393.0

所以要检查一个脚本是否运行在一个预定的操作系统上变得十分简单。例如要检查是否运行在 Windows 10 上,请试试这行代码:

1
2
3
PS C:\> [Environment]::OSVersion.Version.Major -eq 10

True

PowerShell 技能连载 - 检查变量是否为 $NULL

如果您想检查一个变量是否为 $Null(空),请记住始终将 $null 放在比较运算符的左边。大多数情况下,顺序不重要:

1
2
3
4
5
6
7
8
9
PS C:\> $a = $null

PS C:\> $b = 12

PS C:\> $a -eq $null
True

PS C:\> $b -eq $null
False

然而,如果一个变量为一个数组,则将数组放在对比操作符左边的行为类似过滤器。这时候顺序变得很关键:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# this all produces inconsistent and fishy results

$a = $null
$a -eq $null # works: returns $true

$a = 1,2,3
$a -eq $null # fails: returns $null

$a = 1,2,$null,3,4
$a -eq $null # fails: returns $null

$a = 1,2,$null,3,4,$null,5
$a -eq $null # fails: returns array of 2x $null
($a -eq $null).Count

如果您将变量放在左侧,PowerShell 将检测数组内部的 $null 值,并且返回这些值。如果没有 $null 值,则返回 $null

如果您将变量放在右侧,PowerShell 将检查变量是否为 $null

1
2
3
4
5
6
7
8
9
10
11
12
13
# by reversing the operands, all is FINE:

$a = $null
$null -eq $a # works: $true

$a = 1,2,3
$null -eq $a # works: $false

$a = 1,2,$null,3,4
$null -eq $a # works: $false

$a = 1,2,$null,3,4,$null,5
$null -eq $a # works: $false

可以将 $null 放在比较运算符的左侧而不是右侧,来消除这个问题。

PowerShell 技能连载 - 检查证书详细信息

如果您想检查和查看一个证书文件的详细信息而不需要将它导入证书存储空间,以下是一个简单的例子:

1
2
3
4
5
6
7
# replace path with actual path to CER file
$Path = 'C:\Path\To\CertificateFile\test.cer'

Add-Type -AssemblyName System.Security
[Security.Cryptography.X509Certificates.X509Certificate2]$cert = [Security.Cryptography.X509Certificates.X509Certificate2]::CreateFromCertFile($Path)

$cert | Select-Object -Property *

您现在可以存取所有详细信息并获取指纹或检查失效日期:

1
2
3
4
5
6
PS C:\> $cert.Thumbprint
7A5A350D95247BB173CDF0867ADA2DBFFCCABDE6

PS C:\> $cert.NotAfter

Monday June 12 2017 06:00:00

PowerShell 技能连载 - 到处 ActiveDirectory 模块

要在 PowerShell 中管理 Active Directory 的用户和计算机,您需要 Microsoft 提供的免费的 RSAT 工具中的 Active Directory 模块。

假设您是一个域管理员并且拥有远程管理域控制器的权限,您也可以从 DC 中导出 ActiveDirectory 模块,并且可以通过隐式远程操作在本地使用它。

以下是使用方法:

1
2
3
4
5
6
7
8
9
$DC = 'dc1'  # rename, must be name of one of your domain controllers

# create a session
$s = New-PSSession -ComputerName dc1
# export the ActiveDirectory module from the server to a local module "ADStuff"
Export-PSSession -Session $s -OutputModule ADStuff -Module ActiveDirectory -AllowClobber -Force

# remove session
Remove-PSSession $s

当您运行这段代码时,并且您拥有连接到 DC 的权限时,这段代码创建了一个名为 “ADStuff” 的本地 module,其中包含了所有 AD cmdlet。您可以通过隐式远程处理使用 AD cmdlet而不需要安装 RSAT 工具。

警告:由于所有 cmdlet 实际上都是运行在服务器端,所有结果都被序列化后传到本地。这会改变对象类型,所以当您用将对象通过管道从一个 AD cmdlet 传到另一个 AD cmdlet 时,您可能会遇到绑定问题。只要您在管道之外使用 cmdlet,那么一切都没问题。

PowerShell 技能连载 - 管理 NTFS 权限

由于没有内置的管理 NTFS 权限的 cmdlet,所以有越来越多的开源 PowerShell module 实现这个功能。一个有前途的 module 是由 Raimund Andree,一个德国的 Microsoft 工程师写的。他也将在即将到来的 PowerShell 欧洲会议 (www.psconf.eu) 中演讲。

如果您使用的是 PowerShell 5 或已经安装了 PowerShellGet (www.powershellgallery.com),以下是从 PowerShell Gallery 下载并安装 “NTFSSecurity” module 的方法:

1
2
3
4
5
# review module details
Find-Module -Repository PSGallery -Name NTFSSecurity | Select-Object -Property * | Out-GridView

# download module
Install-Module -Repository PSGallery -Name NTFSSecurity -Scope CurrentUser

要查看所有的新 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
PS C:\> Get-Command -Module NTFSSecurity

CommandType Name Version

----------- ---- -------
Cmdlet Add-NTFSAccess 4.2.3
Cmdlet Add-NTFSAudit 4.2.3
Cmdlet Clear-NTFSAccess 4.2.3
Cmdlet Clear-NTFSAudit 4.2.3
Cmdlet Copy-Item2 4.2.3
Cmdlet Disable-NTFSAccessInheritance 4.2.3
Cmdlet Disable-NTFSAuditInheritance 4.2.3
Cmdlet Disable-Privileges 4.2.3
Cmdlet Enable-NTFSAccessInheritance 4.2.3
Cmdlet Enable-NTFSAuditInheritance 4.2.3
Cmdlet Enable-Privileges 4.2.3
Cmdlet Get-ChildItem2 4.2.3
Cmdlet Get-DiskSpace 4.2.3
Cmdlet Get-FileHash2 4.2.3
Cmdlet Get-Item2 4.2.3
Cmdlet Get-NTFSAccess 4.2.3
Cmdlet Get-NTFSAudit 4.2.3
Cmdlet Get-NTFSEffectiveAccess 4.2.3
Cmdlet Get-NTFSHardLink 4.2.3
Cmdlet Get-NTFSInheritance 4.2.3
Cmdlet Get-NTFSOrphanedAccess 4.2.3
Cmdlet Get-NTFSOrphanedAudit 4.2.3
Cmdlet Get-NTFSOwner 4.2.3
Cmdlet Get-NTFSSecurityDescriptor 4.2.3
Cmdlet Get-NTFSSimpleAccess 4.2.3
Cmdlet Get-Privileges 4.2.3
Cmdlet Move-Item2 4.2.3
Cmdlet New-NTFSHardLink 4.2.3
Cmdlet New-NTFSSymbolicLink 4.2.3
Cmdlet Remove-Item2 4.2.3
Cmdlet Remove-NTFSAccess 4.2.3
Cmdlet Remove-NTFSAudit 4.2.3
Cmdlet Set-NTFSInheritance 4.2.3
Cmdlet Set-NTFSOwner 4.2.3
Cmdlet Set-NTFSSecurityDescriptor 4.2.3
Cmdlet Test-Path2 4.2.3

当您获取到这些 cmdlet,那么增加或设置 NTFS 权限就轻而易举:

1
2
3
4
5
6
$path = 'c:\test1'

mkdir $path

Get-NTFSAccess -Path $Path |
Add-NTFSAccess -Account training14\student14 -AccessRights CreateFiles -AccessType Allow

警告:您需要管理员权限才能更改 NTFS 权限,即使是操作您拥有的文件系统对象。

PowerShell 技能连载 - 使用通配符确定数组是否包含值

当您想了解一个数组是否包含某个指定的元素,PowerShell 提供了 -contains 操作符。然而这个操作符不支持通配符,所以您只能使用精确匹配。

以下是一个帮助您使用通配符过滤数组元素的解决方法:

1
2
3
4
5
6
7
8
9
$a = 'Hanover', 'Hamburg', 'Vienna', 'Zurich'

# is the exact phrase present in array?
$a -contains 'Hannover'
# is ANY phrase present in array that matches the wildcard expression?
(@($a) -like 'Ha*').Count -gt 0

# list all phrases from array that match the wildcard expressions
@($a) -like 'Ha*'

PowerShell 技能连载 - 处理 LDAP 和日期

LDAP 过滤器是一个快速和强大的从 Active Directory 中获取信息的方法。然而,LDAP 过滤器使用的是一个很底层的日期和时间格式。它基本上是一个很大的整形数。幸运的是 PowerShell 包含多种将实际 DateTime 对象转换为这些数字,以及相反操作的方法。

以下是一个使用 ActiveDirectory 模块中 Get-ADUser 方法来查找所有近期更改了密码的用户的示例代码。如果您没有这个 module,请从 Microsoft 下载免费的 RSAT 工具。

1
2
3
4
5
6
7
8
# find all AD Users who changed their password in the last 5 days
$date = (Get-Date).AddDays(-5)
$ticks = $date.ToFileTime()


$ldap = "(&(objectCategory=person)(objectClass=user)(pwdLastSet>=$ticks))"
Get-ADUser -LDAPFilter $ldap -Properties * |
Select-Object -Property Name, PasswordLastSet