PowerShell 技能连载 - (分别)测试文件和文件夹

Test-Path 在测试一个文件或文件夹是否存在时十分有用,它可以用在任何 PowerShell 驱动器上。所以它也可以测试一个变量、一个函数,或一个证书是否存在(举个例子)。

In recent PowerShell versions, Test-Path can now differentiate between containers (i.e. folders) and leafs (i.e. files), too:

在近期的 PowerShell 版本中,Test-Path 还可以区分容器(例如文件夹)和叶子(例如文件):

1
2
3
4
5
6
7
$path = 'c:\windows\explorer.exe'
# any item type
Test-Path -Path $path
# just files
Test-Path -Path $path -PathType Leaf
# just folders
Test-Path -Path $path -PathType Container

PowerShell 技能连载 - 获取 Cmdlet 参数的帮助

在 PowerShell 5.0 中似乎有个 bug,限制了内置帮助窗口的作用。当您以 -ShowWindow 参数运行 Get-Help 命令时,该窗口只显示该 cmdlet 的语法和例子。许多额外信息并没有显示出来。

要获得某个 cmdlet 支持的参数的详细信息,请直接请求该信息。以下代码将解释 Get-Date 中的 -Format 参数是做什么的:

PS C:\> Get-Help -Name Get-Date -Parameter Format

-Format []
    Displays the date and time in the Microsoft .NET Framework format indicated by the
    format specifier. Enter a format specifier. For a list of available format
    specifiers, see DateTimeFormatInfo Class
    (http://msdn.microsoft.com/library/system.globalization.datetimeformatinfo.aspx)
    in MSDN.

    When you use the Format parameter, Windows PowerShell gets only the properties of
    the DateTime object that it needs to display the date in the format that you
    specify. As a result, some of the properties and methods of DateTime objects might
    not be available.

    Starting in Windows PowerShell 5.0, you can use the following additional formats
    as values for the Format parameter.

    -- FileDate. A file or path-friendly representation of the current date in local
    time. It is in the form of yyyymmdd ( using 4 digits, 2 digits, and 2 digits). An
    example of results when you use this format is 20150302.

    -- FileDateUniversal. A file or path-friendly representation of the current date
    in universal time. It is in the form of yyyymmdd + 'Z' (using 4 digits, 2 digits,
    and 2 digits). An example of results when you use this format is 20150302Z.

    -- FileDateTime. A file or path-friendly representation of the current date and
    time in local time, in 24-hour format. It is in the form of yyyymmdd + 'T' +
    hhmmssmsms, where msms is a four-character representation of milliseconds. An
    example of results when you use this format is 20150302T1240514987.

    -- FileDateTimeUniversal. A file or path-friendly representation of the current
    date and time in universal time, in 24-hour format. It is in the form of yyyymmdd
    + 'T' + hhmmssmsms, where msms is a four-character representation of milliseconds,
    + 'Z'. An example of results when you use this format is 20150302T0840539947Z.

    Required?                    false
    Position?                    named
    Default value                none
    Accept pipeline input?       false
    Accept wildcard characters?  false

通过这些信息,您现在可以知道如何格式化日期和时间:

1
2
3
$date = Read-Host -Prompt 'Enter a date'
$weekday = Get-Date -Date $date -Format 'dddd'
"$date is a $weekday"

PowerShell 技能连载 - 用一行代码更新 PowerShell 帮助信息

要获得 PowerShell 最全的输出信息,您需要更新 PowerShell 的帮助至少一次。这将下载并安装当您通过 cmdlet 运行 Get-Help 或是在 PowerShell ISE 中点击一个 cmdlet 并按 F1 时将出现的基础帮助文件集。

更新 PowerShell 帮助需要 Administrator 特权,因为帮助文件存在 Windows 文件夹中。

以下是一个单行命令,演示了如何以管理员特权运行任何 PowerShell 命令。这个命令将更新本地的 PowerShell 帮助文件:

1
Start-Process -FilePath powershell -Verb RunAs -ArgumentList "-noprofile -command Update-Help -UICulture en-us  -Force"

PowerShell 技能连载 - 在 PowerShell ISE 中获得 Cmdlet 的 IntelliSense

如果您在阅读某些加载到 PowerShell ISE 中的 PowerShell 代码,要获取额外信息十分容易。只需要点击想获得详情的 cmdlet,然后按下 CTRL+SPACE 键即可(译者注:可能会和 IME 切换快捷键冲突)。

这将调出 IntelliSense 菜单,即平时按下 “-“ 和 “.” 触发键时显示的菜单。由于只有一个 cmdlet 匹配成功,所以该列表只有一个项目。过一小会儿,就会弹出一个显示该 cmdlet 支持的所有参数的 tooltip。

如果您想了解更多,请按 F1 键。PowerShell ISE 将把当前位置的 cmdlet 名送给 Get-Help 命令。该帮助将在一个独立的新窗口中显示。

PowerShell 技能连载 - 从网站上下载图片

有许多有趣的网站,其中一个是 www.metabene.de (至少面向德国访访客),有 33 页内容,艺术家展示了他的绘画,并提供免费下载(只允许私人使用·私人使用)。

在类似这种情况中,PowerShell 可以帮助您将手动从网站下载图片的操作自动化。在 PowerShell 3.0 中,引入了一个称为 Invoke-WebRequest 的“PowerShell 浏览器”,它能够将人类在一个真实浏览器中操作的大多数事情自动化。

当您运行这段脚本时,它访问所有的 33 个网页,检查所有的图片链接,并将它们保存到硬盘上:

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
# open destination folder (and create it if needed)
$folder = 'c:\drawings'
$exists = Test-Path -Path $folder
if (!$exists) { $null = New-Item -Path $folder -ItemType Directory }
explorer $folder

# walk all 33 web pages that www.metabene.de offers
1..33 | ForEach-Object {
$url = "http://www.metabene.de/galerie/page/$_"

# navigate to website...
$webpage = Invoke-WebRequest -Uri $url -UseBasicParsing

# take sources of all images on this website...
$webpage.Images.src |
Where-Object {
# take only images that were uploaded to this blog
$_ -like '*/uploads/*'
}
} |
ForEach-Object {
# get filename of URL
$filename = $_.Split('/')[-1]
# create local file name
$destination= Join-Path -Path $Folder -ChildPath $filename
# download pictures
Invoke-WebRequest -Uri $url -OutFile $destination
}

PowerShell 技能连载 - Cmelet 错误报告的简单策略

在 PowerShell 中,您可以创建复杂的错误处理代码,但有些时候您可能只是想知道出了什么错并且把它记录下来。不需要额外的技能。

以下是两个可能会遇到错误的 cmdlet。当这些 cmdlet 执行完成时,您将能通过 $data1$data2 获得它们的执行结果,并在控制台中见到许多红色的错误信息:

1
2
$data1 = Get-ChildItem -Path c:\windows -Filter *.ps1 -Recurse
$data2 = Get-Process -FileVersionInfo

现在看看这个实验:

1
2
$data1 = Get-ChildItem -Path c:\windows -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue -ErrorVariable errorList
$data2 = Get-Process -FileVersionInfo -ErrorAction SilentlyContinue -ErrorVariable +errorList

要禁止错误输出并同时将红色的错误信息写入自定义的错误变量 $errorList 并不需要做太多工作。请注意 -ErrorVariable 参数接受的是一个变量名(不含 “$“ 前缀)。并请注意在这个变量名前添加 “+“ 前缀将能把错误信息附加到变量中,而不是替换变量的值。

现在,两个 cmdlet 运行起来都看不到错误信息了。最后,您可以容易地在 $errorList 中容易地分析错误信息,例如用 Out-File 将它们写入某些错误日志文件:

1
2
3
$issues = $errorList.CategoryInfo | Select-Object -Property Category, TargetName
$issues
$issues | Out-File -FilePath $home\Desktop\report.txt -Append

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: ö