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

PowerShell 技能连载 - 用 Cmdlet 来管理 MSI 安装包

适用于 PowerShell 2.0 及以上版本

需要管理 MSI 安装包的朋友可以从这个开源项目中受益:http://psmsi.codeplex.com/

只需要下载 PowerShell 模块——它自己包含了一个安装包。请确保在安装它之前对 MSI 文件进行解锁。否则,Windows 可能会拒绝安装它。

不幸的是,这个模块将它自己安装到一个很特殊的地方(AppData\Local\Apps...),并且扩展了 $env:PSModulePath 环境变量,所以 PowerShell 可以找到这个模块。这是为什么您在安装完模块之后需要重启 PowerShell 的原因,因为 PowerShell 不能自动感知到 $env:PSModulePath 发生了改变。

这是获取新的 MSI 相关 cmdlet 的方法:

PS> Get-Command -Module MSI

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Function        Get-MSIComponentState                              MSI
Function        Get-MSISharedComponentInfo                         MSI
Function        Install-MSIAdvertisedFeature                       MSI
Cmdlet          Add-MSISource                                      MSI
Cmdlet          Clear-MSISource                                    MSI
Cmdlet          Edit-MSIPackage                                    MSI
Cmdlet          Export-MSIPatchXml                                 MSI
Cmdlet          Get-MSIComponentInfo                               MSI
Cmdlet          Get-MSIFeatureInfo                                 MSI
Cmdlet          Get-MSIFileHash                                    MSI
Cmdlet          Get-MSIFileType                                    MSI
Cmdlet          Get-MSILoggingPolicy                               MSI
Cmdlet          Get-MSIPatchInfo                                   MSI
Cmdlet          Get-MSIPatchSequence                               MSI
Cmdlet          Get-MSIProductInfo                                 MSI
Cmdlet          Get-MSIProperty                                    MSI
Cmdlet          Get-MSIRelatedProductInfo                          MSI
Cmdlet          Get-MSISource                                      MSI
Cmdlet          Get-MSISummaryInfo                                 MSI
Cmdlet          Get-MSITable                                       MSI
Cmdlet          Install-MSIPatch                                   MSI
Cmdlet          Install-MSIProduct                                 MSI
Cmdlet          Measure-MSIProduct                                 MSI
Cmdlet          Remove-MSILoggingPolicy                            MSI
Cmdlet          Remove-MSISource                                   MSI
Cmdlet          Repair-MSIProduct                                  MSI
Cmdlet          Set-MSILoggingPolicy                               MSI
Cmdlet          Test-MSIProduct                                    MSI
Cmdlet          Uninstall-MSIPatch                                 MSI
Cmdlet          Uninstall-MSIProduct                               MSI

PowerShell 技能连载 - 读取多行文本

适用于 PowerShell 3.0 及以上版本

有些时候您偶然会见到类似这样的技巧:

$FilePath = "$env:SystemRoot\WindowsUpdate.log"

$ContentsWithLinebreaks = (Get-Content $FilePath) -join "`r`n"

您能否出猜出它的用意?Get-Content 缺省情况下返回由一行一行组成的字符串数组,然后 -join 操作符将该数组转化为一个字符串。

从 PowerShell 3.0 开始,Get-Content 多了一个参数:-Raw。它比起刚才的方法高效的多,并且可以得到相同的结果:

$FilePath = "$env:SystemRoot\WindowsUpdate.log"

$ContentsWithLinebreaks = (Get-Content $FilePath) -join "`r`n"

$ContentsWithLinebreaks2 = Get-Content $FilePath -Raw

$ContentsWithLinebreaks -eq $ContentsWithLinebreaks2

当您使用这段代码时,会发现 $ontentWithLinebreaks$ContentWithLinebreaks2 是不同的。唯一的区别是在 $ContentsWithLinebreaks2 尾部有一个换行符:

PS> $ContentsWithLinebreaks -eq $ContentsWithLinebreaks2.TrimEnd("`r`n")
True

PS>

PowerShell 技能连载 - 要求管理员权限

适用于 PowerShell 4.0 及以上版本

如果您知道某个脚本需要管理员权限,只需要一个简单的 #requres 语句就可以确保符合该需求的才可以运行:

#requires -version 4.0
#requires –runasadministrator


'I am Admin!'

如果这个脚本没有使用管理员身份运行,它将显示一个有意义错误提示信息,说明它为何无法运行。

实际上,在这个例子中您可以看到两条 #requires 语句。第一条确保该脚本至少运行在 PowerShell 4.0 以上的环境中,这是第二条 #requires 的先决条件。它是由 PowerShell 4.0 引入的,不支持 PowerShell 更低的版本。

所以最好不要在 PowerShell 3.0 或更早的环境中使用这个技术。在那些环境中,您还是需要手工确认脚本是否拥有管理员权限。

PowerShell 技能连载 - 分析并移除打印任务

适用于 Windows 8.1 或 Server 2012 R2

Windows 8.1 和 Server 2012 R2 引入了一个名为“PrintManagement”的模块。它包含了管理本地和远程打印机所需的所有 cmdlet。

在前一个技能中我们演示了如何读取打印任务。每个打印任务都有一个 JobStatus 属性告诉您该 PrintJob 是否成功完成。

可以通过这种方式获取所有的状态码:

PS> Import-Module PrintManagement

PS> [Microsoft.PowerShell.Cmdletization.GeneratedTypes.PrintJob.JobStatus]::GetNames([Microsoft.PowerShell.Cmdletization.GeneratedTypes.PrintJob.JobStatus])
Normal
Paused
Error
Deleting
Spooling
Printing
Offline
PaperOut
Printed
Deleted
Blocked
UserIntervention
Restarted
Complete
Retained
RenderingLocally

接下来,您可以过滤已有的打印任务。并且,比如打印出所有已完成或有错误的打印任务。这段代码将列出所有有错误或已完成的打印任务:

$ComputerName = $env:COMPUTERNAME

Get-Printer -ComputerName $ComputerName |  ForEach-Object {
  Get-PrintJob -PrinterName $_.Name -ComputerName $ComputerName |
    Where-Object { $_.JobStatus -eq 'Complete' -or $_.JobStatus -eq 'Error' -or $_.JobStatus -eq 'Printed'}
 }

要移除这些打印任务,只需要加上 Remove-PrintJob 命令:

$ComputerName = $env:COMPUTERNAME

Get-Printer -ComputerName $ComputerName |  ForEach-Object {
  Get-PrintJob -PrinterName $_.Name -ComputerName $ComputerName |
    Where-Object { $_.JobStatus -eq 'Complete' -or $_.JobStatus -eq 'Error' -or $_.JobStatus -eq 'Printed'}
 } |
 Remove-PrintJob -CimSession $ComputerName

PowerShell 技能连载 - 列出所有打印任务

适用于 Windows 8.1 或 Server 2012 R2

Windows 8.1 和 Server 2012 R2 引入了一个名为“PrintManagement”的模块。它包含了管理本地和远程打印机所需的所有 cmdlet。

要列出指定计算机的所有打印任务,首先确定可用的打印机,然后用循环取出每个打印机的打印任务。这实际做起来十分简单:

$ComputerName = $env:COMPUTERNAME

Get-Printer -ComputerName $ComputerName |  ForEach-Object {
  Get-PrintJob -PrinterName $_.Name -ComputerName $ComputerName
 }

如果该代码返回空,那么说明没有打印任务(或者您没有读取它们的权限)。

PowerShell 技能连载 - 远程更新组策略

适用于 Windows 8.1 或 Server 2012 R2

要更新远程计算机上的组策略设置,请使用 Invoke-GPUpdate,并且传入希望更新设置的计算机名。

Invoke-GPUpdate 在远程计算机上创建“gpupdate”计划任务。您可以使用 –RandomDelayInMinutes 指定一个 0 至 44640 分钟(31 天)之间的值。该 cmdlet 将使用一个随机的时间因子来避免网络阻塞。

PowerShell 技能连载 - 管理打印机

适用于 Windows 8.1 和 Server 2012 R2

Windows 8.1 和 Server 2012 R2 带来了一个叫做“PrintManagement”的模块。它包含了管理本地和远程打印机所需的所有 Cmdlet。

以下是一个示例脚本,演示了安装打印机驱动、设置打印机端口、安装打印机、共享该打印机,以及设置某些打印机属性的过程。

$ComputerName = $env:COMPUTERNAME

$DriverName = 'Samsung SCX-483x 5x3x Series XPS'
$IPAddress = '192.168.2.107'
$PortName = 'NetworkPrint_192.168.2.107'
$PrinterName = 'BWPrint'
$ShareName = 'Office 12'

Add-PrinterDriver -ComputerName $ComputerName -Name $DriverName
Add-PrinterPort -Name $PortName -ComputerName $ComputerName
Add-Printer -ComputerName $ComputerName -Name $PrinterName -DriverName $DriverName -Shared -ShareName $ShareName -PortName $PortName
Set-PrintConfiguration -ComputerName $ComputerName -PrinterName $PrinterName -PaperSize A4

要使用它,请确保您修改了 $IPAddress 并指向一个存在的打印机。请将 $ComputerName 修改指向一个远程计算机而不是您的本地计算机。

要列出 PrintManagement 模块所带的所有 Cmdlet,请试试以下代码:

PS> Get-Command -Module PrintManagement

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Function        Add-Printer                                        PrintManagement
Function        Add-PrinterDriver                                  PrintManagement
Function        Add-PrinterPort                                    PrintManagement
Function        Get-PrintConfiguration                             PrintManagement
Function        Get-Printer                                        PrintManagement
Function        Get-PrinterDriver                                  PrintManagement
Function        Get-PrinterPort                                    PrintManagement
Function        Get-PrinterProperty                                PrintManagement
Function        Get-PrintJob                                       PrintManagement
Function        Read-PrinterNfcTag                                 PrintManagement
Function        Remove-Printer                                     PrintManagement
Function        Remove-PrinterDriver                               PrintManagement
Function        Remove-PrinterPort                                 PrintManagement
Function        Remove-PrintJob                                    PrintManagement
Function        Rename-Printer                                     PrintManagement
Function        Restart-PrintJob                                   PrintManagement
Function        Resume-PrintJob                                    PrintManagement
Function        Set-PrintConfiguration                             PrintManagement
Function        Set-Printer                                        PrintManagement
Function        Set-PrinterProperty                                PrintManagement
Function        Suspend-PrintJob                                   PrintManagement
Function        Write-PrinterNfcTag                                PrintManagement

如您所见,它们实际上是 PowerShell 函数而不是二进制 Cmdlet。

PowerShell 技能连载 - 简化 .NET 类型

适用于 PowerShell 所有版本

PowerShell 为多数常见的 .NET 类型定义了一个短名字。要查看已有多少个 .NET 类型定义了短名称,请使用以下代码:

PS> [System.Management.Automation.LanguagePrimitives]::ConvertTypeNameToPSTypeName("System.String")
[string]

PS> [System.Management.Automation.LanguagePrimitives]::ConvertTypeNameToPSTypeName("System.Int32")
[int]

PS> [System.Management.Automation.LanguagePrimitives]::ConvertTypeNameToPSTypeName("System.Management.ManagementObject")
[wmi]

PS> [System.Management.Automation.LanguagePrimitives]::ConvertTypeNameToPSTypeName("System.DirectoryServices.DirectoryEntry")
[adsi]

PS>

要查用另一种方法看真实的 .NET 名称,请使用以下方法:

PS> [string].FullName
System.String

PS> [int].FullName
System.Int32

PS> [wmi].FullName
System.Management.ManagementObject

PS> [adsi].FullName
System.DirectoryServices.DirectoryEntry

PS>

通过这个技巧,您还可以更好地理解 PowerShell 转换数据类型的机制:

PS> [System.Management.Automation.LanguagePrimitives]::ConvertTypeNameToPSTypeName("UInt8")
[Byte]

PS>

这表明了,当 PowerShell 遇到一个无符号 8 位整型数值,将自动把它转换为一个 Byte 数据。整个魔法是由 ConvertTypeNameToPSTypeName() 完成的。在内部,PowerShell 使用一个检索表来转换特定的数据类型:

$field = [System.Management.Automation.LanguagePrimitives].GetField('nameMap', 'NonPublic,Static')
$field.GetValue([System.Management.Automation.LanguagePrimitives])

该检索表看起来类似这样:

Key                                                            Value
---                                                            -----
SInt8                                                          SByte
UInt8                                                          Byte
SInt16                                                         Int16
UInt16                                                         UInt16
SInt32                                                         Int32
UInt32                                                         UInt32
SInt64                                                         Int64
UInt64                                                         UInt64
Real32                                                         Single
Real64                                                         double
Boolean                                                        bool
String                                                         string
DateTime                                                       DateTime
Reference                                                      CimInstance
Char16                                                         char
Instance                                                       CimInstance
BooleanArray                                                   bool[]
UInt8Array                                                     byte[]
SInt8Array                                                     Sbyte[]
UInt16Array                                                    uint16[]
SInt16Array                                                    int64[]
UInt32Array                                                    UInt32[]
SInt32Array                                                    Int32[]
UInt64Array                                                    UInt64[]
SInt64Array                                                    Int64[]
Real32Array                                                    Single[]
Real64Array                                                    double[]
Char16Array                                                    char[]
DateTimeArray                                                  DateTime[]
StringArray                                                    string[]
ReferenceArray                                                 CimInstance[]
InstanceArray                                                  CimInstance[]
Unknown                                                        UnknownType