Private/Set-HDTBlockIndent.ps1

function Set-HDTBlockIndent {
    <#
        .SYNOPSIS
            Shifts a copied block to the indentation of where it is being
            pasted.
 
        .DESCRIPTION
            YAML IS WHITESPACE-SIGNIFICANT, so a block copied from inside a
            group and pasted beside a top-level step arrives two columns out -
            and the difference between that and a parse error is a couple of
            spaces the administrator cannot see.
 
            EVERY LINE SHIFTS BY THE SAME AMOUNT, which is what preserves the
            block's own internal shape: the properties stay indented relative to
            their dash line, and a comment above it stays aligned with it.
 
            THE SHIFT IS TAKEN FROM THE DASH LINE, not from the first line of
            the block. A block usually starts with a comment, and a comment may
            legally sit at any column; measuring from it would move the step to
            wherever the comment happened to be.
 
            IT NEVER SHIFTS A LINE LEFT PAST COLUMN ZERO. A block pasted from a
            deep group into a shallow one would otherwise produce negative
            indentation, which in practice means the line loses characters.
 
        .PARAMETER Block
            The copied lines.
 
        .PARAMETER Indent
            The column the dash line should end up at.
 
        .INPUTS
            None. This command does not accept pipeline input.
 
        .OUTPUTS
            System.String[]
 
        .EXAMPLE
            Set-HDTBlockIndent -Block $block -Indent 6
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',
        Justification = 'Returns reindented copies of in-memory lines; it changes no state.')]
    [CmdletBinding()]
    [OutputType([string[]])]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [AllowEmptyCollection()]
        [AllowEmptyString()]
        [string[]] $Block,

        [Parameter(Mandatory = $true, Position = 1)]
        [int] $Indent
    )

    Set-StrictMode -Version Latest
    $ErrorActionPreference = 'Stop'

    # The dash line is the block's anchor; a leading comment may sit anywhere.
    $current = -1

    foreach ($line in $Block) {
        if ($line -match '^(\s*)-\s+\S') {
            $current = $Matches[1].Length
            break
        }
    }

    if ($current -lt 0 -or $current -eq $Indent) {
        return [string[]] @($Block)
    }

    $shift = $Indent - $current
    $result = New-Object -TypeName System.Collections.ArrayList

    foreach ($line in $Block) {
        if ([string]::IsNullOrWhiteSpace($line)) {
            [void] $result.Add($line)
            continue
        }

        if ($shift -gt 0) {
            [void] $result.Add((' ' * $shift) + $line)
            continue
        }

        # Never past column zero: the line would start losing characters.
        $lead = 0
        if ($line -match '^(\s*)') { $lead = $Matches[1].Length }

        $take = [Math]::Min(-$shift, $lead)

        [void] $result.Add($line.Substring($take))
    }

    return [string[]] @($result)
}