PSPuppetOrchestrator.psm1

Function Get-PuppetJob {
    <#
    .SYNOPSIS
        Get details on a puppet job.
    .DESCRIPTION
        Get details on a puppet job.
    .PARAMETER ID
        The ID of the job.
    .PARAMETER Token
        The Puppet API orchestrator token.
    .PARAMETER Master
        The Puppet master.
    .EXAMPLE
        PS> Get-PuppetJob -Token $token -Master $master -ID 906
 
        description :
        report : @{id=https://puppet:8143/orchestrator/v1/jobs/906/report}
        name : 906
        events : @{id=https://puppet:8143/orchestrator/v1/jobs/906/events}
        command : task
        type : task
        state : failed
        nodes : @{id=https://puppet:8143/orchestrator/v1/jobs/906/nodes}
        status : {@{state=ready; enter_time=2019-09-04T16:50:09Z; exit_time=2019-09-04T16:50:10Z}, @{state=running; enter_time=2019-09-04T16:50:10Z; exit_time=2019-09-04T16:50:43Z}, @{state=failed; enter_time=2019-09-04T16:50:43Z; exit_time=}}
        id : https://puppet:8143/orchestrator/v1/jobs/906
        environment : @{name=production}
        options : @{description=; transport=pxp; noop=False; task=powershell_tasks::getkb; sensitive=System.Object[]; params=; scope=; environment=production}
        timestamp : 2019-09-04T16:50:43Z
        owner : @{email=; is_revoked=False; last_login=2019-09-04T16:48:50.049Z; is_remote=False; login=admin; is_superuser=True; id=42bf351c-f9ec-40af-84ad-e976fec7f4bd; role_ids=System.Object[]; display_name=Administrator; is_group=False}
        node_count : 3
        node_states : @{failed=1; finished=2}
    #>


    Param(
        [Parameter(Mandatory)]
        [int]$ID,
        [Parameter(Mandatory)]
        [string]$Token,
        [Parameter(Mandatory)]
        [string]$Master
    )

    $hoststr = "https://$master`:8143/orchestrator/v1/jobs/$id"
    $headers = @{'X-Authentication' = $Token}
    $result  = Invoke-RestMethod -Uri $hoststr -Method Get -Headers $headers
    $content = $result

    Write-Output $content
}

Function Get-PuppetJobReport {
    <#
    .SYNOPSIS
        Get the report for a given Puppet job.
    .DESCRIPTION
        Get the report for a given Puppet job.
    .PARAMETER ID
        The ID of the job.
    .PARAMETER Token
        The Puppet API orchestrator token.
    .PARAMETER Master
        The Puppet master.
    .EXAMPLE
        PS> Get-PuppetJobReport -Master $master -Token $token -ID 906
 
        node state start_timestamp finish_timestamp timestamp events
        ---- ----- --------------- ---------------- --------- ------
        den3w108r2psv2 failed 2019-09-04T16:50:10Z 2019-09-04T16:50:12Z 2019-09-04T16:50:12Z {}
        den3w108r2psv3 finished 2019-09-04T16:50:10Z 2019-09-04T16:50:42Z 2019-09-04T16:50:42Z {}
        den3w108r2psv4 finished 2019-09-04T16:50:10Z 2019-09-04T16:50:43Z 2019-09-04T16:50:43Z {}
    #>


    Param(
        [Parameter(Mandatory)]
        [int]$ID,
        [Parameter(Mandatory)]
        [string]$Token,
        [Parameter(Mandatory)]
        [string]$Master
    )

    $hoststr = "https://$master`:8143/orchestrator/v1/jobs/$id/report"
    $headers = @{'X-Authentication' = $Token}
    $result  = Invoke-RestMethod -Uri $hoststr -Method Get -Headers $headers
    $result.count
    foreach ($server in $result.report) {
        Write-Output $server
    }
}

Function Get-PuppetJobResults {
    <#
    .SYNOPSIS
        Returns Hello world
    .DESCRIPTION
        Returns Hello world
    .PARAMETER ID
        x
    .PARAMETER Token
        x
    .PARAMETER Master
        x
    .EXAMPLE
        PS> Get-HelloWorld
 
        Runs the command
    #>


    Param(
        [Parameter(Mandatory)]
        [int]$ID,
        [Parameter(Mandatory)]
        [string]$Token,
        [Parameter(Mandatory)]
        [string]$Master
    )

    $hoststr = "https://$master`:8143/orchestrator/v1/jobs/$id/nodes"
    $headers = @{'X-Authentication' = $Token}
    $result  = Invoke-RestMethod -Uri $hoststr -Method Get -Headers $headers
    Write-Output $result.items
}

Function Get-PuppetPCPNodeBrokerDetails {
    <#
    .SYNOPSIS
        Returns Hello world
    .DESCRIPTION
        Returns Hello world
    .PARAMETER Node
        x
    .PARAMETER Token
        x
    .PARAMETER Master
        x
    .EXAMPLE
        PS> Get-HelloWorld
 
        Runs the command
    #>


    Param(
        [Parameter(Mandatory)]
        [string]$Token,
        [Parameter(Mandatory)]
        [string]$Master,
        [Parameter(Mandatory)]
        [string]$Node
    )

    $hoststr = "https://$master`:8143/orchestrator/v1/inventory/$node"
    $headers = @{'X-Authentication' = $Token}
    $result  = Invoke-RestMethod -Uri $hoststr -Method Get -Headers $headers
    Write-Output $result
}

Function Get-PuppetTask {
    <#
    .SYNOPSIS
        Returns Hello world
    .DESCRIPTION
        Returns Hello world
    .PARAMETER Module
        x
    .PARAMETER Token
        x
    .PARAMETER Master
        x
    .PARAMETER Name
        x
    .EXAMPLE
        PS> Get-HelloWorld
 
        Runs the command
    #>


    Param(
        [Parameter(Mandatory)]
        [string]$Token,
        [Parameter(Mandatory)]
        [string]$Master,
        [Parameter()]
        [string]$Module,
        [Parameter(Mandatory)]
        [string]$Name
    )

    $hoststr = "https://$master`:8143/orchestrator/v1/tasks/$Module/$Name"
    $headers = @{'X-Authentication' = $Token}

    # try and get the task in it's standard form $moduleName/$taskName
    try {
        $result  = Invoke-RestMethod -Uri $hoststr -Method Get -Headers $headers -ErrorAction SilentlyContinue
    } catch {
        # try and get the task again assuming it's built in with a default task name of 'init' (e.g. reboot/init)
        try {
            $hoststr = "https://$master`:8143/orchestrator/v1/tasks/$name/init"
            $result  = Invoke-RestMethod -Uri $hoststr -Method Get -Headers $headers
        } catch {
            Write-Error $_.exception.message
        }
    }

    if ($result) {
        Write-Output $result
    }
}

Function Get-PuppetTasks {
    <#
    .SYNOPSIS
        Get a list of Puppet Tasks.
    .DESCRIPTION
        Get a list of Puppet Tasks.
    .PARAMETER Environment
        The environment to use.
    .PARAMETER Token
        The Puppet API orchestrator token.
    .PARAMETER Master
        The Puppet master.
    .EXAMPLE
        PS> Get-PuppetTasks -token $token -master $master
 
        id name permitted
        -- ---- ---------
        https://puppet:8143/orchestrator/v1/tasks/powershell_tasks/getkb powershell_tasks::getkb True
        https://puppet:8143/orchestrator/v1/tasks/powershell_tasks/account_audit powershell_tasks::account_audit True
        https://puppet:8143/orchestrator/v1/tasks/powershell_tasks/switch powershell_tasks::switch True
        https://puppet:8143/orchestrator/v1/tasks/powershell_tasks/ps1exec powershell_tasks::ps1exec True
        https://puppet:8143/orchestrator/v1/tasks/powershell_tasks/disablesmbv1 powershell_tasks::disablesmbv1 True
    #>


    Param(
        [Parameter(Mandatory)]
        [string]$token,
        [Parameter(Mandatory)]
        [string]$master,
        [Parameter()]
        [string]$environment='production'
    )
    $uri     = "https://$master`:8143/orchestrator/v1/tasks"
    $headers = @{'X-Authentication' = $Token}
    $body    = @{'environment' = $environment}
    $result  = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers -Body $body
    Write-Output $result.items
}

Function Invoke-PuppetTask {
    <#
    .SYNOPSIS
        Returns Hello world
    .DESCRIPTION
        Returns Hello world
    .PARAMETER Token
        The Puppet API orchestrator token.
    .PARAMETER Master
        x
    .PARAMETER Task
        x
    .PARAMETER Environment
        x
    .PARAMETER Parameters
        x
    .PARAMETER Description
        x
    .PARAMETER Scope
        x
    .PARAMETER ScopeType
        x
    .PARAMETER Wait
        x
    .EXAMPLE
        PS> Get-HelloWorld
 
        Runs the command
    #>


    Param(
        [Parameter(Mandatory)]
        [string]$Token,
        [Parameter(Mandatory)]
        [string]$Master,
        [Parameter(Mandatory)]
        [string]$Task,
        [Parameter()]
        [string]$Environment = 'production',
        [Parameter()]
        [PSCustomObject]$Parameters = @{},
        [Parameter()]
        [string]$Description = '',
        [Parameter(Mandatory)]
        [PSCustomObject[]]$Scope,
        [Parameter(Mandatory)]
        [ValidateSet('nodes')]
        [string]$ScopeType,
        [Parameter()]
        [int]$Wait
    )

    $req = [PSCustomObject]@{
        environment = $Environment
        task        = $Task
        params      = $Parameters
        description = $Description
        scope       = [PSCustomObject]@{
            $ScopeType  = $Scope
        }
    } | ConvertTo-Json

    $hoststr = "https://$master`:8143/orchestrator/v1/command/task"
    $headers = @{'X-Authentication' = $Token}

    $result  = Invoke-RestMethod -Uri $hoststr -Method Post -Headers $headers -Body $req
    $content = $result

    if ($wait) {
        # sleep 5s for the job to register
        Start-Sleep -Seconds 5

        $jobSplat = @{
            token = $Token
            master = $master
            id = $content.job.name
        }

        # create a timespan
        $timespan = New-TimeSpan -Seconds $Wait
        # start a timer
        $stopwatch = [diagnostics.stopwatch]::StartNew()

        # get the job state every 5 seconds until our timeout is met
        while ($stopwatch.elapsed -lt $timespan) {
            # options are new, ready, running, stopping, stopped, finished, or failed
            $job = Get-PuppetJob @jobSplat
            if (($job.State -eq 'stopped') -or ($job.State -eq 'finished') -or ($job.State -eq 'failed')) {
                Write-Output $job
                break
            }
            Start-Sleep -Seconds 5
        }
        if ($stopwatch.elapsed -ge $timespan) {
            Write-Error "Timeout of $wait`s has exceeded."
            break
        }
    } else {
        Write-Output $content.job
    }
}

Function Wait-PuppetNodePCPBroker {
    <#
    .SYNOPSIS
        Returns Hello world
    .DESCRIPTION
        Returns Hello world
    .PARAMETER Timeout
        x
    .PARAMETER Token
        x
    .PARAMETER Master
        x
    .PARAMETER Node
        x
    .EXAMPLE
        PS> Get-HelloWorld
 
        Runs the command
    #>


    Param(
        [Parameter(Mandatory)]
        [string]$Token,
        [Parameter(Mandatory)]
        [string]$Master,
        [Parameter(Mandatory)]
        [string]$Node,
        [Parameter()]
        [int]$Timeout = 300
    )

    $detailsSplat = @{
        token = $Token
        master = $master
        node = $node
    }

    # create a timespan
    $timespan = New-TimeSpan -Seconds $timeout
    # start a timer
    $stopwatch = [diagnostics.stopwatch]::StartNew()

    # get the broker status every 5 seconds until our timeout is met
    while ($stopwatch.elapsed -lt $timespan) {
        # get the broker status
        if (($one = Get-PuppetNodePCPBrokerDetails @detailsSplat).connected -eq $false) {
            # broker status is disconnected, sleep 5s and check agian to confirm not a blip or false positive
            Write-Verbose "Broker status is $($one.connected), (timeout: $($stopwatch.elapsed.TotalSeconds)s of $Timeout`s elapsed)."
            Write-Verbose "Sleping 5 seconds and checking again."
            Start-Sleep -Seconds 5
            if (($two = Get-PuppetNodePCPBrokerDetails @detailsSplat).connected -eq $false) {
                Write-Verbose "Broker status is still $($two.connected), (timeout: $($stopwatch.elapsed.TotalSeconds)s of $Timeout`s elapsed)."
                # broker status is disconnected, break out of the loop
                break
            }
        } else {
            Write-Verbose "Broker status is $($one.connected), (timeout: $($stopwatch.elapsed.TotalSeconds)s of $Timeout`s elapsed)."
        }
        Start-Sleep -Seconds 5
    }
    if ($stopwatch.elapsed -ge $timespan) {
        Write-Error "Timeout of $Timeout`s has exceeded."
        break
    }

    Write-Verbose "$Node broker status confirmed disconnected."

    # get the broker status every 5 seconds until our timeout is met
    while ($stopwatch.elapsed -lt $timespan) {
        # get the broker status
        if (($three = Get-PuppetNodePCPBrokerDetails @detailsSplat).connected -eq $true) {
            # broker status is connected, sleep 5s and check agian to confirm not a blip or false positive
            Write-Verbose "Broker status is $($three.connected), (timeout: $($stopwatch.elapsed.TotalSeconds)s of $Timeout`s elapsed)."
            Write-Verbose "Sleping 5 seconds and checking again."
            Start-Sleep -Seconds 5
            if (($four = Get-PuppetNodePCPBrokerDetails @detailsSplat).connected -eq $true) {
                Write-Verbose "Broker status is still $($four.connected), (timeout: $($stopwatch.elapsed.TotalSeconds)s of $Timeout`s elapsed)."
                # broker status is connected, break out of the loop
                break
            }
        } else {
            Write-Verbose "Broker status is $($three.connected), (timeout: $($stopwatch.elapsed.TotalSeconds)s of $Timeout`s elapsed)."
        }
        Start-Sleep -Seconds 5
    }
    if ($stopwatch.elapsed -ge $timespan) {
        Write-Error "Timeout of $Timeout`s has exceeded."
        break
    }

    Write-Verbose "$Node broker status confirmed connected."
}