为什么我在PowerShell中看不到脚本的参数?

时间:2014-01-22 23:12:25

标签: function powershell parameters

我正在开发一个脚本,它会有效地花时间和我提供的任何输入并将其吐出到现有的文本文件中。

我创建的参数是$ Input和$ logPath。 $ input应该能够接受管道输入或使用“-Input”,而$ logPath参数需要“-logpath”。

我不确定我做错了什么,因为在ISE中使用自动完成时我看不到那些开关。如果我尝试管道输入,我得到:

  

“Out-LogFile:输入对象不能绑定到任何参数   该命令要么是因为命令不接受管道输入,要么是   输入及其属性与任何参数都不匹配   拿管道输入。在行:1字符:10“

如果我试图坚持开关而不是管道输入我可以使用一个,但一旦我输入一个我不能使用第二个开关。

这是我的功能,感谢任何帮助:

function Global:Out-LogFile {
    #Planned function for outputting to a specified log file.
     <#
    .SYNOPSIS
    Adds to log files.

    .DESCRIPTION
    Updates a specified log file with a new line. The log file must already exist. See: Get-help New-LogFile

    .PARAMETER logPath
    Specifies a path for your new log (including file name).

    .EXAMPLE
    Get-ChildItem C:\ | Out-LogFile
    Piped input.

    #>

    [CmdletBinding()]

    param(
        [Parameter(Mandatory=$True,
                  ValueFromPipeline=$True,
                  ValueFromPipelineByPropertyName=$True,
                  HelpMessage="input to append to logFile",
                  ParameterSetName='Input')]
        [string[]]$Input,


        [Parameter(Mandatory=$True,
                  HelpMessage="Please enter the path to your log file",
                  ParameterSetName='logPath')]
        [string]$logPath
    )

    #Check to see that $logpath physically exists as a log file.
    Try {
        Write-Verbose Checking for existing log file.
        gi -Path $logPath -ErrorVariable $logPathError | Out-Null
    }

    Catch {
        throw "quitting! logPath does not exist, did you use the -logpath parameter? see: $logPathError"
    }

    #Create new time object, give it properties of Hours, minutes, seconds, milliseconds.
    Try {
        Write-Verbose "Creating Time object for recording log timestamps"
        $time = New-Object PSObject -ErrorVariable $timeError
        $time | Add-Member -MemberType NoteProperty -Name Hours -Value (Get-Date).Hour
        $time | Add-Member -MemberType NoteProperty -Name Minutes -Value (Get-Date).Minute
        $time | Add-Member -MemberType NoteProperty -Name Seconds -Value (Get-Date).Second
        $time | Add-Member -MemberType NoteProperty -Name Milliseconds -Value (Get-Date).Millisecond
        #declare "currentTime" variable used to place timestamps in log files. 
        [string]$currentTime = $time.Hours.ToString() + ":" + $time.Minutes.ToString() + ":" + $time.Seconds.ToString() + ":" + $time.Milliseconds.ToString() + "   "

    }

    Catch {
        throw "Can't create PSObject: time. See: $timeError"
    }

    Try {
        #Append data to log file
        Write-Verbose "Writing line to log file"
        [string]$currentTime + [string]$Input >> $logPath

    }
    Catch {
        throw "Quitting! Can't write to log file"
    }


}

1 个答案:

答案 0 :(得分:5)

您已为$Input$logPath指定了不同的参数集名称。这实际上意味着它们是互斥的,PowerShell不允许您同时使用它们(这就是为什么它们没有出现在ISE的自动完成中)。由于您总是希望在这种情况下同时使用两者,因此根本不需要指定自定义参数集。

其他注意事项:

虽然我有你在这里,但我要指出一些可能存在问题的其他事情:

您已将输入参数命名为$input,这是您不应该做的,因为$input是PowerShell中的预定义/自动生成的变量(具体而言,$input是一个提供对当前管道的访问的枚举器对象)因此,为函数参数赋予相同的名称可能会导致脚本以意外的方式运行。

例如,如果您尝试手动将值传递给参数,请执行以下操作:

Out-LogFile -Input "string1" -logPath test.txt

您的脚本不会输出任何内容,因为$input指的是在这种情况下没有任何内容的管道。我建议将$input重命名为$Message$InputObject,这与其他Out- cmdlet一致。


这个块有几个问题:

    Try {
        Write-Verbose Checking for existing log file.
        gi -Path $logPath -ErrorVariable $logPathError | Out-Null 
    }
    Catch {
        throw "quitting! logPath does not exist, did you use the -logpath parameter? see: $logPathError"
    }

首先,它总是会抛出一个异常,因为你的Write-Verbose文本不在引号中,所以而不是将整个句子视为字符串,将“Checking”一词传递给Write-Verbose' s Message参数然后“for”被传递给接受字符串的下一个位置参数(当然,它不存在)。因此,您将收到一个“ParameterBindingException”,其中包含以下内容:

Write-Verbose : A positional parameter cannot be found that accepts argument 'for'.

或者更确切地说,您会看到该异常,除非您已捕获它,然后在catch块中抛出另一个异常,该异常表示该脚本正在退出且该logPath不存在。

但即使您在Write-Verbose上修复了未加引号的字符串,如果Get-Item无法找到$logPath,脚本也不会退出并且不会抛出自定义异常。这是因为当Get-Item无法找到某个项目时,它会抛出ItemNotFoundException

在PowerShell中,有终止错误非终止错误ItemNotFoundException。是 - 终止错误。终止错误总是终止脚本(因此名称),但根据当前$ErrorActionPreference不同处理非终止错误。默认情况下,$ErrorActionPreference设置为“Continue”,这实际上意味着当抛出非终止异常时,将显示错误并继续脚本;它没有被try-catch块捕获。

确定文件是否存在的更好方法是通过Test-Path cmdlet:

    if (!(Test-Path -Path $logPath))
    {
        throw [System.IO.FileNotFoundException]("Could not find the file specified in logPath")
    }

这整个块是不必要的(并且是获取时间字符串的一种非常迂回的方式):

    #Create new time object, give it properties of Hours, minutes, seconds, milliseconds.
    Try {
        Write-Verbose "Creating Time object for recording log timestamps"
        $time = New-Object PSObject -ErrorVariable $timeError
        $time | Add-Member -MemberType NoteProperty -Name Hours -Value (Get-Date).Hour
        $time | Add-Member -MemberType NoteProperty -Name Minutes -Value (Get-Date).Minute
        $time | Add-Member -MemberType NoteProperty -Name Seconds -Value (Get-Date).Second
        $time | Add-Member -MemberType NoteProperty -Name Milliseconds -Value (Get-Date).Millisecond
        #declare "currentTime" variable used to place timestamps in log files. 
        [string]$currentTime = $time.Hours.ToString() + ":" + $time.Minutes.ToString() + ":" + $time.Seconds.ToString() + ":" + $time.Milliseconds.ToString() + "   "

    }

    Catch {
        throw "Can't create PSObject: time. See: $timeError"
    }

以特定格式获取日期/时间字符串的最简单方法是在DateTime对象上调用ToString()方法。在括号中,我们可以指定standardcustom格式。 Get-Date返回一个DateTime对象,以便我们可以写:

$currentTime = (Get-Date).ToString("hh:mm:ss:fff") + "   "

基本上做同样的事情,除了你和PowerShell的工作都不那么重要。


最后,没有任何理由将您的写操作包含在try-catch块中。如果写入操作失败(例如,由于文件是只读的),这将是一个非终止错误,并且无论如何都不会被捕获。