PowerShell 技能连载 - 局域网唤醒

无需外部“局域网唤醒”工具了。如果要唤醒网络计算机,只需告诉 PowerShell 目标计算机的 MAC 地址即可。这是一个组成 magic packet 并唤醒机器的函数:

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
function Invoke-WakeOnLan
{
param
(
# one or more MAC addresses
[Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
# MAC address must be a following this regex pattern
[ValidatePattern('^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$')]
[string[]]
$MacAddress
)

begin
{
# instantiate a UDP client
$UDPclient = [System.Net.Sockets.UdpClient]::new()
}
process
{
foreach ($_ in $MacAddress)
{
try {
$currentMacAddress = $_

# get byte array from MAC address
$mac = $currentMacAddress -split '[:-]' |
# convert the hex number into byte
ForEach-Object {
[System.Convert]::ToByte($_, 16)
}

#region compose the "magic packet"

# create a byte array with 102 bytes initialized to 255 each
$packet = [byte[]](,0xFF * 102)

# leave the first 6 bytes untouched, and
# repeat the target MAC address bytes in bytes 7 through 102
6..101 | ForEach-Object {
# $_ is indexing in the byte array,
# $_ % 6 produces repeating indices between 0 and 5
# (modulo operator)
$packet[$_] = $mac[($_ % 6)]
}

#endregion

# connect to port 4000 on broadcast address
$UDPclient.Connect(([System.Net.IPAddress]::Broadcast),4000)

# send the magic packet to the broadcast address
$null = $UDPclient.Send($packet, $packet.Length)
Write-Verbose "Sent magic packet to $currentMacAddress..."
}
catch
{
Write-Warning "Unable to send ${mac}: $_"
}
}
}
end
{
# release the UDP client and free its memory
$UDPclient.Close()
$UDPclient.Dispose()
}
}

运行该函数后,可以通过以下方法唤醒计算机:

1
Invoke-WakeOnLan -MacAddress '24:EE:9A:54:1B:E5', '98:E7:43:B5:B2:2F' -Verbose

要找出目标机器的MAC地址,请在目标机器上运行此行代码或通过远程处理:

1
Get-CimInstance -Query 'Select * From Win32_NetworkAdapter Where NetConnectionStatus=2' | Select-Object -Property Name, Manufacturer, MacAddress

可以在这里找到更多信息:https://powershell.one/code/11.html

PowerShell 技能连载 - 转换十六进制数据

当您添加 “0x” 前缀时,PowerShell 可以交互地转换十六进制数字:

1
2
PS> 0xAB0f
43791

如果十六进制数存储在字符串中,则可以通过将类型应用于表达式来调用转换:

1
2
3
4
PS> $a = 'ab0f'

PS> [int]"0x$a"
43791

PowerShell 技能连载 - 自学习参数完成

对于用户而言,参数完成非常棒,因为始终建议使用有效的参数。许多内置的 PowerShell 命令带有参数完成功能。当您输入以下内容时,您可以看到该效果:

1
PS> Get-EventLog -LogName

-LogName 之后输入一个空格,以在 PowerShell ISE 编辑器中触发自动参数完成。在 PowerShell 控制台中,按 TAB 键。而在 Visual Studio Code 中,按 CTRL + SPACE。Get-EventLog 会自动建议计算机上实际存在的日志的日志名称。

您可以将相同的参数完成功能添加到自己的函数参数中。在前面的技巧中,我们解释了如何添加静态建议。现在让我们来看看如何添加自学习参数完成功能!

假设您使用 -Co​​mputerName 参数编写 PowerShell 函数。为了使您的函数更易于使用,请添加参数完成,以便自动向用户建议计算机名称和 IP 地址。

显然,您无法知道对用户很重要的计算机名称和IP地址,因此您无法添加静态列表。而是使用两个自定义属性:

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# define [AutoLearn()]
class AutoLearnAttribute : System.Management.Automation.ArgumentTransformationAttribute
{
# define path to store hint lists
[string]$Path = "$env:temp\hints"

# define ID to manage multiple hint lists
[string]$Id = 'default'

# define prefix character used to delete the hint list
[char]$ClearKey = '!'

# define parameterless constructor
AutoLearnAttribute() : base()
{}

# define constructor with parameter for ID
AutoLearnAttribute([string]$Id) : base()
{
$this.Id = $Id
}

# Transform() is called whenever there is a variable or parameter assignment,
# and returns the value that is actually assigned
[object] Transform([System.Management.Automation.EngineIntrinsics]$engineIntrinsics, [object] $inputData)
{
# make sure the folder with hints exists
$exists = Test-Path -Path $this.Path
if (!$exists) { $null = New-Item -Path $this.Path -ItemType Directory }

# create a filename for hint list
$filename = '{0}.hint' -f $this.Id
$hintPath = Join-Path -Path $this.Path -ChildPath $filename

# use a hash table to keep hint list
$hints = @{}

# read hint list if it exists
$exists = Test-Path -Path $hintPath
if ($exists)
{
Get-Content -Path $hintPath -Encoding Default |
# remove leading and trailing blanks
ForEach-Object { $_.Trim() } |
# remove empty lines
Where-Object { ![string]::IsNullOrEmpty($_) } |
# add to hash table
ForEach-Object {
# value is not used, set it to $true
$hints[$_] = $true
}
}

# does the user input start with the clearing key?
if ($inputData.StartsWith($this.ClearKey))
{
# remove the prefix
$inputData = $inputData.SubString(1)

# clear the hint list
$hints.Clear()
}

# add new value to hint list
if(![string]::IsNullOrWhiteSpace($inputData))
{
$hints[$inputData] = $true
}
# save hints list
$hints.Keys | Sort-Object | Set-Content -Path $hintPath -Encoding Default

# return the user input (if there was a clearing key at its start,
# it is now stripped)
return $inputData
}
}

# define [AutoComplete()]
class AutoCompleteAttribute : System.Management.Automation.ArgumentCompleterAttribute
{
# define path to store hint lists
[string]$Path = "$env:temp\hints"

# define ID to manage multiple hint lists
[string]$Id = 'default'

# define parameterless constructor
AutoCompleteAttribute() : base([AutoCompleteAttribute]::_createScriptBlock($this))
{}

# define constructor with parameter for ID
AutoCompleteAttribute([string]$Id) : base([AutoCompleteAttribute]::_createScriptBlock($this))
{
$this.Id = $Id
}

# create a static helper method that creates the script block that the base constructor needs
# this is necessary to be able to access the argument(s) submitted to the constructor
# the method needs a reference to the object instance to (later) access its optional parameters
hidden static [ScriptBlock] _createScriptBlock([AutoCompleteAttribute] $instance)
{
$scriptblock = {
# receive information about current state
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)

# create filename for hint list
$filename = '{0}.hint' -f $instance.Id
$hintPath = Join-Path -Path $instance.Path -ChildPath $filename

# use a hash table to keep hint list
$hints = @{}

# read hint list if it exists
$exists = Test-Path -Path $hintPath
if ($exists)
{
Get-Content -Path $hintPath -Encoding Default |
# remove leading and trailing blanks
ForEach-Object { $_.Trim() } |
# remove empty lines
Where-Object { ![string]::IsNullOrEmpty($_) } |
# filter completion items based on existing text
Where-Object { $_.LogName -like "$wordToComplete*" } |
# create argument completion results
Foreach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
}.GetNewClosure()
return $scriptblock
}
}

这就是您想要为自己的 PowerShell 函数添加尽可能多的自学习自动完成功能所需要的全部。

这是一个利用这两个属性的新的 PowerShell 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Connect-MyServer
{
param
(
[string]
[Parameter(Mandatory)]
# auto-learn user names to user.hint
[AutoLearn('user')]
# auto-complete user names from user.hint
[AutoComplete('user')]
$UserName,

[string]
[Parameter(Mandatory)]
# auto-learn computer names to server.hint
[AutoLearn('server')]
# auto-complete computer names from server.hint
[AutoComplete('server')]
$ComputerName
)

"Hello $Username, connecting you to $ComputerName"
}

运行代码后,会产生一个新的 Connect-MyServer 命令。-UserName-ComputerName 参数均提供自学习自动补全功能:每当您为这些参数之一分配值时,该参数都会“记住”该参数,并在下次向您建议记住的值。

首次调用 Connect-MyServer 时,没有参数完成。再次调用它时,系统会建议您以前的输入,并且随着时间的推移,您的函数会“学习”对用户重要的参数。

这两个参数使用独立的建议。只需确保在两个属性中都为建议列表提供名称即可。在上面的示例中,-UserName 参数使用 “user” 建议列表,而 -ComputerName 参数使用 “server” 建议列表。

如果要清除有关参数的建议,请在参数前添加一个感叹号。该调用将清除 -ComputerName 参数的建议:

1
2
PS> Connect-MyServer -UserName tobias -ComputerName !server12
Hello tobias, connecting you to server12

重要说明:由于 PowerShell 中存在一个长期存在的错误,参数定义完成在定义实际功能的编辑器脚本窗格中不起作用。它始终可以在交互式控制台(这是最重要的用例)和任何其他脚本窗格中使用。

有关此处使用的技术的更多详细信息,请访问 https://powershell.one/powershell-internals/attributes/custom-attributes

PowerShell 技能连载 - 添加参数自动完成(第 2 部分)

在上一个技能中,我们讨论了已添加到 PowerShell 7 新的 [ArgumentCompletions()] 属性,以及如何使用它向函数参数添加复杂的参数完成功能。

不幸的是,该属性在 Windows PowerShell 中不可用,因此使用此属性,您的代码将不再与 Windows PowerShell 兼容。

当然,您还可以将属性添加到 Windows PowerShell。当您在Windows PowerShell中运行以下代码时, [ArgumentCompletions()] 属性将变为可用。PowerShell 7 代码仍然保持兼容,现在您也可以在Windows PowerShell中开始使用此属性:

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
# are we running in Windows PowerShell?
if ($PSVersionTable.PSEdition -ne 'Core')
{
# add the attribute [ArgumentCompletions()]
$code = @'
using System;
using System.Collections.Generic;
using System.Management.Automation;

public class ArgumentCompletionsAttribute : ArgumentCompleterAttribute
{

private static ScriptBlock _createScriptBlock(params string[] completions)
{
string text = "\"" + string.Join("\",\"", completions) + "\"";
string code = "param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams);@(" + text + ") -like \"*$WordToComplete*\" | Foreach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }";
return ScriptBlock.Create(code);
}

public ArgumentCompletionsAttribute(params string[] completions) : base(_createScriptBlock(completions))
{
}
}
'@

$null = Add-Type -TypeDefinition $code *>&1
}

如您所见,代码仅在 Windows PowerShell 中运行时才添加新属性。在PowerShell 7中,该属性已内置。

现在,无论您打算在 Windows PowerShell 还是Windows 7 中使用它,都可以在函数中使用复杂的参数完成。只需将上面的代码添加到代码中,以确保存在该属性。

这是使用属性并提供参数完成的函数的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Get-Country
{
param
(
# suggest country names:
[ArgumentCompletions('USA','Germany','Norway','Sweden','Austria','YouNameIt')]
[string]
$Name
)

# return parameter
$PSBoundParameters
}

当您在 PowerShell ISE(它是纯粹的 Windows PowerShell)中运行代码,然后在交互式控制台中使用 Get-Country 时,PowerShell ISE 会自动为 -Name 参数建议参数值(国家/地区名称)。

这里还有两件事要考虑:

  • 由于 PowerShell 中存在长期的错误,这种类型的参数完成功能在定义实际功能的编辑器脚本窗格中不起作用。它始终可以在交互式控制台(这是最重要的用例)和任何其他脚本窗格中使用。
  • [ValidateSet()] 属性相反,新的 [ArgumentCompletions()] 属性并不将用户输入限制为列出的值。新属性仅提供您定义的建议,而不以任何方式限制用户输入。

有关此处使用的技术的更多详细信息,请访问 https://powershell.one/powershell-internals/attributes/auto-completion

PowerShell 技能连载 - 添加参数自动完成(第 1 部分)

在 PowerShell 函数参数中添加参数完成功能可以极大地提高函数的可用性。一种常见的方法是将 [ValidateSet()] 属性添加到您的参数中:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Get-Country
{
param
(
# suggest country names
[ValidateSet('USA','Germany','Norway','Sweden','Austria','YouNameIt')]
[string]
$Name
)

# return parameter
$PSBoundParameters
}

现在,当用户使用 Get-Country 命令并传入 -Name 参数时,该函数现在会在用户按下 TAB 时建议国家/地区名称。像 PowerShell ISE 或 Visual Studio Code 这样的复杂PowerShell 编辑器甚至会自动打开 IntelliSense 菜单,或者在您按 CTRL + SPACE 显示所有的值。

但是,[ValidateSet()] 属性将用户限制为列出的值。无法输入其他值。如果只想为 -ComputerName 参数建议最常用的服务器名称,则将用户限制为仅使用这些服务器名称。这不是一个好主意。

从 PowerShell 7 开始,有一个名为 [ArgumentCompletions()] 的新属性,该属性几乎与 [ValidateSet()] 相似,但它跳过了验证部分。它提供相同的参数补全,但不限制用户输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Get-Country
{
param
(
# suggest country names
[ArgumentCompletions('USA','Germany','Norway','Sweden','Austria','YouNameIt')]
[string]
$Name
)

# return parameter
$PSBoundParameters
}

此版本的 Get-Country 提供国家名称建议,但是如果您愿意,您仍然可以输入其他任何国家名称。

重要提示:由于 PowerShell 中的错误,参数自动完成对于定义具体功能的脚本窗格不起作用。而在 PowerShell 控制台和任何其他编辑器脚本窗格中,参数自动完成可以正常工作。

Windows PowerShell 中缺少新的 [ArgumentCompletions()] 属性,因此在使用它时,您的函数不再与 Windows PowerShell 兼容。我们将在即将到来的提示中解决此问题。

PowerShell 技能连载 - 解析 Windows 产品密钥(第 2 部分)

在上一个技能中,我们解释了如何向 WMI 请求 Windows 的部分产品密钥。如果您丢失了原始产品密钥,可以通过以下方法恢复完整密钥:

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
89
90
91
92
93
94
function Get-WindowsProductKey{
\# test whether this is Windows 7 or older function Test-Win7 {
$OSVersion = [System.Environment]::OSVersion.Version ($OSVersion.Major -eq 6 -and $OSVersion.Minor -lt 2) -or $OSVersion.Major -le 6 }

\# implement decoder $code = @'// original implementation: https://github.com/mrpeardotnet/WinProdKeyFinder
using System;
using System.Collections;

public static class Decoder
{
public static string DecodeProductKeyWin7(byte[] digitalProductId)
{
const int keyStartIndex = 52;
const int keyEndIndex = keyStartIndex + 15;
var digits = new[]
{
'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R',
'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9',
};
const int decodeLength = 29;
const int decodeStringLength = 15;
var decodedChars = new char[decodeLength];
var hexPid = new ArrayList();
for (var i = keyStartIndex; i <= keyEndIndex; i++)
{
hexPid.Add(digitalProductId[i]);
}
for (var i = decodeLength - 1; i >= 0; i--)
{
// Every sixth char is a separator.
if ((i + 1) % 6 == 0)
{
decodedChars[i] = '-';
}
else
{
// Do the actual decoding.
var digitMapIndex = 0;
for (var j = decodeStringLength - 1; j >= 0; j--)
{
var byteValue = (digitMapIndex << 8) | (byte)hexPid[j];
hexPid[j] = (byte)(byteValue / 24);
digitMapIndex = byteValue % 24;
decodedChars[i] = digits[digitMapIndex];
}
}
}
return new string(decodedChars);
}

public static string DecodeProductKey(byte[] digitalProductId)
{
var key = String.Empty;
const int keyOffset = 52;
var isWin8 = (byte)((digitalProductId[66] / 6) & 1);
digitalProductId[66] = (byte)((digitalProductId[66] & 0xf7) | (isWin8 & 2) * 4);

const string digits = "BCDFGHJKMPQRTVWXY2346789";
var last = 0;
for (var i = 24; i >= 0; i--)
{
var current = 0;
for (var j = 14; j >= 0; j--)
{
current = current*256;
current = digitalProductId[j + keyOffset] + current;
digitalProductId[j + keyOffset] = (byte)(current/24);
current = current%24;
last = current;
}
key = digits[current] + key;
}

var keypart1 = key.Substring(1, last);
var keypart2 = key.Substring(last + 1, key.Length - (last + 1));
key = keypart1 + "N" + keypart2;

for (var i = 5; i < key.Length; i += 6)
{
key = key.Insert(i, "-");
}

return key;
}
}'@ \# compile C# Add-Type -TypeDefinition $code
\# get raw product key $digitalId = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name DigitalProductId).DigitalProductId
$isWin7 = Test-Win7 if ($isWin7)
{
\# use static C# method [Decoder]::DecodeProductKeyWin7($digitalId)
}
else {
\# use static C# method: [Decoder]::DecodeProductKey($digitalId)
}
}

PowerShell 技能连载 - 解析 Windows 产品密钥(第 1 部分)

有很多脚本示例,甚至还有密钥恢复工具,它们都承诺会返回完整的产品密钥,但是在许多情况下,返回的密钥不是 Windows 产品密钥。

当您使用密钥恢复工具时,通常会丢失产品密钥,因此没有简单的方法来检查密钥恢复脚本或工具返回的承诺密钥是否正确。

幸运的是,WMI 至少可以返回“部分”产品密钥。这样,您可以验证恢复的密钥是否是有效的。

SoftwareLicensingProduct WMI 类返回有关大多数 Microsoft 产品的许可状态的详细信息。下面的此行获取所有以 “Windows” 开头且许可证状态为非 0 的 Microsoft 产品的所有许可信息:

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
PS> Get-CimInstance -ClassName SoftwareLicensingProduct -Filter 'Name LIKE "Windows%" AND LicenseStatus>0'


ADActivationCsvlkPid :
ADActivationCsvlkSkuId :
ADActivationObjectDN :
ADActivationObjectName :
ApplicationID : 55c92734-d682-4d71-983e-d6ec3f16059f
AutomaticVMActivationHostDigitalPid2 :
AutomaticVMActivationHostMachineName :
AutomaticVMActivationLastActivationTime : 01.01.1601 01:00:00
Description : Windows(R) Operating System, OEM_DM channel
DiscoveredKeyManagementServiceMachineIpAddress :
DiscoveredKeyManagementServiceMachineName :
DiscoveredKeyManagementServiceMachinePort : 0
EvaluationEndDate : 01.01.1601 01:00:00
ExtendedGrace : 4294967295
GenuineStatus : 0
GracePeriodRemaining : 0
IAID :
ID : bd3762d7-270d-4760-8fb3-d829ca45278a
IsKeyManagementServiceMachine : 0
KeyManagementServiceCurrentCount : 4294967295
KeyManagementServiceFailedRequests : 4294967295
KeyManagementServiceLicensedRequests : 4294967295
KeyManagementServiceLookupDomain :
KeyManagementServiceMachine :
KeyManagementServiceNonGenuineGraceRequests : 4294967295
KeyManagementServiceNotificationRequests : 4294967295
KeyManagementServiceOOBGraceRequests : 4294967295
KeyManagementServiceOOTGraceRequests : 4294967295
KeyManagementServicePort : 0
KeyManagementServiceProductKeyID :
KeyManagementServiceTotalRequests : 4294967295
KeyManagementServiceUnlicensedRequests : 4294967295
LicenseDependsOn :
LicenseFamily : Professional
LicenseIsAddon : False
LicenseStatus : 1
LicenseStatusReason : 1074066433
MachineURL :
Name : Windows(R), Professional edition
OfflineInstallationId : 563276155667058052465840741114524545879016766601431504369777043
PartialProductKey : WFG6P
...

不幸的是,此调用需要很长时间才能完成。为了加快速度,请告诉 WMI 您要做什么,以便该调用不会计算您不需要的大量信息。下面的调用仅从所需实例中读取 PartialProductKey 属性,并且速度更快:

1
2
3
PS> Get-CimInstance -Query 'Select PartialProductKey From SoftwareLicensingProduct Where Name LIKE "Windows%" AND LicenseStatus>0' | Select-Object -ExpandProperty PartialProductKey

WFG6P

PowerShell 技能连载 - 读取操作系统详情

通过读取适当的注册表值,PowerShell 可以轻松检索重要的操作系统详细信息,例如内部版本号和版本:

1
2
3
4
# read operating system info
Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion' |
# pick selected properties
Select-Object -Property CurrentBuild,CurrentVersion,ProductId, ReleaseID, UBR

不过,其中一些值使用加密格式。例如,InstallTime 注册表项只是一个非常大的整数。

1
2
3
4
PS> $key = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
PS> (Get-ItemProperty -Path $key).InstallTime

132119809618946052

事实证明,这些是时间 tick 值,通过使用 [DateTime]类型及其 FromFileTime() 静态方法,您可以轻松地将时间 tick 值转换为有意义的安装日期:

1
2
3
4
5
6
PS> $key = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
PS> $ticks = (Get-ItemProperty -Path $key).InstallTime
PS> $date = [DateTime]::FromFileTime($ticks)
PS> "Your OS Install Date: $date"

Your OS Install Date: 09/03/2019 12:42:41

您可以在遇到时间 tick 值时使用 FromFileTime()。例如,Active Directory 也以这种格式存储日期。

PowerShell 技能连载 - 在控制台中提示输入凭据

当您运行 Get-Credential 或提示您输入用户名和密码时,Windows PowerShell (powershell.exe) 始终会打开一个单独的凭据对话框。而新的 PowerShell 7 (pwsh.exe) 则在控制台内提示:

1
2
3
4
5
6
7
8
9
10
11
PS> Get-Credential

PowerShell credential request
Enter your credentials.
User: Tobias
Password for user Tobias: ******


UserName Password
-------- --------
Tobias System.Security.SecureString

如果您更喜欢控制台提示而不是打开单独的对话框,则可以切换 Windows PowerShell 的默认行为。您需要管理员特权才能更改注册表设置:

1
2
$key = "HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds"
Set-ItemProperty -Path $key -Name ConsolePrompting -Value $true

若要恢复默认行为,请将值更改为 $false,或通过 Remove-ItemProperty 删除注册表值。

PowerShell 技能连载 - 在 PowerShell Gallery 搜索新模块

官方的 PowerShell Gallery 是一个公共仓库,其中包含数千个免费的 PowerShell 模块。无需重新设计轮子,而是完全可以浏览 gallery 以查找可重用的代码,这些代码可按原样使用或用作自己项目的起点。让我们看一下如何从 PowerShell 库中发现和下载 PowerShell 代码。

您可以在 https://powershellgallery.com 上使用其图形前端来搜索代码,但是 Find-Module cmdlet 是一种更好,更强大的方法。如果您正在寻找通过 PowerShell 管理 Office 365 的方法,可以通过下面这行代码获取包含 “Office” 关键字的所有模块:

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
Name                                                  CompanyName                               PublishedDate       Description
---- ----------- ------------- -----------
OfficeOnlineServerDsc {PowerShellTeam, gaelcolas, dsccommunity} 03.04.2020 22:01:30 The OfficeOnlineSe...
Office365DnsChecker rhymeswithmogul 30.03.2020 14:15:00 Checks a domain's ...
Microsoft.Graph.DevicesApps.OfficeConfiguration msgraph-sdk-powershell 17.03.2020 01:24:39 Microsoft Graph Po...
IntraOffice.ContentRepository.Powershell rderegt 06.03.2020 14:26:35 Client library for...
Office365DSC NikCharleboisPFE 04.03.2020 23:13:30 This DSC module is...
Office365PowershellUtils joshn-whatcomtrans.net 03.03.2020 00:26:59 A collection of cm...
Office365Cmdlets CData 20.02.2020 20:13:29 CData Cmdlets for ...
MSPOffice365Tools majorwitteman 13.02.2020 20:26:15 Collection of Offi...
AdminToolbox.Office365 {TaylorLee, Taylor_Lee} 27.01.2020 15:26:36 Functions for work...
OfficeAddinManager DarrenDK 17.12.2019 07:10:08 Module for managin...
PSP-Office365 powershellpr0mpt 20.11.2019 10:57:08 Helper module to g...
Office365MailAliases Cloudenius 17.11.2019 11:57:07 This module contai...
Office365Toolkit PatrickJD84 03.09.2019 03:01:36 A collection of sc...
Office365.Connect nicomartens 22.08.2019 07:58:43 Uses the Windows C...
Office365TokenGet junecastillote 17.07.2019 03:21:07 Helps you acquire ...
BitTitan.Runbooks.Office365SecurityAndCompliance.Beta BT_AutomationEngineers 14.05.2019 08:41:04 PowerShell module ...
BitTitan.Runbooks.Office365SecurityAndCompliance BT_AutomationEngineers 12.03.2019 07:22:10 PowerShell module ...
Office365Module Giertz 24.01.2019 22:56:08 test for ez
ZIM.Office365 Mikezim 14.12.2018 11:53:54 Provides a set of ...
MZN.Office365 michael.zimmerman 14.12.2018 08:10:26 Provides a set of ...
JumpCloud.Office365.SSO Scottd3v 14.06.2018 16:13:13 Functions to enabl...
Office365GraphAPI chenxizhang 12.06.2017 15:14:57 Office 365 Graph A...
Office365Connect Gonjer 18.05.2017 21:13:41 Office365Connect i...
RackspaceCloudOffice {mlk, paul.trampert.rackspace} 28.09.2016 14:34:25 REST client for th...
Office365 StevenAyers 16.07.2016 10:53:36 For Microsoft Part...
OfficeProvider abaker 01.03.2016 21:00:35 OfficeProvider all...

该列表包括发布者和模块描述,并按从新到旧的顺序对模块进行排序。PublishedDate 列指示模块是否是最近刚添加到 gallery中,这样您可以立即查看它是否维护良好并且值得一看。

如果您发现某个特定模块有趣,请获取其所有元数据:

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
PS> Find-Module -Name Office365PowershellUtils -Repository PSGallery | Select-Object -Property *


Name : Office365PowershellUtils
Version : 1.1.5
Type : Module
Description : A collection of cmdlets for managing Office365
Author : R. Josh Nylander
CompanyName : joshn-whatcomtrans.net
Copyright : (c) 2012 WTA. All rights reserved.
PublishedDate : 03.03.2020 00:26:59
InstalledDate :
UpdatedDate :
LicenseUri :
ProjectUri :
IconUri :
Tags : {PSModule}
Includes : {Function, RoleCapability, Command, DscResource...}
PowerShellGetFormatVersion :
ReleaseNotes :
Dependencies : {}
RepositorySourceLocation : https://www.powershellgallery.com/api/v2
Repository : PSGallery
PackageManagementProvider : NuGet
AdditionalMetadata : @{summary=A collection of cmdlets for managing Office365; versionDownloadCount=33; ItemType=Module;
copyright=(c) 2012 WTA. All rights reserved.; PackageManagementProvider=NuGet; CompanyName=Whatcom
Transportation Authority; SourceName=PSGallery; tags=PSModule; created=03.03.2020 00:26:59 +01:00;
description=A collection of cmdlets for managing Office365; published=03.03.2020 00:26:59 +01:00;
developmentDependency=False; NormalizedVersion=1.1.5; downloadCount=296;
GUID=c6b26555-2b5f-45bc-affe-ef1c31580df3; lastUpdated=02.04.2020 16:50:22 +02:00; Authors=R. Josh
Nylander; updated=2020-04-02T16:50:22Z; Functions=Find-MsolUsersWithLicense
Update-MsolLicensedUsersFromGroup Update-MsolUserUsageLocation Change-ProxyAddress Add-ProxyAddress
Remove-ProxyAddress Set-ProxyAddress Sync-ProxyAddress Test-ProxyAddress Get-ProxyAddressDefault
Enable-SecurityGroupAsDistributionGroup Disable-SecurityGroupAsDistributionGroup Start-DirSync
Get-NextDirSync Suspend-UserMailbox Resume-UserMailbox Test-Mailbox Get-MailboxMemberOf
Clear-MailboxMemberOf Use-Office365 Export-PSCredential Import-PSCredential; isLatestVersion=True;
PowerShellVersion=3.0; IsPrerelease=false; isAbsoluteLatestVersion=True; packageSize=16635; FileList=Office3
65PowershellUtils.nuspec|Function_Connect-Office365.ps1|Office365PowershellUtils.psd1|Office365PowerShellUti
ls_mod.psm1|PSCredentials.psm1|README|SampleMigrationScripts\Monitor-MoveStats.ps1|SampleMigrationScripts\Re
sume-FirstFiveSuspended.ps1|SampleMigrationScripts\Set-MailboxTimeZone.ps1|SampleMigrationScripts\Set-Remote
RoutingAddress.ps1|SampleMigrationScripts\Set-RetentionPolicy.ps1|SampleMigrationScripts\Set-RoleAssignmentP
olicy.ps1; requireLicenseAcceptance=False}

如果您只对源代码感兴趣,请使用 Save-Module 并将模块下载到您选择的文件夹中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# path to source code
$path = "c:\sources"

# name of module to investigate
$moduleName = "Office365PowershellUtils"

# create folder
$null = New-Item -Path $path -ItemType Directory

# download module
Save-Module -Name $moduleName -Path $path -Repository PSGallery

# open folder with sources
explorer (Join-Path -Path $path -ChildPath $moduleName)

如果您想按原样实际使用该模块,请改用 Install-Module

1
PS> Install-Module -Name Office365PowershellUtils -Scope CurrentUser -Repository PSGallery