PowerShell 技能连载 - 本地帐户的内置支持

从 PowerShell 5.1 开始,终于内置支持了本地用户账户。PowerShell 5.1 现在支持 Windows 10 和 Windows Server 2016:

PS C:\> Get-Command -Module *LocalAccounts | Select-Object -ExpandProperty Name

Add-LocalGroupMember
Disable-LocalUser
Enable-LocalUser
Get-LocalGroup
Get-LocalGroupMember
Get-LocalUser
New-LocalGroup
New-LocalUser
Remove-LocalGroup
Remove-LocalGroupMember
Remove-LocalUser
Rename-LocalGroup
Rename-LocalUser
Set-LocalGroup
Set-LocalUser

PowerShell 技能连载 - 使用 Add-Member 时请注意!

Add-Member 常用来创建自定义对象,例如:

1
2
3
4
5
$o = New-Object -TypeName PSObject
$o | Add-Member -MemberType NoteProperty -Name Notes -Value 'Something'
$o | Add-Member -MemberType NoteProperty -Name Date -Value (Get-Date)

$o

这可以工作,结果类似这样:

PS C:\> $o

Notes     Date
-----     ----
Something 10/28/2016 3:56:53 PM

然而,这样做效率不高。因为 Add-Member 时动态地扩展现有的对象,而不是创建新的对象。以上代码可以用这种方法更容易地实现:

1
2
3
4
5
6
$o = [PSCustomObject]@{
Notes = 'Something'
Date = Get-Date
}

$o

Add-Member 可以做更多高级的事情,例如添加脚本属性和方法。请检查当您向以上对象添加动态脚本属性时发生了什么:

1
2
3
4
5
6
$o = [PSCustomObject]@{
Notes = 'Something'
Date = Get-Date
}

$o | Add-Member -MemberType ScriptProperty -Name CurrentDate -Value { Get-Date }

现在请看多次查询该对象时,它的 DateCurrentDate 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PS C:\> $o

Notes Date CurrentDate
----- ---- -----------
Something 10/28/2016 4:01:54 PM 10/28/2016 4:01:57 PM



PS C:\> $o

Notes Date CurrentDate
----- ---- -----------
Something 10/28/2016 4:01:54 PM 10/28/2016 4:02:00 PM



PS C:\> $o

Notes Date CurrentDate
----- ---- -----------
Something 10/28/2016 4:01:54 PM 10/28/2016 4:02:02 PM

Date 属性返回的是静态信息而CurrentDate 属性总是返回当前时间,因为它的值是一个脚本,每次查询这个属性的时候都会执行一次。

PowerShell 技能连载 - PSCustomObject 到底如何工作

在前一个技能中我们介绍了如何快速用 PSCustomObject 创建一个新对象:

$o = [PSCustomObject]@{
    Date     = Get-Date
    BIOS     = Get-WmiObject -Class Win32_BIOS
    Computer = $env:COMPUTERNAME
    OS       = [Environment]::OSVersion
    Remark   = 'Some remark'
}

实际中,[PSCustomObject] 并不是一个类型,并且也不是在转型一个哈希表。这个场景背后实际发生的是两个步骤的组合,您也可以分别执行这两个步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
#requires -Version 3.0

# create an ordered hash table
$hash = [Ordered]@{
Date = Get-Date
BIOS = Get-WmiObject -Class Win32_BIOS
Computer = $env:COMPUTERNAME
OS = [Environment]::OSVersion
Remark = 'Some remark'
}

# turn hash table in object
$o = New-Object -TypeName PSObject -Property $hash

由于这段代码用到了 PowerShell 3.0 引入的排序的哈希表,所以无法在 PowerShell 2.0 中使用相同的做法。要支持 PowerShell 2.0 ,请用无序的(传统的)哈希表代替:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#requires -Version 2.0

# create a hash table
$hash = @{
Date = Get-Date
BIOS = Get-WmiObject -Class Win32_BIOS
Computer = $env:COMPUTERNAME
OS = [Environment]::OSVersion
Remark = 'Some remark'
}

# turn hash table in object
$o = New-Object -TypeName PSObject -Property $hash

$o

PowerShell 技能连载 - 创建新对象的快速方法

要将一系列信息打包起来的最好方法就是将它们存储在自定义对象中。最简单最快捷的方法就是用 PSCustomObject

1
2
3
4
5
6
7
8
#requires -Version 3.0
$o = [PSCustomObject]@{
Date = Get-Date
BIOS = Get-WmiObject -Class Win32_BIOS
Computer = $env:COMPUTERNAME
OS = [Environment]::OSVersion
Remark = 'Some remark'
}

在大括号内,将一系列信息(或命令执行结果)存储在键中。这将创建一个将包含一系列信息的对象:

PS C:\> $o


Date : 10/28/2016 3:47:27 PM
BIOS : \DESKTOP-7AAMJLF\root\cimv2:Win32_BIOS.Name=”1.4.4”,SoftwareElementID=”1.4.4”,SoftwareElementState=3,TargetOpera
tingSystem=0,Version=”DELL - 1072009”
Computer : DESKTOP-7AAMJLF
OS : Microsoft Windows NT 10.0.14393.0
Remark : Some remark



PS C:> $o.Remark
Some remark

PS C:\> $o.OS

Platform ServicePack Version      VersionString
-------- ----------- -------      -------------
 Win32NT             10.0.14393.0 Microsoft Windows NT 10.0.14393.0


PS C:> $o.OS.VersionString
Microsoft Windows NT 10.0.14393.0

PS C:\>

PowerShell 技能连载 - 利用命令行历史

PowerShell 将您的所有交互命令行输入“记录”到它的命令行历史中,而 Get-History 负责显示它们。如果您运行了一段时间 PowerShell 并且觉得运行的效果不错,那么可以用以下脚本将所有的交互命令从命令行历史中复制到剪贴板中。接下来您可以将它们粘贴到 PowerShell ISE 中,并使之成为一个脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# define how old your commands may be at most to be included
$MaxAgeHours = 4

# get all command history items that were started after this
$DateLimit = (Get-Date).AddHours(-$MaxAgeHours)


# get all command-line commands
Get-History |
# exclude all that were aborted
Where-Object ExecutionStatus -eq Completed |
# exclude all that are older than the limit set above
Where-Object StartExecutionTime -gt $DateLimit |
# get just the command-line
Select-Object -ExpandProperty CommandLine |
# copy all to clipboard
clip.exe

PowerShell 技能连载 - 获取PowerShell Gallery 模块的最新版本

www.powershellgallery.com ,Microsoft 发布了一个公开的脚本和模块的仓库。您可以在这里和其他人交流 PowerShell 代码(请见网站)。

要使用这个仓库,您需要 PowerShell 5 或者手动安装 PowerShellGet 模块(在 powershellgallery.com 可以下载到)。接下来您可以使用诸如 Find/Save/Install/Update/Remove-Script/Module 等 cmdlet。

目前缺乏的是一个查看模块当前最新版本号的方法。以下是解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function Get-PublishedModuleVersion($Name)
{
# access the main module page, and add a random number to trick proxies
$url = "https://www.powershellgallery.com/packages/$Name/?dummy=$(Get-Random)"
$request = [System.Net.WebRequest]::Create($url)
# do not allow to redirect. The result is a "MovedPermanently"
$request.AllowAutoRedirect=$false
try
{
# send the request
$response = $request.GetResponse()
# get back the URL of the true destination page, and split off the version
$response.GetResponseHeader("Location").Split("/")[-1] -as [Version]
# make sure to clean up
$response.Close()
$response.Dispose()
}
catch
{
Write-Warning $_.Exception.Message
}
}

Get-PublishedModuleVersion -Name ISESteroids

当您运行 Get-PublishedModuleVersion 并传入发布的模块名,执行结果类似如下:

PS C:\> Get-PublishedModuleVersion -Name ISESteroids

Major  Minor  Build  Revision
-----  -----  -----  --------
2      6      3      25

这个操作非常非常快,而且可以用来检测已安装的模块,看它们是否是最新版本。

PowerShell 技能连载 - (分别)测试文件和文件夹

Test-Path 在测试一个文件或文件夹是否存在时十分有用,它可以用在任何 PowerShell 驱动器上。所以它也可以测试一个变量、一个函数,或一个证书是否存在(举个例子)。

In recent PowerShell versions, Test-Path can now differentiate between containers (i.e. folders) and leafs (i.e. files), too:

在近期的 PowerShell 版本中,Test-Path 还可以区分容器(例如文件夹)和叶子(例如文件):

1
2
3
4
5
6
7
$path = 'c:\windows\explorer.exe'
# any item type
Test-Path -Path $path
# just files
Test-Path -Path $path -PathType Leaf
# just folders
Test-Path -Path $path -PathType Container

PowerShell 技能连载 - 获取 Cmdlet 参数的帮助

在 PowerShell 5.0 中似乎有个 bug,限制了内置帮助窗口的作用。当您以 -ShowWindow 参数运行 Get-Help 命令时,该窗口只显示该 cmdlet 的语法和例子。许多额外信息并没有显示出来。

要获得某个 cmdlet 支持的参数的详细信息,请直接请求该信息。以下代码将解释 Get-Date 中的 -Format 参数是做什么的:

PS C:\> Get-Help -Name Get-Date -Parameter Format

-Format []
    Displays the date and time in the Microsoft .NET Framework format indicated by the
    format specifier. Enter a format specifier. For a list of available format
    specifiers, see DateTimeFormatInfo Class
    (http://msdn.microsoft.com/library/system.globalization.datetimeformatinfo.aspx)
    in MSDN.

    When you use the Format parameter, Windows PowerShell gets only the properties of
    the DateTime object that it needs to display the date in the format that you
    specify. As a result, some of the properties and methods of DateTime objects might
    not be available.

    Starting in Windows PowerShell 5.0, you can use the following additional formats
    as values for the Format parameter.

    -- FileDate. A file or path-friendly representation of the current date in local
    time. It is in the form of yyyymmdd ( using 4 digits, 2 digits, and 2 digits). An
    example of results when you use this format is 20150302.

    -- FileDateUniversal. A file or path-friendly representation of the current date
    in universal time. It is in the form of yyyymmdd + 'Z' (using 4 digits, 2 digits,
    and 2 digits). An example of results when you use this format is 20150302Z.

    -- FileDateTime. A file or path-friendly representation of the current date and
    time in local time, in 24-hour format. It is in the form of yyyymmdd + 'T' +
    hhmmssmsms, where msms is a four-character representation of milliseconds. An
    example of results when you use this format is 20150302T1240514987.

    -- FileDateTimeUniversal. A file or path-friendly representation of the current
    date and time in universal time, in 24-hour format. It is in the form of yyyymmdd
    + 'T' + hhmmssmsms, where msms is a four-character representation of milliseconds,
    + 'Z'. An example of results when you use this format is 20150302T0840539947Z.

    Required?                    false
    Position?                    named
    Default value                none
    Accept pipeline input?       false
    Accept wildcard characters?  false

通过这些信息,您现在可以知道如何格式化日期和时间:

1
2
3
$date = Read-Host -Prompt 'Enter a date'
$weekday = Get-Date -Date $date -Format 'dddd'
"$date is a $weekday"

PowerShell 技能连载 - 用一行代码更新 PowerShell 帮助信息

要获得 PowerShell 最全的输出信息,您需要更新 PowerShell 的帮助至少一次。这将下载并安装当您通过 cmdlet 运行 Get-Help 或是在 PowerShell ISE 中点击一个 cmdlet 并按 F1 时将出现的基础帮助文件集。

更新 PowerShell 帮助需要 Administrator 特权,因为帮助文件存在 Windows 文件夹中。

以下是一个单行命令,演示了如何以管理员特权运行任何 PowerShell 命令。这个命令将更新本地的 PowerShell 帮助文件:

1
Start-Process -FilePath powershell -Verb RunAs -ArgumentList "-noprofile -command Update-Help -UICulture en-us  -Force"

PowerShell 技能连载 - 在 PowerShell ISE 中获得 Cmdlet 的 IntelliSense

如果您在阅读某些加载到 PowerShell ISE 中的 PowerShell 代码,要获取额外信息十分容易。只需要点击想获得详情的 cmdlet,然后按下 CTRL+SPACE 键即可(译者注:可能会和 IME 切换快捷键冲突)。

这将调出 IntelliSense 菜单,即平时按下 “-“ 和 “.” 触发键时显示的菜单。由于只有一个 cmdlet 匹配成功,所以该列表只有一个项目。过一小会儿,就会弹出一个显示该 cmdlet 支持的所有参数的 tooltip。

如果您想了解更多,请按 F1 键。PowerShell ISE 将把当前位置的 cmdlet 名送给 Get-Help 命令。该帮助将在一个独立的新窗口中显示。