Public/Output/Write-Border.ps1

function Write-Border {
  [CmdletBinding(DefaultParameterSetName = "single")]
  [OutputType([System.String])]

  Param(
    # The string of text to process
    [Parameter(Position = 0, Mandatory, ValueFromPipeline, ParameterSetName = 'single')]
    [ValidateNotNullOrEmpty()]
    [string]$Text,

    [Parameter(Position = 0, Mandatory, ParameterSetName = 'block')]
    [ValidateNotNullOrEmpty()]
    [Alias("tb")]
    [string[]]$TextBlock,

    # The character to use for the border. It must be a single character.
    [ValidateNotNullOrEmpty()]
    [alias("border")]
    [string]$Character = "*",

    # add blank lines before and after text
    [Switch]$InsertBlanks,

    # insert X number of tabs
    [int]$Tab = 0,

    [Parameter(HelpMessage = "Enter an ANSI escape sequence to color the border characters." )]
    [string]$ANSIBorder,

    [Parameter(HelpMessage = "Enter an ANSI escape sequence to color the text." )]
    [string]$ANSIText
  )

  Begin {
    # "Starting $($myinvocation.mycommand)" -Prefix begin | Write-Verbose
    $tabs = "`t" * $tab
    # "Using a tab of $tab" -Prefix BEGIN | Write-Verbose

    # "Using border character $Character" -Prefix begin | Write-Verbose
    $ansiClear = "$([char]0x1b)[0m"
    if ($PSBoundParameters.ContainsKey("ANSIBorder")) {
      # "Using an ANSI border Color" -Prefix Begin | Write-Verbose
      $Character = "{0}{1}{2}" -f $PSBoundParameters.ANSIBorder, $Character, $ansiClear
    }

    #define regex expressions to detect ANSI escapes. Need to subtract their
    #length from the string if used. Issue #79
    [regex]$ansiopen = "$([char]0x1b)\[\d+[\d;]+m"
    [regex]$ansiend = "$([char]0x1b)\[0m"
  }

  Process {

    if ($pscmdlet.ParameterSetName -eq 'single') {
      # "Processing '$text'"
      #get length of text
      $adjust = 0
      if ($ansiopen.IsMatch($text)) {
        $adjust += ($ansiopen.matches($text) | Measure-Object length -Sum).sum
        $adjust += ($ansiend.matches($text) | Measure-Object length -Sum).sum
        # "Adjusting text length by $adjust."
      }

      $len = $text.Length - $adjust
      if ($PSBoundParameters.ContainsKey("ANSIText")) {
        # "Using an ANSIText color"
        $text = "{0}{1}{2}" -f $PSBoundParameters.ANSIText, $text, $AnsiClear
      }
    } else {
      # "Processing text block"
      #test if text block is already using ANSI
      if ($ansiopen.IsMatch($TextBlock)) {
        # "Text block contains ANSI sequences"
        $txtarray | ForEach-Object -Begin { Set-Variable -Name tempLen -Value @() } -Process {
          $adjust = 0
          $adjust += ($ansiopen.matches($_) | Measure-Object length -Sum).sum
          $adjust += ($ansiend.matches($_) | Measure-Object length -Sum).sum
          # "Length detected as $($_.length)"
          # "Adding adjustment $adjust"
          $tempLen += $_.length - $adjust
        }
        $len = $tempLen | Sort-Object -Descending | Select-Object -First 1
      } elseif ($PSBoundparameters.ContainsKey("ANSIText")) {
        # "Using ANSIText for the block"
        $txtarray = $textblock.split("`n").Trim() | ForEach-Object { "{0}{1}{2}" -f $PSBoundParameters.ANSIText, $_, $AnsiClear }
        $len = ($txtarray | Sort-Object -Property length -Descending | Select-Object -First 1 -ExpandProperty length) - ($psboundparameters.ANSIText.length + 4)
      } else {
        # "Processing simple text block"
        $txtarray = $textblock.split("`n").Trim()
        $len = $txtarray | Sort-Object -Property length -Descending | Select-Object -First 1 -ExpandProperty length
      }
      # "Added $($txtarray.count) text block elements"
    }

    # "Using a length of $len"
    #define a horizontal line
    $hzline = $Character * ($len + 4)

    if ($pscmdlet.ParameterSetName -eq 'single') {
      # "Defining Single body"
      $body = "$tabs$Character $text $Character"
    } else {
      # "Defining Textblock body"
      [string[]]$body = $null
      foreach ($item in $txtarray) {
        if ($item) {
          # "$item [$($item.length)]"
        } else {
          # "detected blank line"
        }
        if ($ansiopen.IsMatch($item)) {
          $adjust = $len
          $adjust += ($ansiopen.matches($item) | Measure-Object length -Sum).sum
          $adjust += ($ansiend.matches($item) | Measure-Object length -Sum).sum
          # "Adjusting length to $adjust"
          $body += "$tabs$Character $(($item).PadRight($adjust)) $Character`r"
        } elseif ($PSBoundparameters.ContainsKey("ANSIText")) {
          #adjust the padding length to take the ANSI value into account
          $adjust = $len + ($psboundparameters.ANSIText.length + 4)
          # "Adjusting length to $adjust"
          $body += "$tabs$Character $(($item).PadRight($adjust)) $Character`r"
        } else {
          $body += "$tabs$Character $(($item).PadRight($len)) $Character`r"
        }
      }
    }
    # "Defining top border"
    [string[]]$out = "`n$tabs$hzline"
    $lines = $body.split("`n")
    # "Adding $($lines.count) lines" | Write-Verbose
    if ($InsertBlanks) {
      # "Prepending blank line"
      $out += "$tabs$character $((" ")*$len) $character"
    }
    foreach ($item in $lines ) {
      $out += $item
    }
    if ($InsertBlanks) {
      # "Appending blank line"
      $out += "$tabs$character $((" ")*$len) $character"
    }
    # "Defining bottom border"
    $out += "$tabs$hzline"
    $out
  }
}