PowerShell 技能连载 - 获取端口分配列表

IANA(互联网数字分配机构)维护了一个包含所有已知的端口分配的 CSV 文件。PowerShell 可以为您下载这个列表:

1
2
3
4
$out = "$env:temp\portlist.csv"
$url = 'https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.csv'
$web = Invoke-WebRequest -Uri $url -UseBasicParsing -OutFile $out
Import-Csv -Path $out -Encoding UTF8

返回的结果是一个包含所有的端口分配的面向对象格式的列表。接下来您可以使用这个信息例如过滤特定的端口:

1
2
3
Import-Csv -Path $out -Encoding UTF8 |
Where-Object 'transport protocol' -eq 'tcp' |
Where-Object 'Port Number' -lt 1000

PowerShell 技能连载 - 世界时钟

PowerShell 提供了 Get-TimeZone 命令,能返回所有定义过的时区和它们的时差。以下是列出世界时钟相关的代码:

1
2
3
4
5
6
7
8
9
10
11
12
$isSummer = (Get-Date).IsDaylightSavingTime()


Get-TimeZone -ListAvailable | ForEach-Object {
$dateTime = [DateTime]::UtcNow + $_.BaseUtcOffset
$cities = $_.DisplayName.Split(')')[-1].Trim()
if ($isSummer -and $_.SupportsDaylightSavingTime)
{
$dateTime = $dateTime.AddHours(1)
}
'{0,-30}: {1:HH:mm"h"} ({2})' -f $_.Id, $dateTime, $cities
}

结果类似如下:

Dateline Standard Time         : 18:41h ()
UTC-11                         : 19:41h (Coordinated Universal Time-11)
Aleutian Standard Time         : 21:41h (Aleutian Islands)
Hawaiian Standard Time         : 20:41h (Hawaii)
Marquesas Standard Time        : 21:11h (Marquesas Islands)
Alaskan Standard Time          : 22:41h (Alaska)
UTC-09                         : 21:41h (Coordinated Universal Time-09)
Pacific Standard Time (Mexico) : 23:41h (Baja California)
UTC-08                         : 22:41h (Coordinated Universal Time-08)
Pacific Standard Time          : 23:41h ()
US Mountain Standard Time      : 23:41h (Arizona)
Mountain Standard Time (Mexico): 00:41h (Chihuahua, La Paz, Mazatlan)
Mountain Standard Time         : 00:41h ()
Central America Standard Time  : 00:41h (Central America)
Central Standard Time          : 01:41h ()
Easter Island Standard Time    : 01:41h (Easter Island)
Central Standard Time (Mexico) : 01:41h (Guadalajara, Mexico City, Monterrey)
Canada Central Standard Time   : 00:41h (Saskatchewan)
SA Pacific Standard Time       : 01:41h (Bogota, Lima, Quito, Rio Branco)
Eastern Standard Time (Mexico) : 02:41h (Chetumal)
Eastern Standard Time          : 02:41h ()

PowerShell 技能连载 - 设置时区

只有拥有了管理员特权才可以修改电脑的时间和日期,但任何用户都可以修改时区,例如当您在旅游时。PowerShell 5 提供了一系列非常简单的 cmdlet 来管理时区。首先,检查您的当前设置:

1
2
3
4
5
6
7
8
9
PS> Get-TimeZone


Id : W. Europe Standard Time
DisplayName : (UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien
StandardName : Mitteleuropäische Zeit
DaylightName : Mitteleuropäische Sommerzeit
BaseUtcOffset : 01:00:00
SupportsDaylightSavingTime : True

下一步,尝试修改时区。以下代码打开一个包含所有可用时区的窗口:

1
PS> Get-TimeZone -ListAvailable | Out-GridView

当您知道您希望设置的时区的正式 ID 后,请使用 Set-TimeZone 命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
PS> Set-TimeZone -Id 'Chatham Islands Standard Time'

PS> Get-Date

Samstag, 27. Mai 2017 18:32:53



PS> Set-TimeZone -Id 'W. Europe Standard Time'

PS> Get-Date

Samstag, 27. Mai 2017 07:48:02

PowerShell 技能连载 - 查找一个脚本中的所有变量

在前一个技能中我们掩饰了如何分析一段脚本块的内容并且搜索变量或命令。这种技术也适用于基于文本的脚本。以下脚本将会检查自己并且提取出变量和命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$filepath = $PSCommandPath
$tokens = $errors = $null

$ast = [System.Management.Automation.Language.Parser]::ParseFile($filepath, [ref]$tokens, [ref]$errors )

# find variables
$ast.FindAll( { $true }, $true) |
Where-Object { $_.GetType().Name -eq 'VariableExpressionAst' } |
Select-Object -Property VariablePath -ExpandProperty Extent |
Select-Object -Property * -ExcludeProperty *ScriptPosition |
Out-GridView -Title 'Variables'


# find commands
$ast.FindAll( { $true }, $true) |
Where-Object { $_.GetType().Name -eq 'CommandAst' } |
Select-Object -ExpandProperty Extent |
Select-Object -Property * -ExcludeProperty *ScriptPosition |
Out-GridView -Title 'Commands'

请确保将脚本保存到硬盘,或为 $filepath 指定一个不同的实际存在的脚本路径。

PowerShell 技能连载 - 查找一个脚本块中的所有变量

要分析一个脚本快中的内容,您可以简单地检查 AST,并且,例如创建一个包含代码中所有变量的清单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$code = {

$a = "Test"
$b = 12
Get-Service
Get-Process
$berta = 100

}


$code.Ast.FindAll( { $true }, $true) |
Where-Object { $_.GetType().Name -eq 'VariableExpressionAst' } |
Select-Object -Property VariablePath -ExpandProperty Extent |
Out-GridView

如果您想查看所有的命令,请试试以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$code = {

$a = "Test"
$b = 12
Get-Service
Get-Process
$berta = 100

}


$code.Ast.FindAll( { $true }, $true) |
Where-Object { $_.GetType().Name -eq 'CommandAst' } |
Select-Object -ExpandProperty Extent |
Select-Object -Property * -ExcludeProperty *ScriptPosition |
Out-GridView

这在根据脚本块自动生成文档的时候非常有用。

PowerShell 技能连载 - 在计划任务中运行 PowerShell 脚本

如果您需要以固定的频率运行一段 PowerShell 脚本,何不以计划任务的方式运行它呢?以下是一段帮您新建一个每天上午 6 点执行一个 PowerShell 脚本的计划任务的代码:

1
2
3
4
5
6
7
8
9
10
11
#requires -Modules ScheduledTasks
#requires -Version 3.0
#requires -RunAsAdministrator

$TaskName = 'RunPSScriptAt6'
$User= "train\tweltner"
$scriptPath = "\\Server01\Scripts\find-newaduser.ps1"

$Trigger= New-ScheduledTaskTrigger -At 6:00am -Daily
$Action= New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-executionpolicy bypass -noprofile -file $scriptPath"
Register-ScheduledTask -TaskName $TaskName -Trigger $Trigger -User $User -Action $Action -RunLevel Highest -Force

PowerShell 技能连载 - 查看函数源码

以下是一种快速查看 PowerShell 函数源码的方法:

1
${function:Clear-Host} | clip

这将会把 Clear-Host 的源代码复制到剪贴板中,并且当您粘贴它时,您可以看到 Clear-Host 是如何工作的:

1
2
3
4
5
$RawUI = $Host.UI.RawUI
$RawUI.CursorPosition = @{X=0;Y=0}
$RawUI.SetBufferContents(
@{Top = -1; Bottom = -1; Right = -1; Left = -1},
@{Character = ' '; ForegroundColor = $rawui.ForegroundColor; BackgroundColor = $rawui.BackgroundColor})

通常可以从这里学到很多东西。如果您想用非空格的字符填充 PowerShell 控制台,例如绿底白字的 ‘X’,请试试这段代码:

1
2
3
$host.UI.RawUI.SetBufferContents(
@{Top = -1; Bottom = -1; Right = -1; Left = -1},
@{Character = 'X'; ForegroundColor = 'Yellow'; BackgroundColor = 'Green'})

请注意这只能在真正的 PowerShell 控制台宿主中起作用。

PowerShell 技能连载 - More 命令的现代版替代品

在 PowerShell 控制台中,您仍然可以用 more 管道,就像在 cmd.exe 中一样一页一页查看结果。然而,more 不支持实时管道,所以所有数据需要首先收集好。这将占用很长时间和内存:

1
dir c:\windows -Recurse -ea 0  | more

一个更好的方法是使用 PowerShell 自带的分页功能:

1
dir c:\windows -Recurse -ea 0  | Out-Host -Paging

请注意这些都需要一个真正的控制台窗口,而在图形界面的宿主中不能工作。

PowerShell 技能连载 - 远程创建 SMB 共享

以下几行代码能在远程服务器上创建一个 SMB 共享:

1
2
3
4
5
6
7
8
#requires -Version 3.0 -Modules CimCmdlets, SmbShare -RunAsAdministrator
$computername = 'Server12'
$shareName = 'ScriptExchange'
$fullAccess = 'domain\groupName'

$session = New-CimSession -ComputerName $computername
New-SMBShare -Name $shareName -Path c:\Scripts -FullAccess $fullAccess -CimSession $session
Remove-CimSession -CimSession $session

您可以在客户端将该共享映射为一个网络驱动器。请注意这个网络共享是单用户的,所以如果您使用 Administrator 账户做了映射,那么无法在 Windows Explorer 中存取。

1
2
3
$computername = 'Server12'
$shareName = 'ScriptExchange'
net use * "\\$computername\$shareName"