PoshCode Logo PowerShell Code Repository

Write-Indented by Joel Bennett 32 months ago
embed code: <script type="text/javascript" src="http://PoshCode.org/embed/3386"></script>download | new post

Wrappers for Write-Host and Write-Verbose that support indenting, including automatic indenting based on stack depth.

  1. function Write-Host {
  2. #.Synopsis
  3. #  Wraps Write-Host with support for indenting based on stack depth.
  4. #.Description
  5. #  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.
  6. #
  7. #  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.
  8. #.Example
  9. #  write-host "no newline test >" -nonewline
  10. #  no newline test >C:\PS>
  11. #
  12. #  This command displays the input to the console, but because of the NoNewline parameter, the output is followed directly by the prompt.
  13. #.Example
  14. #  C:\PS> write-host (2,4,6,8,10,12) -Separator ", -> " -foregroundcolor DarkGreen -backgroundcolor white
  15. #  2, -> 4, -> 6, -> 8, -> 10, -> 12
  16. #
  17. #  This command displays the even numbers from 2 through 12. The Separator parameter is used to add the string , -> (comma, space, -, >, space).
  18. #.Example
  19. #  write-host "Red on white text." -ForegroundColor red -BackgroundColor white
  20. #  Red on white text.
  21. #
  22. #  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.
  23. #.Example
  24. #  $WriteHostAutoIndent = $true
  25. #  C:\PS>&{
  26. #  >> Write-Host "Level 1"
  27. #  >> &{ Write-Host "Level 2"
  28. #  >> &{ Write-Host "Level 3" }
  29. #  >> Write-Host "Level 2"
  30. #  >> } }
  31. #    Level 1
  32. #      Level 2
  33. #        Level 3
  34. #      Level 2
  35. #
  36. #  This command displays how you can set WriteHostAutoIndent to control the output of a series of nested functions that use Write-Host for logging...
  37. #.Inputs
  38. #  System.Object
  39. #  You can pipe objects to be written to the host
  40. #.Outputs
  41. #  None
  42. #  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.
  43. [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=113426', RemotingCapability='None')]
  44. param(
  45.    # Objects to display in the console.
  46.    [Parameter(Position=0, ValueFromPipeline=$true, ValueFromRemainingArguments=$true)]
  47.    [System.Object[]]
  48.    ${Object},
  49.  
  50.    # Specifies that the content displayed in the console does not end with a newline character.
  51.    [switch]
  52.    ${NoNewline},
  53.  
  54.    # String to the output between objects displayed on the console.
  55.    [System.Object]
  56.    ${Separator},
  57.  
  58.    # Specifies the text color. There is no default.
  59.    [System.ConsoleColor]
  60.    ${ForegroundColor},
  61.  
  62.    # Specifies the background color. There is no default
  63.    [System.ConsoleColor]
  64.    ${BackgroundColor},
  65.  
  66.    # If set, Write-Host will indent based on the stack depth.  Defaults to the global preference variable $WriteHostAutoIndent (False).
  67.    [Switch]
  68.    $AutoIndent = $(if($Global:WriteHostAutoIndent){$Global:WriteHostAutoIndent}else{$False}),
  69.    
  70.    # Amount to indent (before auto indent).  Defaults to the global preference variable $WriteHostPadIndent (0).
  71.    [Int]
  72.    $PadIndent = $(if($Global:WriteHostPadIndent){$Global:WriteHostPadIndent}else{0}),
  73.  
  74.    # Number of spaces in each indent. Defaults to the global preference variable WriteHostIndentSize (2).
  75.    [Int]
  76.    $IndentSize = $(if($Global:WriteHostIndentSize){$Global:WriteHostIndentSize}else{2})
  77. )
  78. begin
  79. {
  80.    function Get-ScopeDepth {
  81.       $depth = 0
  82.       trap { continue } # trap outside the do-while scope
  83.       do { $null = Get-Variable PID -Scope (++$depth) } while($?)
  84.       return $depth - 3
  85.    }
  86.    
  87.    if($PSBoundParameters.ContainsKey("AutoIndent")) { $null = $PSBoundParameters.Remove("AutoIndent") }
  88.    if($PSBoundParameters.ContainsKey("PadIndent"))  { $null = $PSBoundParameters.Remove("PadIndent")  }
  89.    if($PSBoundParameters.ContainsKey("IndentSize")) { $null = $PSBoundParameters.Remove("IndentSize") }
  90.    
  91.    $Indent = $PadIndent
  92.    
  93.    if($AutoIndent) { $Indent += (Get-ScopeDepth) * $IndentSize }
  94.    $Width = $Host.Ui.RawUI.BufferSize.Width - $Indent
  95.  
  96.    if($PSBoundParameters.ContainsKey("Object")) {
  97.       $OFS = $Separator
  98.       $PSBoundParameters["Object"] = $(
  99.          foreach($line in $Object) {
  100.             $line = "$line".Trim("`n").Trim("`r")
  101.             for($start = 0; $start -lt $line.Length; $start += $Width -1) {
  102.                $Count = if($Width -gt ($Line.Length - $start)) { $Line.Length - $start} else { $Width - 1}
  103.                (" " * $Indent) + $line.SubString($start,$Count).Trim()
  104.             }
  105.          }
  106.       ) -join ${Separator}
  107.    }
  108.    
  109.     try {
  110.         $outBuffer = $null
  111.         if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  112.         {
  113.             $PSBoundParameters['OutBuffer'] = 1
  114.         }
  115.         $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Host', [System.Management.Automation.CommandTypes]::Cmdlet)
  116.         $scriptCmd = {& $wrappedCmd @PSBoundParameters }
  117.         $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  118.         $steppablePipeline.Begin($PSCmdlet)
  119.     } catch {
  120.         throw
  121.     }
  122. }
  123.  
  124. process
  125. {
  126.     try {
  127.       $OFS = $Separator
  128.       $_ = $(
  129.          foreach($line in $_) {
  130.             $line = "$line".Trim("`n").Trim("`r")
  131.             for($start = 0; $start -lt $line.Length; $start += $Width -1) {
  132.                $Count = if($Width -gt ($Line.Length - $start)) { $Line.Length - $start} else { $Width - 1}
  133.                (" " * $Indent) + $line.SubString($start,$Count).Trim()
  134.             }
  135.          }
  136.       ) -join ${Separator}
  137.       $steppablePipeline.Process($_)
  138.     } catch {
  139.         throw
  140.     }
  141. }
  142.  
  143. end
  144. {
  145.     try {
  146.         $steppablePipeline.End()
  147.     } catch {
  148.         throw
  149.     }
  150. }
  151. }
  152.  
  153.  
  154. function Write-Verbose {
  155. #.Synopsis
  156. #  Wraps Write-Verbose with support for indenting based on stack depth. Writes text to the verbose message stream.
  157. #.Description
  158. #  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.
  159. #.Example
  160. #  $VerbosePreference = "Continue"
  161. #  C:\PS>write-verbose "Testing Verbose"
  162. #  VERBOSE: Testing Verbose
  163. #
  164. #  Setting the VerbosePreference causes Write-Verbose output to be displayed in the console
  165. #.Example
  166. #  C:\PS> write-Verbose (2,4,6,8,10,12) -Separator ", -> "
  167. #  VERBOSE: 2, -> 4, -> 6, -> 8, -> 10, -> 12
  168. #
  169. #  This command displays the even numbers from 2 through 12. The Separator parameter is used to add the string , -> (comma, space, -, >, space).
  170. #.Example
  171. #  $WriteVerboseAutoIndent = $true
  172. #  C:\PS>&{
  173. #  >> Write-Verbose "Level 1"
  174. #  >> &{ Write-Verbose "Level 2"
  175. #  >> &{ Write-Verbose "Level 3" }
  176. #  >> Write-Verbose "Level 2"
  177. #  >> } }
  178. #  VERBOSE:   Level 1
  179. #  VERBOSE:     Level 2
  180. #  VERBOSE:       Level 3
  181. #  VERBOSE:     Level 2
  182. #
  183. #  This command displays how you can set WriteHostAutoIndent to control the output of a series of nested functions that use Write-Verbose for logging...
  184. #.Inputs
  185. #  System.Object
  186. #  You can pipe objects to be written to the verbose message stream.
  187. #.Outputs
  188. #  None
  189. #  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
  190. [CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=113429', RemotingCapability='None')]
  191. param(
  192.    # Objects to display in the console.
  193.    [Parameter(Position=0, ValueFromPipeline=$true, ValueFromRemainingArguments=$true)]
  194.    [System.Object[]]
  195.    ${Message},
  196.  
  197.    # String to the output between objects displayed on the console.
  198.    [System.Object]
  199.    ${Separator},
  200.  
  201.    # If set, Write-Verbose will indent based on the stack depth.  Defaults to the global preference variable $WriteVerboseAutoIndent (False).
  202.    [Switch]
  203.    $AutoIndent = $(if($Global:WriteVerboseAutoIndent){$Global:WriteVerboseAutoIndent}else{$False}),
  204.    
  205.    # Amount to indent (before auto indent).  Defaults to the global preference variable $WriteVerbosePadIndent (0).
  206.    [Int]
  207.    $PadIndent = $(if($Global:WriteVerbosePadIndent){$Global:WriteVerbosePadIndent}else{0}),
  208.  
  209.    # Number of spaces in each indent. Defaults to the global preference variable WriteVerboseIndentSize (2).
  210.    [Int]
  211.    $IndentSize = $(if($Global:WriteVerboseIndentSize){$Global:WriteVerboseIndentSize}else{2})
  212. )
  213. begin
  214. {
  215.    function Get-ScopeDepth {
  216.       $depth = 0
  217.       trap { continue } # trap outside the do-while scope
  218.       do { $null = Get-Variable PID -Scope (++$depth) } while($?)
  219.       return $depth - 3
  220.    }
  221.    
  222.    if($PSBoundParameters.ContainsKey("AutoIndent")) { $null = $PSBoundParameters.Remove("AutoIndent") }
  223.    if($PSBoundParameters.ContainsKey("PadIndent"))  { $null = $PSBoundParameters.Remove("PadIndent")  }
  224.    if($PSBoundParameters.ContainsKey("IndentSize")) { $null = $PSBoundParameters.Remove("IndentSize") }
  225.    if($PSBoundParameters.ContainsKey("Separator")) { $null = $PSBoundParameters.Remove("Separator") }
  226.    
  227.    $Indent = $PadIndent
  228.    
  229.    if($AutoIndent) { $Indent += (Get-ScopeDepth) * $IndentSize }
  230.    $Prefix = "VERBOSE: ".Length
  231.    $Width = $Host.Ui.RawUI.BufferSize.Width - $Indent - $Prefix
  232.  
  233.    
  234.    if($PSBoundParameters.ContainsKey("Message")) {
  235.       $OFS = $Separator
  236.       $PSBoundParameters["Message"] = $(
  237.          foreach($line in $Message) {
  238.             $line = "$line".Trim("`n").Trim("`r")
  239.             for($start = 0; $start -lt $line.Length; $start += $Width - 1) {
  240.                $Count = if($Width -gt ($Line.Length - $start)) { $Line.Length - $start} else { $Width - 1}
  241.                if($start) {
  242.                   (" " * ($Indent + $Prefix)) + $line.SubString($start,$Count).Trim()
  243.                } else {
  244.                   (" " * $Indent) + $line.SubString($start,$Count).Trim()
  245.                }
  246.             }
  247.          }
  248.       ) -join "`n"
  249.    }
  250.    
  251.     try {
  252.         $outBuffer = $null
  253.         if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  254.         {
  255.             $PSBoundParameters['OutBuffer'] = 1
  256.         }
  257.         $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Verbose', [System.Management.Automation.CommandTypes]::Cmdlet)
  258.         $scriptCmd = {& $wrappedCmd @PSBoundParameters }
  259.         $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  260.         $steppablePipeline.Begin($PSCmdlet)
  261.     } catch {
  262.         throw
  263.     }
  264. }
  265.  
  266. process
  267. {
  268.     try {
  269.       $OFS = $Separator
  270.       $_ = $(
  271.          foreach($line in $_) {
  272.             $line = "$line".Trim("`n").Trim("`r")
  273.             for($start = 0; $start -lt $line.Length; $start += $Width - 1) {
  274.                $Count = if($Width -gt ($Line.Length - $start)) { $Line.Length - $start} else { $Width - 1}
  275.                if($start) {
  276.                   (" " * ($Indent + $Prefix)) + $line.SubString($start,$Count).Trim()
  277.                } else {
  278.                   (" " * $Indent) + $line.SubString($start,$Count).Trim()
  279.                }
  280.                
  281.             }
  282.          }
  283.       ) -join "`n"
  284.       $steppablePipeline.Process($_)
  285.     } catch {
  286.         throw
  287.     }
  288. }
  289.  
  290. end
  291. {
  292.     try {
  293.         $steppablePipeline.End()
  294.     } catch {
  295.         throw
  296.     }
  297. }
  298. }

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me