重载内置函数,如 Write-Verbose



我刚刚了解到使用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"

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

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

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

我推荐后者,除非您对主机有一些时髦的输出要求。

如果你继续创建自己的 Write-Verbose 函数,你应该在参数之前使用 [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,因为这会弄乱默认的流重定向(等)。如果要将信息打印到流,我强烈建议使用写入详细、写入调试、写入信息、写入输出 cmdlet。

有关不使用写入主机的详细信息,请访问:

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

希望这能回答你的问题。

同意

@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

最新更新