PowerShell 技能连载 - 进程终结器(和一些陷阱)

适用于 PowerShell 3.0 及以上版本

在前一个技能中我们介绍了如何利用 Out-GridView 做一个选择对话框,并且提供了一些建议。一个点子是列出所有桌面应用,并且允许用户选择一个进程并终结它。

要列出所有桌面应用,请试试这段代码:

PS> Get-Process | Where-Object MainWindowTitle | Select-Object -Property Name, Description, MainWindowTitle, StartTime

这行代码对进程列表进行过滤并只列出设置了 MainWindowTitle 的进程。实际上,它返回了一个包含窗体的列表,忽略了所有不可见的后台进程。

接下来,将结果通过管道输出到 Out-GridView 并允许单选:

PS> Get-Process | Where-Object MainWindowTitle | Select-Object -Property Name, Description, MainWindowTitle, StartTime | Out-GridView -Title 'Kill Application' -OutputMode Single | Stop-Process -WhatIf

这行代码将打开一个网格视图窗口,显示所有运行中的进程。当您选中一个进程并点击“确定”按钮,将会杀掉该进程。不过,还差一点:这段示例代码包含了 -WhatIf 开关,所以只是 Stop-Process 只是模拟操作。

所以这是个好东西,因为您可能会注意到选择一个进程将会导致杀掉所有同名的进程。

这是由于 Stop-Process 可以接受两个不同的信息:名字(字符串),或是进程 ID (int)。由于这行代码使用了 Select-Object 来筛选属性,并且不包含进程 ID,所以 Stop-Process 将会使用进程名字,并杀掉所有同名的进程。

要实现杀除更具体的进程,请确保包含了进程的 ID:

PS> Get-Process | Where-Object MainWindowTitle | Select-Object -Property Name, Id, Description, MainWindowTitle, StartTime | Out-GridView -Title 'Kill Application' -OutputMode Single | Stop-Process -WhatIf

PowerShell 技能连载 - 将结果复制到剪贴板

适用于 PowerShell 3.0 及以上版本

在前一个技能中我们介绍了如何简单地从 Out-GridView 的网格视图窗口中复制粘贴信息。不过这并不会复制列头。

您可以将这行代码加到任意命令中,并将它的结果复制到剪贴板中(包括列头):

PS> Get-Service | Format-Table -AutoSize -Wrap | Out-String -Width 200 | clip.exe

当您运行完这行代码后,所有服务的清单就保存到剪贴板中了,接下来可以将内容粘贴到 Word 或其它接受文本输入的应用程序中。

请注意 Format-TableOut-String 的用法:它们确保数据不会按照 PowerShell 控制台的边界来格式化。相反地,可用的宽度被设为设为 200 字符,如果结果仍比这个长,那么将会折行。

如果忽略掉这两个 cmdlet,然后查看一下结果:如果没有它们,文本将会输出到 PowerShell 控制台。过长的结果将会被截断。

为了简化操作,您可以将这行代码封装为一个简单的函数,例如:

PS> function Out-Clipboard { $input | Format-Table -AutoSize -Wrap | Out-String -Width 1000 | clip.exe }

现在,当您想将结果复制到剪贴板时,可以使用 Out-Clipboard

PS> Get-Process | Out-Clipboard

PowerShell 技能连载 - Out-GridView:通用对话框

适用于 PowerShell 3.0 及以上版本

默认情况下,Out-GridView 是一条单行道:您可以将数据用管道输出到该命令,将结果显示在一个网格视图窗口中,但是您无法将数据再往下传递。

当您添加了 -PassThru 开关参数时,情况就变了。这时 Out-GridView 的右下角显示了两个新按钮:“确定”和“取消”。它将自己变为一个通用的对话框。

试试这行代码:

PS> Get-Service | Where-Object CanStop | Out-GridView -Title 'Stoppable Services' -PassThru

这将打开一个标题为 “Stoppable Services” 的网格视图窗口,并列出所有可停止的服务(您可能还需要管理员权限才可以停止它们)。

您现在可以选择一个或多个项目(按住 CTRL 键多选),然后点击网格视图窗口右下角的“确定”按钮。

如您所见,返回了选中的对象。

要将这行代码变为一个有用的工具,您可以将 Out-GridView 的结果输出到 cmdlet,来执行具体的操作。这行代码将试图停止所有选中的服务:

PS> Get-Service | Where-Object CanStop | Out-GridView -Title 'Stoppable Services' -PassThru | Stop-Service -WhatIf

请注意,出于安全考虑,我们对 Stop-Service 命令增加了 -WhatIf 参数,所以该 cmdlet 只会模拟停止服务。当您移除了这个参数,该行代码就不是模拟执行,而是真实停止服务了。

只需要坐下喝杯咖啡,然后思考一下它的原理:Out-GridView 接受任何类型的数据,所以您可以用它创建任何工具。例如,使用 Active Directory cmdlet Get-ADUser 来查找当前禁用的用户,然后让 PowerShell 为您启用所有选中的用户。

或者显示一个有主窗口的进程(桌面应用),并且杀掉所有选中的进程。

如果想达到这个目的,您可能会期望 Out-GridView 禁止多选。要想只允许选择单条记录,请试试以下代码:

PS> 1..10 | Out-GridView -Title 'Pick favorite number' -OutputMode Single

PowerShell 技能连载 - 查找所有可停止的服务

适用于 PowerShell 3.0 及以上版本

Get-Service 可以列出您计算机上所有已安装的服务。不过它没有可以选择仅包含运行或停止的服务的参数。

用一个简单的 Where-Object 从句,您可以实现这个目的。最常见的是,您会见到类似如下的用法:

PS> Get-Service | Where-Object Status -eq Running

基本上,Where-Object 可以指定对象拥有的任意属性并且允许您定义需要的条件。

如果您打算获得一个可停止的服务的列表,那么上述代码不能达到您所要的目的。一些服务可能正在运行但是不能被停止。稍微调整一下过滤条件,您就可以达到所要的目的了。这段代码列出所有运行中并且可以停止的服务:

PS> Get-Service | Where-Object CanStop

并且这种写法缩短了代码量:由于 “CanStop“ 属性本身是个布尔值(truefalse),所以无需使用比较运算符。

要查看这个列表的补集,即所有不可停止的服务,可使用比较运算符:

PS> Get-Service | Where-Object CanStop -eq $false

请注意用 Where-Object 的简化语法,您无法取得相反的结果。以下代码并不会生效:

PS> Get-Service | Where-Object !CanStop

PS> Get-Service | Where-Object -not CanStop

要使用这些条件,或者要合并比较条件,请使用完整语法:

PS> Get-Service | Where-Object { !$_.CanStop -and $_.Status -eq 'Running' }

PowerShell 技能连载 - 导出 Out-GridView 的内容

适用于 PowerShell 3.0 及以上版本

Out-GridView 是一个非常有用的将结果输出到一个外部窗口的 cmdlet。和输出到控制台不同,Out-GridView 不会将文本截断。不过它好像没有很明显的方法将信息拷贝出来。

试试这种方法!首先,生成一些数据,然后将它用管道输出到网格视图窗口:

PS> Get-Process | Out-GridView

接下来,可以用顶部的文本框过滤结果,或单击列头来排序。

最后,要将信息导出到别的地方,例如要将进程列表导出到一个 Word 文档中,只需要在结果的任意位置单击,然后按下 CTRL+A 全选,然后按 CTRL+C 将选中的内容复制到剪贴板。

这样,您可以简单地将复制的数据粘贴到您要的应用程序中。不幸的是,列头并不会被复制到剪贴板中。

请注意 Out-GridView 有个内置的限制:它只能显示最多 30 个属性(列)。所以如果您的输入数据有更多的属性,您可能需要限制只显示您确实需要的属性:

PS> Get-Process | Select-Object -Property Name, Company, StartTime | Out-GridView

PowerShell 技能连载 - 获得一个干净的 PowerShell 环境

适用于 PowerShell 3.0 及以上版本

当您在 PowerShell ISE 中开发 PowerShell 脚本时,您可能做了很多更改和修订,并且测试运行了脚本。

这将“污染”您的环境:所有在脚本作用域内定义的变量仍然是定义过的状态,所以后续的测试不再是在一个干净的缺省环境中执行。

要确保一个脚本是在一个完全干净的测试环境中执行,您当然可以重启 PowerShell ISE。一个更便捷的方法是打开一个新的 PowerShell 选项卡:在 PowerShell ISE 中,选择文件/新建 PowerShell 选项卡。

这个操作将在脚本面板中新建一个选项卡。该选项卡代表一个全新的 PowerShell 宿主。您可以在这个新选项卡中加载您的测试脚本,并且在那儿进行测试。当测试完毕后,只需要点击关闭选项卡,即可从内存中消除掉它的所有相关内容。

请注意您可以在多个标签页中连续打开同一个脚本。当您这么操作时,ISE 会警告您该脚本已在另一个选项卡中打开了。当您编辑该脚本时,所有的编辑操作都会作用到所有打开该脚本的选项卡实例。

PowerShell 技能连载 - 将 PowerShell 工具增加到 Windows 8 启动屏幕

适用于 Windows 8/Windows 8.1

您可能注意到了 Windows 8 启动屏幕默认没有 PowerShell ISE 之类的 PowerShell 工具。当您转到开始屏幕并且输入 “ISE” 时,搜不到任何结果。

要改变这种情况,请确保开始屏幕显示了“管理员工具”。在开始屏幕上,将鼠标移动到最右侧,直到出来一个菜单。然后,点击“设置”,然后点击“磁贴”。

现在打开“显示管理员工具”的滑块。

当您做完这步,Windows 8 启动屏幕将会显示 PowerShell 工具,并且当您键入 “ISE” 时内置的搜索工具将会显示 PowerShell ISE。

在搜索结果中右键单击 “Windows PowerShell ISE” 可以看到额外的选项,并且可以将编辑器钉在任务栏上。

PowerShell 技能连载 - 查找 AD 复制失败信息

适用于 Windows 8.1、Server 2012 R2

在 Windows 8.1 和 Server 2012 R2 中,查看 Active Directory 复制失败的信息变得更简单了。Get-ADReplicationFailure 这个新的 cmdlet 将会输出最近的复制失败信息。用它来检查一个特定的域控制器的方法:

PS> Get-ADReplicationFailure dc1.test.com

或者检查整个站点:

PS> Get-ADReplicationFailure -Scope Site -Target Hannover

该 cmdlet 是随 Windows 8.1 和 Server 2012 R2 发布的 ActiveDirectory 模块的一部分。在您使用它之前,请确保您在控制面板/软件/启用或关闭 Windows 功能中启用了它。它是“远程服务器管理工具 (RSAT)”的一部分。如果您的 Windows 8.1 没有预装 RSAT,您可以从这里下载它:http://www.microsoft.com/de-de/download/details.aspx?id=39296。

要查看该模块提供的其它 cmdlet,请试试这行代码:

PS> Get-Command -Module ActiveDirectory

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Add-ADCentralAccessPolicyMember                    ActiveDir...
Cmdlet          Add-ADComputerServiceAccount                       ActiveDir...
Cmdlet          Add-ADDomainControllerPasswordReplicationPolicy    ActiveDir...
Cmdlet          Add-ADFineGrainedPasswordPolicySubject             ActiveDir...
(...)

请注意针对 Windows 8.1/Server 2012 R2 的 RSAT提供了一些额外的 cmdlet,这些 cmdlet 在针对 Windows 早期版本的 RSAT 中并没有提供。

PowerShell 技能连载 - 有用的静态 .NET 方法

适用于 PowerShell 所有版本

PowerShell 可以调用 .NET 类型的静态方法。以下是一些很好用的单行代码:

[Math]::Round(7.9)

[Convert]::ToString(576255753217, 8)

[Guid]::NewGuid()

[Net.Dns]::GetHostByName('schulung12')

[IO.Path]::GetExtension('c:\test.txt')

[IO.Path]::ChangeExtension('c:\test.txt', 'bak')

要查看更多的用法,请删除类型(方括号中的文字)后的代码,然后键入两个冒号。PowerShell ISE 将会自动弹出一个快捷菜单列出该类型可用的方法。在 PowerShell 控制台中,只需要按下 TAB 键即可得到自动完成的建议。

您也可以将一个类型通过管道输出到 Get-Member 命令:

PS> [Math] | Get-Member -MemberType *Method -Static


   TypeName: System.Math

Name            MemberType Definition
----            ---------- ----------
Abs             Method     static sbyte Abs(sbyte value), static int16 Abs(int16 value), static int Abs(int value), sta...
Acos            Method     static double Acos(double d)
Asin            Method     static double Asin(double d)
Atan            Method     static double Atan(double d)
Atan2           Method     static double Atan2(double y, double x)
BigMul          Method     static long BigMul(int a, int b)
Ceiling         Method     static decimal Ceiling(decimal d), static double Ceiling(double a)
Cos             Method     static double Cos(double d)
Cosh            Method     static double Cosh(double value
DivRem          Method     static int DivRem(int a, int b, [ref] int result), static long DivRem(long a, long b, [ref] ...
Equals          Method     static bool Equals(System.Object objA, System.Object objB)
Exp             Method     static double Exp(double d)
Floor           Method     static decimal Floor(decimal d), static double Floor(double d)
IEEERemainder   Method     static double IEEERemainder(double x, double y)
Log             Method     static double Log(double d), static double Log(double a, double newBase)
Log10           Method     static double Log10(double d)
Max             Method     static sbyte Max(sbyte val1, sbyte val2), static byte Max(byte val1, byte val2), static int1...
Min             Method     static sbyte Min(sbyte val1, sbyte val2), static byte Min(byte val1, byte val2), static int1...
Pow             Method     static double Pow(double x, double y)
ReferenceEquals Method     static bool ReferenceEquals(System.Object objA, System.Object objB)
Round           Method     static double Round(double a), static double Round(double value, int digits), static double ...
Sign            Method     static int Sign(sbyte value), static int Sign(int16 value), static int Sign(int value), stat...
Sin             Method     static double Sin(double a)
Sinh            Method     static double Sinh(double value)
Sqrt            Method     static double Sqrt(double d)
Tan             Method     static double Tan(double a)
Tanh            Method     static double Tanh(double value)
Truncate        Method     static decimal Truncate(decimal d), static double Truncate(double d)

要查看某个方法的所有重载的签名,请去掉圆括号:

PS> Get-Something -Path test
You entered test.

PS> [Math]::Round

OverloadDefinitions
-------------------
static double Round(double a
static double Round(double value, int digits)
static double Round(double value, System.MidpointRounding mode)
static double Round(double value, int digits, System.MidpointRounding mode
static decimal Round(decimal d
static decimal Round(decimal d, int decimals)
static decimal Round(decimal d, System.MidpointRounding mode)
static decimal Round(decimal d, int decimals, System.MidpointRounding mode)

PowerShell 技能连载 - 为必须的参数弹出一个对话框

适用于 PowerShell 所有版本

通常,但您将一个参数定义为必选的,并且用户没有传入对应的实参,PowerShell 能够处理好这种情况并提示用户输入这个值:

function Get-Something
{
  param
  (
    [Parameter(Mandatory = $true)]
    $Path
  )

  "You entered $Path."
}

结果类似这样(您无法控制提示信息):

PS> Get-Something -Path test
You entered test.

PS> Get-Something
Cmdlet Get-Something at command pipeline position 1
Supply values for the following parameters:
Path: test
You entered test.

PS>

但是您是否知道还可以通过这种方式获取一个必选参数?

function Get-Something
{
  param
  (
    $Path = $(Read-Host 'Please, enter a Path value')
  )

  "You entered $Path."
}

这种方法将控制权交给您,以下是它看起来的样子:

PS> Get-Something -Path test
You entered test.

PS> Get-Something
Please, enter a Path value: test
You entered test.

PS>