重载内置函数,如Write-Verbose

时间:2016-02-25 06:50:33

标签: oop powershell

我刚学会了使用Write-Verbose& Write-Debug超过我自己的Write-Log功能,您可以在下面找到:

Function Write-Log 
{
    param($logType, $logString, $logFile, [switch]$newLine)

    $time = get-date -Format "HH:mm:ss"
    $date = get-date -Format "yyyy-MM-dd"
    $line = "[${date}][${time}][$logType] ${logString}"

    if ($logFile) 
    {
        $retryDelay = 0.5; 
        $maxRetries = 10; 
        $retries = 0;

        while($retries -lt $maxRetries) 
        {
            try 
            {
                $line | out-file -Encoding utf8 -Append $logFile
                break; 
            } 
            catch 
            {
                ++$retries;
                Sleep $retryDelay; 
            }
        }
    }

    if ($logType -eq 'INFO') 
    {
        write-host -ForegroundColor Green $line 
    } 
    elseif ($logType -eq 'WARN') 
    {
        write-host -ForegroundColor Yellow $line
    } 
    elseif ($logType -eq 'ERROR') 
    {
        write-host -ForegroundColor Red $line
    }

    if ($newLine -eq $true)
    {
        write-host 
    }
}

这有助于让我的脚本输出尽可能地混乱,并且包含一个时间戳,在调试时很方便。

问题

有没有办法重载Write-Verbose所以它的行为方式如下?

PS > Write-Verbose -Message 'I am a verbose message!' 

[2016-02-25][07:44:36] VERBOSE: I am a verbose message! 

修改

我发现了以下内容,但遗憾的是,$VerbosePreference变量并未兑现:

$VerbosePreference = "SilentlyContinue"

Function Private:Write-Verbose ($Message) 
{
    $time = get-date -Format "HH:mm:ss"
    $date = get-date -Format "yyyy-MM-dd"
    $line = "[${date}][${time}] "

    Write-Host $line -NoNewline 

    &{Write-Verbose -Message $Message}

}

Write-Verbose -Message "Test"

上面只输出日期和时间戳,没有消息。

2 个答案:

答案 0 :(得分:2)

Write-Verbose驻留在Microsoft.PowerShell.Utility中,所以这不可能是afaik;没有操纵和改变Powershell中的内置行为(应该避免)。

您可以在脚本/会话范围中创建自己的“Write-Verbose”函数;这将输出所需的结果(使用cmdletbinding());或者使用输出消息,例如“VERBOSE:[2016-02-25] [07:44:36]您的日志消息”(依赖于write-verbose的默认行为)。

我建议使用后者,除非你的主机有一些时髦的输出要求。

如果你继续创建自己的Write-Verbose函数,你应该在params之前使用[cmdletbinding()];因为这可以将默认参数/开关传递给您的函数(例如-verbose / -information,-debug等)。 有关cmdletbinding和参数绑定的详细信息,请参阅:

https://blogs.technet.microsoft.com/heyscriptingguy/2012/07/07/weekend-scripter-cmdletbinding-attribute-simplifies-powershell-functions/

https://posh2scripting.wordpress.com/2013/06/05/what-is-cmdletbinding/

最后一件事;不推荐在脚本中直接使用Write-host,因为这会混淆默认的流重定向(等)。如果您要向流打印信息,我强烈建议使用Write-Verbose,Write-Debug,Write-information,Write-Output cmdlet。

有关不使用Write-host的更多信息,请访问:

http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/

http://powershell.com/cs/blogs/donjones/archive/2012/04/06/2012-scripting-games-commentary-stop-using-write-host.aspx

希望这能回答你的问题。

答案 1 :(得分:0)

同意@CmdrTchort对这个问题的回答。

提供此答案是为了实现Write-Verbose的自定义实现,可以代之以使用(即拨打Write-CustomVerbose而不是Write-Verbose。显然这不会影响引用库中仍使用Write-Verbose的任何现有代码或代码。

function Write-CustomVerbose {
    [CmdletBinding(DefaultParameterSetName='UseTimestamp')]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [AllowEmptyString()]
        [string]$Message
        ,
        [Parameter(Mandatory = $false, ParameterSetName='UseTimestamp')]
        [string]$TimestampFormat = ((Get-Culture).DateTimeFormat.UniversalSortableDateTimePattern)
        ,
        [Parameter(Mandatory = $false, ParameterSetName='UseTimestamp')]
        [switch]$UseLocalTime #defaults to UTC
        ,
        [Parameter(Mandatory = $false, ParameterSetName='DoNotUseTimestamp')]
        [switch]$ExcludeTimestamp #defaults to include the timestamp (as that's why we're using this function over the standard write-verbose

    )
    begin {
        [string]$FormattedMessage = '{0}'
        if(-not $ExcludeTimestamp.IsPresent) {
            $FormattedMessage = "{1:$TimestampFormat}: $FormattedMessage"
        }
    }
    process {
        #get the time here rather than in begin as we want it to be accurate per message from pipeline
        [DateTime]$Now = Get-Date
        if(-not $UseLocalTime.IsPresent){$Now = $Now.ToUniversalTime()}
        #output the results
        write-verbose ($FormattedMessage -f $Message, $Now)
    }
}

使用示例:1..1000 | Write-CustomVerbose -Verbose -UseLocalTime -TimestampFormat 'HH:mm'

<强>更新

这是一个稍微高级的版本,允许您一次劫持所有流:

function Write-Custom {
    [CmdletBinding(DefaultParameterSetName='UseTimestamp')]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSCustomObject]$InputObject
        ,
        [Parameter(Mandatory = $false, ParameterSetName='UseTimestamp')]
        [string]$TimestampFormat = ((Get-Culture).DateTimeFormat.UniversalSortableDateTimePattern)
        ,
        [Parameter(Mandatory = $false, ParameterSetName='UseTimestamp')]
        [switch]$UseLocalTime #defaults to UTC
        ,
        [Parameter(Mandatory = $false, ParameterSetName='DoNotUseTimestamp')]
        [switch]$ExcludeTimestamp #defaults to include the timestamp (as that's why we're using this function over the standard write-verbose

    )
    begin {
        [string]$FormattedMessage = '{0}'
        if(-not $ExcludeTimestamp.IsPresent) {
            $FormattedMessage = "{1:$TimestampFormat}: $FormattedMessage"
        }
    }
    process {
        #get the time here rather than in begin as we want it to be accurate per message from pipeline
        [DateTime]$Now = Get-Date
        if(-not $UseLocalTime.IsPresent){$Now = $Now.ToUniversalTime()}
        #determine output back to original stream
        [bool]$outputStream = $true
        if($InputObject.WriteErrorStream)  {$outputStream=$false;write-error   ($FormattedMessage -f $InputObject, $Now)}
        if($InputObject.WriteWarningStream){$outputStream=$false;write-warning ($FormattedMessage -f $InputObject, $Now)}
        if($InputObject.WriteVerboseStream){$outputStream=$false;write-verbose ($FormattedMessage -f $InputObject, $Now) -Verbose}
        if($InputObject.WriteDebugStream)  {$outputStream=$false;write-debug   ($FormattedMessage -f $InputObject, $Now) -Debug}
        if($outputStream){$InputObject}
    }
}

#demo
1..20 | %{
    if($_ % 2 -eq 0) {Write-Output  $_}
    if($_ -eq 11)    {Write-Error   $_ -ErrorAction Continue 2>&1} #bit of a hack required to get error output to flow further along the pipeline.
    if($_ -eq 13)    {Write-Warning $_}
    if($_ -eq 15)    {Write-Verbose $_ -Verbose}
    if($_ -eq 17)    {Write-Debug   $_ -Debug}
} *>&1 | Write-Custom