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

PowerShell 技能连载 - 将代码转为大写

适用于 PowerShell 3.0 及以上版本

在 PowerShell ISE 中要将 PowerShell 的代码转为全大写,请选中文本,并按下 CTRL + SHIFT + U

To turn text to all lowercase letters, press CTRL+U.
要将文本转为全小写,请按 CTRL+U

PowerShell 技能连载 - 映射驱动器

适用于 PowerShell 3.0 及以上版本

要永久地映射一个网络驱动器,请使用 New-PSDrive 加上 -Persist 参数。这个参数使得驱动器在 PowerShell 之外可见。

要真正地创建一个永久的网络驱动器,请确保加上 -Scope Global。如果 New-PSDrive 在全局作用域范围之外运行(例如,在一个脚本中运行),该驱动器只会在脚本运行时出现在文件管理器中。

这个实例代码演示了如何映射一个网络驱动器:

New-PSDrive -Name k -PSProvider FileSystem -Root \\storage2\vid -Persist -Scope Global

PowerShell 技能连载 - 在输出中使用系统的错误颜色

适用于 PowerShell 所有版本

如果您的脚本希望输出警告或错误信息,您可以使用 Write-WarningWrite-Error 指令。两个 cmdlet 都会使用缺省的 PowerShell 颜色来显示警告和错误。然而,这两个 cmdlet 也会为您的输出结果套用一个文字模板:

PS> Write-Warning -Message 'This  is a warning'
WARNING: This is a warning

PS> Write-Error -Message  'Something went wrong'
Write-Error -Message 'Something went wrong'  : Something went wrong
    +  CategoryInfo          : NotSpecified: (:)  [Write-Error], WriteErrorException
    +  FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

Write-Error 添加了一堆无意义的异常详细信息,而您所需要的只是错误文本。一个更好的方式是:

PS>  $host.UI.WriteErrorLine('Something went wrong...')
Something went wrong...

警告和错误的颜色可以通过这种方式配置:

PS>  $host.UI.WriteErrorLine('Something went wrong...')
Something went wrong...

PS> $host.PrivateData.ErrorBackgroundColor  = 'White'

PS>  $host.UI.WriteErrorLine('Something went wrong...')
Something  went wrong...

PS> $host.PrivateData

(...)
ErrorForegroundColor                      : #FFFF0000
ErrorBackgroundColor                      : #FFFFFFFF
WarningForegroundColor                    : #FFFF8C00
WarningBackgroundColor                    : #00FFFFFF
VerboseForegroundColor                    : #FF00FFFF
VerboseBackgroundColor                    : #00FFFFFF
DebugForegroundColor                      : #FF00FFFF
DebugBackgroundColor                      : #00FFFFFF
(...)

PowerShell 技能连载 - 解析 IP 地址(和参数类型)

适用于 PowerShell 2.0 及以上版本

这个例子演示了两件事情:如何限制一个参数为指定的数据类型、如何使用 .NET 方法来将 IP 地址转化为机器名:

function Resolve-IPAddress
{
    param (
        [IPAddress]
        $IPAddress
    )

    [Net.DNS]::GetHostByAddress($IPAddress)
}

通过为 $IPAddress 参数前附加一个类型(例如“IPAddress”),您可以让 PowerShell 来校验输入数据的合法性。

System.Net.DNS” .NET 类型提供了许多有用的静态方法供您解析 IP 地址。请注意在 PowerShell 中您不需要为 .NET 类型指定“System”命名空间。如果您愿意,您也可以使用完整的“`System.Net.DNS”全名。

这是您使用了新的 Resolve-IPAddress 函数的效果:

PS> Resolve-IPAddress -IPAddress 127.0.0.1

HostName                     Aliases                     AddressList
--------                     -------                     -----------
TobiasAir1                   {}                          {127.0.0.1}



PS> Resolve-IPAddress -IPAddress 300.200.100.1
 Resolve-IPAddress : Cannot process argument transformation on parameter
'IPAddress'. Cannot convert value "300.200.100.1" to type "System.Net.IPAddress".
Error: "An invalid IP address was specified."
At line:1 char:30
+ Resolve-IPAddress -IPAddress 300.200.100.1
+                              ~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Resolve-IPAddress], ParameterBindin
   gArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Resolve-IPAddres
   s

PowerShell 技能连载 - 条件断点

适用于 PowerShell 3.0 及以上版本

PowerShell ISE 只支持行断点:它们的作用是当调试器命中指定的行时,使代码暂停执行。您可以在 PowerShell ISE 中按 F9 来切换行断点。只需要保证脚本已经保存。未保存的脚本(“无标题”)中的断点是无效的。

一个更复杂的做法是使用动态(或称为“条件”)断点。它们并不是关联于某一行上而是和某一种情况有关联。

要在某个变量被赋予一个新值的时候使脚本停下来,请使用这段示例代码(请先保存后执行):

$bp = Set-PSBreakpoint -Variable a -Mode Write -Script $psise.CurrentFile.FullPath

$a = 1
$a

$a

$a = 200
$a

Remove-PSBreakpoint -Breakpoint $bp

当您运行它时,PowerShell 调试器将会在 $a 被赋予一个新值的时候暂停脚本执行。

您甚至可以为它绑定一个更复杂的条件。这个例子将只会在对 $a 赋予一个大于 100 的整数值时才使脚本暂停。

$Condition = { if ($a -is [Int] -and $a -gt 100) { break }  }
$bp = Set-PSBreakpoint -Variable a -Mode Write -Script $psise.CurrentFile.FullPath -Action $Condition

$a = 1
$a

$a

$a = 200
$a

Remove-PSBreakpoint -Breakpoint $bp

PowerShell 技能连载 - 检测 64 位操作系统

适用于 Windows 7/Server 2008 R2

要检测一个脚本是运行在 32 位环境还是 64 位环境是十分简单的:只需要检查指针的大小,看是等于 4 字节还是 8 字节:

if ([IntPtr]::Size -eq 8)
{
    '64-bit'
}
else
{
    '32-bit'
}

不过这并不会告诉您操作系统的类型。这是由于 PowerShell 脚本可以在 64 位机器中运行在 32 位进程里。

要检测 OS 类型,请试试这段代码:

if ([Environment]::Is64BitOperatingSystem)
{
    '64-bit'
}
else
{
    '32-bit'
}

而且,Environment 类也可以检查您的进程类型:

if ([Environment]::Is64BitProcess)
{
    '64-bit'
}
else
{
    '32-bit'
}

PowerShell 技能连载 - 创建 NTFS 安全报告

适用于 PowerShell 所有版本

如果您希望审计您文件系统中的 NTFS 权限,以下是您起步的建议。

这个脚本递归扫描 Windows 目录和子目录。只要将 $Path 替换为其它路径就可以扫描您文件系统的其它路径。

$Path = 'C:\Windows'

Get-ChildItem -Path $Path -Recurse -Directory -ErrorAction SilentlyContinue |
  ForEach-Object {
    $result = $_ | Select-Object -Property FullName, ExplicitePermissions, Count, Preview
    $result.ExplicitePermissions = (Get-Acl -Path $_.FullName -ErrorAction SilentlyContinue).Access |
      Where-Object { $_.isInherited -eq $false }
    $result.Count = $result.ExplicitePermissions.Count
    $result.Preview = $result.ExplicitePermissions.IdentityReference -join ','
    if ($result.ExplicitePermissions.Count -gt 0)
    {
      $result
    }
  } | Out-GridView

该脚本读取每个子文件夹的安全描述符并查找非继承的安全控制项。如果找到了,那么就加这个信息加入文件夹对象。

结果将输出到一个网格视图窗口。如果您移除掉 Out-GridView,那么您会得到类似如下的信息:

PS> G:\

FullName                   ExplicitePermissions                          Count Preview
--------                   --------------------                          ----- -------
C:\windows\addins          {System.Security.Access...                        9 CREATOR OWNER,NT AUTHOR...
C:\windows\AppPatch        {System.Security.Access...                        9 CREATOR OWNER,NT AUTHOR...
C:\windows\Boot            {System.Security.Access...                        8 NT AUTHORITY\SYSTEM,NT ...
C:\windows\Branding        {System.Security.Access...                        9 CREATOR OWNER,NT AUTHOR...
C:\windows\Cursors         {System.Security.Access...                        9 CREATOR OWNER,NT AUTHOR...
C:\windows\de-DE           {System.Security.Access...                        9 CREATOR OWNER,NT AUTHOR...
C:\windows\diagnostics     {System.Security.Access...                        8 NT AUTHORITY\SYSTEM,NT ...
C:\windows\Downloaded P... {System.Security.Access...                       11 CREATOR OWNER,NT AUTHOR...

您可以将这个例子作为更深入的工具的基础。例如,您可以将缺省受信任者(例如“CREATOR”,或“SYSTEM”)加入一个列表,并从结果中排除这个列表。

PowerShell 技能连载 - 查找非继承的权限

适用于 PowerShell 所有版本

通常,文件系统的 NTFS 权限是继承的。然而,您可以显式地为文件和文件夹添加权限。

您可以使用这段示例代码查找何处禁用了继承以及何处添加了权限项目:

Get-ChildItem c:\Windows -Recurse -Directory -ErrorAction SilentlyContinue |
  Where-Object { (Get-Acl -Path $_.FullName -ErrorAction SilentlyContinue).Access |
  Where-Object { $_.isInherited -eq $false } }

在这个例子中,Get-ChildItem 在 Windows 文件夹中搜索所有子文件夹。您可以将“C:\Windows”改为您想测试的任意文件夹。

然后,该脚本读取每个文件夹的安全描述符并查看是否有 isInherited 属性被设为 $false 的存取控制记录。

如果结果为真,该文件夹会汇报给您。

PowerShell 技能连载 - 不通过 ProgID 操作 COM 对象

适用于 PowerShell 所有版本

通常在操作 COM 对象时,它们需要将自身在注册表中注册,并且 PowerShell 需要注册的 ProgID 字符串来加载对象。

以下是一个例子:

$object = New-Object -ComObject Scripting.FileSystemObject
$object.Drives

若不使用 New-Object 命令,您也可以用 .NET 方法来实现相同的目的:

$type = [Type]::GetTypeFromProgID('Scripting.FileSystemObject')
$object = [Activator]::CreateInstance($type)
$object.Drives

采用后一种方法,您甚至可以实例化一个未暴露 ProgID 的 COM 对象。您所需的只是 GUID:

$clsid = New-Object Guid '0D43FE01-F093-11CF-8940-00A0C9054228'
$type = [Type]::GetTypeFromCLSID($clsid)
$object = [Activator]::CreateInstance($type)
$object.Drives