custom/Invoke-RwPowerShellCommand.ps1

Function Invoke-RwPowerShellCommand {
    [cmdletbinding(DefaultParameterSetName = 'ByName')]
    param (
        [Parameter(
            ParameterSetName = 'ByName',
            Mandatory
        )]
        [Parameter(
            ParameterSetName = 'ByNameRaw',
            Mandatory
        )]
        [Alias('Name','AssetName')]
        [string]$RunnerName,

        [Parameter(
            ParameterSetName = 'ById',
            Mandatory
        )]
        [Parameter(
            ParameterSetName = 'ByIdRaw',
            Mandatory
        )]
        [Alias('Id','RunnerId')]
        [string]$AssetId,

        [Parameter(Mandatory)]
        [Alias('Command')]
        [scriptblock]$ScriptBlock,

        [switch]$PWSH,

        [switch]$LeaveJob,

        [Parameter(
            ParameterSetName = 'ById',
            Mandatory
        )]
        [Parameter(
            ParameterSetName = 'ByName',
            Mandatory
        )]
        [int]$SerializeDepth = 2,

        [Parameter(
            ParameterSetName = 'ById',
            Mandatory
        )]
        [Parameter(
            ParameterSetName = 'ByName',
            Mandatory
        )]
        [switch]$DefaultPropertiesOnly,

        [Parameter(
            ParameterSetName = 'ByIdRaw',
            Mandatory
        )]
        [Parameter(
            ParameterSetName = 'ByNameRaw',
            Mandatory
        )]
        [switch]$Raw
    )
    # Load the run command from the Action Repository
    $runCommand = Get-RwRepository -Name 'PowerShell:RunCommand'

    if ($null -ne $runCommand) {
        # If RunnerID is not passed, look it up
        if ($PSCmdlet.ParameterSetName -like 'ByName*') {

            $AssetId = (Get-RwRunnerByName -AssetName $RunnerName).AssetId
        }

        # Create a set to assign the job to
        $assignSet = New-RwSet

        # Add the runner to the Job
        Add-RwSetToSet -TargetSetId $assignSet -ObjectIds $AssetId | Out-Null

        # Generate a name, it should use Get-RwJobRandomJobName,
        # however that is currently bugged.
        $jobName = (Invoke-RestMethod -Headers @{Authorization = "Session $($env:RunwaySessionToken)"} -Uri 'https://portal.runway.host/api/v2/jobs/name' -Method Get)

        # Create the job
        $nj = New-RwJob -IsEnabled -IsHidden:$false -EndpointSetId $assignSet -Name $jobName -Schedule (New-RwJobScheduleObject -ScheduleType 'RunNow' -RepeatMinutes 0) -Actions @(
            @{
                RepositoryActionId = $runCommand.Id
                Settings = @{
                    Command = $ScriptBlock
                    PWSH = $PWSH.IsPresent
                    'Serialize Depth' = $SerializeDepth
                    'Default Properties Only' = $DefaultPropertiesOnly.IsPresent
                    'Debug' = $true
                    'Raw Output' = $Raw.IsPresent
                }
            }
        )
        
        # Wait for the job to complete
        $job = Get-RwJob -JobId $nj.JobId
        While($job.TotalEndpointsFinished -lt $job.TotalEndpointsAssigned) {
            Start-Sleep -Seconds 2
            $job = Get-RwJob -JobId $nj.JobId
        }

        # Once it completes, look up the thread id for the job and runner
        $completedThread = Get-RwJobThread -JobId $job.Id | Where-Object {$_.ProdigalObjectId -eq $AssetId}
        
        # With the thread ID, pull the thread log
        Get-RwJobThreadLastLog -ThreadId $completedThread.Id -OutFile .\rwtmp.txt

        if ($Raw.IsPresent) {
            # Get the contents
            Get-Content .\rwtmp.txt | Where-Object {$_ -notlike '# *'}
        } else {
            # Write the content to disk, it will be in CliXml format
            Get-Content .\rwtmp.txt | Where-Object {$_ -notlike '# *'} | Out-File .\results.xml -Force

            # Import the output
            Import-Clixml .\results.xml

            # Clean up XML file
            Remove-Item .\results.xml
        }

        # Clean up the files
        Remove-Item .\rwtmp.txt

        # Clean up the job
        if (-not $LeaveJob.IsPresent) {
            Remove-RwJob -JobId $nj.JobId | Out-Null
        }
    } else {
        Write-Warning "Unable to find 'PowerShell:RunCommand' action. Add the command to your Runway tenant and then retry."
    }
}