尝试编写接受流水线输入的 powershell cmdlet [英] trying to write powershell cmdlet accepting pipelined input

查看:89
本文介绍了尝试编写接受流水线输入的 powershell cmdlet的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解 powershell 并将函数编写为 cmdlet,在其中一篇文章中找到了以下代码示例,但它似乎不想作为 cmdlet 工作,即使它具有 [cmdletbinding()] 文件顶部的声明.

I'm trying to get my head around powershell and write a function as cmdlet, found the following code sample in one of the articles, but it doesnt seem to want to work as cmdlet even though it has [cmdletbinding()] declaration on the top of the file.

当我尝试做类似的事情时

When I try to do something like

1,2,3,4,5 | .\measure-data 

它返回空响应(如果我在文件底部调用它并运行文件本身,该函数本身就可以正常工作).

it returns empty response (the function itself works just fine if I invoke it at the bottom of the file and run the file itself).

这是我正在使用的代码,任何帮助将不胜感激:)

Here's the code that I am working with, any help will be appreciated :)

Function Measure-Data {
    <#
    .Synopsis
    Calculate the median and range from a collection of numbers
    .Description
    This command takes a collection of numeric values and calculates the
    median and range. The result is written as an object to the pipeline.
    .Example
    PS C:\> 1,4,7,2 | measure-data

    Median                                    Range
    ------                                    -----
    3                                        6

    .Example
    PS C:\> dir c:\scripts\*.ps1 | select -expand Length | measure-data

    Median                                    Range
    ------                                    -----
    1843                                   178435
    #>

    [cmdletbinding()]
    Param (
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
        [ValidateRange([int64]::MinValue,[int64]::MaxValue)]
        [psobject]$InputObject 
    )
    
    Begin {
        #define an array to hold incoming data
        Write-Verbose "Defining data array"
        $Data=@()
    } #close Begin
    
    Process {
        #add each incoming value to the $data array
        Write-Verbose "Adding $inputobject"
        $Data+=$InputObject
    } #close process
    
    End {
        #take incoming data and sort it
        Write-Verbose "Sorting data"
        $sorted = $data | Sort-Object
    
        #count how many elements in the array
        $count = $data.Count
        Write-Verbose "Counted $count elements"
        
        #region calculate median
    
        if ($sorted.count%2) {
            <#
            if the number of elements is odd, add one to the count
            and divide by to get middle number. But arrays start
            counting at 0 so subtract one
            #>
            Write-Verbose "processing odd number"            
            [int]$i = (($sorted.count+1)/2-1)            
            #get the corresponding element from the sorted array
            $median = $sorted[$i]    
        }
        else {
            <#
            if number of elements is even, find the average
            of the two middle numbers
            #>
            Write-Verbose "processing even number"
            $i = $sorted.count/2
            #get the lower number
            $x = $sorted[$i-1]
            #get the upper number
            $y = $sorted[-$i]
            #average the two numbers to calculate the median
            $median = ($x+$y)/2
        } #else even
    
        #endregion
    
        #region calculate range

        Write-Verbose "Calculating the range"
        $range = $sorted[-1] - $sorted[0]
    
        #endregion
    
        #region write result

        Write-Verbose "Median = $median"
        Write-Verbose "Range = $range"
        #define a hash table for the custom object
        $hash = @{Median=$median;Range=$Range}
    
        #write result object to pipeline
        Write-Verbose "Writing result to the pipeline"
        New-Object -TypeName PSobject -Property $hash
    
        #endregion
    } #close end
} #close measure-data

这是我从中获取代码的文章:https://mcpmag.com/articles/2013/10/15/blacksmith-part-4.aspx

this the article where I took the code from: https://mcpmag.com/articles/2013/10/15/blacksmith-part-4.aspx

也许我应该添加文章前面部分中的此代码版本工作得很好,但是在添加使其成为正确 cmdlet 的所有内容(例如帮助部分和详细行)之后,这件事只是不想工作,我相信有一些遗漏,我有一种感觉,这可能是因为它是为 powershell 3 编写的,我正在 win 10 ps 5-point-something 上测试它,但老实说,我什至不知道我朝哪个方向应该寻找,这就是为什么我向你求助

edit: maybe I should add that versions of this code from previous parts of the article worked just fine, but after adding all the things that make it a proper cmdlet like the help section and verbose lines, this thing just doesnt want to work, and I believe there is something missing, I have a feeling that this could be because it was written for powershell 3 and I am testing it on win 10 ps 5-point-something, but honestly I dont even know in which direction I should look for, that's why I ask you for help

推荐答案

代码没有任何问题(除了可能的优化),但是你怎么称呼它的方式不行:

There is nothing wrong with the code (apart from possible optimizations), but the way how you call it can't work:

1,2,3,4,5 | .\measure-data

当您调用包含命名函数的脚本文件时,预计没有任何反应".实际上,脚本会运行,但 PowerShell 不知道它应该调用哪个函数(可能有多个).所以它只运行函数之外的任何代码.

When you call a script file that contains a named function, it is expected that "nothing happens". Actually, the scripts runs, but PowerShell does not know which function it should call (there could be multiple). So it just runs any code outside of functions.

您有两种方法可以解决问题:

You have two options to fix the problem:

删除 function 关键字和属于它的花括号.保留 [cmdletbinding()]Param 部分.

Remove the function keyword and the curly braces that belong to it. Keep the [cmdletbinding()] and Param sections.

[cmdletbinding()]
Param (
    [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
    [ValidateRange([int64]::MinValue,[int64]::MaxValue)]
    [psobject]$InputObject 
)

Begin {
    # ... your code ...
} #close Begin

Process {
    # ... your code ...
} #close process

End {
    # ... your code ...
}

现在脚本本身就是函数"并且可以这样调用:

Now the script itself is the "function" and can be called as such:

1,2,3,4,5 | .\measure-data

选项 2

将脚本变成模块.基本上你只需要用 .psm1 扩展名保存它(还有更多内容,但对于入门来说就足够了.

Option 2

Turn the script into a module. Basically you just need to save it with .psm1 extension (there is more to it, but for getting started it will suffice).

在要使用该函数的脚本中,您必须导入该模块,然后才能使用其函数.如果未安装该模块,您可以通过指定其完整路径来导入.

In the script where you want to use the function you have to import the module before you can use its functions. If the module is not installed, you can import it by specifying its full path.

# Import module from directory where current script is located
Import-Module $PSScriptRoot\measure-data.psm1

# Call a function of the module
1,2,3,4,5 | Measure-Data

模块是单个脚本文件中有多个函数的方式.当一个函数被多次调用时它也更有效,因为 PowerShell 只需要解析它一次(它记住 Import-Module 调用).

A module is the way when there are multiple functions in a single script file. It is also more efficient when a function will be called muliple times, because PowerShell needs to parse it only once (it remembers Import-Module calls).

这篇关于尝试编写接受流水线输入的 powershell cmdlet的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆