PowerShell 技能连载 - 检查文件名的非法字符

文件的命名是十分敏感的,不能包含某些特定的保留字符。要验证文件名并确保这些字符是合法的,以下对昨天的脚本(检查文件系统路径)做了一点改进。这个脚本检查文件名的合法性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# check path:
$filenameToCheck = 'testfile:?.txt'

# get invalid characters and escape them for use with RegEx
$illegal =[Regex]::Escape(-join [System.Io.Path]::GetInvalidFileNameChars())
$pattern = "[$illegal]"

# find illegal characters
$invalid = [regex]::Matches($filenameToCheck, $pattern, 'IgnoreCase').Value | Sort-Object -Unique

$hasInvalid = $invalid -ne $null
if ($hasInvalid)
{
"Do not use these characters in file names: $invalid"
}
else
{
'OK!'
}

结果如下:

Do not use these characters in file names: : ?

PowerShell 技能连载 - 查找文件路径中的非法字符(基于文件系统)

之前我们演示了如何使用简易的基于正则表达式的方法来查找字符串中的非法字符。我们鼓励您将这种策略运用到各种需要验证的字符串中。

如果您希望检测文件系统中的非法字符,以下是一个简单的适配:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# check path:
$pathToCheck = 'c:\test\<somefolder>\f|le.txt'

# get invalid characters and escape them for use with RegEx
$illegal =[Regex]::Escape(-join [System.Io.Path]::GetInvalidPathChars())
$pattern = "[$illegal]"

# find illegal characters
$invalid = [regex]::Matches($pathToCheck, $pattern, 'IgnoreCase').Value | Sort-Object -Unique

$hasInvalid = $invalid -ne $null
if ($hasInvalid)
{
"Do not use these characters in paths: $invalid"
}
else
{
'OK!'
}

非法的字符是从 GetInvalidPathChars() 中提取的并且用正则表达式转换为转义字符串。这个列表放在方括号中,所以当其中任一字符匹配成功时,RegEx 将能够报告匹配结果。

以下是结果:

Do not use these characters in paths: | < >

PowerShell 技能连载 - 查找多个非法字符

之前发,我们演示了如何用 -match 操作符来查找一段文本中的非法字符。不过,-match 操作符只能查找第一个匹配项。要列出字符串中的所有非法字符,请使用这种方法:

1
2
3
4
5
6
7
8
9
10
11
# some email address
$mail = 'THOMAS.börßen_senbÖrg@test.com'
# list of legal characters, inverted by "^"
$pattern = '[^a-z0-9\.@]'

# find all matches, case-insensitive
$allMatch = [regex]::Matches($mail, $pattern, 'IgnoreCase')
# create list of invalid characters
$invalid = $allMatch.Value | Sort-Object -Unique

'Illegal characters found: {0}' -f ($invalid -join ', ')

结果看起来如下:

Illegal characters found: _, ö, ß

PowerShell 技能连载 - 检查电子邮件地址(或其它文本)中的非法字符

这是一个清晰的检测和验证数据的快捷方法。假设您需要验证一个电子邮件地址是否包含非法字符:

1
2
3
4
5
6
7
8
9
10
11
12
13
# some email address
$mail = 'thomas.börsenberg@test.com'
# list of allowed characters
$pattern = '[^a-z0-9\.@]'

if ($mail -match $pattern)
{
('Invalid character in email address: {0}' -f $matches[0])
}
else
{
'Email address is good.'
}

这段代码使用了正则表达式。正则表达式列出所有合法的字符(从 a 到 z,以及某些特殊字符)。在前面加上“^”,列表的含义发生反转,代表所有非法字符。如果找到至少一个字符,则返回第一个非法字符。

Invalid character in email address: ö

PowerShell 技能连载 - PowerShell Remoting and HTTP 403 Error

如果您在使用 PowerShell 远程操作时遇到“HTTP 403”错误,一个潜在的原因可能是代理服务器影响了请求。

不过,要禁用代理服务器很容易。只需要在您的呼叫中增加一个 session 选项并且将 ProxyAccessType 设置为“NoProxyServer”即可:

1
2
3
4
5
6
7
8
# you are connecting to this computer
# the computer in $destinationcomputer needs to have
# PowerShell remoting enabled
$DestinationComputer = 'server12'

$option = New-PSSessionOption -ProxyAccessType NoProxyServer

Invoke-Command -ScriptBlock { "Connected to $env:computername" } -ComputerName $DestinationComputer -SessionOption $option

PowerShell 技能连载 - 在单侧启用 CredSSP

如之前所示,CredSSP 可以用在远程代码上,避免二次连接问题。不过,要使用 CredSSP 验证方式您得在客户端和服务端分别设置,才能使它们彼此信任。

这并不意味着您必须物理接触那台服务器。如果您想在您的计算机和任何一台服务器(假设那台服务器上启用了 PowerShell 远程连接)建立一个 CredSSP 信任关系,只需要做这些:

1
2
3
4
5
6
7
8
#requires -Version 2.0 -RunAsAdministrator

# this is the server you want to communicate with using CredSSP
# the server needs to have PowerShell remoting enabled already
$Server = 'NameOfServer'

Enable-WSManCredSSP -Role Client -DelegateComputer $Server -Force
Invoke-Command { Enable-WSManCredSSP -Role Server } -ComputerName $Server

如您所见,Enable-WSManCredSSP 可以远程执行。

PowerShell 技能连载 - 用 CredSSP 解决二次远程连接

在钱一个技能中我们演示了当您的远程代码试图通过第三方身份认证时会遇到的二次远程连接问题。

在您在客户端和服务端之间创建了一个可信的连接之后,可以传递您的凭据(只需要做一次,并且需要管理员权限)。

在客户端,运行这段代码:

1
Enable-WSManCredSSP -Role Client -DelegateComputer nameOfServer

在服务端,运行这段代码:

1
Enable-WSManCredSSP -Role Server

现在将 PowerShell 代码从客户端发送到服务端并执行时,服务端能够将您的凭据送给第三方验证通过,所以远程代码可以通过文件服务器的身份认证并访问共享文件夹:

1
2
3
4
5
6
7
8
#requires -Version 3.0

$code =
{
Get-ChildItem -Path \\fls01\#TRAIN1\PowerShell\Class
}

Invoke-Command -Authentication Credssp -ScriptBlock $code -ComputerName nameOfServer -Credential myCompany\myName

请注意当您使用 CredSSP 验证时,您必须提交显式的凭据(用 -Credential)且无法通过 Kerberos 透明传输当前的身份。

PowerShell 技能连载 - 理解二次远程连接问题

当您用 Invoke-Command 远程执行 PowerShell 代码时,您的凭据将会锁定在首个连接的机器上。

PowerShell 远程连接默认情况下不会传递您的凭据,不会使用您的凭据来登录别的系统。这听起来是个好主意,不过在某些情况也严重限制了您的代码。

这是一个典型的错误代码:

1
2
3
4
5
6
$code =
{
Get-ChildItem -Path \\fls01\#TRAIN1\PowerShell\Class
}

Invoke-Command -ScriptBlock $code -ComputerName server1

这段代码试图在远程访问一个文件共享。但是即便您有权限访问该共享,这段远程代码也无法使用您的身份进行第三方验证(在这个例子中是文件服务器)。

PowerShell 技能连载 - 查找隐藏的自启动程序

Ever wondered why some programs launch whenever you log into Windows? Here’s a one liner listing autostarts that affect your login:
是否好奇为什么有些程序在登录 Windows 的时候会自动启动?这是一行列出登录时自启动项的代码:

1
2
3
4
5
#requires -Version 3

Get-CimInstance -ClassName Win32_StartupCommand |
Select-Object -Property Command, Description, User, Location |
Out-GridView

PowerShell 技能连载 - Getting List of Current Group Memberships

当您可以通过 Active Directory 来获取一个用户的组成员,有一个简单的方法是直接通过用户的 access token 获取信息,而不需要 AD 联系人。

这行代码将取出当前用户所在的所有组的 SID:

1
2
#requires -Version 3.0
[System.Security.Principal.WindowsIdentity]::GetCurrent().Groups.Value

这是获取翻译后的组名的方法:

1
2
#requires -Version 3.0
[System.Security.Principal.WindowsIdentity]::GetCurrent().Groups.Translate( [System.Security.Principal.NTAccount])

如果这个列表中有重复,那么您就可以知道有多个 SID 指向同一个名字。这种情况在您曾经迁移过 AD(SID 历史)时可能会发生。只需要将结果用管道输出到 Sort-Object -Unique 就能移除重复。