动态参数 - 使用动态ValidateSet

时间:2018-04-13 14:54:58

标签: powershell dynamic parameters

我有一个脚本,我一直在努力提供SCCM日志文件的解析。此脚本采用计算机名和磁盘上的位置来构建动态参数列表,然后将其呈现给用户以选择要解析的日志文件。麻烦的是我似乎无法获得动态参数的ValidateSet部分来为用户提供值。此外,在尝试调用函数时,脚本不会显示-log动态参数。

当你第一次运行它时,你没有看到我上面提到的动态参数Log。如果你然后使用-log然后点击tab,你将获得你所在目录中文件的命令完成者。不是你所期望的;您希望它能够显示在动态参数执行期间收集的日志文件名称。

PSVersion 5.1.14409.1012

所以问题是如何让PowerShell向用户展示正确的验证设置项?

arrow functions

如果您在错误日志中发出其中一项,则会获得正确的行为: enter image description here

以下是我使用的两个函数:

function Get-CCMLog
{
    [CmdletBinding()]
    param([Parameter(Mandatory=$true,Position=0)]$ComputerName = '$env:computername', [Parameter(Mandatory=$true,Position=1)]$path = 'c:\windows\ccm\logs')
    DynamicParam
    {
        $ParameterName = 'Log'
        if($path.ToCharArray() -contains ':')
        {

            $FilePath = "\\$ComputerName\$($path -replace ':','$')"
            if(test-path $FilePath)
            {
                $logs = gci "$FilePath\*.log"
                $LogNames = $logs.basename

                $logAttribute = New-Object System.Management.Automation.ParameterAttribute
                $logAttribute.Position = 2
                $logAttribute.Mandatory = $true
                $logAttribute.HelpMessage = 'Pick A log to parse'                

                $logCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
                $logCollection.add($logAttribute)

                $logValidateSet = New-Object System.Management.Automation.ValidateSetAttribute($LogNames)
                $logCollection.add($logValidateSet)

                $logParam = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName,[string],$logCollection)

                $logDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
                $logDictionary.Add($ParameterName,$logParam)
                return $logDictionary
            }
        }
    }
    begin {
        # Bind the parameter to a friendly variable
        $Log = $PsBoundParameters[$ParameterName]
    }

    process {
        # Your code goes here
        #dir -Path $Path
        $sb2 = "$((Get-ChildItem function:get-cmlog).scriptblock)`r`n"
        $sb1 = [scriptblock]::Create($sb2)
        $results = Invoke-Command -ComputerName $ComputerName -ScriptBlock $sb1 -ArgumentList "$path\$log.log"
        [PSCustomObject]@{"$($log)Log"=$results}
    }
}
function Get-CMLog
{
    param(
    [Parameter(Mandatory=$true,
               Position=0,
               ValueFromPipelineByPropertyName=$true)]
    [Alias("FullName")]
    $Path,
    $tail =10
    )
    PROCESS
    {

        if(($Path -isnot [array]) -and (test-path $Path -PathType Container) )
        {
            $Path = Get-ChildItem "$path\*.log"
        }

        foreach ($File in $Path)
        {
            if(!( test-path $file))
            {
                $Path +=(Get-ChildItem "$file*.log").fullname
            }
            $FileName = Split-Path -Path $File -Leaf
            if($tail)
            {
                $lines = Get-Content -Path $File -tail $tail 
            }
            else {
                $lines = get-cotnet -path $file
            }
            ForEach($l in $lines ){
                $l -match '\<\!\[LOG\[(?<Message>.*)?\]LOG\]\!\>\<time=\"(?<Time>.+)(?<TZAdjust>[+|-])(?<TZOffset>\d{2,3})\"\s+date=\"(?<Date>.+)?\"\s+component=\"(?<Component>.+)?\"\s+context="(?<Context>.*)?\"\s+type=\"(?<Type>\d)?\"\s+thread=\"(?<TID>\d+)?\"\s+file=\"(?<Reference>.+)?\"\>' | Out-Null
                    if($matches)
                    {
                        $UTCTime = [datetime]::ParseExact($("$($matches.date) $($matches.time)$($matches.TZAdjust)$($matches.TZOffset/60)"),"MM-dd-yyyy HH:mm:ss.fffz", $null, "AdjustToUniversal")
                        $LocalTime = [datetime]::ParseExact($("$($matches.date) $($matches.time)"),"MM-dd-yyyy HH:mm:ss.fff", $null)
                    }
                    [pscustomobject]@{
                        UTCTime = $UTCTime
                        LocalTime = $LocalTime
                        FileName = $FileName
                        Component = $matches.component
                        Context = $matches.context
                        Type = $matches.type
                        TID = $matches.TI
                        Reference = $matches.reference
                        Message = $matches.message
                }
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

问题是你在if语句中拥有scriptblock中的所有动态逻辑,并且只有在提供的路径包含分号(':')时才处理参数添加。 您可以将其更改为:

if($path.ToCharArray() -contains ':') {
    $FilePath = "\\$ComputerName\$($path -replace ':','$')"
} else {
    $FilePath = $path
}

并从那里继续您的代码

答案 1 :(得分:0)