PowerShell 技能连载 - 持有一个进程的句柄

当您打开一个 EXE 文件时,PowerShell 将会开心地启动它,然后什么也不管:

如果您希望持有该进程的句柄,比如希望获得它的进程 ID,或者过一会儿检查该进程运行得如何,或者要中止它,请使用 Start-Process–PassThru 参数。以下代码将返回一个进程对象:

PowerShell 技能连载 - 使用 $PSScriptRoot 加载资源

从 PowerShell 3.0 开始,有一个称为 $PSScriptRoot 的变量可用。该变量之前只在模块中可用。它总是指向当前脚本所在的文件夹(所以它仅在您明确地保存了它以后才生效)。

您可以使用 $PSScriptRoot 来加载相对于您脚本位置的额外资源。例如,如果您打算将一些函数放在同一个文件夹中的一个独立的“library”脚本中,以下代码将加载该 library 脚本并且导入它包含的所有函数:

# this loads the script "library1.ps1" if it is located in the very
# same folder as this script.
# Requires PowerShell 3.0 or better.

. "$PSScriptRoot\library1.ps1"

类似地,如果您希望将您的 library 脚本保存在一个子文件夹中,请试验以下脚本(假设库脚本放在您脚本所在文件夹中的“resources”子文件夹下):

# this loads the script "library1.ps1" if it is located in the subfolder
# "resources" in the folder this script is in.
# Requires PowerShell 3.0 or better.

. "$PSScriptRoot\resources\library1.ps1"

PowerShell 技能连载 - 用 PowerShell 为 VBScript 文件签名

您很可能知道 Set-AuthenticodeSignature 可以用来为 PowerShell 脚本签名。但您是否知道这个 cmdlet 可以为任何支持目标接口包 (SIP) 的任何文件呢?

这段代码可以从一个 PFX 文件中读取数字证书,然后从您的 home 文件夹中扫描 VBScript 文件,然后将数字签名应用到脚本文件上:

# change path to point to your PFX file:
$pfxpath = 'C:\Users\Tobias\Documents\PowerShell\testcert.pfx'
# change password to the password needed to read the PFX file:
# (this password was set when you exported the certificate to a PFX file)
$password = 'topsecret'

# load certificate
Add-Type -AssemblyName System.Security
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($pfxpath, $password, 'Exportable')

# apply signature to all VBScript files
# REMOVE -WHATIF TO ACTUALLY SIGN
Get-ChildItem -Path $home -Filter *.vbs -Recurse -ErrorAction SilentlyContinue |
  Set-AuthenticodeSignature -Certificate $cert -WhatIf

PowerShell 技能连载 - 正确地按日期时间筛选

当您使用 Where-Object 通过日期或时间来过滤信息时,它工作得很好——前提是您使用了正确的过滤格式。请不要使用输出结果中的格式。

要指定一个日期或时间,请永远使用中性文化的格式:

“year-month-day hour:minute:second”,所以 2014 年 5 月 14 日应该表述成这样:“2014-05-12 12:30:00”。

或者换种方法处理:当您输出结果时,PowerShell 将根据您控制面板的设置来格式化日期和时间。当您输入信息(例如过滤规则)时,PowerShell 永远期望接收一个通用的日期和时间格式。这是有道理的:脚本须在任何文化环境中运行一致。而结果需要格式化成读者的语言文化格式。

所以要在您的 Windows 文件夹中查找所有自从 2012 年 4 月 30 日以来没有修改过的文件,请尝试以下代码:

用 PowerShell 屏蔽腾讯 QQ 秀

我们在 用 PowerShell 屏蔽腾讯 QQ 的广告 这篇文章中介绍过了如何屏蔽 QQ 聊天窗口的横幅广告,那么如何屏蔽 QQ 秀的广告呢?请参见 QQ2013 删除QQ秀广告

但是其中的步骤有点繁琐。我们把整个流程用 PowerShell 写一遍,对于用户只要执行一下即可:

$folder = "${env:ProgramFiles}\Tencent\QQ\Plugin\Com.Tencent.QQShow\"
$folder
$rdbFile = Join-Path $folder 'Bundle.rdb'
$rdbDir = Join-Path $folder 'Bundle'

$xmlPath = Join-Path $folder 'Bundle\I18N\2052\UrlBundle.xml'

if (Test-Path "$rdbFile.bak") {
    Write-Warning "$rdbFile.bak 文件已存在,请确认是否已经替换?"
    Write-Warning "程序退出。"
    return
}

$rdbFile
.\RDB.exe """$rdbFile"""
move $rdbFile "$rdbFile.bak"
.\D4QQenc.exe (Join-Path $folder 'Bundle\I18N\2052\UrlBundle.xml.enc')

del (Join-Path $folder 'Bundle\I18N\2052\UrlBundle.xml.enc')

[xml]$urlBundle = Get-Content $xmlPath -Encoding UTF8 | where { $_ -ne '' }

@('IDS_QQSHOW_MARKET', 'IDS_3DSHOW_MARKET', 'IDS_FLASHSHOW_MARKET') | foreach {
    $id = $_
    ($urlBundle.StringBundle.String | where { $_.id -eq $id })."#text" = ''
}
$urlBundle.OuterXml | Set-Content $xmlPath -Encoding UTF8

.\RDB.exe """$rdbDir"""

您也可以从这里 下载 写好的脚本,祝您使用愉快。
本方法在 QQ2013(SP6) 上验证通过。

PowerShell 技能连载 - 在 PowerShell ISE 中创建干净的测试环境

当您在 PowerShell ISE 编辑器中开发 PowerShell 脚本时,您需要在一个干净的环境中运行最终的测试,确保不会被之前运行时残留的变量或者函数干扰。

创建一个干净的测试环境的最简单方法是:选择文件菜单,然后选择“新建 PowerShell 选项卡”。这将为您带来一个新的标签页,并且该页代表一个全新的 PowerShell 宿主。完美的测试环境!

PowerShell 技能连载 - 从 PFX 文件中导入多个证书

Get-PfxCertificate 可以从 PFX 文件中导入数字证书。然而,他只能获取一个证书。所以如果您的 PFX 文件中包含多个证书,您无法使用这个 cmdlet 获取其它的证书。

若要从一个 PFX 文件中导入多个证书,只要使用以下代码:

$pfxpath = 'C:\PathToPfxFile\testcert.pfx'
$password = 'topsecret'

Add-Type -AssemblyName System.Security
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$cert.Import($pfxpath, $password, 'Exportable')
$cert

PowerShell 技能连载 - 在 Remoting 中使用完整限定名

当您尝试使用 PowerShell Remoting 时,您也许会因为您使用的机器名不是完整限定名而导致连接错误。Kerberos 验证可能需要也可能不需要使用完整限定名,这取决于您的 DNS 配置。

所以也许您使用如下方式连接的时候会发生错误:

Enter-PSSession -ComputerName storage1

当发生错误的时候,请向 DNS 查询完整限定名:

[System.Net.Dns]::GetHostByName('storage1').HostName

然后,用查出的名字来代替主机名。如果主机启用了 Remoting 并且正确地配置了,您现在应该可以连上了。

PowerShell 技能连载 - 确保向后兼容

假设您创建了这个函数:

function Test-Function
{
  param
  (
    [Parameter(Mandatory=$true)]
    $ServerPath
  )

  "You selected $ServerPath"
}

它现在可以正常工作,但是在半年之后的代码审查中,您的老板希望您使用标准的参数名称,将“ServerPath”改名为“ComputerName”。那么您对您的代码做出适当的修改:

function Test-Function
{
  param
  (
    [Parameter(Mandatory=$true)]
    $ComputerName
  )

  "You selected $ComputerName"
}

然而,您不能很容易地控制哪些人调用了您的函数,而且他们使用了旧的参数。所以要确保向后兼容,请确保您的函数使用旧的参数名也可以工作:

function Test-Function
{
  param
  (
    [Parameter(Mandatory=$true)]
    [Alias("ServerPath")]
    $ComputerName
  )

  "You selected $ComputerName"
}

旧的代码任然可以运行,并且新的代码(以及代码自动完成)将会使用新的名称: