WMI 和 Get-CimInstance 可以为您提供许多有用的信息,但是返回的对象通常包含许多空属性:
1 | PS> Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -Property * |
另外,属性不一定要排序。您可以通过识别和排序不为空的属性来进行修复:
1 | # get all WMI information |
WMI 和 Get-CimInstance 可以为您提供许多有用的信息,但是返回的对象通常包含许多空属性:
1 | PS> Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -Property * |
另外,属性不一定要排序。您可以通过识别和排序不为空的属性来进行修复:
1 | # get all WMI information |
通常,您的代码需要声明某些先决条件。例如,您可能要确保给定的文件夹存在,并使用如下代码:
1 | # path to download files to |
您可以开始使用断言函数库,而不必一遍又一遍地写代码。这是确保文件夹存在的一种:
1 | filter Assert-FolderExists |
使用此函数,您的代码将变得更加整洁。这些代码将文件夹路径分配给变量,并同时确保文件夹存在:
1 | # making sure a bunch of folders exist |
在此处阅读有关此技术的更多信息:https://powershell.one/code/10.html。
无需外部“局域网唤醒”工具了。如果要唤醒网络计算机,只需告诉 PowerShell 目标计算机的 MAC 地址即可。这是一个组成 magic packet 并唤醒机器的函数:
1 | function Invoke-WakeOnLan |
运行该函数后,可以通过以下方法唤醒计算机:
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。
当您添加 “0x” 前缀时,PowerShell 可以交互地转换十六进制数字:
1 | PS> 0xAB0f |
如果十六进制数存储在字符串中,则可以通过将类型应用于表达式来调用转换:
1 | PS> $a = 'ab0f' |
对于用户而言,参数完成非常棒,因为始终建议使用有效的参数。许多内置的 PowerShell 命令带有参数完成功能。当您输入以下内容时,您可以看到该效果:
1 | PS> Get-EventLog -LogName |
在 -LogName 之后输入一个空格,以在 PowerShell ISE 编辑器中触发自动参数完成。在 PowerShell 控制台中,按 TAB 键。而在 Visual Studio Code 中,按 CTRL + SPACE。Get-EventLog 会自动建议计算机上实际存在的日志的日志名称。
您可以将相同的参数完成功能添加到自己的函数参数中。在前面的技巧中,我们解释了如何添加静态建议。现在让我们来看看如何添加自学习参数完成功能!
假设您使用 -ComputerName 参数编写 PowerShell 函数。为了使您的函数更易于使用,请添加参数完成,以便自动向用户建议计算机名称和 IP 地址。
显然,您无法知道对用户很重要的计算机名称和IP地址,因此您无法添加静态列表。而是使用两个自定义属性:
1 | # define [AutoLearn()] |
这就是您想要为自己的 PowerShell 函数添加尽可能多的自学习自动完成功能所需要的全部。
这是一个利用这两个属性的新的 PowerShell 函数:
1 | function Connect-MyServer |
运行代码后,会产生一个新的 Connect-MyServer 命令。-UserName 和 -ComputerName 参数均提供自学习自动补全功能:每当您为这些参数之一分配值时,该参数都会“记住”该参数,并在下次向您建议记住的值。
首次调用 Connect-MyServer 时,没有参数完成。再次调用它时,系统会建议您以前的输入,并且随着时间的推移,您的函数会“学习”对用户重要的参数。
这两个参数使用独立的建议。只需确保在两个属性中都为建议列表提供名称即可。在上面的示例中,-UserName 参数使用 “user” 建议列表,而 -ComputerName 参数使用 “server” 建议列表。
如果要清除有关参数的建议,请在参数前添加一个感叹号。该调用将清除 -ComputerName 参数的建议:
1 | PS> Connect-MyServer -UserName tobias -ComputerName !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 | # are we running in Windows PowerShell? |
如您所见,代码仅在 Windows PowerShell 中运行时才添加新属性。在PowerShell 7中,该属性已内置。
现在,无论您打算在 Windows PowerShell 还是Windows 7 中使用它,都可以在函数中使用复杂的参数完成。只需将上面的代码添加到代码中,以确保存在该属性。
这是使用属性并提供参数完成的函数的示例:
1 | function Get-Country |
当您在 PowerShell ISE(它是纯粹的 Windows PowerShell)中运行代码,然后在交互式控制台中使用 Get-Country 时,PowerShell ISE 会自动为 -Name 参数建议参数值(国家/地区名称)。
这里还有两件事要考虑:
[ValidateSet()] 属性相反,新的 [ArgumentCompletions()] 属性并不将用户输入限制为列出的值。新属性仅提供您定义的建议,而不以任何方式限制用户输入。有关此处使用的技术的更多详细信息,请访问 https://powershell.one/powershell-internals/attributes/auto-completion。
PowerShell 技能连载 - 添加参数自动完成(第 1 部分)
在 PowerShell 函数参数中添加参数完成功能可以极大地提高函数的可用性。一种常见的方法是将 [ValidateSet()] 属性添加到您的参数中:
1 | function Get-Country |
现在,当用户使用 Get-Country 命令并传入 -Name 参数时,该函数现在会在用户按下 TAB 时建议国家/地区名称。像 PowerShell ISE 或 Visual Studio Code 这样的复杂PowerShell 编辑器甚至会自动打开 IntelliSense 菜单,或者在您按 CTRL + SPACE 显示所有的值。
但是,[ValidateSet()] 属性将用户限制为列出的值。无法输入其他值。如果只想为 -ComputerName 参数建议最常用的服务器名称,则将用户限制为仅使用这些服务器名称。这不是一个好主意。
从 PowerShell 7 开始,有一个名为 [ArgumentCompletions()] 的新属性,该属性几乎与 [ValidateSet()] 相似,但它跳过了验证部分。它提供相同的参数补全,但不限制用户输入:
1 | function Get-Country |
此版本的 Get-Country 提供国家名称建议,但是如果您愿意,您仍然可以输入其他任何国家名称。
重要提示:由于 PowerShell 中的错误,参数自动完成对于定义具体功能的脚本窗格不起作用。而在 PowerShell 控制台和任何其他编辑器脚本窗格中,参数自动完成可以正常工作。
Windows PowerShell 中缺少新的 [ArgumentCompletions()] 属性,因此在使用它时,您的函数不再与 Windows PowerShell 兼容。我们将在即将到来的提示中解决此问题。
PowerShell 技能连载 - 解析 Windows 产品密钥(第 2 部分)
在上一个技能中,我们解释了如何向 WMI 请求 Windows 的部分产品密钥。如果您丢失了原始产品密钥,可以通过以下方法恢复完整密钥:
1 | function Get-WindowsProductKey{ |
PowerShell 技能连载 - 解析 Windows 产品密钥(第 1 部分)
有很多脚本示例,甚至还有密钥恢复工具,它们都承诺会返回完整的产品密钥,但是在许多情况下,返回的密钥不是 Windows 产品密钥。
当您使用密钥恢复工具时,通常会丢失产品密钥,因此没有简单的方法来检查密钥恢复脚本或工具返回的承诺密钥是否正确。
幸运的是,WMI 至少可以返回“部分”产品密钥。这样,您可以验证恢复的密钥是否是有效的。
SoftwareLicensingProduct WMI 类返回有关大多数 Microsoft 产品的许可状态的详细信息。下面的此行获取所有以 “Windows” 开头且许可证状态为非 0 的 Microsoft 产品的所有许可信息:
1 | PS> Get-CimInstance -ClassName SoftwareLicensingProduct -Filter 'Name LIKE "Windows%" AND LicenseStatus>0' |
不幸的是,此调用需要很长时间才能完成。为了加快速度,请告诉 WMI 您要做什么,以便该调用不会计算您不需要的大量信息。下面的调用仅从所需实例中读取 PartialProductKey 属性,并且速度更快:
1 | PS> Get-CimInstance -Query 'Select PartialProductKey From SoftwareLicensingProduct Where Name LIKE "Windows%" AND LicenseStatus>0' | Select-Object -ExpandProperty PartialProductKey |
通过读取适当的注册表值,PowerShell 可以轻松检索重要的操作系统详细信息,例如内部版本号和版本:
1 | # read operating system info |
不过,其中一些值使用加密格式。例如,InstallTime 注册表项只是一个非常大的整数。
1 | PS> $key = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion' |
事实证明,这些是时间 tick 值,通过使用 [DateTime]类型及其 FromFileTime() 静态方法,您可以轻松地将时间 tick 值转换为有意义的安装日期:
1 | PS> $key = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion' |
您可以在遇到时间 tick 值时使用 FromFileTime()。例如,Active Directory 也以这种格式存储日期。