PowerShell 技能连载 - 合并执行结果

适用于 PowerShell 所有版本

假设您想检查可疑的服务状态,例如启动类型为“自动”而状态处于停止的,或检查服务的 ExitCode 为非正常值的。

以下是一些示例代码,演示如何查询这些场景并将执行结果合并为一个变量。

Sort-Object 确保您的结果在输出到 grid view 窗口之前是不重复的。

$list = @()

$list += Get-WmiObject -Class Win32_Service -Filter 'State="Stopped" and StartMode="Auto" and ExitCode!=0' |
  Select-Object -Property Name, DisplayName, ExitCode, Description, PathName, DesktopInteract

$list += Get-WmiObject -Class Win32_Service -Filter 'ExitCode!=0 and ExitCode!=1077' |
  Select-Object -Property Name, DisplayName, ExitCode, Description, PathName, DesktopInteract


$list |
  # remove identical (-Unique)
  Sort-Object -Unique -Property Name |
  Out-GridView

PowerShell 技能连载 - 计算倒计时小时数

适用于 PowerShell 所有版本

当遇到生日或重要的赛事时,您可能会想到用 PowerShell 来计算事件还有多少小时到来。以下是实现方法:

$result = New-TimeSpan -End '2014-12-25 06:45:00'
$hours = [Int]$result.TotalHours
'Another {0:n0} hours to go...' -f $hours

这个例子计算距离 2014 年圣诞节还剩余的小时数。只需要替换代码中的日期,就可以得到距您期待的事件到来还有多少小时。

PowerShell 技能连载 - 使用 -f 操作符合并字符串和数据

适用于 PowerShell 所有版本

用双引号包围的字符串能够解析变量,所以类似这样的书写方式很常见:

$name = $host.Name
"Your host is called $name."

然而,这种技术有一些限制。如果您想显示对象的属性而不只是变量,将会失败:

PS> "Your host is called $host.Name."
Your host is called System.Management.Automation.Internal.Host.InternalHost.Name.

这是因为 PowerShell 只会解析变量(在例子中是 $host),而不是代码中的剩余部分。

而且您也无法控制数字格式。这段代码可以工作,但是显示的小数位数太多,看起来不美观:

# get available space in bytes for C: drive
$freeSpace = ([WMI]'Win32_LogicalDisk.DeviceID="C:"').FreeSpace

# convert to MB
$freeSpaceMB = $freeSpace / 1MB

# output
"Your C: drive has $freeSpaceMB MB space available."

-f 操作符可以解决这两个问题。它的左侧是一个静态的文本模板,右侧是提供给模板用的值:

# insert any data into the text template
'Your host is called {0}.' -f $host.Name

# calculate free space on C: in MB
$freeSpace = ([WMI]'Win32_LogicalDisk.DeviceID="C:"').FreeSpace
$freeSpaceMB = $freeSpace /1MB

# output with just ONE digit after the comma
'Your C: drive has {0:n1} MB space available.' -f $freeSpaceMB

如您所见,使用 -f 可以给您带来两个好处:占位符(花括号)指示 PowerShell 插入点的位置,并且占位符还可以接受格式化信息。“n1”代表小数点后 1 位。只需要调整数值就能满足您的需要。

PowerShell 技能连载 - 播放 WAV 声音

适用于 PowerShell 3.0 或以上版本

PowerShell 可以用内置的 SoundPlayer 类播放 WAV 背景声音。它可以接受一个 WAV 文件的路径参数,然后可以指定只播放一次还是循环播放。

以下代码将循环播放一段声音:

$player = New-Object -TypeName System.Media.SoundPlayer
$player.SoundLocation = 'C:\Windows\Media\chimes.wav'
$player.Load()
$player.PlayLooping()

当您的脚本执行完以后,可以通过这行代码停止播放:

$player.Stop()

如果您想将自定义的声音文件和您的 PowerShell 脚本一块分发,只需要将它存放在脚本的同一个文件夹下,然后用 $PSScriptRoot 来引用脚本所在的文件夹。

这个例子将播放脚本目录下的 _mySound.wav_:

$player = New-Object -TypeName System.Media.SoundPlayer
$player.SoundLocation = "$PSScriptRoot\mySound.wav"
$player.Load()
$player.PlayLooping()

# do something...
Start-Sleep -Seconds 5

$player.Stop()

请注意 $PSScriptRoot 需要 PowerShell 3.0 或以上版本。当然,它也需要您先将脚本保存到文件。

PowerShell 技能连载 - 获取系统开机时长

适用于 PowerShell 所有版本

Windows 每次启动的时候,都启动一个高精度计数器,这个计数器将返回系统运行的毫秒数:

$millisecondsUptime = [Environment]::TickCount
"I am up for $millisecondsUptime milliseconds!"

由于您很难对毫秒有兴趣,所以请使用 New-TimeSpan 来将毫秒(顺便提一下,也可以是任何其它时间间隔)转换为有意义的单位:

$millisecondsUptime = [Environment]::TickCount
"I am up for $millisecondsUptime milliseconds!"

$timespan = New-TimeSpan -Seconds ($millisecondsUptime/1000)
$timespan

那么现在,您可以使用 TimeSpan 型的 $timespan 对象以您想要的任何格式来汇报启动的时间:

$millisecondsUptime = [Environment]::TickCount
"I am up for $millisecondsUptime milliseconds!"

$timespan = New-TimeSpan -Seconds ($millisecondsUptime/1000)
$hours = $timespan.TotalHours

"System is up for {0:n0} hours now." -f $hours

由于 New-TimeSpan 无法直接处理毫秒,所以需要做一个特殊处理。该脚本直接将毫秒数除以 1000,会引入一个小误差。

要将毫秒数转换为一个 TimeSpan 对象而不损失任何精度,请试试以下代码:

$timespan = [Timespan]::FromMilliseconds($millisecondsUptime)

在这个例子中,它们没有区别。但是它在其它情况下可能很有用。例如,您还可以使用 FromTicks() 方法将时钟周期数(Windows 系统中的最小时间周期单位)转换为时间间隔。

PowerShell 技能连载 - 查找插入的 U 盘

适用于 PowerShell 所有版本

如果您想知道是否有已插入电脑的 USB 存储设备,那么 WMI 可以做到:

Get-WmiObject -Class Win32_PnPEntity |
  Where-Object { $_.DeviceID -like 'USBSTOR*' }

这将返回所有“USBSTOR”类的即插即用设备。

如果您想用 WMI 查询语言(WQL),您还可以用命令过滤器来实现:

Get-WmiObject -Query 'Select * From Win32_PnPEntity where DeviceID Like "USBSTOR%"'

PowerShell 技能连载 - 测试服务的响应性

适用于 PowerShell 所有版本

要测试某个服务是否仍然可响应,可以使用这个聪明的点子。首先,向 WMI 查询您想要检查的服务。WMI 将会开心地返回对应进程的 ID。

接下来,查询该进程。进程对象将会告知您该进程是冻结还是可响应的状态:

function Test-ServiceResponding($ServiceName)
{
  $service = Get-WmiObject -Class Win32_Service -Filter "Name='$ServiceName'"
  $processID = $service.processID

  $process = Get-Process -Id $processID

  $process.Responding
}

这个例子将会检测 Spooler 服务是否可响应:

PS> Test-ServiceResponding -ServiceName Spooler
True

请注意,该示例代码假设服务正在运行。如果您想试试的话,您可以自己检测一下,排除非正在运行的服务。

PowerShell 技能连载 - 获取 WMI 设备清单

适用于 PowerShell 所有版本

WMI 服务可以用来汇报许多关于计算机硬件的详细信息。通常,每种类型的硬件表现为一个对应的 WMI 类。不过,不太容易找出这些硬件的类。

由于所有硬件类都继承自相同的 WMI 根类(CIM_LogicalDevice),所以您可以使用这个根类来查找所有的硬件:

Get-WmiObject -Class CIM_LogicalDevice | Out-GridView

这将返回一个基本的硬件清单。不过您还可以做更多的事情。通过一点额外的代码,您可以用 WMI 获取一个硬件的类名清单:

Get-WmiObject -Class CIM_LogicalDevice |
  Select-Object -Property __Class, Description |
  Sort-Object -Property __Class -Unique |
  Out-GridView

您现在可以使用这些类名中的任意一个来查询某种特定的硬件,获取其详细信息:

PS> Get-WmiObject -Class Win32_SoundDevice

Manufacturer        Name                Status                       StatusInfo
------------        ----                ------                       ----------
Cirrus Logic, Inc.  Cirrus Logic CS4... OK                                    3
Intel(R) Corpora... Intel(R) Display... OK                                    3

PowerShell 技能连载 - 获取睡眠或休眠的时间

适用于 PowerShell 所有版本

如果您希望确认某台机器是否频繁地进入睡眠或者休眠模式,以下是一个读取对应的日志并返回详细信息的函数。它能汇报计算机何时进入睡眠模式,以及它进入睡眠模式的时长:

function Get-HibernationTime
{

  # get hibernation events
  Get-EventLog -LogName system -InstanceId 1 -Source Microsoft-Windows-Power-TroubleShooter |
  ForEach-Object {
    # create new object for results
    $result = 'dummy' | Select-Object -Property ComputerName, SleepTime, WakeTime, Duration

    # store details in new object, convert datatype where appropriate
    [DateTime]$result.Sleeptime = $_.ReplacementStrings[0]
    [DateTime]$result.WakeTime = $_.ReplacementStrings[1]
    $time = $result.WakeTime - $result.SleepTime
    $result.Duration = ([int]($time.TotalHours * 100))/100
    $result.ComputerName = $_.MachineName

    # return result
    $result
  }
}

PowerShell 技能连载 - 理解顺序过滤

适用于 PowerShell 所有版本

当您在解析基于文本的日志文件时,或是需要过滤其它类型的信息时,往往需要使用 Where-Object 命令。以下是一些常见的场景,演示如何合并过滤器:

# logical AND filter for ALL keywords
Get-Content -Path C:\windows\WindowsUpdate.log |
  Where-Object { $_ -like '*successfully installed*' } |
  Where-Object { $_ -like '*framework*' } |
  Out-GridView

# above example can also be written in one line
# by using the -and operator
# the resulting code is NOT faster, though, just harder to read
Get-Content -Path C:\windows\WindowsUpdate.log |
  Where-Object { ($_ -like '*successfully installed*') -and ($_ -like '*framework*') } |
  Out-GridView

# logical -or (either condition is met) can only be applied in one line
Get-Content -Path C:\windows\WindowsUpdate.log |
  Where-Object { ($_ -like '*successfully installed*') -or ($_ -like '*framework*') } |
  Out-GridView