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>

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)。

PowerShell 技能连载 - 管理终端服务设置

_需要 ActiveDirectory 模块

有些时候您也许希望在一个 AD 账户中直接存取终端服务相关的属性。以下是一些演示如何实现该功能的示例代码:

$Identity = 'SomeUserName'

$distinguishedName = (Get-ADUser -Identity $Identity -Properties distinguishedName).distinguishedName
$ADUser = [ADSI]"LDAP://$distinguishedName"

$TSProfilePath = $ADUser.psbase.InvokeGet('terminalservicesprofilepath')
$TSHomeDir = $ADUser.psbase.InvokeGet('TerminalServicesHomeDirectory')
$TSHomeDrive = $ADUser.psbase.InvokeGet('TerminalServicesHomeDrive')
$TSAllowLogOn = $ADUser.psbase.InvokeGet('allowLogon')

PowerShell 技能连载 - 凭据混淆器

适用于 PowerShell ISE 3.0 及以上版本

虽然一般不建议将密码硬编码在脚本里,但有些情况下已经这么做了。相比于硬编码明文密码,一个最基本的改进是将密码混淆。密码混淆是一种弱的保护方式,但它能确保非掌握 PowerShell 知识的人员轻易地得到密码。

这是段小脚本会询问用户名和密码,然后生成一段混淆脚本来产生凭据对象。

当您运行下面这段脚本生成的脚本,在 $cred 变量将会保存一个包含用户名和密码的凭据对象,它可以用于任何带 -Credential 参数的 cmdlet。

$cred = Get-Credential -Message 'Enter Domain\Username and Password'
$pwd = $cred.Password
$user = $cred.UserName
$key = 1..32 | ForEach-Object { Get-Random -Maximum 256 }
$pwdencrypted = $pwd | ConvertFrom-SecureString -Key $key

$private:ofs = ' '

$generatedScript = @()
$generatedScript += '$password = ''{0}''' -f $pwdencrypted
$generatedScript += '$key = ''{0}''' -f "$key"

$generatedScript += '$passwordSecure = ConvertTo-SecureString -String $password -Key ([Byte[]]$key.Split('' ''))'
$generatedScript += '$cred = New-Object system.Management.Automation.PSCredential(''{0}'', $passwordSecure)' -f $user
$generatedScript += '$cred'

$file = $psise.CurrentPowerShellTab.Files.Add()
$file.Editor.Text = $generatedScript | Out-String
$file.Editor.SetCaretPosition(1,1)

自动生成的密码脚本看起来类似这样:

$password = '76492d1116743f0423413b16050a5345MgB8AHMAUQA3AFAAVwB0AGkAUQBUAC8AdwBqADYAUABVAFYAUwB4AEYAYgB4AFEAPQA9AHwAZgA0ADgAOQA4AGYANwA0AGEAMAA0ADUANwA5ADkAMwA5ADkAMwA1ADUANQA0AGYANwA5AGQANwBkAGYAOQBmAGEAYQA3ADMAYgBkADIAOQA3AGMAYQBmADUAMgA3ADEANwA3AGEAYgBmADAAYgA1AGYAYwAyADYAYgAzADkAOAA='
$key = '187 98 34 82 148 52 13 86 246 2 130 197 217 97 147 98 75 197 149 246 74 35 27 7 211 15 131 93 182 231 171 3'
$passwordSecure = ConvertTo-SecureString -String $password -Key ([Byte[]]$key.Split(' '))
$cred = New-Object system.Management.Automation.PSCredential('mickey\mouse', $passwordSecure)
$cred

PowerShell 技能连载 - 自动展开和内存消耗

适用于 PowerShell 3.0 及以上版本

在 PowerShell 3.0 中,增加了一个称为“自动回滚”的特性。通过这个特性,您可以这样书写代码:

(Get-ChildItem -Path $env:windir\system32 -Filter *.dll).VersionInfo

这行代码查找 System32 子文件夹下的所有 DLL 文件并且对它们进行迭代,对每个文件返回其 VersionInfo 属性(实际上是 DLL 版本)。在使用自动展开功能之前,您需要手工编写循环语句:

Get-ChildItem -Path $env:windir\system32 -Filter *.dll | ForEach-Object { $_.VersionInfo }

当您运行以上两段代码时,它们返回完全相同的结果。然而,您将立刻发现自动展开特性所带来的代价:它消耗了更多的时间才返回结果。第一行结果出来时可能要消耗 10 秒之多的时间,而“传统”的方法几乎是连续地返回信息。

总体消耗的时间是差不多的。实际上,自动展开特性等价的代码如下:

$data = Get-ChildItem -Path $env:windir\system32 -Filter *.dll
Foreach ($element in $data) { $element.VersionInfo }

自动展开代码更直观,更容易书写手写循环兼容性更好,更快输出结果。

PowerShell 技能连载 - 复制命令行历史

适用于 PowerShell 所有版本

要将 PowerShell 会话中键入过的所有 PowerShell 命令保存下来,请试试这行代码:

(Get-History).CommandLine | clip.exe

它将所有的命令拷贝至剪贴板。然后您就可以将它们粘贴到 PowerShell ISE 并保存为文件。

PowerShell 技能连载 - 获取计算机序列号

适用于 PowerShell 所有版本

在前一个技巧里我们演示了如何通过 DELL 的序列号在线检查保修状态。其它厂家也会提供类似的服务。

这段代码可以读取序列号:

$ComputerName = $env:COMPUTERNAME

$serial = (Get-WmiObject -ComputerName $ComputerName -Class Win32_BIOS).SerialNumber
"Your computer serial is $serial"

PowerShell 技能连载 - 在线检测 DELL 保修

适用于 PowerShell 2.0 及以上版本

如果您拥有一台 DELL 电脑,您可以通过 Web Service 提交电脑的序列号得到授权信息:

$serial = '36GPL41'

$service = New-WebServiceProxy -Uri http://143.166.84.118/services/assetservice.asmx?WSDL
$guid = [Guid]::NewGuid()

$info = $service.GetAssetInformation($guid,'warrantycheck',$serial)
$info.Entitlements

结果可能看起来如下:

$info.Entitlements


ServiceLevelCode        : TS
ServiceLevelDescription : P, ProSupport
Provider                : DELL
StartDate               : 23.03.2004 00:00:00
EndDate                 : 23.03.2007 00:00:00
DaysLeft                : 0
EntitlementType         : Expired

ServiceLevelCode        : ND
ServiceLevelDescription : C, NBD ONSITE
Provider                : UNY
StartDate               : 23.03.2005 00:00:00
EndDate                 : 23.03.2007 00:00:00
DaysLeft                : 0
EntitlementType         : Expired

ServiceLevelCode        : ND
ServiceLevelDescription : C, NBD ONSITE
Provider                : UNY
StartDate               : 23.03.2004 00:00:00
EndDate                 : 24.03.2005 00:00:00
DaysLeft                : 0
EntitlementType         : Expired

这些从 Web Service 返回的信息还包括了其它有用的信息,例如计算机的系统类型:

PS> $info.AssetHeaderData


ServiceTag     : 36GPL41
SystemID       : PLX_PNT_CEL_GX270
Buid           : 11
Region         : Americas
SystemType     : OptiPlex
SystemModel    : GX270
SystemShipDate : 23.03.2004 07:00:00