PSAnsibleHelperFunctions4Linux.psm1

function Exit-Json
{
<#
    .SYNOPSIS
        Helper function to convert a PowerShell object to JSON and output it, exiting
        the script
     
    .DESCRIPTION
        A detailed description of the Exit-Json function.
     
    .PARAMETER obj
        This is the object that you are object that you are passing. Typically this is the $results hash table.
     
    .EXAMPLE
        Exit-Json $result
     
    .NOTES
        Additional information about the function.
#>

    
    param
    (
        $obj
    )
    
    # If the provided $obj is undefined, define one to be nice
    If (-not $obj.GetType)
    {
        $obj = @{ }
    }
    
    if (-not $obj.ContainsKey('changed'))
    {
        Set-Attr -obj $obj -name "changed" -value $false
    }
    
    Write-Output $obj | ConvertTo-Json -Compress -Depth 99
    Exit
}

function Set-Attr
{
<#
    .SYNOPSIS
        Sets the attribute of a property
     
    .DESCRIPTION
        adds a value to the property of an object.
     
    .PARAMETER obj
        A description of the obj parameter.
     
    .PARAMETER name
        A description of the name parameter.
     
    .PARAMETER value
        A description of the value parameter.
     
    .EXAMPLE
                PS C:\> Set-Attr
     
    .NOTES
        Additional information about the function.
#>

    
    param
    (
        $obj,
        $name,
        $value
    )
    
    # If the provided $obj is undefined, define one to be nice
    If (-not $obj.GetType)
    {
        $obj = @{ }
    }
    
    Try
    {
        $obj.$name = $value
    }
    Catch
    {
        $obj | Add-Member -Force -MemberType NoteProperty -Name $name -Value $value
    }
}


function Fail-Json
{
<#
    .SYNOPSIS
        A brief description of the Fail-Json function.
     
    .DESCRIPTION
        A detailed description of the Fail-Json function.
     
    .PARAMETER obj
        This is the object you are passing in. Typically this is $results hsa the changed =$true/$false hashtable
     
    .PARAMETER message
        pass in a failed message that ansible will display.
     
    .EXAMPLE
                PS C:\> Fail-Json -obj $results -msg "This task failed"
     
    .NOTES
        Additional information about the function.
#>

    
    param
    (
        $obj,
        $message = $null
    )
    
    if ($obj -is [hashtable] -or $obj -is [psobject])
    {
        # Nothing to do
    }
    elseif ($obj -is [string] -and $message -eq $null)
    {
        # If we weren't given 2 args, and the only arg was a string,
        # create a new Hashtable and use the arg as the failure message
        $message = $obj
        $obj = @{ }
    }
    else
    {
        # If the first argument is undefined or a different type,
        # make it a Hashtable
        $obj = @{ }
    }
    
    # Still using Set-Attr for PSObject compatibility
    Set-Attr $obj "msg" $message
    Set-Attr $obj "failed" $true
    
    if (-not $obj.ContainsKey('changed'))
    {
        Set-Attr $obj "changed" $false
    }
    
    write-output $obj | ConvertTo-Json -Compress -Depth 99
    Exit 1
}

function Get-AnsibleParam
{
<#
    .SYNOPSIS
        This is equivalent to the param block of a PowerShell cmdlet.
     
    .DESCRIPTION
        This is how you will pass in the parameters from Yaml file to the powershell script.
     
    .PARAMETER obj
        A description of the obj parameter.
     
    .PARAMETER name
        name of the parameter in ansible yaml file
     
    .PARAMETER default
        the default if none given
     
    .PARAMETER resultobj
        A description of the resultobj parameter.
     
    .PARAMETER failifempty
        equivalent of mandatory
     
    .PARAMETER emptyattributefailmessage
        Custom messages for empty attributes
     
    .PARAMETER ValidateSet
        equivalent to PowerShell validateSet
     
    .PARAMETER ValidateSetErrorMessage
        custom error for validate set
     
    .PARAMETER type
        the type for the parameter.
        some examples are [string][int]
     
    .PARAMETER aliases
        The aliases for this parameter
     
    .EXAMPLE
                PS C:\> Get-AnsibleParam
     
    .NOTES
        Additional information about the function.
#>

    
    param
    (
        $obj,
        $name,
        $default = $null,
        $resultobj = @{ },
        $failifempty = $false,
        $emptyattributefailmessage,
        $ValidateSet,
        $ValidateSetErrorMessage,
        $type = $null,
        $aliases = @()
    )
    
    # Check if the provided Member $name or aliases exist in $obj and return it or the default.
    try
    {
        
        $found = $null
        # First try to find preferred parameter $name
        $aliases = @($name) + $aliases
        
        # Iterate over aliases to find acceptable Member $name
        foreach ($alias in $aliases)
        {
            if ($obj.ContainsKey($alias))
            {
                $found = $alias
                break
            }
        }
        
        if ($found -eq $null)
        {
            throw
        }
        $name = $found
        
        if ($ValidateSet)
        {
            
            if ($ValidateSet -contains ($obj.$name))
            {
                $value = $obj.$name
            }
            else
            {
                if ($ValidateSetErrorMessage -eq $null)
                {
                    #Auto-generated error should be sufficient in most use cases
                    $ValidateSetErrorMessage = "Get-AnsibleParam: Argument $name needs to be one of $($ValidateSet -join ",") but was $($obj.$name)."
                }
                Fail-Json -obj $resultobj -message $ValidateSetErrorMessage
            }
            
        }
        else
        {
            $value = $obj.$name
        }
        
    }
    catch
    {
        if ($failifempty -eq $false)
        {
            $value = $default
        }
        else
        {
            if (!$emptyattributefailmessage)
            {
                $emptyattributefailmessage = "Get-AnsibleParam: Missing required argument: $name"
            }
            Fail-Json -obj $resultobj -message $emptyattributefailmessage
        }
        
    }
    
    # If $value -eq $null, the parameter was unspecified by the user (deliberately or not)
    # Please leave $null-values intact, modules need to know if a parameter was specified
    # When $value is already an array, we cannot rely on the null check, as an empty list
    # is seen as null in the check below
    if ($value -ne $null -or $value -is [array])
    {
        if ($type -eq "path")
        {
            # Expand environment variables on path-type
            $value = Expand-Environment($value)
            # Test if a valid path is provided
            if (-not (Test-Path -IsValid $value))
            {
                $path_invalid = $true
                # could still be a valid-shaped path with a nonexistent drive letter
                if ($value -match "^\w:")
                {
                    # rewrite path with a valid drive letter and recheck the shape- this might still fail, eg, a nonexistent non-filesystem PS path
                    if (Test-Path -IsValid $(@(Get-PSDrive -PSProvider Filesystem)[0].Name + $value.Substring(1)))
                    {
                        $path_invalid = $false
                    }
                }
                if ($path_invalid)
                {
                    Fail-Json -obj $resultobj -message "Get-AnsibleParam: Parameter '$name' has an invalid path '$value' specified."
                }
            }
        }
        elseif ($type -eq "str")
        {
            # Convert str types to real Powershell strings
            $value = $value.ToString()
        }
        elseif ($type -eq "bool")
        {
            # Convert boolean types to real Powershell booleans
            $value = $value | ConvertTo-Bool
        }
        elseif ($type -eq "int")
        {
            # Convert int types to real Powershell integers
            $value = $value -as [int]
        }
        elseif ($type -eq "float")
        {
            # Convert float types to real Powershell floats
            $value = $value -as [float]
        }
        elseif ($type -eq "list")
        {
            if ($value -is [array])
            {
                # Nothing to do
            }
            elseif ($value -is [string])
            {
                # Convert string type to real Powershell array
                $value = $value.Split(",").Trim()
            }
            elseif ($value -is [int])
            {
                $value = @($value)
            }
            else
            {
                Fail-Json -obj $resultobj -message "Get-AnsibleParam: Parameter '$name' is not a YAML list."
            }
            # , is not a typo, forces it to return as a list when it is empty or only has 1 entry
            write-output $value
        }
    }
    
    Write-Output $value
}

#Alias Get-attr-->Get-AnsibleParam for backwards compat. Only add when needed to ease debugging of scripts
If (!(Get-Alias -Name "Get-attr" -ErrorAction SilentlyContinue)) {
    New-Alias -Name Get-attr -Value Get-AnsibleParam
}

# Helper filter/pipeline function to convert a value to boolean following current
# Ansible practices
# Example: $is_true = "true" | ConvertTo-Bool
Function ConvertTo-Bool {
    param (
        [parameter(valuefrompipeline = $true)]
        $obj
    )
    
    $boolean_strings = "yes", "on", "1", "true", 1
    $obj_string = [string]$obj
    
    if (($obj -is [boolean] -and $obj) -or $boolean_strings -contains $obj_string.ToLower()) {
        Write-Output $true
    }
    else {
        Write-Output $false
    }
}

Function Parse-Args($arguments, $supports_check_mode = $false) {
    $params = New-Object psobject
    If ($arguments.Length -gt 0) {
        $params = Get-Content $arguments[0] -raw | ConvertFrom-Json -AsHashtable
    }
    Else {
        $params = $complex_args
    }
    $check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
    If ($check_mode -and -not $supports_check_mode) {
        Exit-Json @{
            skipped = $true
            changed = $false
            msg     = "remote module does not support check mode"
        }
    }
    write-output $params
}

#Alias Get-attr-->Get-AnsibleParam for backwards compat. Only add when needed to ease debugging of scripts
If (!(Get-Alias -Name "Get-attr" -ErrorAction SilentlyContinue)) {
    New-Alias -Name Get-attr -Value Get-AnsibleParam
}

Export-ModuleMember -Function * -Alias *