# encoding: ascii
# api: powershell
# title: Write-Indented
# description: Wrappers for Write-Host and Write-Verbose that support indenting, including automatic indenting based on stack depth.
# version: 0.1
# type: function
# author: Joel Bennett
# license: CC0
# function: Write-Host
# x-poshcode-id: 3386
# x-archived: 2015-05-01T23:39:41
# x-published: 2012-04-28T21:25:00
#
#
function Write-Host {
#.Synopsis
# Wraps Write-Host with support for indenting based on stack depth.
#.Description
# This Write-Host cmdlet customizes output. You can indent the text using PadIndent, or indent based on stack depth using AutoIndent or by setting the global variable $WriteHostAutoIndent = $true.
#
# You can specify the color of text by using the ForegroundColor parameter, and you can specify the background color by using the BackgroundColor parameter. The Separator parameter lets you specify a string to use to separate displayed objects. The particular result depends on the program that is hosting Windows PowerShell.
#.Example
# write-host "no newline test >" -nonewline
# no newline test >C:\PS>
#
# This command displays the input to the console, but because of the NoNewline parameter, the output is followed directly by the prompt.
#.Example
# C:\PS> write-host (2,4,6,8,10,12) -Separator ", -> " -foregroundcolor DarkGreen -backgroundcolor white
# 2, -> 4, -> 6, -> 8, -> 10, -> 12
#
# This command displays the even numbers from 2 through 12. The Separator parameter is used to add the string , -> (comma, space, -, >, space).
#.Example
# write-host "Red on white text." -ForegroundColor red -BackgroundColor white
# Red on white text.
#
# This command displays the string "Red on white text." The text is red, as defined by the ForegroundColor parameter. The background is white, as defined by the BackgroundColor parameter.
#.Example
# $WriteHostAutoIndent = $true
# C:\PS>&{
# >> Write-Host "Level 1"
# >> &{ Write-Host "Level 2"
# >> &{ Write-Host "Level 3" }
# >> Write-Host "Level 2"
# >> } }
# Level 1
# Level 2
# Level 3
# Level 2
#
# This command displays how you can set WriteHostAutoIndent to control the output of a series of nested functions that use Write-Host for logging...
#.Inputs
# System.Object
# You can pipe objects to be written to the host
#.Outputs
# None
# Write-Host sends objects to the host. It does not return any objects. However, the host might display the objects that Write-Host sends to it.
[CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=113426', RemotingCapability='None')]
param(
# Objects to display in the console.
[Parameter(Position=0, ValueFromPipeline=$true, ValueFromRemainingArguments=$true)]
[System.Object[]]
${Object},
# Specifies that the content displayed in the console does not end with a newline character.
[switch]
${NoNewline},
# String to the output between objects displayed on the console.
[System.Object]
${Separator},
# Specifies the text color. There is no default.
[System.ConsoleColor]
${ForegroundColor},
# Specifies the background color. There is no default
[System.ConsoleColor]
${BackgroundColor},
# If set, Write-Host will indent based on the stack depth. Defaults to the global preference variable $WriteHostAutoIndent (False).
[Switch]
$AutoIndent = $(if($Global:WriteHostAutoIndent){$Global:WriteHostAutoIndent}else{$False}),
# Amount to indent (before auto indent). Defaults to the global preference variable $WriteHostPadIndent (0).
[Int]
$PadIndent = $(if($Global:WriteHostPadIndent){$Global:WriteHostPadIndent}else{0}),
# Number of spaces in each indent. Defaults to the global preference variable WriteHostIndentSize (2).
[Int]
$IndentSize = $(if($Global:WriteHostIndentSize){$Global:WriteHostIndentSize}else{2})
)
begin
{
function Get-ScopeDepth {
$depth = 0
trap { continue } # trap outside the do-while scope
do { $null = Get-Variable PID -Scope (++$depth) } while($?)
return $depth - 3
}
if($PSBoundParameters.ContainsKey("AutoIndent")) { $null = $PSBoundParameters.Remove("AutoIndent") }
if($PSBoundParameters.ContainsKey("PadIndent")) { $null = $PSBoundParameters.Remove("PadIndent") }
if($PSBoundParameters.ContainsKey("IndentSize")) { $null = $PSBoundParameters.Remove("IndentSize") }
$Indent = $PadIndent
if($AutoIndent) { $Indent += (Get-ScopeDepth) * $IndentSize }
$Width = $Host.Ui.RawUI.BufferSize.Width - $Indent
if($PSBoundParameters.ContainsKey("Object")) {
$OFS = $Separator
$PSBoundParameters["Object"] = $(
foreach($line in $Object) {
$line = "$line".Trim("`n").Trim("`r")
for($start = 0; $start -lt $line.Length; $start += $Width -1) {
$Count = if($Width -gt ($Line.Length - $start)) { $Line.Length - $start} else { $Width - 1}
(" " * $Indent) + $line.SubString($start,$Count).Trim()
}
}
) -join ${Separator}
}
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Host', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
try {
$OFS = $Separator
$_ = $(
foreach($line in $_) {
$line = "$line".Trim("`n").Trim("`r")
for($start = 0; $start -lt $line.Length; $start += $Width -1) {
$Count = if($Width -gt ($Line.Length - $start)) { $Line.Length - $start} else { $Width - 1}
(" " * $Indent) + $line.SubString($start,$Count).Trim()
}
}
) -join ${Separator}
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
}
function Write-Verbose {
#.Synopsis
# Wraps Write-Verbose with support for indenting based on stack depth. Writes text to the verbose message stream.
#.Description
# This Write-Verbose customizes output. You can indent the text using PadIndent, or indent based on stack depth using AutoIndent or by setting the global variable $WriteHostAutoIndent = $true.
#.Example
# $VerbosePreference = "Continue"
# C:\PS>write-verbose "Testing Verbose"
# VERBOSE: Testing Verbose
#
# Setting the VerbosePreference causes Write-Verbose output to be displayed in the console
#.Example
# C:\PS> write-Verbose (2,4,6,8,10,12) -Separator ", -> "
# VERBOSE: 2, -> 4, -> 6, -> 8, -> 10, -> 12
#
# This command displays the even numbers from 2 through 12. The Separator parameter is used to add the string , -> (comma, space, -, >, space).
#.Example
# $WriteVerboseAutoIndent = $true
# C:\PS>&{
# >> Write-Verbose "Level 1"
# >> &{ Write-Verbose "Level 2"
# >> &{ Write-Verbose "Level 3" }
# >> Write-Verbose "Level 2"
# >> } }
# VERBOSE: Level 1
# VERBOSE: Level 2
# VERBOSE: Level 3
# VERBOSE: Level 2
#
# This command displays how you can set WriteHostAutoIndent to control the output of a series of nested functions that use Write-Verbose for logging...
#.Inputs
# System.Object
# You can pipe objects to be written to the verbose message stream.
#.Outputs
# None
# Write-Verbose sends objects to the verbose message stream. It does not return any objects. However, the host might display the objects if the $VerbosePreference
[CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=113429', RemotingCapability='None')]
param(
# Objects to display in the console.
[Parameter(Position=0, ValueFromPipeline=$true, ValueFromRemainingArguments=$true)]
[System.Object[]]
${Message},
# String to the output between objects displayed on the console.
[System.Object]
${Separator},
# If set, Write-Verbose will indent based on the stack depth. Defaults to the global preference variable $WriteVerboseAutoIndent (False).
[Switch]
$AutoIndent = $(if($Global:WriteVerboseAutoIndent){$Global:WriteVerboseAutoIndent}else{$False}),
# Amount to indent (before auto indent). Defaults to the global preference variable $WriteVerbosePadIndent (0).
[Int]
$PadIndent = $(if($Global:WriteVerbosePadIndent){$Global:WriteVerbosePadIndent}else{0}),
# Number of spaces in each indent. Defaults to the global preference variable WriteVerboseIndentSize (2).
[Int]
$IndentSize = $(if($Global:WriteVerboseIndentSize){$Global:WriteVerboseIndentSize}else{2})
)
begin
{
function Get-ScopeDepth {
$depth = 0
trap { continue } # trap outside the do-while scope
do { $null = Get-Variable PID -Scope (++$depth) } while($?)
return $depth - 3
}
if($PSBoundParameters.ContainsKey("AutoIndent")) { $null = $PSBoundParameters.Remove("AutoIndent") }
if($PSBoundParameters.ContainsKey("PadIndent")) { $null = $PSBoundParameters.Remove("PadIndent") }
if($PSBoundParameters.ContainsKey("IndentSize")) { $null = $PSBoundParameters.Remove("IndentSize") }
if($PSBoundParameters.ContainsKey("Separator")) { $null = $PSBoundParameters.Remove("Separator") }
$Indent = $PadIndent
if($AutoIndent) { $Indent += (Get-ScopeDepth) * $IndentSize }
$Prefix = "VERBOSE: ".Length
$Width = $Host.Ui.RawUI.BufferSize.Width - $Indent - $Prefix
if($PSBoundParameters.ContainsKey("Message")) {
$OFS = $Separator
$PSBoundParameters["Message"] = $(
foreach($line in $Message) {
$line = "$line".Trim("`n").Trim("`r")
for($start = 0; $start -lt $line.Length; $start += $Width - 1) {
$Count = if($Width -gt ($Line.Length - $start)) { $Line.Length - $start} else { $Width - 1}
if($start) {
(" " * ($Indent + $Prefix)) + $line.SubString($start,$Count).Trim()
} else {
(" " * $Indent) + $line.SubString($start,$Count).Trim()
}
}
}
) -join "`n"
}
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Verbose', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
try {
$OFS = $Separator
$_ = $(
foreach($line in $_) {
$line = "$line".Trim("`n").Trim("`r")
for($start = 0; $start -lt $line.Length; $start += $Width - 1) {
$Count = if($Width -gt ($Line.Length - $start)) { $Line.Length - $start} else { $Width - 1}
if($start) {
(" " * ($Indent + $Prefix)) + $line.SubString($start,$Count).Trim()
} else {
(" " * $Indent) + $line.SubString($start,$Count).Trim()
}
}
}
) -join "`n"
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
}