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 撰写心灵鸡汤

关于励志段子

微信上传着一个励志段子,大意是:

如果26个英文字母 A B C D EF G H I J K L M N O P Q R S T U V W X Y Z 分别等于:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 1516 17 18 19 20 21 22 23 24 25 26。那么:

  • Knowledge (知识): K+N+O+W+L+E+D+G+E= 11+14+15+23+12+5+4+7+5=96%
  • Workhard (努力工作):W+O+R+K+H+A+R+D= 23+15+18+11+8+1+18+4 =98%
  • Luck(好运) L+U+C+K=12+21+3+11=47%
  • Love(爱情) L+O+V+E=12+15+22+5=54%
  • Money(金钱) M+O+N+E+Y=13+15+14+5+25=72%
  • Leadership(领导能力)L+E+A+D+E+R+S+H+I+P=12+5+1+4+5+18+19+9+16=89%
  • ATTITUDE(心态)A+T+T+I+T+U+D+E=1+20+20+9+20+21+4+5=100%

于是得出结论:用什么样的态度去看待人生,就会得到什么样的人生。

分析

这样的心灵鸡汤是怎样来的呢?我们用 PowerShell 脚本来琢磨一下。

1
2
3
4
5
6
7
8
function Get-Weight([string]$word) {
$word = $word.ToLower()
#Write-Host ([System.Text.Encoding]::ASCII.GetBytes($word) |
# ForEach-Object { $_ - 96 })
return ([System.Text.Encoding]::ASCII.GetBytes($word) |
ForEach-Object { $_ - 96 } |
Measure-Object -Sum).Sum
}

这个函数可以对任意字符串求值,例如以下测试代码将返回 6(abc = 1+2+3):

1
Get-Weight 'abc'

现在可以测试一下段子里用到的几个单词,并对结果进行排序:

1
2
'Knowledge', 'Workhard', 'Luck', 'Love', 'Money', 'Leadership', 'ATTITUDE' |
Sort-Object -Property @{Expression = { Get-Weight $_ }}

结果符合预期:

Luck
Love
Money
Knowledge
Leadership
Workhard
ATTITUDE

如何撰写鸡汤

以上实现了输入任意字符串数组,对它们进行求值和排序。但是如何选出这些单词呢?我们可以找一篇长文,例如从麻省理工找到莎士比亚的《哈姆雷特》全文,将它输进去拆解成单词试试:

1
2
3
4
5
$resp = Invoke-WebRequest 'http://shakespeare.mit.edu/hamlet/full.html'
$fullText = $resp.ParsedHtml.documentElement.innerText
$words = [regex]::Matches($fullText, '\b\w+\b') |
ForEach-Object { $_.Value } |
Sort-Object -Unique

这样几行代码,就可以将《哈姆雷特》全文的所有单词挑出来进行排序,并将结果保存在 $words 变量中。

最后套用我们上面写好的函数即可实现对所有单词求值排序:

1
2
3
4
5
$words |
Sort-Object -Property @{Expression = { Get-Weight $_ }} |
ForEach-Object {
"$_`t$(Get-Weight $_)"
}

结果大概是这样:

word weight
a 1
c 3
d 4
e 5
bad 7
be 7
I 9
letters 99
firmament 99
temperance 100
Writing 100
prosperously 199
unproportioned 200

有了这个长长的表格之后,撰写鸡汤就容易多了。只要按顺序挑出一些单词,设计一下台词即可。

完整的代码如下:

function Get-Weight([string]$word) {
    $word = $word.ToLower()
    #Write-Host ([System.Text.Encoding]::ASCII.GetBytes($word) |
    #    ForEach-Object { $_ - 96 })
    return ([System.Text.Encoding]::ASCII.GetBytes($word) |
        ForEach-Object { $_ - 96 } |
        Measure-Object -Sum).Sum
}

# Test
# Get-Weight 'abc'

if (!$resp) {
    $resp = Invoke-WebRequest 'http://shakespeare.mit.edu/hamlet/full.html'
}

$fullText = $resp.ParsedHtml.documentElement.innerText
$words = [regex]::Matches($fullText, '\b\w+\b') |
    ForEach-Object { $_.Value } |
    Sort-Object -Unique

# The following code will procuce output:
# Luck
# Love
# Money
# Knowledge
# Leadership
# Workhard
# ATTITUDE
'Knowledge', 'Workhard', 'Luck', 'Love', 'Money', 'Leadership', 'ATTITUDE' |
    Sort-Object -Property @{Expression = { Get-Weight $_ }}

$words |
    Sort-Object -Property @{Expression = { Get-Weight $_ }} |
    ForEach-Object {
        "$_`t$(Get-Weight $_)"
    }

后记

完整的代码可以在这里下载。鸡汤的原文请参见《是哪位高人琢磨出的这条微信,太牛了》。顺便发现了原文中的一个计算 bug——Leadership(领导能力)应是L+E+A+D+E+R+S+H+I+P=12+5+1+4+5+18+19+8+9+16=97%,而不是 89%。

怎么样,有没有一点理工男秒杀心灵鸡汤的味道?

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>

PowerShell 技能连载 - 使用打开文件夹对话框

适用于 PowerShell 所有版本

为了在您的脚本中输入一些东西,以下是一个简单的打开“打开文件”对话框并让用户选择一个文件的函数。

function Show-OpenFileDialog
{
  param
  ($Title = 'Pick a File', $Filter = 'All|*.*|PowerShell|*.ps1')

  $type = 'Microsoft.Win32.OpenFileDialog'


  $dialog = New-Object -TypeName $type
  $dialog.Title = $Title
  $dialog.Filter = $Filter
  if ($dialog.ShowDialog() -eq $true)
  {
    $dialog.FileName
  }
  else
  {
    Write-Warning 'Cancelled'
  }
}

如您所见,您可以控制该对话框的标题栏和显示的文件类型。

PowerShell 技能连载 - 记录拒绝存取的文件夹

适用于 PowerShell 所有版本

当您用 Get-ChildItem 浏览文件系统的时候,您可能偶尔会碰到没有查看权限的文件夹。如果您希望将抛出次异常的所有文件夹都记录下来,请试试这个方法:

$result = Get-ChildItem -Path c:\Windows -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue -ErrorVariable abcd

Write-Warning 'Unable to access these folders:'
Write-Warning ($abcd.TargetObject -join "`r`n")

这个技巧是隐藏所有错误提示(-ErrorAction SilentlyContinue)但将错误都保存到一个变量中(-ErrorVariable abce)。