Skip to content

Instantly share code, notes, and snippets.

@Jaykul
Created January 21, 2017 08:00
Show Gist options
  • Save Jaykul/a1cfb8405334b47ab0de484d21f5f0d3 to your computer and use it in GitHub Desktop.
Save Jaykul/a1cfb8405334b47ab0de484d21f5f0d3 to your computer and use it in GitHub Desktop.
A wrapper to improve Write-Information
using namespace System.Management.Automation
function Write-Information {
<#
.Synopsis
An enhancement to the built-in Write-Information to make it show the calling script line
.Description
Creates a stopwatch that tracks the time elapsed while a script runs, and adds caller position and time to the output
.Example
.Example
#>
[CmdletBinding(DefaultParameterSetName="InformationOutput")]
param(
# Specifies an informational message that you want to display to users as they run a script or command.
# Note that this is a rich object, and the -InformationVariable can collect those objects, but the stream will just get the ToString()
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName="InformationOutput", Position=0)]
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName="VerboseOutput", Position=0)]
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName="WarningOutput", Position=0)]
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName="DebugOutput", Position=0)]
[PSObject]$MessageData,
# Specifies a simple string that you can use to sort and filter messages that you have added to the information stream with Write-Information
[String[]]$Tags,
# When set, output to the verbose stream in addition to the information stream
[Parameter(Mandatory=$true, ParameterSetName="VerboseOutput")]
[Alias("AsVerbose")]
[switch]$VerboseOutput,
# When set, output to the warning stream in addition to the information stream
[Parameter(Mandatory=$true, ParameterSetName="WarningOutput")]
[Alias("AsWarning")]
[switch]$WarningOutput,
# When set, output to the debug stream in addition to the information stream
[Parameter(Mandatory=$true, ParameterSetName="DebugOutput")]
[Alias("AsDebug")]
[switch]$DebugOutput
)
begin {
if(-not ${Trace Message Timer}) {
${global:Trace Message Timer} = New-Object System.Diagnostics.Stopwatch
${global:Trace Message Timer}.Start()
# Clean up automatically when we hit the prompt
$PreTraceTimerPrompt = $function:prompt
$function:prompt = {
if(${global:Trace Message Timer}) {
${global:Trace Message Timer}.Stop()
Remove-Variable "Trace Message Timer" -Scope global -ErrorAction SilentlyContinue
}
& $PreTraceTimerPrompt
${function:global:prompt} = $PreTraceTimerPrompt
}.GetNewClosure()
}
$Script:LastElapsed = $Script:Elapsed
$Script:Elapsed = ${Trace Message Timer}.Elapsed.Duration()
# Note this requires a host with RawUi
$w = $Host.UI.RawUi.BufferSize.Width
}
process {
$Message = [PSCustomObject]@{Data=$MessageData} | Format-Table -HideTableHeaders -AutoSize -Wrap | Out-String -Stream
$Location = if($MyInvocation.CommandOrigin -eq "Runspace") {
"line:{0}" -f "$($MyInvocation.ScriptLineNumber)".PadRight(4)
}
else {
"{0}, line:{1}" -f ($MyInvocation.ScriptName | Split-Path -Leaf), "$($MyInvocation.ScriptLineNumber)".PadRight(4)
}
$Information = [InformationRecord]::new($MessageData, $Location)
foreach($Tag in $Tags) { $Information.Tags.Add($Tag) }
$PSCmdlet.WriteInformation($Information)
$Tail = $(if($Elapsed.TotalHours -ge 1.0) {
"{0:h\:mm\:ss\.ffff}" -f $Elapsed
}
elseif($Elapsed.TotaMinutes -ge 1.0) {
"{0:mm\m\ ss\.ffff\s}" -f $Elapsed
}
else {
"{0:ss\.ffff\s}" -f $Elapsed
}).PadLeft(12)
$Tail = $Location + $Tail
# "WARNING: ".Length = 10
$Length = ($Message.Length + 10 + $Tail.Length)
# Twenty-five is a minimum 15 character message...
$PaddedLength = if($Length -gt $w -and $w -gt (25 + $Tail.Length)) {
[string[]]$words = -split $message
$short = 10 # "VERBOSE: ".Length
$count = 0 # Word count so far
$lines = 0
do {
do {
$short += 1 + $words[$count++].Length
} while (($words.Count -gt $count) -and ($short + $words[$count].Length) -lt $w)
$Lines++
if(($Message.Length + $Tail.Length) -gt ($w * $lines)) {
$short = 0
}
} while($short -eq 0)
$Message.Length + ($w - $short) - $Tail.Length
} else {
$w - 10 - $Tail.Length
}
$Message = "$Message ".PadRight($PaddedLength, "$([char]8331)") + $Tail
if($VerboseOutput) {
Write-Verbose $Message
}
elseif($WarningOutput) {
Write-Warning $Message
}
elseif($DebugOutput) {
Write-Debug $Message
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment