当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 构建更多 PowerShell 函数

作者:精品下载站 日期:2024-12-14 07:54:01 浏览:14 分类:玩电脑

构建更多 PowerShell 函数


在最近的一篇文章中,我讨论了开发 PowerShell 函数时可能经历的过程。最后,我不仅为我的 PowerShell 工具箱提供了一个新工具,而且还拥有了一个可以重复使用的功能大纲。如果您阅读了上一篇文章,那么您应该认识到“规模管理”的概念。在可能的情况下,我希望我的功能不只适用于某一件事或计算机适用于许多人。实现这一目标的一种方法是合并远程处理。我构建的进程内存工具利用 Invoke-Command 来运行一个简单的 PowerShell 表达式,使用 Get-Process 来检索我想要的信息。我可以重复使用该技术来完成各种任务。我们再做一个。

每当您构建 PowerShell 脚本或函数时,我都会强调您应该从可以从控制台运行的一个或一组命令开始。这将是脚本或函数的核心。您的许多脚本都围绕这个核心添加了便利性、错误处理和其他修饰。对于我的下一个函数,我想复制运行 winver.exe 命令时显示的信息。要亲自查看,请在提示符下或在“运行”框中运行 winver

显示的大部分信息可以通过使用 Get-CimInstance 查询 Win32_OperatingSystem 类来检索。我认为 Get-WmiObject 已被弃用,现在很少使用它。不过,我也知道可以在注册表中找到相同的信息。因此,为了改变节奏,我决定查询注册表以获取相同的信息,并最终得到此代码。

$RegPath = 'HKLM:\SOFTWARE\Microsoft\Windows nt\CurrentVersion\'

Get-ItemProperty -Path $RegPath | Select-Object -Property ProductName, EditionID, ReleaseID,
@{Name = "Build"; Expression = {"$($_.CurrentBuild).$($_.UBR)"}},
@{Name = "InstalledUTC"; Expression = { ([datetime]"1/1/1601").AddTicks($_.InstallTime) }},
@{Name = "Computername"; Expression = {$env:computername}}

我一直在考虑将对象写入管道,因此我定义了一些自定义属性,这些属性不仅复制我在 winver 中看到的内容,而且可能也很有用。

[玩转系统] 构建更多 PowerShell 函数

现在我有了可以运行的代码,我可以将此代码插入到我的函数的脚本块中。事实上,让我先退后一步。

我最终编写的 Get-ProcessMemory 函数成为了我可以重复使用的绝佳模型。所以我创建了该文件的模板版本。您可以从 GitHub 获取模板。

Get-Something.ps1:


Function Get-Something {
     Get-Something

.INPUTS
System.String
.OUTPUTS
Custom object
.NOTES
Learn more about PowerShell: http://jdhitsolutions.com/blog/essential-powershell-resources/
.LINK
Invoke-Command
#>

    [cmdletbinding()]
    [OutputType("custom object")]
    [alias('wver')]

    Param (
        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName,Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string[]]$Computername = $env:COMPUTERNAME,
        [PSCredential]$Credential,
        [switch]$UseSSL,
        [Int32]$ThrottleLimit,
        [ValidateSet('Default', 'Basic', 'Credssp', 'Digest', 'Kerberos', 'Negotiate', 'NegotiateWithImplicitCredential')]
        [ValidateNotNullorEmpty()]
        [string]$Authentication = "default"
    )

    Begin {

        Write-Verbose "Starting $($MyInvocation.Mycommand)"

        $sb = {

            #add your code
            #you can pass local variables with $using or define scriptblock parameters and pass arguments

        } #close scriptblock

        #update PSBoundParameters so it can be splatted to Invoke-Command
        $PSBoundParameters.Add("ScriptBlock", $sb) | Out-Null
        $PSBoundParameters.Add("HideComputername", $True) | Out-Null
    } #begin

    Process {
        if (-Not $PSBoundParameters.ContainsKey("Computername")) {
            #add the default value if nothing was specified
            $PSBoundParameters.Add("Computername", $Computername) | Out-Null
        }
        $PSBoundParameters | Out-String | Write-Verbose
        Invoke-Command @PSBoundParameters | Select-Object -Property * -ExcludeProperty RunspaceID, PS*
    } #process

    End {

        Write-Verbose "Ending $($MyInvocation.Mycommand)"

    } #end
} #close function

我什至为所有远程处理参数添加了基于评论的帮助。在开始块中,有一个部分用于定义我打算运行远程处理的脚本块。这就是我将粘贴与注册表相关的代码的地方。我不需要传递任何其他参数。如果我这样做了,我会添加它们并更新帮助。重要的步骤包括更新脚本块以通过使用 $using: 引用或将 ArgumentList 参数传递给 Invoke-Command 来合并这些值。我的模板将 PSBoundParameters 映射到 Invoke-Command,因此我(或您)需要相应地添加或删除参数。

完成后,我有了一个名为 Get-WindowsVersion 的新命令。

[玩转系统] 构建更多 PowerShell 函数

现在我有了一个可扩展的 PowerShell 工具!

尽管我总是强调“PowerShell 管道中的对象”的重要性,但我认识到有时我们确实需要一个字符串或一段文本。当运行 winver.exe 时,这基本上就是我所看到的。显然,图形工具无法缩放。但 PowerShell 可以。我已经在函数的输出中获得了用于创建字符串的所有信息。我最初的想法是向函数添加一个参数,例如 -AsString,如果使用该参数,则会将字符串而不是对象写入管道。那将是一种懒惰的方式,我意识到这是错误的方式。

PowerShell 函数应该只将一种类型的对象写入管道,而我可能会创建一个函数来执行两件事。答案自然是编写第二个函数 Get-WindowsVersionString。这实际上很容易编写,因为我需要做的就是为每台计算机调用 Get-WindowsVersion 函数并根据结果创建字符串。这成为进程脚本块。

Process {

    $results = Get-WindowsVersion @PSBoundParameters

    #write a version string for each computer
`   foreach ($result in $results) {
        "{0} Version {1} (OS Build {2})" -f $result.ProductName, $result.releaseID, $result.build
    }

} #process

该函数的参数与 Get-WindowsVersion 相同,因此我所要做的就是使用 splatting“传递”它们。您可以在函数的详细输出中看到流程。

[玩转系统] 构建更多 PowerShell 函数

最终结果是我有两个函数可以轻松获取我需要的不同格式的信息。这两个函数的代码也在 Github 上。

Get-WindowsVersion.ps1:


Function Get-WindowsVersion {
 Get-WindowsVersion

ProductName  : Windows 10 Pro
EditionID    : Professional
ReleaseId    : 1809
Build        : 17763.195
InstalledUTC : 12/17/2018 2:18:37 PM
Computername : BOVINE320

Query the local host.
.EXAMPLE
PS C:\scripts> get-windowsversion -Computername srv1,srv2,win10 -Credential company\artd | format-table


ProductName                             EditionID          ReleaseId Build      InstalledUTC          Computername
-----------                             ---------          --------- -----      ------------          ------------
Windows Server 2016 Standard Evaluation ServerStandardEval 1607      14393.2273 12/26/2018 4:07:25 PM SRV1
Windows Server 2016 Standard Evaluation ServerStandardEval 1607      14393.2273 12/26/2018 4:08:07 PM SRV2
Windows 10 Enterprise Evaluation        EnterpriseEval     1703      15063.1387 12/26/2018 4:08:11 PM WIN10


Get windows version information from remote computers using an alternate credential.

.Example
PS C:\> Get-WindowsVersion -Computername win10 -AsString
Windows 10 Enterprise Evaluation Version 1703 (OS Build 15063.1387)

Get a string
.INPUTS
System.String
.OUTPUTS
Custom object
.NOTES
Learn more about PowerShell: http://jdhitsolutions.com/blog/essential-powershell-resources/
.LINK
WinVer.exe
.LINK
Invoke-Command
#>

    [cmdletbinding()]
    [OutputType("custom object")]
    [alias('wver')]

    Param (
        [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string[]]$Computername = $env:COMPUTERNAME,
        [PSCredential]$Credential,
        [switch]$UseSSL,
        [Int32]$ThrottleLimit,
        [ValidateSet('Default', 'Basic', 'Credssp', 'Digest', 'Kerberos', 'Negotiate', 'NegotiateWithImplicitCredential')]
        [ValidateNotNullorEmpty()]
        [string]$Authentication = "default"
    )

    Begin {

        Write-Verbose "Starting $($MyInvocation.Mycommand)"

        $sb = {
            $RegPath = 'HKLM:\SOFTWARE\Microsoft\Windows nt\CurrentVersion\'

            Get-ItemProperty -Path $RegPath | Select-Object -Property ProductName, EditionID, ReleaseID,
            @{Name = "Build"; Expression = {"$($_.CurrentBuild).$($_.UBR)"}},
            @{Name = "InstalledUTC"; Expression = { ([datetime]"1/1/1601").AddTicks($_.InstallTime) }},
            @{Name = "Computername"; Expression = {$env:computername}}

        } #close scriptblock

        #update PSBoundParameters so it can be splatted to Invoke-Command
        $PSBoundParameters.Add("ScriptBlock", $sb) | Out-Null
        $PSBoundParameters.add("HideComputername", $True) | Out-Null
    } #begin

    Process {

        if (-Not $PSBoundParameters.ContainsKey("Computername")) {
            #add the default value if nothing was specified
            $PSBoundParameters.Add("Computername", $Computername) | Out-Null
        }
        $PSBoundParameters | Out-String | Write-Verbose
        $results = Invoke-Command @PSBoundParameters | Select-Object -Property * -ExcludeProperty RunspaceID, PS*
        if ($AsString) {
            #write a version string for each computer
`           foreach ($result in $results) {
                "{0} Version {1} (OS Build {2})" -f $result.ProductName, $result.releaseID, $result.build
            }
        }
        else {
            $results
        }

    } #process

    End {

        Write-Verbose "Ending $($MyInvocation.Mycommand)"

    } #end
} #close function


Function Get-WindowsVersionString {
 Get-WindowsVersionString -Computername win10 -credential company\artd
Windows 10 Enterprise Evaluation Version 1703 (OS Build 15063.1387)

Get a string version of Windows version information from a remote computer and use an alternate credential.
.EXAMPLE
PS C:\> Get-WindowsVersionString
Windows 10 Pro Version 1809 (OS Build 17763.195)

Get version information for the current computer.
.EXAMPLE
PS C:\> import-csv .\company.csv | Select Computername,@{Name="Version";Expression={ get-windowsversionstring $_.computername}}

Computername Version
------------ -------
Dom1         Windows Server 2016 Standard Evaluation Version 1607 (OS Build 14393.2273)
Srv1         Windows Server 2016 Standard Evaluation Version 1607 (OS Build 14393.2273)
Srv2         Windows Server 2016 Standard Evaluation Version 1607 (OS Build 14393.2273)
Win10        Windows 10 Enterprise Evaluation Version 1703 (OS Build 15063.1387)

Import data from a CSV file and display version information.

.INPUTS
System.String
.OUTPUTS
System.String
.NOTES
Learn more about PowerShell: http://jdhitsolutions.com/blog/essential-powershell-resources/
.LINK
Get-WindowsVersion
.LINK
Winver.exe
#>
    [cmdletbinding()]
    [OutputType("system.string")]

    Param (
        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string[]]$Computername = $env:COMPUTERNAME,
        [PSCredential]$Credential,
        [switch]$UseSSL,
        [Int32]$ThrottleLimit,
        [ValidateSet('Default', 'Basic', 'Credssp', 'Digest', 'Kerberos', 'Negotiate', 'NegotiateWithImplicitCredential')]
        [ValidateNotNullorEmpty()]
        [string]$Authentication = "default"
    )

    Begin {

        Write-Verbose "Starting $($MyInvocation.Mycommand)"

    } #begin

    Process {

        $results = Get-WindowsVersion @PSBoundParameters

        #write a version string for each computer
    `   foreach ($result in $results) {
            "{0} Version {1} (OS Build {2})" -f $result.ProductName, $result.releaseID, $result.build
        }

    } #process

    End {

        Write-Verbose "Ending $($MyInvocation.Mycommand)"

    } #end
}

如果向下滚动我的 Get-Something 模板的代码,您将在文件末尾看到一个注释块。这是一个 json 代码片段。您可以将其复制并粘贴到 VSCode 的 PowerShell 片段 json 文件中。如果您不知道如何到达那里,请单击齿轮图标并选择用户片段。选择 powershell.json 文件。将代码片段粘贴到此文件中。注意你的逗号!

有了这个片段,我可以通过开始输入“get-something”来快速构建一个新函数。

[玩转系统] 构建更多 PowerShell 函数

按 Enter 键插入片段。添加您的脚本块(您已经知道它可以工作,对吧?),调整参数,更新帮助,然后您就完成了!

我希望您发现最后几篇文章对构建您自己的 PowerShell 脚本和函数很有帮助。我的最终结果不是目标,实际上也没有那么重要。您应该关注的主要内容是 PowerShell 工具制作的流程和模式。如果你可以“模板化”它,那就更好了。随时欢迎您的反馈。我对你面临的障碍或你觉得难以理解的事情非常感兴趣。您可能还对 PowerShell 脚本和工具制作书籍感兴趣,以了解更多脚本范例和概念。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯