Search code examples
powershellfunctionreturn

Pass multiple variables from function to use further in script


I am trying to create a variable of true/false within a function and then use that variable later in the script. My current function has a return which works, but i can not seem to understand how to return or create new object to pass multiple variables.

As the script works now, the function is called with a parameter of a tag name which calls an API call that retrieves JSON file and then parses through that file and performs a few steps. When I call the function I want it to return the HTML table as well as a true or false variable if the $values from the json contain anything below 1.

function Request-API {
    [CmdletBinding()]
    [OutputType([psobject])]
    param (
        $tagName
    )
    Invoke-WebRequest -Uri "***removed for company privacy*** -Headers $headers -OutFile $DataExplorerJson

    #Store API results as variable
    $json = Get-Content $DataExplorerJson -Raw  | ConvertFrom-Json
    
    #Check values and set $subjectCheck to TRUE if there are failures
    $values = @($json.result.data.values)
    foreach ($i in $values) {
        if ($i -lt 1) {
            $subjectCheck = $true
        } 
    } 
    Write-Output "SubjectCheck "$subjectCheck
    

    ###Create $report object of containing table data
    ## Retrives value status from JSON.  If greater than 1 sets to PASS
    $condition = '1'
    try {
        $report = $json.result.data | ForEach-Object {
            $status = 'FAIL'
            if ($_.values[0] -ge $condition) {
                $status = 'PASS'
            }
            #Adds synthetic monitor names and $values to object
            [pscustomobject]@{
                Application = $_.dimensionmap.PSObject.Properties.Match('*.name').Value
                Status      = $status
            }
        }
    }
    catch {
        ## Write-Output 'No failures occured'
    }
    
    #Convert report to HTML and add XML
    [xml]$fullTable = $report | Select-Object Application, Status | ConvertTo-Html -Fragment
    
    ##Set color for PASS & FAIL stastuses
    try {
        $fullTable.SelectNodes("/table/tr/td[text()='PASS']").SetAttribute('class', 'pass')
        $fullTable.SelectNodes("/table/tr/td[text()='FAIL']").SetAttribute('class', 'fail')
    }
    catch {
        ## Write-Output 'No failures occured'
    }
    return $fullTable
}

## Call function with $tag param
$medicalReview = 'Medical%20Review~'
$priorAuth = 'Prior%20Auth~'

$medicalReviewTable = Request-API $medicalReview
$subjectMR = $subjectCheck
Write-Host "subject check subjectMR: "$subjectMR
$priorAuthTable = Request-API $priorAuth
$subjectPA = $subjectCheck
Write-Host "subject check subjectPA: "$subjectPA

if($subjectMR -eq $true -or $subjectPA -eq $true) {
    $subject = 'Dynatrace Synthetic On Demand Monitoring Report - FAIL'
} else {
    $subject = 'Dynatrace Synthetic On Demand Monitoring Report - PASS'
}

The code starting with "#Check values and set $subjectCheck" is where the issue is. I know the $subjectCheck is not passing the variable.

I have also tried:

 $values = @($json.result.data.values)
    foreach ($i in $values) {
        if ($i -lt 1) {
            $subjectCheck = New-Object -Property $true -TypeName psobject
        } 
    } 
    Write-Output "SubjectCheck "$subjectCheck

I do not think I am fully understanding functions, but after so much reading I truly don't know how to handle this.


Solution

  • Output Stream

    One way to do it is to just send both objects to the output stream from the function, which effectively returns an array of values:

    function Get-TwoResults
    {
        write-output "one"
        write-output "two"
    }
    
    $results = Get-TwoResults
    $results[0] # displays "one"
    $results[1] # displays "two"
    

    You can also "unpack" the items in the return array into multiple variables like this:

    $first, $second = Get-TwoResults
    $first  # displays "one"
    $second # displays "two"
    

    See Assigning Multiple Vvariables for more details.

    Custom Objects

    Another option is to bundle the values into properties of a custom object:

    
    function Get-CustomObject
    {
        write-output [pscustomobject] @{
            "First"  = "one"
            "Second" = "two"
        }
    }
    
    $object = Get-CustomObject
    $object
    
    # displays:
    #
    # Name                           Value
    # ----                           -----
    # First                          one
    # Second                         two
    

    and you can access the properties like this:

    $object.First  # displays "one"
    $object.Second # displays "two"
    

    Write-Output

    Note that you don't specifically need to put the command name write-output in the above code samples - any uncaptured expression results are implicitly returned to the output stream as if you'd called write-output.

    The two samples below work just as well as the ones above:

    function Get-TwoResults
    {
        "one"
        "two"
    }
    
    function Get-CustomObject
    {
        [pscustomobject] @{
            "First"  = "one"
            "Second" = "two"
        }
    }
    

    Note also that return $x is functionally equivalent to write-output $x; return.