Write-GitHubOutput.ps1

function Write-GitHubOutput
{
    <#
    .Synopsis
        Writes GitHub Output
    .Description
        Writes formal Output to a GitHub step.
 
        This output can be referenced in subsequent steps.
    .Example
        Write-GitHubOutput @{
            key = 'value'
        }
    .Example
        Get-Random -Minimum 1 -Maximum 10 | Write-GitHubOutput -Name RandomNumber
    .Link
        Write-GitHubError
    #>

    [OutputType([string])]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "",
        Justification="Directly outputs in certain scenarios")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("Test-ForUnusableFunction", "",
        Justification="Directly outputs in certain scenarios")]
    param(
    # The InputObject. Values will be converted to a JSON array.
    [Parameter(Mandatory,ValueFromPipeline)]
    [PSObject]
    $InputObject,

    # The Name of the Output. By default, 'Output'.
    [string]
    $Name = 'Output',

    # The JSON serialization depth. By default, 10 levels.
    [int]
    $Depth = 10
    )

    begin {
        $inQ    = [Collections.Queue]::new()
    }
    process {
        #region Output Dictionaries
        if ($InputObject -is [Collections.IDictionary]) {
            $gitOut =
                foreach ($kv in $InputObject.GetEnumerator()) {
                    "::set-output name=$($kv.Key)::$($kv.Value)"
                }

            if ($env:GITHUB_WORKFLOW -and $DebugPreference -eq 'SilentlyContinue') {
                Write-Host ($gitOut -join [Environment]::NewLine)
            } else {
                $gitOut
            }
        }
        #endregion Output Dictionaries
        #region Output Errors
        elseif ($InputObject -is [Management.Automation.ErrorRecord]) {
            $gitHubErrorParams = @{
                Message = $InputObject.Exception.Message
            }
            $stackTraceLine =
                @($InputObject.ScriptStackTrace -split 'at <ScriptBlock>,' -ne '' -match ':*line')[0]
            if ($stackTraceLine) {
                $stackTraceLineParts = @($stackTraceLine -split ':')
                $gitHubErrorParams.Line = $stackTraceLineParts[-1] -replace 'line' -replace '\s'

                $file = $stackTraceLineParts[0..($stackTraceLineParts.Count - 2)] -join ':'
                if ($file -notlike '*<*>*') {
                    $gitHubErrorParams.File = $file
                }

            }
            Write-GitHubError @gitHubErrorParams
        }
        #endregion Output Errors
        #region Output Warnings
        elseif ($InputObject -is [Management.Automation.WarningRecord])
        {
            Write-GitHubWarning -Message $InputObject.Message
        }
        #endregion Output Warnings
        #region Output Debug and Verbose
        elseif ($InputObject -is [Management.Automation.VerboseRecord] -or
            $InputObject -is [Management.Automation.DebugRecord])
        {
            Write-GitHubDebug -Message $InputObject.Message
        }
        #endregion Output Debug and Verbose
        #region Enqueue Remaining Input
        else
        {
            $inQ.Enqueue($InputObject)
        }
        #endregion Enqueue Remaining Input
    }

    end {
        $gitOut =
            if ($inQ.Count) {
                "::set-output name=$name::$($inQ.ToArray() | ConvertTo-Json -Compress -Depth $depth)"
                $inQ.Clear()
            }

        if ($gitOut) {
            if ($env:GITHUB_WORKFLOW -and $DebugPreference -eq 'SilentlyContinue') {
                Write-Host ($gitOut -join [Environment]::NewLine)
            } else {
                $gitOut
            }
        }
    }
}