PowerShell 技能连载 - 等待按键

适用于 PowerShell 所有版本,仅适用于 PowerShell 控制台

若希望脚本执行结束时,保持 PowerShell 控制台程序为打开状态,您也许希望增加一句“按任意键继续”语句。以下是实现方式:

Write-Host 'Press Any Key!' -NoNewline
$null = [Console]::ReadKey('?')

这段代码仅适用于真实的 PowerShell 控制台。它在 ISE 编辑器或其它未使用真实互操作键盘缓冲区的控制台程序中并不适用。

PowerShell 技能连载 - 查找脚本中的错误

适用于 PowerShell 所有版本

没有比这种更简单的方法来查找脚本中的语法错误了。只需要用这个过滤器:

filter Test-SyntaxError
{
   $text = Get-Content -Path $_.FullName
   if ($text.Length -gt 0)
   {
      $err = $null
      $null = [System.Management.Automation.PSParser]::Tokenize($text, [ref] $err)
      if ($err) { $_ }
   }
}

通过使用这个过滤器,您可以快速地扫描文件夹,甚至整台计算机,列出所有包含语法错误的 PowerShell 文件。

以下代码将在您的用户文件夹下遍历并查找所有的 PowerShell 脚本并列出包含语法错误的文件:

PS> dir $home -Filter *.ps1 -Recurse -Exclude *.ps1xml | Test-SyntaxError

PowerShell 技能连载 - 检测文本中是否含有大写字母

适用于 PowerShell 任何版本

可以使用正则表达式来检测一个字符串是否包含至少一个大写字母:

$text1 = 'this is all lower-case'
$text2 = 'this is NOT all lower-case'

$text1 -cmatch '[A-Z]'
$text2 -cmatch '[A-Z]'

得到的结果分别是“Frue”和“False”。

要检测一段文本是否只包含小写字母,请试试这段代码:

$text1 = 'this is all lower-case'
$text2 = 'this is NOT all lower-case'

$text1 -cmatch '^[a-z\s-]*$'
$text2 -cmatch '^[A-Z\s-]*$'

得到的结果分别是“True”和“False”。

实际上检测起来会更麻烦,因为您需要包括所有合法的字符。在这个例子中,我选择了 a-z 的小写字母、空格和减号。

这些“合法”的字符被包含在“^”和“$”(行首符和行尾符)之间。星号是一个量词(任意数量个“合法的”字符)。

PowerShell 技能连载 - 获取字符串的行数

适用于 PowerShell 所有版本

以下是一个获取字符串(而不是字符串数组!)行数的技巧:

$text = @'
This is some
sample text
Let's find out
the number of lines.
'@

$text.Length - $text.Replace("`n",'').Length + 1

技术上来说,这个例子用的是 here-string 来创建多行字符串,不过这只是一个例子。它对所有类型的字符串都有效,无论它的来源是什么。

PowerShell 技能连载 - 移除非法的路径字符

适用于 PowerShell 所有版本

在路径名中,有些字符,例如冒号和双引号,都是非法的。如果您的脚本中的路径名称来自于外部信息,那么您可能希望最终的路径名是合法的。

以下是一个将路径中所有非法字符替换成下划线的函数:

function Get-LegalPathName($Path)
{
  $illegalChars = [System.IO.Path]::GetInvalidFileNameChars()

  foreach($illegalChar in $illegalChars)
  { $Path = $Path.Replace($illegalChar, '_') }

  $Path
}

这是结果看起来的样子:

PS> Get-LegalPathName 'some:"illegal"\path<chars>.txt'
some__illegal__path_chars_.txt

PowerShell 技能连载 - 忽略输出结果

适用于 PowerShell 所有版本

由于 PowerShell 会将所有命令的执行结果返回,所以在 PowerShell 脚本中忽略掉所有不希望返回的结果是十分重要的。

有很多方法能实现这个目的,以下是最常见的两种。请注意每行都会尝试在您的 C: 创建一个新的文件夹。New-Item 命令将会返回一个新的文件夹对象,但是如果您只是希望创建一个新的文件夹,那么您很可能希望忽略掉返回的结果:

1
2
3
$null = New-Item -Path c:\newfolderA -ItemType Directory

New-Item -Path c:\newfolderB -ItemType Directory | Out-Null

哪么那种方式更好呢?当然是第一种方式了。将不需要的结果通过管道传送给 Out-Null 的开销是很大的,能达到将近 40 倍的差别。只调用一次的差别并不明显,但如果在一个循环中的话,差异就很明显了。

So better get into the habit of using $null rather than Out-Null!
所以最好养成习惯使用 $null 而不是 Out-Null

PowerShell 技能连载 - 同时支持可选参数和必选参数

适用于 PowerShell 所有版本

一个函数的参数是否能既为可选的,又为必选的呢?这是可以的,基于不同的上下文即可。

一个参数可以在当其它参数存在的时候为必选的,否则为可选的。

function Connect-Somewhere
{
 [CmdletBinding(DefaultParameterSetName='A')]
 param
 (
 [Parameter(ParameterSetName='A',Mandatory=$false)]
 [Parameter(ParameterSetName='B',Mandatory=$true)]
 $ComputerName,
 [Parameter(ParameterSetName='B',Mandatory=$false)]
 $Credential
 )
 $chosen = $PSCmdlet.ParameterSetName
 "You have chosen $chosen parameter set."
}

# -Computername is optional
Connect-Somewhere
# here, -Computername is mandatory
Connect-Somewhere -Credential test

PowerShell 技能连载 - 快速处理路径

适用于 PowerShell 所有版本

以下是一系列有用的(并且易用的)用于处理文件路径的系统函数:

[System.IO.Path]::GetFileNameWithoutExtension('file.ps1')
[System.IO.Path]::GetExtension('file.ps1')
[System.IO.Path]::ChangeExtension('file.ps1', '.copy.ps1')

[System.IO.Path]::GetFileNameWithoutExtension('c:\test\file.ps1')
[System.IO.Path]::GetExtension('c:\test\file.ps1')
[System.IO.Path]::ChangeExtension('c:\test\file.ps1', '.bak')

所有这些方法都能接受文件名称或完整路径参数、能返回路径的不同部分,或改变其中的部分,例如扩展名。

PowerShell 技能连载 - 查找最大值和最小值

适用于 PowerShell 所有版本

要查找一系列数据中的最小值和最大值,请使用 Measure-Object 命令:

$list = 1,4,3,1,3,12,990

$result = $list | Measure-Object -Minimum -Maximum
$result.Minimum
$result.Maximum

它对输入的任何数据类型都有效。以下是稍作修改的代码,可以返回 Windows 文件夹中最旧和最新的文件:

$list = Get-ChildItem -Path C:\windows

$result = $list | Measure-Object -Property LastWriteTime -Minimum -Maximum
$result.Minimum
$result.Maximum

如果您的输入数据有多个属性,只需要加上 -Property 参数,并选择您想检测的属性即可。