PowerShell 技能连载 - 查找昨天以来的错误

要获取一个时间段内的数据,相对日期的作用十分重要,它能避免硬编码日期和时间值。

这段代码将会从系统日志中获取昨天起(24 小时以内)的所有错误和警告事件:

$today = Get-Date
$1day = New-TimeSpan -Days 1

$yesterday = $today - $1day

Get-EventLog -LogName system -EntryType Error, Warning -After $yesterday

PowerShell 技能连载 - 导出数据到 Excel

您可以轻松地在 PowerShell 中将对象数据转化为 CSV 文件。以下代码生成当前进程的 CSV 报告:

要在 Microsoft Excel 中打开 CSV 文件,您可以使用 Invoke-Item 来打开文件,但是这仅当您的 CSV 文件扩展名确实关联到 Excel 应用程序的时候才有效。

以下代码将确保在 Microsoft Excel 中打开 CSV 文件。它展示了一种超出您 Excel 应用(假设它已经安装了,并且无须检测它是否存在)的方法:

$report = "$env:temp\report.csv"
$ExcelPath = 'C:\Program Files*\Microsoft Office\OFFICE*\EXCEL.EXE'
$RealExcelPath = Resolve-Path -Path $ExcelPath | Select-Object -First 1 -ExpandProperty Path
& $RealExcelPath $report

PowerShell 技能连载 - 查找一个时间点附近的日志

经常地,您会需要浏览某个指定日期附近的所有系统事件。我们假设某台机器在 08:47 崩溃了,您需要查看该时间前后 2 分钟之内的事件。

以下是一个完成以上任务的脚本:

$deltaminutes = 2
$delta = New-TimeSpan -Minutes $deltaminutes

$time = Read-Host -Prompt 'Enter time of event (yyyy-MM-dd HH:mm:ss or HH:mm)'

$datetime = Get-Date -Date $time
$start = $datetime - $delta
$end = $datetime + $delta

$result = @(Get-EventLog -LogName System -Before $end -After $start)
$result += Get-EventLog -LogName Application -Before $end -After $start

$result | Sort-Object -Property TimeGenerated -Descending |
  Out-GridView -Title "Events +/− $deltaminutes minutes around $datetime"

当您运行它时,它需要用户输入一个时间或日期 + 时间值。然后,您可以获得该时间点前后 2 分钟之内系统和应用程序日志中的所有事件。

如果您没有获取到任何数据,那么说明在这段时间段中没有任何事件。

这段代码示范了您可以获取一个时间段之内的事件,并且示范了如何查询多个事件日志。

PowerShell 技能连载 - 自动连接到公共热点

许多手机服务提供商在机场和公共场所提供公共热点。要连接热点,您往往需要浏览一个登录页面,然后手动输入您的凭据。

以下是一个自动做以上事情的脚本。它在 t-mobile.de 运营商环境下调是通过。但是您可以调整脚本以适应其它的运营商。

function Start-Hotspot
{
  param
  (
    [System.String]
    $Username = 'XYZ@t-mobile.de',

    [System.String]
    $Password = 'topsecret'
  )

  # change this to match your provider logon page URL
  $url = 'https://hotspot.t-mobile.net/wlan/start.do'

  $r = Invoke-WebRequest -Uri $url -SessionVariable fb

  $form = $r.Forms[0]

  # change this to match the website form field names:
  $form.Fields['username'] = $Username
  $form.Fields['password'] = $Password

  # change this to match the form target URL
  $r = Invoke-WebRequest -Uri ('https://hotspot.t-mobile.net' + $form.Action) -WebSession $fb -Method POST -Body $form.Fields
  Write-Host 'Connected' -ForegroundColor Green
  Start-Process 'http://www.google.de'
}

简而言之,Invoke-WebRequest 可以到导航到一个页面,填充表单数据,然后提交表单。要能提交正确的数据,您需要查看登录网页的的源代码(导航到该页面,在浏览器中右键单击选择显示 HTML 源代码)。

然后,识别出您希望填充的表单,然后将脚本代码中的表单名称和动作改为您从 HTML 代码中识别出来的值。

PowerShell 技能连载 - 字符串左右对齐

如果您需要确保给定的字符串有一致的宽度,那么您可以使用 .NET 方法来适当地对齐字符串:

$mytext = 'Test'

$paddedText = $mytext.PadLeft(15)
"Here is the text: '$paddedText'"

$paddedText = $mytext.PadRight(15)
"Here is the text: '$paddedText'"

以下是结果:

您甚至可以自己指定补充的字符(如果您不想使用空格来补的话):

PowerShell 技能连载 - 轻松地格式化数字

用户常常需要格式化数字并且限制小数的位数,或者是在左侧补零。有一个简单标准的方法:使用操作符 -f

以下代码的作用是左侧补零:

$number = 68
'{0:d7}' -f $number

这段代码将生成一个左补零的 7 位数字。调整“d”后的数字可以控制位数。

要限制小数的位数,请使用“n”来代替“d”。这一次,“n”后的数字控制小数的位数:

$number = 35553568.67826738
'{0:n1}' -f $number

类似地,用“p”来格式化百分比:

$number = 0.32562176536
'{0:p2}' -f $number

PowerShell 技能连载 - 消除重复

Sort-Object 有一个很棒的特性:使用 -Unique 参数,您可以移除重复对象:

这也可以用于对象类型的结果。请看这个例子,它将从您的系统事件日志中获取最后的 40 条错误:

它的结果也许完全正确,但是您实际上可能得到很多重复的条目。

通过使用 -Unique 参数,您可以基于多个属性消除重复的结果:

这样,您再也看不到多于一条具有相同 InstanceID 消息的结果了。

您可以再次对结果排序,以使得结果按时间排序。

所以结论是:Sort-Objects-Unique 参数可以一次性应用到多个属性上。

PowerShell 技能连载 - 担心隐藏的输入密码请求

您可以在任何主机上运行 PowerShell,powershell.exe 和 powershell_ise.exe 随着 Windows 发布。比起简单的 PowerShell 控制台,许多人更喜欢图形化的 ISE 编辑器。

一旦您开始使用控制台程序,您必须意识到 ISE 编辑器没有真实的控制台。在 ISE 编辑器中,任何时候一个控制台程序想要与您互动时,它将会运行失败。

所以 choice.exe 在控制台中工作正常,但是您在 ISE 编辑器中运行相同的命令时,却没有办法使 choice.exe 接收您的按键。

有些时候,这可能会导致意外的结果。当您在 ISE 编辑器中运行 driverquery.exe 加上 /S Servername 参数从远程系统中读取驱动器信息时,编辑器会假死。

当您在控制台中运行相同的命令时,您会知道原因:driverquery.exe 可能会显示一个提示并期望输入密码。ISE 编辑器无法处理这个提示和您的输入——由于它没有控制台缓冲区。

所以当您的脚本用到了控制台应用程序时,您最好在传统的 PowerShell 控制台中运行它们。

PowerShell 技能连载 - 为对象增加信息

有时会遇到这样的需求:需要向命令的执行结果增加额外的信息。也许您从不同的机器获取信息,并且希望保存数据来源的引用。或者,您也许希望增加一个日期,以便知道数据是何时创建的。

向对象附加信息(增加额外的信息列)是很简单的。这段代码将为一个服务列表增加新的“SourceComputer”属性以及日期。

Get-Service |
  Add-Member -MemberType NoteProperty -Name SourceComputer -Value $env:COMPUTERNAME -PassThru |
  Add-Member -MemberType NoteProperty -Name Date -Value (Get-Date) -PassThru |
  Select-Object -Property Name, Status, SourceComputer, Date

请记着您新增的属性需要在使用 Select-Object 以及显式地要求显式它们的时候,才会在结果中显示出来。

PowerShell 技能连载 - 用 Select-Object -First 节省时间!

Select-Object 命令有一个 -First 参数,接受一个数字值。它将只返回前 x 个元素。听起来挺简单的,而且它的确就这么简单。

以下代码从您的 Windows 文件夹中获取前 4 个 PowerShell 脚本:

从 PowerShell 3.0 开始,-First 不仅选择指定数量的结果,而且它还通知管道的上游命令,告知它操作已完成,有效地中止管道操作。

所以如果您想得到某个命令一定数量的结果,那么您总是可以使用 Select-Object -First x ——在特定的场景里这可以显著地加速您的代码执行效率。

我们假设您需要在您的用户文件夹之下的某个地方找一个名为“test.txt”的文件,并且假设只有一个这个名字的文件。而您只是不知道它放在哪个位置,那么您可以使用 Get-ChildItem-Recurse 来递归查找所有的文件夹:

Get-ChildItem -Path $home -Filter test.txt -Recurse -ErrorAction SilentlyContinue

当您执行这段代码时,Get-ChildItem 最终将找到您的文件——并且继续搜索您的文件夹树,也许要持续几分钟才能找完。因为它不知道是否有其它的文件。

所以,您知道的,如果您事先确定结果的数量,那么试试以下的代码:

Get-ChildItem -Path $home -Filter test.txt -Recurse -ErrorAction SilentlyContinue |
  Select-Object -First 1

这一次,Get-ChildItem 将会在找到一个文件后立即停止。