Powershell 的基础使用IV 函数与注释

Powershell 的基础使用IV 函数与注释

前言

这里是相关基础知识的函数与注释篇.

基本函数语法规则

见基本函数

1
2
3
4
5
6
7
function [<scope:>]<name> [([type]$parameter1[,[type]$parameter2])]
{
begin {<statement list>}
process {<statement list>}
end {<statement list>}
clean {<statement list>}
}

用例

根据定义, 可以很快写出一个基础的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Get-Time([string]$Zone = '中国') {
# 获取与 UTC 的偏移量
$offset = Get-TimeZone -ListAvailable | where-Object { $_.StandardName.Contains($Zone) -or $_.DisplayName.Contains($Zone) } | Select-Object -First 1
if (($null -eq $offset) -or ('' -eq $offset)) {
Write-Error "请求的地区不存在: $Zone"
}
# UTC 时间
[datetime]$utc = Get-Date -AsUTC
$gs = [regex]::Match($offset.BaseUtcOffset, '(?<h>[+-]{0,1}\d{2}):(?<m>[+-]{0,1}\d{2}):(?<s>[+-]{0,1}\d{2})').Groups
[int]$hour = $gs['h'].Value
[int]$minute = $gs['m'].Value
[int]$second = $gs['s'].Value
return $utc.AddHours($hour).AddMinutes($minute).AddSeconds($second)
}

Get-Time
Get-Time -$Zone '俄罗斯'
Get-Time '澳大利亚'
$hk = '香港' | Get-Time
[DateTimeOffset]::new($hk).ToUnixTimeMilliseconds()

或者以下形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function Get-Time {
param(
[parameter(ValueFromPipeline)]
[string]$Zone = '中国'
)
begin {
# UTC 时间
[datetime]$utc = Get-Date -AsUTC
}

process {
# 获取与 UTC 的偏移量
$offset = Get-TimeZone -ListAvailable | where-Object { $_.StandardName.Contains($Zone) -or $_.DisplayName.Contains($Zone) } | Select-Object -First 1
if (($null -eq $offset) -or ('' -eq $offset)) {
Write-Error "请求的地区不存在: $Zone"
}
$gs = [regex]::Match($offset.BaseUtcOffset, '(?<h>[+-]{0,1}\d{2}):(?<m>[+-]{0,1}\d{2}):(?<s>[+-]{0,1}\d{2})').Groups
$out = $utc.AddHours($gs['h'].Value).AddMinutes($gs['m'].Value).AddSeconds($gs['s'].Value)
$out | Add-Member -MemberType NoteProperty -Name Zone -Value $Zone
$out | Add-Member -MemberType NoteProperty -Name Present -Value $out.ToString()
return $out
}
end {}
}

Get-Time
Get-Time -Zone 中国
@('悉尼' , '东京', '俄罗斯') | Get-Time | Select-Object -Property @('Zone', 'Present') | Format-Table
$h = Get-Time '香港'
[DateTimeOffset]::new($h).ToUnixTimeMilliseconds()

Get-Time
Get-Time -Zone 中国
@('悉尼' , '东京', '俄罗斯') | Get-Time | Select-Object -Property @('Zone', 'Present') | Format-Table
$h = Get-Time '香港'
[DateTimeOffset]::new($h).ToUnixTimeMilliseconds()

这个函数输出对应地区的时间, 还输出了香港地区的时间戳:

1
2
3
4
5
6
7
8
9
10
11
2024年6月16日 10:46:35
2024年6月16日 10:46:35


Zone Present
---- -------
悉尼 2024/6/16 12:46:35
东京 2024/6/16 11:46:35
俄罗斯 2024/6/16 4:46:35

1718534795735

一些小结

  • 函数可以使用第一种最简化的版本, 默认支持管道
  • 可以变换到第二个版本, 需要在 process 块执行, 同时注意到需要高级参数 ValueFromPipeline, where-Object 中的过滤当前对象默认是 $_, 而管道块当前迭代对象也是 $_, 使用该参数之后函数的管道值将指向参数 $Zone
  • begin 在多管道时只运行一次, 这里使用了共享参数 $utc, 见 增加开关参数

增加开关参数

增加一个标记,打印当前请求的地区信息

修改上边的代码, 增加入参, 修改 beginprocess, clean 块中的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function Get-Time {
param(
[parameter(ValueFromPipeline)]
[string]$Zone = '中国',
[switch]
$PrintReq
)
begin {
# UTC 时间
[datetime]$utc = Get-Date -AsUTC
if ($PrintReq) {
Write-Host "`e[33m初始化 UTC 的时间`e[0m"
}
}

process {
if ($PrintReq) {
Write-Host "`e[34m正在获取 [$Zone] 地区的时间`e[0m"
}
# 获取与 UTC 的偏移量
$offset = Get-TimeZone -ListAvailable | where-Object { $_.StandardName.Contains($Zone) -or $_.DisplayName.Contains($Zone) } | Select-Object -First 1
if (($null -eq $offset) -or ('' -eq $offset)) {
Write-Error "请求的地区不存在: $Zone"
}
$gs = [regex]::Match($offset.BaseUtcOffset, '(?<h>[+-]{0,1}\d{2}):(?<m>[+-]{0,1}\d{2}):(?<s>[+-]{0,1}\d{2})').Groups
$out = $utc.AddHours($gs['h'].Value).AddMinutes($gs['m'].Value).AddSeconds($gs['s'].Value)
$out |
Add-Member -MemberType NoteProperty -Name Zone -Value $Zone -PassThru |
Add-Member -MemberType NoteProperty -Name Present -Value $out.ToString()
return $out
}
end {
if ($PrintReq) {
Write-Host "`e[35m关闭函数`e[0m"
}
}
}

Get-Time -PrintReq
@('悉尼' , '东京', '俄罗斯') | Get-Time -PrintReq | Select-Object -Property @('Zone', 'Present') | Format-Table

上边的输出为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
初始化 UTC 的时间
正在获取 [中国] 地区的时间

2024年6月16日 11:00:26
关闭函数
初始化 UTC 的时间
正在获取 [悉尼] 地区的时间


正在获取 [东京] 地区的时间
正在获取 [俄罗斯] 地区的时间
关闭函数
Zone Present
---- -------
悉尼 2024/6/16 13:00:26
东京 2024/6/16 12:00:26
俄罗斯 2024/6/16 5:00:26

一些小结

  • 可以观察到, 初始化 只输出了两次, 在管道流的初始化, 关闭 同理, 如果只使用 Get-Time,$PrintReq 会初始化为 False
  • 使用开关参数避免了手动输入 -PrintReq $true 的尴尬局面
  • -PassThru 也是一个开关参数, 返回管道中的 $_ 对象

增加参数校验

避免手动检查抛错, 选择用高级参数限制输入, 对以上的函数, 仅做 非空检查即可

修改之后的函数为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function Get-Time {
param(
[parameter(ValueFromPipeline)]
[ValidateNotNullOrWhiteSpace()]
[string]$Zone = '中国',
[switch]
$PrintReq
)
begin {
# UTC 时间
[datetime]$utc = Get-Date -AsUTC
if ($PrintReq) {
Write-Host "`e[33m初始化 UTC 的时间`e[0m"
}
}

process {
if ($PrintReq) {
Write-Host "`e[34m正在获取 [$Zone] 地区的时间`e[0m"
}
# 获取与 UTC 的偏移量
$offset = Get-TimeZone -ListAvailable | where-Object { $_.StandardName.Contains($Zone) -or $_.DisplayName.Contains($Zone) } | Select-Object -First 1
if (($null -eq $offset) -or ('' -eq $offset)) {
Write-Error "请求的地区不存在: $Zone"
}
$gs = [regex]::Match($offset.BaseUtcOffset, '(?<h>[+-]{0,1}\d{2}):(?<m>[+-]{0,1}\d{2}):(?<s>[+-]{0,1}\d{2})').Groups
$out = $utc.AddHours($gs['h'].Value).AddMinutes($gs['m'].Value).AddSeconds($gs['s'].Value)
$out |
Add-Member -MemberType NoteProperty -Name Zone -Value $Zone -PassThru |
Add-Member -MemberType NoteProperty -Name Present -Value $out.ToString()
return $out
}
end {
if ($PrintReq) {
Write-Host "`e[35m关闭函数`e[0m"
}
}
}
Get-Time
try {
Get-Time -Zone ' '
}
catch [System.Management.Automation.ParameterBindingException] {
[System.Management.Automation.ParameterBindingException]$e = $_.Exception;
Write-Host "检测到参数错误, 错误参数: $($e.ParameterName)"
}
catch {
Write-Host "检测到运行错误: $($_.Exception.Message)"
}

使用 Get-Time - ' ' 将得到一个校验错误: 如下

1
2
2024年6月16日 11:47:00
检测到参数错误, 错误参数: Zone

一些小结

  • 参数校验以 Validate 开始
  • 参数校验抛出的错误为 ParameterBindingException
  • 使用 try--catch 捕捉错误

完善函数声明与注释

以下是完整的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<# 

<#

.SYNOPSIS
获取地区时间
.DESCRIPTION
根据指定地区, 获取地区时间, 默认为中国

.PARAMETER Zone
指定地区

.PARAMETER PrintReq
输出 debug 信息

.OUTPUTS
datetime 地区时间

.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.datetime?view=net-8.0

.LINK
https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.management/get-timezone?view=powershell-7.4

.EXAMPLE
Get-Time

.EXAMPLE
Get-Time '美国'

.EXAMPLE
Get-Time -Zone '美国'

.INPUTS
地区信息

#>

function Get-Time {
param(
[parameter(ValueFromPipeline, Mandatory = $false, Position = 0)]
[ValidateNotNullOrWhiteSpace()]
[string]$Zone = '中国',
[switch]
$PrintReq
)
begin {
# UTC 时间
[datetime]$utc = Get-Date -AsUTC
if ($PrintReq) {
Write-Host "`e[33m初始化 UTC 的时间`e[0m"
}
}

process {
if ($PrintReq) {
Write-Host "`e[34m正在获取 [$Zone] 地区的时间`e[0m"
}
# 获取与 UTC 的偏移量
$offset = Get-TimeZone -ListAvailable | where-Object { $_.StandardName.Contains($Zone) -or $_.DisplayName.Contains($Zone) } | Select-Object -First 1
if (($null -eq $offset) -or ('' -eq $offset)) {
throw "请求的地区不存在: $Zone"
}
$gs = [regex]::Match($offset.BaseUtcOffset, '(?<h>[+-]{0,1}\d{2}):(?<m>[+-]{0,1}\d{2}):(?<s>[+-]{0,1}\d{2})').Groups
$out = $utc.AddHours($gs['h'].Value).AddMinutes($gs['m'].Value).AddSeconds($gs['s'].Value)
$out |
Add-Member -MemberType NoteProperty -Name Zone -Value $Zone -PassThru |
Add-Member -MemberType NoteProperty -Name Present -Value $out.ToString()
return $out
}
end {
if ($PrintReq) {
Write-Host "`e[35m关闭函数`e[0m"
}
}
}
try {
Get-Time '未知'
}
catch [System.Management.Automation.ParameterBindingException] {
[System.Management.Automation.ParameterBindingException]$e = $_.Exception;
Write-Host "检测到参数错误, 错误参数: $($e.ParameterName)"
}
catch {
Write-Host "检测到运行错误: $($_.Exception.Message)"
}

Get-Help Get-Time -Full

以及输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
检测到运行错误: 请求的地区不存在: 未知

NAME
Get-Time

SYNOPSIS
获取地区时间


SYNTAX
Get-Time [[-Zone] <String>] [-PrintReq] [<CommonParameters>]


DESCRIPTION
根据指定地区, 获取地区时间, 默认为中国


PARAMETERS
-Zone <String>
指定地区

Required? false
Position? 1
Default value 中国
Accept pipeline input? true (ByValue)
Accept wildcard characters? false

-PrintReq [<SwitchParameter>]
输出 debug 信息

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

<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer, PipelineVariable, and OutVariable. For more information, see
about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216).

INPUTS
地区信息


OUTPUTS
datetime 地区时间

-------------------------- EXAMPLE 1 --------------------------

PS > Get-Time

-------------------------- EXAMPLE 2 --------------------------

PS > Get-Time '美国'

-------------------------- EXAMPLE 3 --------------------------

PS > Get-Time -Zone '美国'

RELATED LINKS
https://learn.microsoft.com/en-us/dotnet/api/system.datetime?view=net-8.0
https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.management/get-timezone?view=powershell-7.4

额外资料