PowervRA.psm1

<#
     _____ _____
    | __ \ | __ \ /\
    | |__) |____ _____ _ ____ _| |__) | / \
    | ___/ _ \ \ /\ / / _ \ '__\ \ / / _ / / /\ \
    | | | (_) \ V V / __/ | \ V /| | \ \ / ____ \
    |_| \___/ \_/\_/ \___|_| \_/ |_| \_\/_/ \_\
 
#>


# --- Clean up vRAConnection variable on module remove
$ExecutionContext.SessionState.Module.OnRemove = {

    Remove-Variable -Name vRAConnection -Force -ErrorAction SilentlyContinue

}
<#
    - Function: NewDynamicParam
#>


Function NewDynamicParam {
<#
    .SYNOPSIS
        Helper function to simplify creating dynamic parameters
     
    .DESCRIPTION
        Helper function to simplify creating dynamic parameters
 
        Example use cases:
            Include parameters only if your environment dictates it
            Include parameters depending on the value of a user-specified parameter
            Provide tab completion and intellisense for parameters, depending on the environment
 
        Please keep in mind that all dynamic parameters you create will not have corresponding variables created.
           One of the examples illustrates a generic method for populating appropriate variables from dynamic parameters
           Alternatively, manually reference $PSBoundParameters for the dynamic parameter value
 
    .NOTES
        Note: NewDynamicParam function from @PSCookieMonster https://github.com/RamblingCookieMonster/PowerShell/blob/master/New-DnamicParam.ps1
         
        Credit to http://jrich523.wordpress.com/2013/05/30/powershell-simple-way-to-add-dynamic-parameters-to-advanced-function/
            Added logic to make option set optional
            Added logic to add RuntimeDefinedParameter to existing DPDictionary
            Added a little comment based help
 
        Credit to BM for alias and type parameters and their handling
 
    .PARAMETER Name
        Name of the dynamic parameter
 
    .PARAMETER Type
        Type for the dynamic parameter. Default is string
 
    .PARAMETER Alias
        If specified, one or more aliases to assign to the dynamic parameter
 
    .PARAMETER ValidateSet
        If specified, set the ValidateSet attribute of this dynamic parameter
 
    .PARAMETER Mandatory
        If specified, set the Mandatory attribute for this dynamic parameter
 
    .PARAMETER ParameterSetName
        If specified, set the ParameterSet attribute for this dynamic parameter
 
    .PARAMETER Position
        If specified, set the Position attribute for this dynamic parameter
 
    .PARAMETER ValueFromPipelineByPropertyName
        If specified, set the ValueFromPipelineByPropertyName attribute for this dynamic parameter
 
    .PARAMETER HelpMessage
        If specified, set the HelpMessage for this dynamic parameter
     
    .PARAMETER DPDictionary
        If specified, add resulting RuntimeDefinedParameter to an existing RuntimeDefinedParameterDictionary (appropriate for multiple dynamic parameters)
        If not specified, create and return a RuntimeDefinedParameterDictionary (appropriate for a single dynamic parameter)
 
        See final example for illustration
 
    .EXAMPLE
         
        function Show-Free
        {
            [CmdletBinding()]
            Param()
            DynamicParam {
                $options = @( gwmi win32_volume | %{$_.driveletter} | sort )
                NewDynamicParam -Name Drive -ValidateSet $options -Positin 0 -Mandatory
            }
            begin{
                #have to manually populate
                $drive = $PSBoundParameters.drive
            }
            process{
                $vol = gwmi win32_volume -Filter "driveletter='$drive'"
                "{0:N2}% free on {1}" -f ($vol.Capacity / $vol.FreeSpace),$drive
            }
        } #Show-Free
 
        Show-Free -Drive <tab>
 
    # This example illustrates the use of NewDynamicParam to create a single dyamic parameter
    # The Drive parameter ValidateSet populates with all available volumes on the computer for handy tab completion / intellisense
 
    .EXAMPLE
 
    # I found many cases where I needed to add more than one dynamic parameter
    # The DPDictionary parameter lets you specify an existing dictionary
    # The block of code in the Begin block loops through bound parameters and defines variables if they don't exist
 
        Function Test-DynPar{
            [cmdletbinding()]
            param(
                [string[]]$x = $Null
            )
            DynamicParam
            {
                #Create the RuntimeDefinedParameterDictionary
                $Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
         
                NewDynamicParam -Name AlwaysParam -ValidateSet @( gwmi win32_volume | %{$_.driveletter} | sort ) -DPDictionry $Dictionary
 
                #Add dynamic parameters to $dictionary
                if($x -eq 1)
                {
                    NewDynamicParam -Name X1Param1 -ValidateSet 1,2 -mandatory -DPDictionry $Dictionary
                    NewDynamicParam -Name X1Param2 -DPDictionry $Dictionary
                    NewDynamicParam -Name X3Param3 -DPDictionary $Dictionary-Type DateTime
                }
                else
                {
                    NewDynamicParam -Name OtherParam1 -Mandatory -DPDictionry $Dictionary
                    NewDynamicParam -Name OtherParam2 -DPDictionry $Dictionary
                    NewDynamicParam -Name OtherParam3 -DPDictionary $Dictionary-Type DateTime
                }
         
                #return RuntimeDefinedParameterDictionary
                $Dictionary
            }
            Begin
            {
                #This standard block of code loops through bound parameters...
                #If no corresponding variable exists, one is created
                    #Get common parameters, pick out bound parameters not in that set
                    Function intTemp { [cmdletbinding()] param() }
                    $BoundKeys = $PSBoundParameters.keys | Where-Object { (get-command intTemp | select -ExpandProperty parameters).Keys -notcontains $_}
                    foreach($param in $BoundKeys)
                    {
                        if (-not ( Get-Variable -name $param -scope 0 -ErrorAction SilentlyContinue ) )
                        {
                            New-Variable -Name $Param -Value $PSBoundParameters.$param
                            Write-Verbose "Adding variable for dynamic parameter '$param' with value '$($PSBoundParameters.$param)'"
                        }
                    }
 
                #Appropriate variables should now be defined and accessible
                    Get-Variable -scope 0
            }
        }
 
    # This example illustrates the creation of many dynamic parameters using Nw-DynamicParam
        # You must create a RuntimeDefinedParameterDictionary object ($dictionary here)
        # To each NewDynamicParam call, add the -DPDictionary parameter pointing to this RuntimeDefinedParaeterDictionary
        # At the end of the DynamicParam block, return the RuntimeDefinedParameterDictionary
        # Initialize all bound parameters using the provided block or similar code
 
    .FUNCTIONALITY
        PowerShell Language
 
#>

param(
    
    [string]
    $Name,
    
    [System.Type]
    $Type = [string],

    [string[]]
    $Alias = @(),

    [string[]]
    $ValidateSet,
    
    [switch]
    $Mandatory,
    
    [string]
    $ParameterSetName="__AllParameterSets",
    
    [int]
    $Position,
    
    [switch]
    $ValueFromPipelineByPropertyName,
    
    [string]
    $HelpMessage,

    [validatescript({
        if(-not ( $_ -is [System.Management.Automation.RuntimeDefinedParameterDictionary] -or -not $_) )
        {
            Throw "DPDictionary must be a System.Management.Automation.RuntimeDefinedParameterDictionary object, or not exist"
        }
        $True
    })]
    $DPDictionary = $false
 
)
    #Create attribute object, add attributes, add to collection
        $ParamAttr = New-Object System.Management.Automation.ParameterAttribute
        $ParamAttr.ParameterSetName = $ParameterSetName
        if($mandatory)
        {
            $ParamAttr.Mandatory = $True
        }
        if($Position -ne $null)
        {
            $ParamAttr.Position=$Position
        }
        if($ValueFromPipelineByPropertyName)
        {
            $ParamAttr.ValueFromPipelineByPropertyName = $True
        }
        if($HelpMessage)
        {
            $ParamAttr.HelpMessage = $HelpMessage
        }
 
        $AttributeCollection = New-Object 'Collections.ObjectModel.Collection[System.Attribute]'
        $AttributeCollection.Add($ParamAttr)
    
    #param validation set if specified
        if($ValidateSet)
        {
            $ParamOptions = New-Object System.Management.Automation.ValidateSetAttribute -ArgumentList $ValidateSet
            $AttributeCollection.Add($ParamOptions)
        }

    #Aliases if specified
        if($Alias.count -gt 0) {
            $ParamAlias = New-Object System.Management.Automation.AliasAttribute -ArgumentList $Alias
            $AttributeCollection.Add($ParamAlias)
        }

 
    #Create the dynamic parameter
        $Parameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter -ArgumentList @($Name, $Type, $AttributeCollection)
    
    #Add the dynamic parameter to an existing dynamic parameter dictionary, or create the dictionary and add it
        if($DPDictionary)
        {
            $DPDictionary.Add($Name, $Parameter)
        }
        else
        {
            $Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
            $Dictionary.Add($Name, $Parameter)
            $Dictionary
        }
}

<#
    - Function: xRequires
#>


function xRequires {
<#
    .SYNOPSIS
    Checks the required API Version for the current function
 
    .DESCRIPTION
    Checks the required API Version for the current function
 
    .PARAMETER Version
    The API Version that the function supports.
 
    The version number passed to this parameter must be in the following format.. it can't be a single character.
 
    - 6.2.4
    - 7.0
    - 7.0.1
    - 7.1
    - 7.2
 
    .INPUTS
    System.Int
    System.Management.Automation.PSObject.
 
    .OUTPUTS
    None
 
    .EXAMPLE
 
    function Get-Example {
 
        # This function does not support API versions lower than Version 7
        xRequires -Version "7.0"
 
    }
 
#>


[CmdletBinding()][Alias("FunctionRequires")]
    Param (
        [Parameter(Mandatory=$true, Position=0)]
        [String]$Version
    )

    # --- Test for vRA API version
    if (-not $Global:vRAConnection){
        throw "vRA Connection variable does not exist. Please run Connect-vRAServer first to create it"
    }

    # --- Convert version strings to [version] objects
    $APIVersion = [version]$Global:vRAConnection.APIVersion
    $RequiredVersion = [version]$Version

    if ($APIVersion -lt $RequiredVersion) {
        $PSCallStack = Get-PSCallStack
        Write-Error -Message "$($PSCallStack[1].Command) is not supported with vRA API version $($Global:vRAConnection.APIVersion)"
        break
    }
}

<#
    - Function: Connect-vRAServer
#>


function Connect-vRAServer {
    <#
        .SYNOPSIS
        Connect to a vRA Server
 
        .DESCRIPTION
        Connect to a vRA Server and generate a connection object with Servername, Token etc
 
        .PARAMETER Server
        vRA Server to connect to
 
        .PARAMETER Username
        Username to connect with
        For domain accounts ensure to specify the Username in the format username@domain, not Domain\Username
 
        .PARAMETER Password
        Password to connect with
 
        .PARAMETER Credential
        Credential object to connect with
        For domain accounts ensure to specify the Username in the format username@domain, not Domain\Username
 
        .PARAMETER APIToken
        API Token to connect with
 
        .PARAMETER IgnoreCertRequirements
        Ignore requirements to use fully signed certificates
 
        .PARAMETER SslProtocol
        Alternative Ssl protocol to use from the default
        Requires vRA 7.x and above
        Windows PowerShell: Ssl3, Tls, Tls11, Tls12
        PowerShell Core: Tls, Tls11, Tls12
 
        .INPUTS
        System.String
        Switch
 
        .OUTPUTS
        System.Management.Automation.PSObject.
 
        .EXAMPLE
        $cred = Get-Credential
        Connect-vRAServer -Server vraappliance01.domain.local -Credential $cred
 
        .EXAMPLE
        $SecurePassword = ConvertTo-SecureString “P@ssword” -AsPlainText -Force
        Connect-vRAServer -Server vraappliance01.domain.local -Username TenantAdmin01 -Password $SecurePassword -IgnoreCertRequirements
 
        .EXAMPLE
        Connect-vRAServer -Server api.mgmt.cloud.vmware.com -APIToken 'CuIKrjQgI6htiyRgIyd0ZtQM91fqg6AQyQhwPFJYgzBsaIKxKcWHLAGk81kknulQ'
 
        .EXAMPLE
        Connect-vRAServer -Server vraappliance01.domain.local -APIToken 'CuIKrjQgI6htiyRgIyd0ZtQM91fqg6AQyQhwPFJYgzBsaIKxKcWHLAGk81kknulQ' -IgnoreCertRequirements
    #>

    [CmdletBinding(DefaultParameterSetName="Username")][OutputType('System.Management.Automation.PSObject')]

        Param (

            [parameter(Mandatory=$true)]
            [ValidateNotNullOrEmpty()]
            [String]$Server,

            [parameter(Mandatory=$true,ParameterSetName="Username")]
            [ValidateNotNullOrEmpty()]
            [String]$Username,

            [parameter(Mandatory=$true,ParameterSetName="Username")]
            [ValidateNotNullOrEmpty()]
            [SecureString]$Password,

            [Parameter(Mandatory=$true,ParameterSetName="Credential")]
            [ValidateNotNullOrEmpty()]
            [Management.Automation.PSCredential]$Credential,

            [parameter(Mandatory=$true,ParameterSetName="APIToken")]
            [ValidateNotNullOrEmpty()]
            [String]$APIToken,

            [parameter(Mandatory=$false)]
            [Switch]$IgnoreCertRequirements,

            [parameter(Mandatory=$false)]
            [ValidateSet('Ssl3', 'Tls', 'Tls11', 'Tls12')]
            [String]$SslProtocol
        )

        # --- Handle untrusted certificates if necessary
        $SignedCertificates = $true

        if ($PSBoundParameters.ContainsKey("IgnoreCertRequirements") ){

            if (!$IsCoreCLR) {

                if ( -not ("TrustAllCertsPolicy" -as [type])) {

                    Add-Type @"
                    using System.Net;
                    using System.Security.Cryptography.X509Certificates;
                    public class TrustAllCertsPolicy : ICertificatePolicy {
                        public bool CheckValidationResult(
                            ServicePoint srvPoint, X509Certificate certificate,
                            WebRequest request, int certificateProblem) {
                            return true;
                        }
                    }
"@

                }
                [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

            }

            $SignedCertificates = $false

        }

        # --- Security Protocol
        $SslProtocolResult = 'Default'

        if ($PSBoundParameters.ContainsKey("SslProtocol") ){

            if (!$IsCoreCLR) {

                $CurrentProtocols = ([System.Net.ServicePointManager]::SecurityProtocol).toString() -split ', '
                if (!($SslProtocol -in $CurrentProtocols)){

                    [System.Net.ServicePointManager]::SecurityProtocol += [System.Net.SecurityProtocolType]::$($SslProtocol)
                }
            }
            $SslProtocolResult = $SslProtocol
        }

        try {

            # --- if a refresh token is supplied, we use iaas login
            if ($PSBoundParameters.ContainsKey("APIToken")){
                # -- iaas login with refresh token
                $URI = "https://$($Server)/iaas/login"

                # --- Create Invoke-RestMethod Parameters
                $JSON = @{
                    refreshToken = $APIToken
                } | ConvertTo-Json
            } else {
                # -- Login with credentials
                $URI = "https://$($Server)/csp/gateway/am/api/login?access_token"

                # --- Convert Secure Credentials to a format for sending in the JSON payload
                if ($PSBoundParameters.ContainsKey("Credential")){

                    $Username = $Credential.UserName
                    $JSONPassword = $Credential.GetNetworkCredential().Password
                }

                if ($PSBoundParameters.ContainsKey("Password")){

                    $JSONPassword = (New-Object System.Management.Automation.PSCredential("username", $Password)).GetNetworkCredential().Password
                }

                # --- Test for a '\' in the username, e.g. DOMAIN\Username, not supported by the API
                if ($Username -match '\\'){

                    throw "The Username format DOMAIN\Username is not supported by the vRA REST API. Please use username@domain instead"
                }

                # --- Create Invoke-RestMethod Parameters
                $JSON = @{
                    username = $Username
                    password = $JSONPassword
                } | ConvertTo-Json
            }



            $Params = @{

                Method = "POST"
                URI = $URI
                Headers = @{
                    "Accept"="application/json";
                    "Content-Type" = "application/json";
                }
                Body = $JSON
            }

            if ((!$SignedCertificates) -and ($IsCoreCLR)) {

                $Params.Add("SkipCertificateCheck", $true)

            }

            if (($SslProtocolResult -ne 'Default') -and ($IsCoreCLR)) {

                $Params.Add("SslProtocol", $SslProtocol)

            }

            $Response = Invoke-RestMethod @Params

            if ('refresh_token' -in $Response.PSobject.Properties.Name) {
                $token = $Response.access_token
                $refreshToken = $Response.refresh_token
            }

            if ('token' -in $Response.PSobject.Properties.Name) {
                $token = $Response.token
                $refreshToken = $APIToken
            }

            # --- Create Output Object
            $Global:vRAConnection = [PSCustomObject] @{

                Server = "https://$($Server)"
                Token = $token
                RefreshToken = $refreshToken
                APIVersion = $Null
                SignedCertificates = $SignedCertificates
                SslProtocol = $SslProtocolResult
            }

            # --- Update vRAConnection with API version
            $Global:vRAConnection.APIVersion = (Get-vRAAPIVersion).APIVersion

        }
        catch [Exception]{

            throw

        }

        Write-Output $vRAConnection
    }



<#
    - Function: Disconnect-vRAServer
#>


function Disconnect-vRAServer {
<#
    .SYNOPSIS
    Disconnect from a vRA server
 
    .DESCRIPTION
    Disconnect from a vRA server by removing the authorization token and the global vRAConnection variable from PowerShell
 
    .EXAMPLE
    Disconnect-vRAServer
 
    .EXAMPLE
    Disconnect-vRAServer -Confirm:$false
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="High")]

    Param ()

    # --- Test for existing connection to vRA
    if (-not $Global:vRAConnection){

        throw "vRA Connection variable does not exist. Please run Connect-vRAServer first to create it"
    }

    if ($PSCmdlet.ShouldProcess($Global:vRAConnection.Server)){

        try {

            # --- Remove custom Security Protocol if it has been specified
            if ($Global:vRAConnection.SslProtocol -ne 'Default'){

                if (!$IsCoreCLR) {

                    [System.Net.ServicePointManager]::SecurityProtocol -= [System.Net.SecurityProtocolType]::$($Global:vRAConnection.SslProtocol)
                }
            }

        }
        catch [Exception]{

            throw

        }
        finally {

            Write-Verbose -Message "Removing vRAConnection global variable"
            Remove-Variable -Name vRAConnection -Scope Global -Force -ErrorAction SilentlyContinue
        }
    }
}

<#
    - Function: Invoke-vRARestMethod
#>


function Invoke-vRARestMethod {
<#
    .SYNOPSIS
    Wrapper for Invoke-RestMethod/Invoke-WebRequest with vRA specifics
 
    .DESCRIPTION
    Wrapper for Invoke-RestMethod/Invoke-WebRequest with vRA specifics
 
    .PARAMETER Method
    REST Method:
    Supported Methods: GET, POST, PUT,DELETE
 
    .PARAMETER URI
    API URI, e.g. /identity/api/tenants
 
    .PARAMETER Headers
    Optionally supply custom headers
 
    .PARAMETER Body
    REST Body in JSON format
 
    .PARAMETER OutFile
    Save the results to a file
 
    .PARAMETER WebRequest
    Use Invoke-WebRequest rather than the default Invoke-RestMethod
 
    .INPUTS
    System.String
    Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Invoke-vRARestMethod -Method GET -URI '/iaas/api/about'
 
    .EXAMPLE
    $JSON = @"
        {
            "name": "TestOnboardingPlan",
            "endpointId": "42fe38765a63bd755921a88814a14",
            "projectId": "9f732951-2279-422a-8045-9b254d427100"
        }
    "@
 
    Invoke-vRARestMethod -Method POST -URI '/relocation/onboarding/plan' -Body $JSON -WebRequest
#>

[CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true, ParameterSetName="Standard")]
        [Parameter(Mandatory=$true, ParameterSetName="Body")]
        [Parameter(Mandatory=$true, ParameterSetName="OutFile")]
        [ValidateSet("GET","POST","PUT","DELETE")]
        [String]$Method,

        [Parameter(Mandatory=$true, ParameterSetName="Standard")]
        [Parameter(Mandatory=$true, ParameterSetName="Body")]
        [Parameter(Mandatory=$true, ParameterSetName="OutFile")]
        [ValidateNotNullOrEmpty()]
        [String]$URI,

        [Parameter(Mandatory=$false, ParameterSetName="Standard")]
        [Parameter(Mandatory=$false, ParameterSetName="Body")]
        [Parameter(Mandatory=$false, ParameterSetName="OutFile")]
        [ValidateNotNullOrEmpty()]
        [System.Collections.IDictionary]$Headers,

        [Parameter(Mandatory=$false, ParameterSetName="Body")]
        [ValidateNotNullOrEmpty()]
        [String]$Body,

        [Parameter(Mandatory=$false, ParameterSetName="OutFile")]
        [ValidateNotNullOrEmpty()]
        [String]$OutFile,

        [Parameter(Mandatory=$false, ParameterSetName="Standard")]
        [Parameter(Mandatory=$false, ParameterSetName="Body")]
        [Parameter(Mandatory=$false, ParameterSetName="OutFile")]
        [Switch]$WebRequest
    )

    # --- Test for existing connection to vRA
    if (-not $Global:vRAConnection){

        throw "vRA Connection variable does not exist. Please run Connect-vRAServer first to create it"
    }

    # --- Create Invoke-RestMethod Parameters
    $FullURI = "$($Global:vRAConnection.Server)$($URI)"

    # --- Add default headers if not passed
    if (!$PSBoundParameters.ContainsKey("Headers")){

        $Headers = @{

            "Accept"="application/json";
            "Content-Type" = "application/json";
            "Authorization" = "Bearer $($Global:vRAConnection.Token)";
        }
    }

    # --- Set up default parmaeters
    $Params = @{

        Method = $Method
        Headers = $Headers
        Uri = $FullURI
    }

    if ($PSBoundParameters.ContainsKey("Body")) {

        $Params.Add("Body", $Body)

        # --- Log the payload being sent to the server
        Write-Debug -Message $Body

    } elseif ($PSBoundParameters.ContainsKey("OutFile")) {

        $Params.Add("OutFile", $OutFile)

    }

    # --- Support for PowerShell Core certificate checking
    if (!($Global:vRAConnection.SignedCertificates) -and ($IsCoreCLR)) {

        $Params.Add("SkipCertificateCheck", $true);
    }

    # --- Support for PowerShell Core SSL protocol checking
    if (($Global:vRAConnection.SslProtocol -ne 'Default') -and ($IsCoreCLR)) {

        $Params.Add("SslProtocol", $Global:vRAConnection.SslProtocol);
    }

    try {

        # --- Use either Invoke-WebRequest or Invoke-RestMethod
        if ($PSBoundParameters.ContainsKey("WebRequest")) {

            Invoke-WebRequest @Params
        }
        else {

            Invoke-RestMethod @Params
        }
    }
    catch {

        throw $_
    }
    finally {

        if (!$IsCoreCLR) {

            <#
                Workaround for bug in Invoke-RestMethod. Thanks to the PowerNSX guys for pointing this one out
                https://bitbucket.org/nbradford/powernsx/src
            #>

            $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($FullURI)
            $ServicePoint.CloseConnectionGroup("") | Out-Null
        }
    }
}

<#
    - Function: Get-vRAAPIVersion
#>


function Get-vRAAPIVersion {
<#
    .SYNOPSIS
    Retrieve vRA API version information
 
    .DESCRIPTION
    Retrieve vRA API version information
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vRAAPIVersion
 
#>

[CmdletBinding()][OutputType('System.Management.Automation.PSObject')]

    Param ()

    try {

        $URI = "/iaas/api/about"
        $Response = Invoke-vRARestMethod -URI $URI -Method GET

        [pscustomobject] @{

            APIVersion = $Response.latestApiVersion
            SupportedAPIs = $Response.supportedApis.apiversion
        }
    }
    catch [Exception]{

        throw
    }
}

<#
    - Function: Get-vRACloudAccount
#>


function Get-vRACloudAccount {
<#
    .SYNOPSIS
    Get a vRA Cloud Account.
 
    .DESCRIPTION
    Get a vRA Cloud Account.
 
    .PARAMETER Id
    The id of the Cloud Account
 
    .PARAMETER Name
    The name of the Cloud Account
 
    .PARAMETER Type
    Cloud Account Type, e.g. vSphere, Azure, AWS, GCP etc
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Get-vRACloudAccount
 
    .EXAMPLE
    Get-vRACloudAccount -Id d6f8b87ba95ab675597c97eefdd9c
 
    .EXAMPLE
    Get-vRACloudAccount -Name vSphere_test
 
    .EXAMPLE
    Get-vRACloudAccount -Type vSphere
 
#>

[CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name,

        [Parameter(Mandatory=$false)]
        [ValidateSet('azure','aws','gcp','nsx-t','nsx-v','vmc','vsphere')]
        [String]$Type
    )

    Begin {
        $APIUrl = '/iaas/cloud-accounts'

        if ($PSBoundParameters.ContainsKey('Type')){

            $APIUrl = $APIUrl + "-$Type"
        }

        function CalculateOutput {

            if ($Type){

                $CloudAccountType = $Type
            }
            else {

                $CloudAccountType = $CloudAccount.cloudAccountType
            }

            [PSCustomObject] @{

                Name = $CloudAccount.name
                Description = $CloudAccount.description
                Id = $CloudAccount.id
                CloudAccountType = $CloudAccountType
                EnabledRegionIds = $CloudAccount.enabledRegionIds
                CustomProperties = $CloudAccount.customProperties
                OrganizationId = $CloudAccount.organizationId
                Links = $CloudAccount._links
            }
        }
    }

    Process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Cloud Account by id
                'ById' {

                    foreach ($CloudAccountId in $Id) {

                        $URI = "$APIUrl/$($CloudAccountId)"

                        $CloudAccount = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        CalculateOutput
                    }

                    break
                }
                # --- Get Cloud Account by name
                'ByName' {

                    $URI = $APIUrl

                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($CloudAccountName in $Name) {

                        $CloudAccount = $Response.content | Where-Object {$_.name -eq $CloudAccountName}

                        if (!$CloudAccount) {

                            throw "Could not find Cloud Account with name: $($CloudAccountName)"

                        }

                        CalculateOutput
                    }

                    break
                }
                # --- No parameters passed so return all Cloud Accounts
                'Standard' {

                    $URI = $APIUrl

                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($CloudAccount in $Response.content) {

                        CalculateOutput
                    }
                }
            }
        }
        catch [Exception]{

            throw
        }
    }

    End {

    }
}

<#
    - Function: Get-vRACloudZone
#>


function Get-vRACloudZone {
<#
    .SYNOPSIS
    Get a vRA Cloud Zone
 
    .DESCRIPTION
    Get a vRA Cloud Zone
 
    .PARAMETER Id
    The ID of the Cloud Zone
 
    .PARAMETER Name
    The Name of the Cloud Zone
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Get-vRACloudZone
 
    .EXAMPLE
    Get-vRACloudZone -Id '3492a6e8-r5d4-1293-b6c4-39037ba693f9'
 
    .EXAMPLE
    Get-vRACloudZone -Name 'TestCloudZone'
 
#>

[CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name
    )

    begin {
        $APIUrl = '/iaas/zones'

        function CalculateOutput {

            [PSCustomObject] @{

                Name = $CloudZone.name
                Description = $CloudZone.description
                Id = $CloudZone.id
                PlacementPolicy = $CloudZone.placementPolicy
                Tags = $CloudZone.tags
                TagsToMatch = $CloudZone.tagsToMatch
                CustomProperties = $CloudZone.customProperties
                Folder = $CloudZone.folder
                OrganizationId = $CloudZone.organizationId
                Links = $CloudZone._links
                UpdatedAt = $CloudZone.updatedAt
            }
        }
    }

    process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Cloud Zone by Id
                'ById' {

                    foreach ($CloudZoneId in $Id){

                        $URI = "$($APIUrl)?`$filter=id eq '$($CloudZoneId)'"
                        $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        foreach ($CloudZone in $Response.content) {

                            CalculateOutput
                        }
                    }

                    break
                }
                # --- Get Cloud Zone by Name
                'ByName' {

                    foreach ($CloudZoneName in $Name){

                        $URI = "$($APIUrl)?`$filter=name eq '$($CloudZoneName)'"
                        $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        foreach ($CloudZone in $Response.content){

                            CalculateOutput
                        }
                    }

                    break
                }
                # --- No parameters passed so return all Cloud Zones
                'Standard' {

                    $URI = $APIUrl
                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($CloudZone in $Response.content){

                        CalculateOutput
                    }
                }
            }
        }
        catch [Exception]{

            throw
        }
    }

    end {

    }
}

<#
    - Function: Get-vRAMachine
#>


function Get-vRAMachine {
<#
    .SYNOPSIS
    Retrieve vRA Machine(s) depending on input
 
    .DESCRIPTION
    Retrieve a list of vRA Machines or a single machine depending on input
 
    .PARAMETER Id
    The ID of the vRA Machine
 
    .PARAMETER Name
    The Name of the vRA Machine
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vRAMachine
 
    .EXAMPLE
    Get-vRAMachine -Id 'b1dd48e71d74267559bb930934470'
 
    .EXAMPLE
    Get-vRAMachine -Name 'iaas01'
 
#>

[CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name

    )
    Begin {

        $APIUrl = "/iaas/api/machines"

        function CalculateOutput {

            foreach ($Record in $Response.content) {
                [PSCustomObject]@{
                    Name = $Record.name
                    PowerState = $Record.powerState
                    IPAddress = $Record.address
                    ExternalRegionId = $Record.externalRegionId
                    CloudAccountIDs = $Record.cloudAccountIds
                    ExternalId = $Record.externalId
                    Id = $Record.id
                    DateCreated = $Record.createdAt
                    LastUpdated = $Record.updatedAt
                    OrganizationId = $Record.organizationId
                    Properties = $Record.customProperties
                }
            }
        }
    }
    Process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Machine by its id
                'ById' {
                    foreach ($machineId in $Id) {
                        $Response = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=id eq '$machineId'" -Method GET
                        CalculateOutput
                    }

                    break
                }

                # --- Get Machine by its name
                'ByName' {
                    foreach ($machineName in $Name) {
                        $Response = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machineName'" -Method GET
                        CalculateOutput
                    }

                    break
                }

                # --- No parameters passed so return all machines
                'Standard' {
                    $Response = Invoke-vRARestMethod -URI $APIUrl -Method GET
                    CalculateOutput
                }

            }


        }
        catch [Exception]{

            throw
        }
    }
    End {

    }
}


<#
    - Function: Get-vRAMachineDisk
#>


function Get-vRAMachineDisk {
<#
    .SYNOPSIS
    Retrieve a vRA Machine's Disks
 
    .DESCRIPTION
    Retrieve the disks for a vRA Machine
 
    .PARAMETER Id
    The ID of the vRA Machine
 
    .PARAMETER Name
    The Name of the vRA Machine
 
    .PARAMETER DiskId
    The Id of the individual Disk to retrieve
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vRAMachineDisk -Id 'b1dd48e71d74267559bb930934470'
 
    .EXAMPLE
    Get-vRAMachineDisk -Name 'iaas01'
 
    .EXAMPLE
    GET-vRAMachineDisk -Name 'iaas01' -DiskId b1dd48e71d74267559bb930919aa8,b1dd48e71d74267559bb930915840
 
#>

[CmdletBinding(DefaultParameterSetName="ByName")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String[]]$DiskId

    )
    Begin {

        $APIUrl = "/iaas/api/machines"

        function CalculateOutput {

            # --- The output comes in two flavors, a list or a single item, we are checking for list here
            if ($Response.content) {
                foreach ($Record in $Response.content) {
                    [PSCustomObject]@{
                        Name = $Record.name
                        Status = $Record.status
                        Owner = $Record.owner
                        ExternalRegionId = $Record.externalRegionId
                        ExternalZoneId = $Record.externalZoneId
                        Description = $Record.description
                        Tags = $Record.tags
                        CapacityInGB = $Record.capacityInGB
                        CloudAccountIDs = $Record.cloudAccountIds
                        ExternalId = $Record.externalId
                        Id = $Record.id
                        DateCreated = $Record.createdAt
                        LastUpdated = $Record.updatedAt
                        OrganizationId = $Record.orgId
                        Properties = $Record.customProperties
                        ProjectId = $Record.projectId
                        Persistent = $Record.persistent
                    }
                }
            } else {
                [PSCustomObject]@{
                    Name = $Response.name
                    Status = $Response.status
                    Owner = $Response.owner
                    ExternalRegionId = $Response.externalRegionId
                    ExternalZoneId = $Response.externalZoneId
                    Description = $Response.description
                    Tags = $Response.tags
                    CapacityInGB = $Response.capacityInGB
                    CloudAccountIDs = $Response.cloudAccountIds
                    ExternalId = $Response.externalId
                    Id = $Response.id
                    DateCreated = $Response.createdAt
                    LastUpdated = $Response.updatedAt
                    OrganizationId = $Response.orgId
                    Properties = $Response.customProperties
                    ProjectId = $Response.projectId
                    Persistent = $Response.persistent
                }
            }

        }
    }
    Process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Machine by its id
                'ById' {

                    # --- Check to see if the DiskId's were optionally present
                    if ($DiskId) {

                        foreach($disk in $DiskId) {

                            $Response = Invoke-vRARestMethod -URI "$APIUrl`/$Id`/disks`/$disk" -Method GET

                            CalculateOutput

                        }

                    } else {

                        $Response = Invoke-vRARestMethod -URI "$APIUrl`/$Id`/disks" -Method GET

                        CalculateOutput

                    }

                    break
                }

                # --- Get Machine by its name
                # --- Will need to retrieve the machine first, then use ID to get final output
                'ByName' {

                    $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$Name'`&`$select=id" -Method GET
                    $machineId = $machineResponse.content[0].id

                    # --- Check to see if the DiskId's were optionally present
                    if ($DiskId) {

                        foreach($disk in $DiskId) {

                            $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId`/disks`/$disk" -Method GET

                            CalculateOutput

                        }


                    } else {

                        $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId`/disks" -Method GET

                        CalculateOutput

                    }


                    break
                }

            }

        }
        catch [Exception]{

            throw
        }
    }
    End {

    }
}


<#
    - Function: Get-vRAProject
#>


function Get-vRAProject {
<#
    .SYNOPSIS
    Get a vRA Project
 
    .DESCRIPTION
    Get a vRA Project
 
    .PARAMETER Id
    The ID of the Project
 
    .PARAMETER Name
    The Name of the Project
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Get-vRAProject
 
    .EXAMPLE
    Get-vRAProject -Id '3492a6e8-4e70-1293-b6c4-39037ba693f9'
 
    .EXAMPLE
    Get-vRAProject -Name 'Test Project'
 
#>

[CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name
    )

    begin {
        $APIUrl = '/iaas/projects'

        function CalculateOutput {

            [PSCustomObject] @{

                Name = $Project.name
                Description = $Project.description
                Id = $Project.id
                Administrators = $Project.administrators
                Members = $Project.members
                Viewers = $Project.viewers
                Zones = $Project.zones
                SharedResources = $Project.sharedResources
                OperationTimeout = $Project.operationTimeout
                OrganizationId = $Project.organizationId
                Links = $Project._links
            }
        }
    }

    process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Project by id
                'ById' {

                    foreach ($ProjectId in $Id){

                        $URI = "$($APIUrl)?`$filter=id eq '$($ProjectId)'"
                        $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        foreach ($Project in $Response.content) {

                            CalculateOutput
                        }
                    }

                    break
                }
                # --- Get Project by name
                'ByName' {

                    foreach ($ProjectName in $Name){

                        $URI = "$($APIUrl)?`$filter=name eq '$($ProjectName)'"
                        $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        foreach ($Project in $Response.content){

                            CalculateOutput
                        }
                    }

                    break
                }
                # --- No parameters passed so return all Projects
                'Standard' {

                    $URI = $APIUrl
                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($Project in $Response.content){

                        CalculateOutput
                    }
                }
            }
        }
        catch [Exception]{

            throw
        }
    }

    end {

    }
}

<#
    - Function: Get-vRARequest
#>


function Get-vRARequest {
    <#
        .SYNOPSIS
        Retrieve a vRA Request
 
        .DESCRIPTION
        Retrieve a vRA Request or list of requests
 
        .PARAMETER RequestId
        Optional - the id of the request you would like to view the detials
 
        .OUTPUTS
        System.Management.Automation.PSObject.
 
        .EXAMPLE
        Get-vRARequest
 
        .EXAMPLE
        Get-vRARequest -RequestId '305337a3-bb92-4638-a618-bf31e8cd1785'
 
    #>

    [CmdletBinding()][OutputType('System.Management.Automation.PSObject')]

        Param (

            [Parameter(Mandatory=$false, ParameterSetName="ById")]
            [ValidateNotNullOrEmpty()]
            [String[]]$RequestId

        )
        Begin {

            $APIUrl = "/iaas/api/request-tracker"

            function CalculateOutput {

                if ($Response.content) {
                    foreach ($Record in $Response.content) {
                        [PSCustomObject]@{
                            Name = $Record.name
                            Progress = $Record.progress
                            Id = $Record.id
                            Status = $Record.status
                            Message = $Record.message
                            Resources = $Record.resources
                        }
                    }
                } else {
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Id = $Response.id
                        Status = $Response.status
                        Message = $Response.message
                        Resources = $Response.resources
                    }
                }
            }
        }
        Process {

            try {

                switch ($PsCmdlet.ParameterSetName) {

                    # --- Get Machine by its id
                    'ById' {

                        # --- Check to see if the DiskId's were optionally present
                        $Response = Invoke-vRARestMethod -URI "$APIUrl/$RequestId" -Method GET

                        CalculateOutput

                        break
                    }

                    default {
                        # --- Check to see if the DiskId's were optionally present
                        $Response = Invoke-vRARestMethod -URI "$APIUrl" -Method GET

                        CalculateOutput

                        break
                    }

                }
            }
            catch [Exception]{

                throw
            }
        }
        End {

        }
    }


<#
    - Function: New-vRACloudAccountAzure
#>


function New-vRACloudAccountAzure {
<#
    .SYNOPSIS
    Create a vRA Cloud Account for Azure
 
    .DESCRIPTION
    Create a vRA Cloud Account for Azure
 
    .PARAMETER Name
    The name of the Cloud Account for Azure
 
    .PARAMETER Description
    A description of the Cloud Account for Azure
 
    .PARAMETER SubscriptionId
    Azure SubscriptionId
 
    .PARAMETER TenantId
    Azure TenantId
 
    .PARAMETER ClientApplicationId
    Azure ClientApplicationId
 
    .PARAMETER ClientApplicationSecretKey
    Azure ClientApplicationSecretKey
 
    .PARAMETER RegionIds
    Azure RegionIds to enable
 
    .PARAMETER CreateDefaultZones
    Enable CreateDefaultZones
 
    .PARAMETER JSON
    A JSON string with the body payload
 
    .INPUTS
    System.String
    System.Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    New-vRACloudAccountAzure -Name "Azure Test" -SubscriptionId "7326edb0-1234-012e-22d8-76f9faf6982" -TenantId "e7c5cdf4-21d1-312e-bddb-8765949cfdab" -ClientApplicationId "123e710b-4e10-33dc-b9b2-de3d9b1fe234" -ClientApplicationSecretKey "X9Y;bYRpe:eds-TY[blCB1he6PmarC1W" -RegionIds "northeurope","japaneast"
 
    .EXAMPLE
    $JSON = @"
 
        {
            "name": "Azure Test",
            "description": "Azure Test",
            "subscriptionId": "7326edb0-1234-012e-22d8-76f9faf6982",
            "tenantId": "e7c5cdf4-21d1-312e-bddb-8765949cfdab",
            "clientApplicationId": "123e710b-4e10-33dc-b9b2-de3d9b1fe234",
            "clientApplicationSecretKey": "X8Y:bYRpe:wzW-FC[blCB1he7PmarC0W",
            "regionIds": [ "northeurope","japaneast" ],
            "createDefaultZones": false
        }
"@
 
    $JSON | New-vRACloudAccountAzure
 
 
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low",DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$SubscriptionId,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$TenantId,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$ClientApplicationId,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$ClientApplicationSecretKey,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String[]]$RegionIds,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [Switch]$CreateDefaultZones,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="JSON")]
        [ValidateNotNullOrEmpty()]
        [String]$JSON

    )

    begin {
        if ($PSBoundParameters.ContainsKey("CreateDefaultZones")) {

            $CreateDefaultZonesStatus = 'true'
        }
        else {

            $CreateDefaultZonesStatus = 'false'
        }
    }

    process {

            if ($PSBoundParameters.ContainsKey("JSON")) {

                $Data = ($JSON | ConvertFrom-Json)

                $Body = $JSON
                $Name = $Data.name
            }
            else {

                # Format RegionIds with surrounding quotes and join into single string
                $RegionIdsAddQuotes = $RegionIDs | ForEach-Object {"`"$_`""}
                $RegionIdsFormatForBodyText = $RegionIdsAddQuotes -join ","

                $Body = @"
                    {
                        "name": "$($Name)",
                        "description": "$($Description)",
                        "subscriptionId": "$($SubscriptionId)",
                        "tenantId": "$($TenantId)",
                        "clientApplicationId": "$($ClientApplicationId)",
                        "clientApplicationSecretKey": "$($ClientApplicationSecretKey)",
                        "regionIds": [ $($RegionIdsFormatForBodyText) ],
                        "createDefaultZones": $($CreateDefaultZonesStatus)
                    }
"@

            }

        # --- Create new Azure Cloud Account
        try {
            if ($PSCmdlet.ShouldProcess($Name)){

                $URI = "/iaas/api/cloud-accounts-azure"
                $CloudAccount = Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                [PSCustomObject] @{

                    Name = $CloudAccount.name
                    Description = $CloudAccount.description
                    Id = $CloudAccount.id
                    CloudAccountType = 'azure'
                    SubscriptionId = $CloudAccount.subscriptionId
                    TenantId = $CloudAccount.tenantId
                    ClientApplicationId = $CloudAccount.clientApplicationId
                    EnabledRegionIds = $CloudAccount.enabledRegionIds
                    CustomProperties = $CloudAccount.customProperties
                    OrganizationId = $CloudAccount.organizationId
                    Links = $CloudAccount._links
                }
            }
        }
        catch [Exception] {

            throw
        }
    }
    end {

    }
}

<#
    - Function: New-vRACloudAccountGCP
#>


function New-vRACloudAccountGCP {
<#
    .SYNOPSIS
    Create a vRA Cloud Account for GCP
 
    .DESCRIPTION
    Create a vRA Cloud Account for GCP
 
    .PARAMETER Name
    The name of the Cloud Account for GCP
 
    .PARAMETER Description
    A description of the Cloud Account for GCP
 
    .PARAMETER ProjectId
    GCP Project Id
 
    .PARAMETER PrivateKeyId
    GCP Private Key Id
 
    .PARAMETER PrivateKey
    GCP Private Key
 
    .PARAMETER ClientEmail
    GCP Client Email
 
    .PARAMETER RegionIds
    GCP RegionIds to enable
 
    .PARAMETER CreateDefaultZones
    Enable CreateDefaultZones
 
    .PARAMETER JSON
    A JSON string with the body payload
 
    .INPUTS
    System.String
    System.Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    $privateKey = @"
-----BEGIN PRIVATE KEY-----
\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDbw8OMwHfait
cx\nKRqp7k2IppvEyuKTPPCNygZvb9HZ6LWV84GWt+RLJ+k5ZmhJ9254qNcV5RUn
sKcF\nhLPD1IPPOGlLTUZ492lH+3k6Uh3RxoGo2fdOuc1SVa/GXREXB0KXj5lYYw
Vjvsu/\n5QYUWwJbUSVd52Q1O4d0toezA/zw54NM5Ijv6P1J2bJ7szODCbh7obb5
J7vtsjfi\n6cik3frRaf13yX/GGghPXOockJ3s7MM4rgfJHSHuQVWOkPaJPiGFd2
d4XMpizAU2\n2hMGbFiAmONgl2HPaw3mqEP3owv1F7ZQ0TWUB1iq3T8xddkacsmB
hyzL4KgPKocR\ng6fh3sjJAgMBAAECggEAFYn+FkM96/w8I5wW+i06SaikrzjAVL
R+EjOJBm6D95LM\ni1YaryI2XJxciizsj0VSPT61F/cEKAfzEsIjGVAwnAR4I3J/
M/dxyOWPh+UI+ai2\nSA2W5M8mncl6qRsxg9uJDhA7tBM+cbx/PT9N5XxXAoq1Oh
sl8eaz+78xFR1Qsu6b\nSwAmL6I2iRR/qijsGYPPyKruEZU3AZg+OETgoHe97F/i
T/dXyIh2YAtaC+g7lpK9\nOA8XavfYHF7tmQ8MnIT0Ez9u2WC5VHJas8+fnQdxkj
o6jwWTgp36hkGcRt+HGLqW\nWDEdzw7TAMTy6KZLZNq39lIwFv24hoyFLECL9o9N
JQKBgQD/gFa3BS/utfmC+oBu\nPIGk/HCTPiQ9bj3leDC8vzmAj3Sohz54xNjvrX
J7XhYGJB3kI+uzjgY0qh45Z/18\ng/bxCEbCW6hgYEkGJu9Pf8hO1E0sMVo3wEFs
ZKymR51+8aqOb27bS/IN5GmLuMby\nZDGZJHELLOjk7PcHJDMo2wsWpQKBgQDcMZ
G/jWLQQJjOGii/I+u7cAB2zOCeBV4w\nlTHEREzOWPZj9gblvBXFlXtaPPpopLdT
RF+rGlP96Dgx0o4wZTT94oL41eYntDBZ\nwY8FJDdPC08AjtYT15ramdc/K+3q+1
QVfG63vC+iSyRP9YBrGFV2bZ8sntQmpC1a\naZMBhz/0VQKBgDlwE45vZxgl5qKw
R+EATzDU40XmqWT5/IYyn9o+ruGc3l/oj328\n2vv+pQbg3tigk+uuu5UQ74o1WD
gVjaHJVOFYt/eHfXG1E5WDeTcHGsHavkKaEasI\n2GxSsZFr9hcMowgEOwqnpxHC
cIvNjUP+jDveL/i8kxKrxtjfJXUg0PxVAoGASjjf\nQy1acI5Fs7t3nq5yCJWC06
Oa10lB7aggRTAohLnSG/HTc18KC7cOhGVnlxxmu0eh\n4+AVDdJYFts9mKyUxzuy
IEShtyJy5d5r4jTJ+/f44lxDZx7XEPaoap/ZK8saFcAC\n5iYl/FPN4rIDXpYuQK
RE8lp7cqcGrqJFrk8zzJ0CgYEAoWa1k6fkuO4XgopiDOgj\n7/sZr6k3fPp9dJYm
roPjeLPtR1AFJJ4NBHlX+r06nZeovTpm3dKPmg01FXV5mUYq\nW1me90GFekjz6W
N/2DOnL7ChnG8ZJp45SKq26g6D+OU5rg83KuNMJQ0w3dXuR2ch\nnLxRJH0dt7oA
44aMzP39X/s=\n
-----END PRIVATE KEY-----
"@
 
    New-vRACloudAccountGCP -Name "GCP Test" -ProjectId "third-folio-255713" -PrivateKeyId "6226de83c0c6c267f4c80fc9c5ac7dda0293ed9e" -PrivateKey $privateKey -clientEmail "321743978432-compute@developer.gserviceaccount.com" -RegionIds "europe-west1","us-west1"
 
    .EXAMPLE
    $JSON = @"
 
        {
            "name": "GCP Test",
            "description": "GCP Test",
            "projectId": "third-folio-255713",
            "privateKeyId": "6226de83c0c6c267f4c80fc9c5ac7dda0293ed9e",
            "privateKey": "-----BEGIN PRIVATE KEY-----\nMIICXgIHAASBgSDHikastc8+I81zCg/qWW8dMr8mqvXQ3qbPAmu0RjxoZVI47tvs\nkYlFAXOf0sPrhO2nUuooJngnHV0639iTHELLOvckNaW2RTHEREdQ5Rq5u+uV3pMk\n7w7Vs4n3urQ4jnqt7rTXbC1DNa/PFeAZatbf7ffBBy0IGO0zc128IshYcwIDAQAB\nAoGBALTNl2JxTvq4SDW/3VH0fZkQXWH1MM10oeMbB2qO5beWb11FGaOO77nGKfWc\nbYgfp5Ogrql2yhBvLAXnxH8bcqqwORtFhlyV68U1y4R+8WxDNh0aevxH8hRS/1X5\n963DJm1JlU0E+vStiktN0tC3ebH5hE+1OxbIHSZ+WOWLYX7JAkEA5uigRgKp8ScG\nauUijvdOLZIhHWq9y5Wz+nOHUuDw8P7wOTKU34QJAoWEe771p9Pf/GTA/kr0BQnP\nQvWUDxGzJwJBAN05C6krwPeryFKrKtjOGJIbiIoY72wRnoNcdEEs3HDRhf48YWFo\nriRbZylzzzNFy/gmzT6XJQTfktGqq+FZD9UCQGIJaGrxHJgfmpDuAhMzGsUsYtTr\niRox0D1Iqa7dhE693t5aBG010OF6MLqdZA1CXrn5SRtuVVaCSLZEL/2J5UcCQQDA\nd3MXucNnN4NPuS/L9HMYJWD7lPoosaORcgyK77bSSNgk+u9WSjbH1uYIAIPSffUZ\nbti+jc2dUg5wb+aeZlgJAkEAurrpmpqj5vg087ZngKfFGR5rozDiTsK5DceTV97K\na1Y+Nzl+XWTxDBWk4YPh2ZlKv402hZEfWBYxUDn5ZkH/bw==\n-----END PRIVATE KEY-----\n",
            "clientEmail": "321743978432-compute@developer.gserviceaccount.com",
            "regionIds": [ "europe-west1","us-west1" ],
            "createDefaultZones": false
        }
"@
 
    $JSON | New-vRACloudAccountGCP
 
 
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low",DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$ProjectId,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$PrivateKeyId,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$PrivateKey,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$ClientEmail,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String[]]$RegionIds,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [Switch]$CreateDefaultZones,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="JSON")]
        [ValidateNotNullOrEmpty()]
        [String]$JSON

    )

    begin {
        if ($PSBoundParameters.ContainsKey("CreateDefaultZones")) {

            $CreateDefaultZonesStatus = 'true'
        }
        else {

            $CreateDefaultZonesStatus = 'false'
        }
    }

    process {

            if ($PSBoundParameters.ContainsKey("JSON")) {

                $Data = ($JSON | ConvertFrom-Json)

                $Body = $JSON
                $Name = $Data.name
            }
            else {

                # Format RegionIds with surrounding quotes and join into single string
                $RegionIdsAddQuotes = $RegionIDs | ForEach-Object {"`"$_`""}
                $RegionIdsFormatForBodyText = $RegionIdsAddQuotes -join ","

                $Body = @"
                    {
                        "name": "$($Name)",
                        "description": "$($Description)",
                        "projectId": "$($ProjectId)",
                        "privateKeyId": "$($PrivateKeyId)",
                        "privateKey": "$($PrivateKey)",
                        "clientEmail": "$($ClientEmail)",
                        "regionIds": [ $($RegionIdsFormatForBodyText) ],
                        "createDefaultZones": $($CreateDefaultZonesStatus)
                    }
"@

            }

        # --- Create new GCP Cloud Account
        try {
            if ($PSCmdlet.ShouldProcess($Name)){

                $URI = "/iaas/api/cloud-accounts-gcp"
                $CloudAccount = Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                [PSCustomObject] @{

                    Name = $CloudAccount.name
                    Description = $CloudAccount.description
                    Id = $CloudAccount.id
                    CloudAccountType = 'gcp'
                    ProjectId = $CloudAccount.projectId
                    PrivateKeyId = $CloudAccount.privateKeyId
                    ClientEmail = $CloudAccount.clientEmail
                    EnabledRegionIds = $CloudAccount.enabledRegionIds
                    CustomProperties = $CloudAccount.customProperties
                    OrganizationId = $CloudAccount.organizationId
                    Links = $CloudAccount._links
                }
            }
        }
        catch [Exception] {

            throw
        }
    }
    end {

    }
}

<#
    - Function: New-vRACloudAccountvSphere
#>


function New-vRACloudAccountvSphere {
    <#
        .SYNOPSIS
        Create a vRA Cloud Account for vSphere
 
        .DESCRIPTION
        Create a vRA Cloud Account for vSphere
 
        .PARAMETER Name
        The name of the Cloud Account for vSphere
 
        .PARAMETER Description
        A description of the Cloud Account for vSphere
 
        .PARAMETER HostName
        vSphere hostname in which this cloud account is created from
 
        .PARAMETER Username
        Username to use when connecting to the vSphere host
 
        .PARAMETER Password
        Password to use when connecting to the vSphere host
 
        .PARAMETER Credential
        Credential object to connect to the vSphere host with
        For domain accounts ensure to specify the Username in the format username@domain, not Domain\Username
 
        .PARAMETER DCId
        Optional - Identifier of a data collector vm deployed in the on-prem infrastructure
 
        .PARAMETER AssociatedCloudAccountIds
        Optional - Any associated cloud accounts you would like to build into
 
        .PARAMETER RegionIds
        Optional - vSphere RegionIds to enable (note: if not supplied, all regions available will be added to the cloud account)
 
        .PARAMETER CreateDefaultZones
        Enable CreateDefaultZones
 
        .PARAMETER AcceptSelfSignedCertificate
        If set, a self-signed certificate will be accepted
 
        .PARAMETER JSON
        A JSON string with the body payload
 
        .INPUTS
        System.String
        System.Switch
 
        .OUTPUTS
        System.Management.Automation.PSObject
 
        .EXAMPLE
        New-vRACloudAccountvSphere -Name "vSphere Test" -HostName "vc.mycompany.com" -Username "administrator@mycompany.com" -Password "cndhjslacd90ascdbasyoucbdh" -RegionIds "Datacenter:datacenter-2" -CreateDefaultZones -AcceptSelfSignedCertificate
 
        .EXAMPLE
        New-vRACloudAccountvSphere -Name "vSphere Test" -HostName "vc.mycompany.com" -Credential (get-credential) -CreateDefaultZones -AcceptSelfSignedCertificate
 
        .EXAMPLE
        $JSON = @"
 
            {
                "hostName": "vc.mycompany.com",
                "acceptSelfSignedCertificate": false,
                "associatedCloudAccountIds": "[ "42f3e0d199d134755684cd935435a" ]",
                "password": "cndhjslacd90ascdbasyoucbdh",
                "createDefaultZones": true,
                "dcid": "23959a1e-18bc-4f0c-ac49-b5aeb4b6eef4",
                "name": "string",
                "description": "string",
                "regionIds": "[ "Datacenter:datacenter-2" ]",
                "username": "administrator@mycompany.com"
            }
 
"@
 
        $JSON | New-vRACloudAccountvSphere
 
 
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low", DefaultParameterSetName = "Username")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory = $false, ParameterSetName = "Username")]
        [Parameter(Mandatory = $false, ParameterSetName = "Credential")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory = $false, ParameterSetName = "Username")]
        [Parameter(Mandatory = $false, ParameterSetName = "Credential")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter(Mandatory = $false, ParameterSetName = "Username")]
        [Parameter(Mandatory = $false, ParameterSetName = "Credential")]
        [ValidateNotNullOrEmpty()]
        [String]$HostName,

        [Parameter(Mandatory = $true, ParameterSetName = "Username")]
        [ValidateNotNullOrEmpty()]
        [String]$username,

        [Parameter(Mandatory = $true, ParameterSetName = "Username")]
        [ValidateNotNullOrEmpty()]
        [SecureString]$Password,

        [Parameter(Mandatory=$true,ParameterSetName="Credential")]
        [ValidateNotNullOrEmpty()]
        [Management.Automation.PSCredential]$Credential,

        [Parameter(Mandatory = $false, ParameterSetName = "Username")]
        [Parameter(Mandatory = $false, ParameterSetName = "Credential")]
        [ValidateNotNullOrEmpty()]
        [String]$DCId,

        [Parameter(Mandatory = $false, ParameterSetName = "Username")]
        [Parameter(Mandatory = $false, ParameterSetName = "Credential")]
        [ValidateNotNullOrEmpty()]
        [String[]]$AssociatedCloudAccountIds,

        [Parameter(Mandatory = $false, ParameterSetName = "Username")]
        [Parameter(Mandatory = $false, ParameterSetName = "Credential")]
        [ValidateNotNullOrEmpty()]
        [String[]]$RegionIds,

        [Parameter(Mandatory = $false, ParameterSetName = "Username")]
        [Parameter(Mandatory = $false, ParameterSetName = "Credential")]
        [Switch]$CreateDefaultZones,

        [Parameter(Mandatory = $false, ParameterSetName = "Username")]
        [Parameter(Mandatory = $false, ParameterSetName = "Credential")]
        [Switch]$AcceptSelfSignedCertificate,

        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = "JSON")]
        [ValidateNotNullOrEmpty()]
        [String]$JSON

    )

    begin {

        $APIUrl = "/iaas/api/cloud-accounts-vsphere"

        if ($PSBoundParameters.ContainsKey("CreateDefaultZones")) {

            $CreateDefaultZonesStatus = 'true'
        }
        else {

            $CreateDefaultZonesStatus = 'false'
        }

        if ($PSBoundParameters.ContainsKey("AcceptSelfSignedCertificate")) {

            $AcceptSelfSignedCertificateStatus = 'true'
        }
        else {

            $AcceptSelfSignedCertificateStatus = 'false'
        }

        # --- Convert Secure Credentials to a format for sending in the JSON payload
        if ($PSBoundParameters.ContainsKey("Credential")){

            $Username = $Credential.UserName
            $JSONPassword = $Credential.GetNetworkCredential().Password
        }

        if ($PSBoundParameters.ContainsKey("Password")){

            $JSONPassword = (New-Object System.Management.Automation.PSCredential("username", $Password)).GetNetworkCredential().Password
        }
        function ProcessReqionIds {
            $RegionEnumerationUrl = "$APIUrl/region-enumeration"

            if ($null -ne $RegionIds -and $RegionIds) {
                # if this is the case, the region ids were supplied, skip the pull
                return $RegionIds
            }
            else {
                # the region id's were not explicitly given, so we will pull all regions and apply
                # we pass in the same body expression, and it will return the list of zones available
                if ($null -eq $Body) {
                    $Body = @"
                    {
                        "hostName": "$($HostName)",
                        "acceptSelfSignedCertificate": $($AcceptSelfSignedCertificateStatus),
                        "associatedCloudAccountIds": [ $($AssociatedCloudAccountIdsFormatForBodyText) ],
                        "password": "$($JSONPassword)",
                        "createDefaultZones": $($CreateDefaultZonesStatus),
                        "dcid": "$($DCId)",
                        "name": "$($Name)",
                        "description": "$($Description)",
                        "username": "$($username)"
                    }
"@

                }

                $Enumeration = Invoke-vRARestMethod -Method POST -URI $RegionEnumerationUrl -Body $Body -Verbose:$VerbosePreference

                # pull the response
                return $Enumeration.externalRegionIds
            }
        }
        function CalculateOutput {
            [PSCustomObject] @{
                Name                = $CloudAccount.name
                HostName            = $CloudAccount.HostName
                Username            = $CloudAccount.username
                Description         = $CloudAccount.description
                Id                  = $CloudAccount.id
                CloudAccountType    = 'vsphere'
                EnabledRegionIds    = $CloudAccount.enabledRegionIds
                CustomProperties    = $CloudAccount.customProperties
                OrganizationId      = $CloudAccount.organizationId
                Links               = $CloudAccount._links
            }
        }
    }

    process {
        # --- Create new Azure Cloud Account
        try {
            if ($PSBoundParameters.ContainsKey("JSON")) {

                $Data = ($JSON | ConvertFrom-Json)
                $Body = $JSON
                # have to handle if regionid's were not provided
                if ($null -eq $Data.regionIds) {
                    # region ids were not natively passed
                    $RegionIdProcessing = ProcessReqionIds
                    $Data | Add-Member -NotePropertyName regionIds -NotePropertyValue $RegionIdProcessing -Force
                    $JSON = $Data | ConvertTo-Json
                    Write-Verbose $JSON
                }
                $Body = $JSON
                $Name = $Data.name
            }
            else {

                # Format AssociatedCloudAccountIds with surrounding quotes and join into single string
                $AssociatedCloudAccountIdsAddQuotes = $AssociatedCloudAccountIds | ForEach-Object { "`"$_`"" }
                $AssociatedCloudAccountIdsFormatForBodyText = $AssociatedCloudAccountIdsAddQuotes -join ","

                $RegionIDs = ProcessReqionIds # process to see if regions were given, if not, we pull all of them

                # Format RegionIds with surrounding quotes and join into single string
                $RegionIdsAddQuotes = $RegionIDs | ForEach-Object { "`"$_`"" }
                $RegionIdsFormatForBodyText = $RegionIdsAddQuotes -join ","

                $Body = @"
                            {
                                "hostName": "$($HostName)",
                                "acceptSelfSignedCertificate": $($AcceptSelfSignedCertificateStatus),
                                "associatedCloudAccountIds": [ $($AssociatedCloudAccountIdsFormatForBodyText) ],
                                "password": "$($JSONPassword)",
                                "createDefaultZones": $($CreateDefaultZonesStatus),
                                "dcid": "$($DCId)",
                                "name": "$($Name)",
                                "description": "$($Description)",
                                "regionIds": [ $($RegionIdsFormatForBodyText) ],
                                "username": "$($username)"
                            }
"@

            }


            if ($PSCmdlet.ShouldProcess($Name)) {

                $CloudAccount = Invoke-vRARestMethod -Method POST -URI $APIUrl -Body $Body -Verbose:$VerbosePreference

                CalculateOutput
            }
        }
        catch [Exception] {

            throw
        }
    }
    end {

    }
}


<#
    - Function: New-vRAMachineAttachedDisk
#>


function New-vRAMachineAttachedDisk {
<#
    .SYNOPSIS
    Retrieve a vRA Machine's Disks
 
    .DESCRIPTION
    Retrieve the disks for a vRA Machine
 
    .PARAMETER Id
    The ID of the vRA Machine
 
    .PARAMETER Name
    The Name of the vRA Machine
 
    .PARAMETER blockDeviceId
    The Id of the individual Disk to attach (Block Device ID)
 
    .PARAMETER DeviceName
    The name we wish to give the device as we attach it to the machine
 
    .PARAMETER DeviceDescription
    A description we can associate with the disk after attaching it to the machine
 
    .PARAMETER WaitForCompletion
    If this flag is added, this function will wait for the request to complete and will return the created Virtual Disk
 
    .PARAMETER CompletionTimeout
    The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
    .PARAMETER Force
    Force this change
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    New-vRAMachineAttachedDisk -Id 'b1dd48e71d74267559bb930934470' -blockDeviceId '123456'
 
    .EXAMPLE
    New-vRAMachineAttachedDisk -Name 'iaas01' -blockDeviceId '123456'
 
    .EXAMPLE
    New-vRAMachineAttachedDisk -Name 'iaas01' -blockDeviceId '123456' -WaitForCompletion
 
    .EXAMPLE
    New-vRAMachineAttachedDisk -Name 'iaas01' -blockDeviceId '123456' -WaitForCompletion -CompletionTimeout 300
 
    .EXAMPLE
    New-vRAMachineAttachedDisk -Name 'iaas01' -blockDeviceId '123456' -DeviceName 'Disk 17' -DeviceDescription 'This is a disk attached from script'
 
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="High",DefaultParameterSetName="ByName")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [Parameter(Mandatory=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$blockDeviceId,

        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String[]]$DeviceName,

        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String[]]$DeviceDescription,

        [Parameter()]
        [switch]$WaitForCompletion,

        [Parameter()]
        [int]$CompletionTimeout = 120,

        [Parameter()]
        [switch]$Force

    )
    Begin {

        $APIUrl = "/iaas/api/machines"

        function CalculateOutput {

            if ($WaitForCompletion) {
                # if the wait for completion flag is given, the output will be different, we will wait here
                # we will use the built-in function to check status
                $elapsedTime = 0
                    do {
                        $RequestResponse = Get-vRARequest -RequestId $Response.id
                        if ($RequestResponse.Status -eq "FINISHED") {
                            foreach ($resource in $RequestResponse.Resources) {
                                $Response = Invoke-vRARestMethod -URI "$resource/disks/$blockDeviceId" -Method GET
                                [PSCustomObject]@{
                                    Name = $Response.name
                                    Status = $Response.status
                                    Owner = $Response.owner
                                    ExternalRegionId = $Response.externalRegionId
                                    ExternalZoneId = $Response.externalZoneId
                                    Description = $Response.description
                                    Tags = $Response.tags
                                    CapacityInGB = $Response.capacityInGB
                                    CloudAccountIDs = $Response.cloudAccountIds
                                    ExternalId = $Response.externalId
                                    Id = $Response.id
                                    DateCreated = $Response.createdAt
                                    LastUpdated = $Response.updatedAt
                                    OrganizationId = $Response.orgId
                                    Properties = $Response.customProperties
                                    ProjectId = $Response.projectId
                                    Persistent = $Response.persistent
                                    RequestId = $Response.id
                                    RequestStatus = "FINISHED"
                                }
                            }
                            break # leave loop as we are done here
                        }
                        $elapsedTime += 5
                        Start-Sleep -Seconds 5
                    } while ($elapsedTime -lt $CompletionTimeout)

                    if ($elapsedTime -gt $CompletionTimeout -or $elapsedTime -eq $CompletionTimeout) {
                        # we have errored out
                        [PSCustomObject]@{
                            Name = $Response.name
                            Progress = $Response.progress
                            Resources = $Response.resources
                            RequestId = $Response.id
                            Message = "We waited for completion, but we hit a timeout at $CompletionTimeout seconds. You may use Get-vRARequest -RequestId $($Response.id) to continue checking status. Here was the original response: $($Response.message)"
                            RequestStatus = $Response.status
                        }
                    }
            } else {
                [PSCustomObject]@{
                    Name = $Response.name
                    Progress = $Response.progress
                    Resources = $Response.resources
                    RequestId = $Response.id
                    Message = $Response.message
                    RequestStatus = $Response.status
                }
            }
        }
    }
    Process {

        try {

            $Body = @"
                {
                    "blockDeviceId": "$($blockDeviceId)",
                    "name": "$($DeviceName)",
                    "description": "$($DeviceDescription)"
                }
"@

            Write-Verbose -Message $Body

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Machine by its id
                'ById' {
                    if ($Force -or $PsCmdlet.ShouldProcess($Id)){
                        # --- Check to see if the DiskId's were optionally present
                        $Response = Invoke-vRARestMethod -URI "$APIUrl`/$Id`/disks" -Method GET -Body $Body

                        CalculateOutput
                    }
                    break
                }

                # --- Get Machine by its name
                # --- Will need to retrieve the machine first, then use ID to get final output
                'ByName' {
                    if ($Force -or $PsCmdlet.ShouldProcess($Name)){
                        $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$Name'`&`$select=id" -Method GET
                        $machineId = $machineResponse.content[0].id

                        $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId`/disks" -Method POST -Body $Body

                        CalculateOutput
                    }
                    break
                }

            }
        }
        catch [Exception]{

            throw
        }
    }
    End {

    }
}


<#
    - Function: New-vRAProject
#>


function New-vRAProject {
<#
    .SYNOPSIS
    Create a vRA Cloud Project
 
    .DESCRIPTION
    Create a vRA Cloud Project
 
    .PARAMETER Name
    The name of the Project
 
    .PARAMETER Description
    A description of the Project
 
    .PARAMETER Zones
    PSCustomObject(s) with properties for a Cloud Zone
 
    .PARAMETER Members
    Members to add to the Project
 
    .PARAMETER Administrators
    Administrators to add to the Project
 
    .PARAMETER OperationTimeout
    Operation Timeout
 
    .PARAMETER SharedResources
    Deployments are shared between all users in the project
 
    .PARAMETER JSON
    A JSON string with the body payload
 
    .INPUTS
    System.String
    System.Switch
    PSCustomObject
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    $CloudZone = [PSCustomObject] @{
 
        zoneId = 'e6b9d1r2d2115a7558039ae2387c'
        priority = 1
        maxNumberInstances = 10
        memoryLimitMb = 107374
    }
 
    $ProjectArguments = @{
 
        Name = 'Test Project'
        Description = 'Test Project'
        Zones = $CloudZone
        Members = 'user1@test.com','user2@test.com'
        Administrators = 'admin1@test.com','admin2@test.com'
        OperationTimeout = 3600
        SharedResources = $true
    }
 
    New-vRAProject @ProjectArguments
 
    .EXAMPLE
    $JSON = @"
        {
            "name": "Test Project",
            "description": "Test Project",
            "zones": [
                {
                    "zoneId": "e6b9d1r2d2115a7558039ae2387c",
                    "priority": 1,
                    "maxNumberInstances": 10,
                    "memoryLimitMB": 107374
                },
                {
                    "zoneId": "r2d2026e33c3648334bcb67eac669",
                    "priority": 2,
                    "maxNumberInstances": 100,
                    "memoryLimitMB": 107374
                }
            ],
            "members": [
                {
                    "email": "user1@test.com"
                },
                {
                    "email": "user2@test.com"
                }
            ],
            "administrators": [
                {
                    "email": "admin1@test.com"
                },
                {
                    "email": "admin2@test.com"
                }
            ],
            "constraints": {},
            "operationTimeout": 3600,
            "sharedResources": true
        }
"@
 
    $JSON | New-vRAProject
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low",DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Description,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [PSCustomObject[]]$Zones,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Members,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Administrators,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [Int]$OperationTimeout,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [Switch]$SharedResources,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="JSON")]
        [ValidateNotNullOrEmpty()]
        [String]$JSON

    )

    begin {

        if ($PSBoundParameters.ContainsKey("SharedResources")) {

            $SharedResourcesStatus = 'true'
        }
        else {

            $SharedResourcesStatus = 'false'
        }
    }

    process {

            if ($PSBoundParameters.ContainsKey("JSON")) {

                $Data = ($JSON | ConvertFrom-Json)

                $Body = $JSON
                $Name = $Data.name
            }
            else {


                $Body = @"
                    {
                        "name": "$($Name)",
                        "description": "$($Description)",
                        "zoneAssignmentConfigurations": [],
                        "members": [],
                        "administrators": [],
                        "operationTimeout": $($OperationTimeout),
                        "sharedResources": $($SharedResourcesStatus)
                    }
"@


                $JSONObject = $Body | ConvertFrom-Json

                # --- Add Cloud Zones
                foreach ($Zone in $Zones){

                    $JSONObject.zoneAssignmentConfigurations += $Zone
                }

                # --- Add Members
                if ($PSBoundParameters.ContainsKey("Members")){

                    foreach ($Member in $Members){

                        $Addition = @"
                        {
                            "email": "$($Member)"
                        }
"@

                        $AdditionObject = $Addition | ConvertFrom-Json
                        $JSONObject.members += $AdditionObject
                    }
                }

                # --- Add Administrators
                if ($PSBoundParameters.ContainsKey("Administrators")){

                    foreach ($Administrator in $Administrators){

                        $Addition = @"
                        {
                            "email": "$($Administrator)"
                        }
"@

                        $AdditionObject = $Addition | ConvertFrom-Json
                        $JSONObject.administrators += $AdditionObject
                    }
                }

                $Body = $JSONObject | ConvertTo-Json -Depth 5
            }

        # --- Create new Project
        try {
            if ($PSCmdlet.ShouldProcess($Name)){

                $URI = "/iaas/api/projects"
                $Project = Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                [PSCustomObject] @{

                    Name = $Project.name
                    Description = $Project.description
                    Id = $Project.id
                    Administrators = $Project.administrators
                    Members = $Project.members
                    Viewers = $Project.viewers
                    Zones = $Project.zones
                    SharedResources = $Project.sharedResources
                    OperationTimeout = $Project.operationTimeout
                    OrganizationId = $Project.organizationId
                    Links = $Project._links
                }
            }
        }
        catch [Exception] {

            throw
        }
    }
    end {

    }
}

<#
    - Function: New-vRAVirtualDisk
#>


function New-vRAVirtualDisk {
    <#
        .SYNOPSIS
        Retrieve a vRA Machine's Disks
 
        .DESCRIPTION
        Retrieve the disks for a vRA Machine
 
        .PARAMETER Name
        The Name you would like to give the new disk/volume
 
        .PARAMETER Encrypted
        Switch indicating if the device will be encrypted during build
 
        .PARAMETER CapacityInGB
        Integer value indicating capacity of the disk in GB
 
        .PARAMETER DeviceDescription
        A description we can associate with the disk after creating it
 
        .PARAMETER Persistent
        Another switch indicating the disk to be a persistent disk
 
        .PARAMETER ProjectId
        The id of the project in which to build the disk/volume in
 
        .PARAMETER ProjectName
        As an alternate, a project name can be given for this operation
 
        .PARAMETER WaitForCompletion
        If this flag is added, this function will wait for the request to complete and will reutnr the created Virtual Disk
 
        .PARAMETER CompletionTimeout
        The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
        .PARAMETER Force
        Force the creation
 
        .OUTPUTS
        System.Management.Automation.PSObject.
 
        .EXAMPLE
        New-vRAVirtualDisk -Name 'test_disk_1' -CapacityInGB 10 -ProjectId 'b1dd48e71d74267559bb930934470'
 
        .EXAMPLE
        New-vRAVirtualDisk -Name 'test_disk_1' -CapacityInGB 10 -ProjectName 'GOLD'
 
        .EXAMPLE
        New-vRAVirtualDisk -Name 'test_disk_1' -CapacityInGB 10 -ProjectName 'GOLD' -WaitForCompletion
 
        .EXAMPLE
        New-vRAVirtualDisk -Name 'test_disk_1' -CapacityInGB 10 -ProjectName 'GOLD' -WaitForCompletion -CompletionTimeout 300
 
        .EXAMPLE
        New-vRAVirtualDisk -Name 'test_disk_1' -CapacityInGB 10 -ProjectId 'b1dd48e71d74267559bb930934470' -Persistent -Encrypted
 
    #>

    [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High",DefaultParameterSetName="ByName")][OutputType('System.Management.Automation.PSObject')]

        Param (

            [Parameter(Mandatory=$true,ParameterSetName="ByName")]
            [Parameter(Mandatory=$true,ParameterSetName="ById")]
            [ValidateNotNullOrEmpty()]
            [String]$Name,

            [Parameter(Mandatory=$true,ParameterSetName="ByName")]
            [Parameter(Mandatory=$true,ParameterSetName="ById")]
            [ValidateNotNullOrEmpty()]
            [int]$CapacityInGB,

            [Parameter(Mandatory=$true,ParameterSetName="ById")]
            [ValidateNotNullOrEmpty()]
            [String[]]$ProjectId,

            [Parameter(Mandatory=$true,ParameterSetName="ByName")]
            [ValidateNotNullOrEmpty()]
            [String[]]$ProjectName,

            [Parameter(Mandatory=$false)]
            [ValidateNotNullOrEmpty()]
            [String[]]$DeviceDescription,

            [Parameter()]
            [switch]$Persistent,

            [Parameter()]
            [switch]$Encrypted,

            [Parameter()]
            [switch]$WaitForCompletion,

            [Parameter()]
            [int]$CompletionTimeout = 120,

            [Parameter()]
            [switch]$Force

        )
        Begin {

            $APIUrl = "/iaas/api/block-devices"

            function CalculateOutput {

                if ($WaitForCompletion) {
                    # if the wait for completion flag is given, the output will be different, we will wait here
                    # we will use the built-in function to check status
                    $elapsedTime = 0
                    do {
                        $RequestResponse = Get-vRARequest -RequestId $Response.id
                        if ($RequestResponse.Status -eq "FINISHED") {
                            foreach ($resource in $RequestResponse.Resources) {
                                $Response = Invoke-vRARestMethod -URI "$resource" -Method GET
                                [PSCustomObject]@{
                                    Name = $Response.name
                                    Status = $Response.status
                                    Owner = $Response.owner
                                    ExternalRegionId = $Response.externalRegionId
                                    ExternalZoneId = $Response.externalZoneId
                                    Description = $Response.description
                                    Tags = $Response.tags
                                    CapacityInGB = $Response.capacityInGB
                                    CloudAccountIDs = $Response.cloudAccountIds
                                    ExternalId = $Response.externalId
                                    Id = $Response.id
                                    DateCreated = $Response.createdAt
                                    LastUpdated = $Response.updatedAt
                                    OrganizationId = $Response.orgId
                                    Properties = $Response.customProperties
                                    ProjectId = $Response.projectId
                                    Persistent = $Response.persistent
                                }
                            }
                            break # leave loop as we are done here
                        }
                        $elapsedTime += 5
                        Start-Sleep -Seconds 5
                    } while ($elapsedTime -lt $CompletionTimeout)
                } else {
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Id = $Response.id
                        Status = $Response.status
                    }
                }

            }
        }
        Process {

            try {


                switch ($PsCmdlet.ParameterSetName) {

                    # --- Get Machine by its id
                    'ById' {
                        if ($Force -or $PsCmdlet.ShouldProcess($ProjectId)){
                            $Body = @"
                                {
                                    "capacityInGB": $($CapacityInGB),
                                    "encrypted": $($Encrypted),
                                    "name": "$($Name)",
                                    "description": "$($DeviceDescription)",
                                    "persistent": $($Persistent),
                                    "projectId": "$($ProjectId)"
                                }
"@

                            # --- Check to see if the DiskId's were optionally present
                            $Response = Invoke-vRARestMethod -URI "$APIUrl" -Method POST -Body $Body

                            CalculateOutput
                        }
                        break
                    }

                    # --- Get Machine by its name
                    # --- Will need to retrieve the machine first, then use ID to get final output
                    'ByName' {
                        if ($Force -or $PsCmdlet.ShouldProcess($ProjectName)){
                            $projResponse = Invoke-vRARestMethod -URI "/iaas/api/projects`?`$filter=name eq '$ProjectName'`&`$select=id" -Method GET
                            $projId = $projResponse.content[0].id

                            $Body = @"
                                {
                                    "capacityInGB": $($CapacityInGB),
                                    "encrypted": $($Encrypted),
                                    "name": "$($Name)",
                                    "description": "$($DeviceDescription)",
                                    "persistent": $($Persistent),
                                    "projectId": "$($projId)"
                                }
"@

                            Write-Verbose $Body
                            $Response = Invoke-vRARestMethod -URI "$APIUrl" -Method POST -Body $Body

                            CalculateOutput
                        }
                        break
                    }

                }
            }
            catch [Exception]{

                throw
            }
        }
        End {

        }
    }


<#
    - Function: Remove-vRACloudAccount
#>


function Remove-vRACloudAccount {
    <#
        .SYNOPSIS
        Remove a Cloud Account
 
        .DESCRIPTION
        Remove a Cloud Account
 
        .PARAMETER Id
        The Id of the Cloud Account
 
        .PARAMETER Name
        The name of the Cloud Account
 
        .INPUTS
        System.String
 
        .EXAMPLE
        Remove-vRACloudAccount -Name CloudAccount1
 
        .EXAMPLE
        Remove-vRACloudAccount -Id '4b3bd194-9b5f-40fd-9ed0-58d997237999'
 
        .EXAMPLE
        Get-vRACloudAccount -Name CloudAccount1 | Remove-vRACloudAccount
 
    #>

    [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High",DefaultParameterSetName="ById")]

    Param (

    [parameter(Mandatory=$true, ValueFromPipelineByPropertyName, ParameterSetName="ById")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$true, ParameterSetName="ByName")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name

    )

    begin {}

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {

                'ById' {

                    foreach ($CloudAccountId in $Id) {

                        if ($PSCmdlet.ShouldProcess($CloudAccountId)){

                            $URI = "/iaas/api/cloud-accounts/$($CloudAccountId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }

                'ByName' {

                    foreach ($CloudAccountName in $Name) {

                        if ($PSCmdlet.ShouldProcess($CloudAccountName)){

                            $CloudAccountId = (Get-vRACloudAccount -Name $CloudAccountName).id
                            $URI = "/iaas/api/cloud-accounts/$($CloudAccountId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }
            }
        }
        catch [Exception]{

            throw
        }
    }
}

<#
    - Function: Remove-vRAProject
#>


function Remove-vRAProject {
    <#
        .SYNOPSIS
        Remove a Cloud Project
 
        .DESCRIPTION
        Remove a Cloud Project
 
        .PARAMETER Id
        The Id of the Cloud Project
 
        .PARAMETER Name
        The Name of the Cloud Project
 
        .INPUTS
        System.String
 
        .EXAMPLE
        Remove-vRAProject -Name Project1
 
        .EXAMPLE
        Remove-vRAProject -Id '4b3bd194-9b5f-40fd-9ed0-58d997237999'
 
        .EXAMPLE
        Get-vRAProject -Name Project1 | Remove-vRAProject
 
    #>

    [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High",DefaultParameterSetName="ById")]

    Param (

    [parameter(Mandatory=$true, ValueFromPipelineByPropertyName, ParameterSetName="ById")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$true, ParameterSetName="ByName")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name

    )

    begin {}

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {

                'ById' {

                    foreach ($ProjectId in $Id) {

                        if ($PSCmdlet.ShouldProcess($ProjectId)){

                            $URI = "/iaas/api/projects/$($ProjectId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }

                'ByName' {

                    foreach ($ProjectName in $Name) {

                        if ($PSCmdlet.ShouldProcess($ProjectName)){

                            $ProjectId = (Get-vRAProject -Name $ProjectName).id
                            $URI = "/iaas/api/projects/$($ProjectId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }
            }
        }
        catch [Exception]{

            throw
        }
    }
}

<#
    - Function: Resize-vRAMachine
#>


function Resize-vRAMachine {
<#
    .SYNOPSIS
    Resize a vRA Machine with the given CPU and Memory inputs
 
    .DESCRIPTION
    Resize a vRA Machine with the given CPU and Memory inputs
 
    .PARAMETER Id
    The ID of the vRA Machine
 
    .PARAMETER Name
    The Name of the vRA Machine
 
    .PARAMETER CPU
    The desired resulting cpu count for the machine
 
    .PARAMETER Memory
    The desired resulting memory in MB for the machine
 
    .PARAMETER Flavor
    As an alternative, you can provide a flavor instead of a cpu or memory option
 
    .PARAMETER WaitForCompletion
    If this flag is added, this function will wait for the resize operation to complete
 
    .PARAMETER CompletionTimeout
    The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
    .PARAMETER Force
    Force this change
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Resize-vRAMachine -Id 'b1dd48e71d74267559bb930934470' -CPU 4 -Memory 8192
 
    .EXAMPLE
    Resize-vRAMachine -Name 'iaas01' -CPU 4 -Memory 8192
 
    .EXAMPLE
    Resize-vRAMachine -Id 'b1dd48e71d74267559bb930934470' -Flavor Small
 
    .EXAMPLE
    Resize-vRAMachine -Name 'iaas01' -Flavor Small
 
    .EXAMPLE
    Resize-vRAMachine -Name 'iaas01' -Flavor Small -WaitForCompletion
 
    .EXAMPLE
    Resize-vRAMachine -Name 'iaas01' -Flavor Small -WaitForCompletion -CompletionTimeout 300
 
#>

[CmdletBinding(DefaultParameterSetName="ResizeByName", SupportsShouldProcess, ConfirmImpact='High')][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ResizeById")]
        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ResizeFlavorById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ResizeByName")]
        [Parameter(Mandatory=$true,ParameterSetName="ResizeFlavorByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name,

        [Parameter(Mandatory=$true,ParameterSetName="ResizeFlavorById")]
        [Parameter(Mandatory=$true,ParameterSetName="ResizeFlavorByName")]
        [ValidateNotNullOrEmpty()]
        [String]$Flavor,

        [Parameter(Mandatory=$true,ParameterSetName="ResizeByName")]
        [Parameter(Mandatory=$true,ParameterSetName="ResizeById")]
        [ValidateNotNullOrEmpty()]
        [int]$CPU,

        [Parameter(Mandatory=$true,ParameterSetName="ResizeByName")]
        [Parameter(Mandatory=$true,ParameterSetName="ResizeById")]
        [ValidateNotNullOrEmpty()]
        [int]$Memory,

        [Parameter()]
        [switch]$WaitForCompletion,

        [Parameter()]
        [int]$CompletionTimeout = 120,

        [Parameter()]
        [switch]$Force

    )
    Begin {

        $APIUrl = "/iaas/api/machines"

        function CalculateOutput {
            if ($WaitForCompletion) {
                # if the wait for completion flag is given, the output will be different, we will wait here
                # we will use the built-in function to check status
                $elapsedTime = 0
                do {
                    $RequestResponse = Get-vRARequest -RequestId $Response.id
                    if ($RequestResponse.Status -eq "FINISHED") {
                        foreach ($resource in $RequestResponse.Resources) {
                            $Record = Invoke-vRARestMethod -URI "$resource" -Method GET
                            [PSCustomObject]@{
                                Name = $Record.name
                                PowerState = $Record.powerState
                                IPAddress = $Record.address
                                ExternalRegionId = $Record.externalRegionId
                                CloudAccountIDs = $Record.cloudAccountIds
                                ExternalId = $Record.externalId
                                Id = $Record.id
                                DateCreated = $Record.createdAt
                                LastUpdated = $Record.updatedAt
                                OrganizationId = $Record.organizationId
                                Properties = $Record.customProperties
                                RequestId = $Response.id
                                RequestStatus = "FINISHED"
                            }
                        }
                        break # leave loop as we are done here
                    }
                    $elapsedTime += 5
                    Start-Sleep -Seconds 5
                } while ($elapsedTime -lt $CompletionTimeout)

                if ($elapsedTime -gt $CompletionTimeout -or $elapsedTime -eq $CompletionTimeout) {
                    # we have errored out
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Resources = $Response.resources
                        RequestId = $Response.id
                        Message = "We waited for completion, but we hit a timeout at $CompletionTimeout seconds. You may use Get-vRARequest -RequestId $($Response.id) to continue checking status. Here was the original response: $($Response.message)"
                        RequestStatus = $Response.status
                    }
                }
            } else {
                [PSCustomObject]@{
                    Name = $Response.name
                    Progress = $Response.progress
                    Resources = $Response.resources
                    RequestId = $Response.id
                    Message = $Response.message
                    RequestStatus = $Response.status
                }
            }
        }
    }
    Process {

        try {


                switch ($PsCmdlet.ParameterSetName) {

                    # --- Resize by Flavor, do not need cpu and memory
                    'ResizeFlavorById' {

                        foreach ($machineId in $Id) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machineId)) {
                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/resize?name=$Flavor" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                    # --- Resize by Flavor, do not need cpu and memory
                    'ResizeFlavorByName' {

                        foreach ($machine in $Name) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machine)) {
                            $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machine'`&`$select=id" -Method GET
                            $machineId = $machineResponse.content[0].Id

                            $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/resize?name=$Flavor" -Method POST
                            CalculateOutput
                            }
                        }
                        break
                    }

                    # --- Resize with cpu and memory for given machine by its id
                    'ResizeById' {

                        foreach ($machineId in $Id) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machineId)) {
                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/resize?memoryInMB=$Memory`&cpuCount=$CPU" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                    # --- Resize with cpu and memory for given machine by its name
                    'ResizeByName' {

                        foreach ($machine in $Name) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machine)) {
                                $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machine'`&`$select=id" -Method GET
                                $machineId = $machineResponse.content[0].Id

                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/resize?memoryInMB=$Memory`&cpuCount=$CPU" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                }
        }
        catch [Exception]{

            throw
        }
    }
    End {

    }
}


<#
    - Function: Restart-vRAMachine
#>


function Restart-vRAMachine {
<#
    .SYNOPSIS
    Restart a vRA Machine
 
    .DESCRIPTION
    Restart a vRA Machine
 
    .PARAMETER Id
    The ID of the vRA Machine
 
    .PARAMETER Name
    The Name of the vRA Machine
 
    .PARAMETER WaitForCompletion
    If this flag is added, this function will wait for the power state of the machine to = ON. (note: machine may still be completing OS boot procedure when this function is complete)
 
    .PARAMETER CompletionTimeout
    The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
    .PARAMETER Force
    Force this change
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Restart-vRAMachine -Id 'b1dd48e71d74267559bb930934470'
 
    .EXAMPLE
    Restart-vRAMachine -Name 'iaas01'
 
    .EXAMPLE
    Restart-vRAMachine -Name 'iaas01' -WaitForCompletion
 
    .EXAMPLE
    Restart-vRAMachine -Name 'iaas01' -WaitForCompletion -CompletionTimeout 300
 
#>

[CmdletBinding(SupportsShouldProcess, ConfirmImpact="High", DefaultParameterSetName="ResetByName")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ResetById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ResetByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name,

        [Parameter()]
        [switch]$WaitForCompletion,

        [Parameter()]
        [int]$CompletionTimeout = 120,

        [Parameter()]
        [switch]$Force

    )
    Begin {

        $APIUrl = "/iaas/api/machines"

        function CalculateOutput {
            if ($WaitForCompletion) {
                # if the wait for completion flag is given, the output will be different, we will wait here
                # we will use the built-in function to check status
                $elapsedTime = 0
                do {
                    $RequestResponse = Get-vRARequest -RequestId $Response.id
                    if ($RequestResponse.Status -eq "FINISHED") {
                        foreach ($resource in $RequestResponse.Resources) {
                            $Record = Invoke-vRARestMethod -URI "$resource" -Method GET
                            [PSCustomObject]@{
                                Name = $Record.name
                                PowerState = $Record.powerState
                                IPAddress = $Record.address
                                ExternalRegionId = $Record.externalRegionId
                                CloudAccountIDs = $Record.cloudAccountIds
                                ExternalId = $Record.externalId
                                Id = $Record.id
                                DateCreated = $Record.createdAt
                                LastUpdated = $Record.updatedAt
                                OrganizationId = $Record.organizationId
                                Properties = $Record.customProperties
                                RequestId = $Response.id
                                RequestStatus = "FINISHED"
                            }
                        }
                        break # leave loop as we are done here
                    }
                    $elapsedTime += 5
                    Start-Sleep -Seconds 5
                } while ($elapsedTime -lt $CompletionTimeout)

                if ($elapsedTime -gt $CompletionTimeout -or $elapsedTime -eq $CompletionTimeout) {
                    # we have errored out
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Resources = $Response.resources
                        RequestId = $Response.id
                        Message = "We waited for completion, but we hit a timeout at $CompletionTimeout seconds. You may use Get-vRARequest -RequestId $($Response.id) to continue checking status. Here was the original response: $($Response.message)"
                        RequestStatus = $Response.status
                    }
                }
            } else {
                [PSCustomObject]@{
                    Name = $Response.name
                    Progress = $Response.progress
                    Resources = $Response.resources
                    RequestId = $Response.id
                    Message = $Response.message
                    RequestStatus = $Response.status
                }
            }

        }
    }
    Process {

        try {

                switch ($PsCmdlet.ParameterSetName) {

                    # --- Restart the given machine by its id
                    'ResetById' {

                        foreach ($machineId in $Id) {
                                if ($Force -or $PsCmdlet.ShouldProcess($machineId)) {
                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/reset" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                    # --- Restart the given machine by its name
                    'ResetByName' {

                        foreach ($machine in $Name) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machine)) {
                                $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machine'`&`$select=id" -Method GET
                                $machineId = $machineResponse.content[0].Id

                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/reset" -Method POST
                                CalculateOutput
                            }
                        }

                        break
                    }

                }
        }
        catch [Exception]{

            throw
        }
    }
    End {

    }
}


<#
    - Function: Restart-vRAMachineGuestOS
#>


function Restart-vRAMachineGuestOS {
<#
    .SYNOPSIS
    Request a guest os restart
 
    .DESCRIPTION
    Request the guest OS to restart
 
    .PARAMETER Id
    The ID of the vRA Machine
 
    .PARAMETER Name
    The Name of the vRA Machine
 
    .PARAMETER WaitForCompletion
    If this flag is added, this function will wait for the power state of the machine to = ON. (note: machine may still be completing OS boot procedure when this function is complete)
 
    .PARAMETER CompletionTimeout
    The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
    .PARAMETER Force
    Force this change
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Restart-vRAMachineGuestOS -Id 'b1dd48e71d74267559bb930934470'
 
    .EXAMPLE
    Restart-vRAMachineGuestOS -Name 'iaas01'
 
    .EXAMPLE
    Restart-vRAMachineGuestOS -Name 'iaas01' -WaitForCompletion
 
    .EXAMPLE
    Restart-vRAMachineGuestOS -Name 'iaas01' -WaitForCompletion -CompletionTimeout 300
 
#>

[CmdletBinding(SupportsShouldProcess, ConfirmImpact="High", DefaultParameterSetName="RebootByName")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="RebootById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="RebootByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name,

        [Parameter()]
        [switch]$WaitForCompletion,

        [Parameter()]
        [int]$CompletionTimeout = 120,

        [Parameter()]
        [switch]$Force

    )
    Begin {

        $APIUrl = "/iaas/api/machines"

        function CalculateOutput {
            if ($WaitForCompletion) {
                # if the wait for completion flag is given, the output will be different, we will wait here
                # we will use the built-in function to check status
                $elapsedTime = 0
                do {
                    $RequestResponse = Get-vRARequest -RequestId $Response.id
                    if ($RequestResponse.Status -eq "FINISHED") {
                        foreach ($resource in $RequestResponse.Resources) {
                            $Record = Invoke-vRARestMethod -URI "$resource" -Method GET
                            [PSCustomObject]@{
                                Name = $Record.name
                                PowerState = $Record.powerState
                                IPAddress = $Record.address
                                ExternalRegionId = $Record.externalRegionId
                                CloudAccountIDs = $Record.cloudAccountIds
                                ExternalId = $Record.externalId
                                Id = $Record.id
                                DateCreated = $Record.createdAt
                                LastUpdated = $Record.updatedAt
                                OrganizationId = $Record.organizationId
                                Properties = $Record.customProperties
                                RequestId = $Response.id
                                RequestStatus = "FINISHED"
                            }
                        }
                        break # leave loop as we are done here
                    }
                    $elapsedTime += 5
                    Start-Sleep -Seconds 5
                } while ($elapsedTime -lt $CompletionTimeout)

                if ($elapsedTime -gt $CompletionTimeout -or $elapsedTime -eq $CompletionTimeout) {
                    # we have errored out
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Resources = $Response.resources
                        RequestId = $Response.id
                        Message = "We waited for completion, but we hit a timeout at $CompletionTimeout seconds. You may use Get-vRARequest -RequestId $($Response.id) to continue checking status. Here was the original response: $($Response.message)"
                        RequestStatus = $Response.status
                    }
                }
            } else {
                [PSCustomObject]@{
                    Name = $Response.name
                    Progress = $Response.progress
                    Resources = $Response.resources
                    RequestId = $Response.id
                    Message = $Response.message
                    RequestStatus = $Response.status
                }
            }

        }
    }
    Process {

        try {

                switch ($PsCmdlet.ParameterSetName) {

                    # --- Restart the given machine by its id
                    'RebootById' {

                        foreach ($machineId in $Id) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machineId)) {
                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/reboot" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                    # --- Restart the given machine by its name
                    'RebootByName' {

                        foreach ($machine in $Name) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machine)) {
                                $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machine'`&`$select=id" -Method GET
                                $machineId = $machineResponse.content[0].Id

                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/reboot" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                }

        }
        catch [Exception]{

            throw
        }
    }
    End {

    }
}


<#
    - Function: Start-vRAMachine
#>


function Start-vRAMachine {
    <#
        .SYNOPSIS
        Power-On a vRA Machine
 
        .DESCRIPTION
        Power-On a vRA Machine
 
        .PARAMETER Id
        The ID of the vRA Machine
 
        .PARAMETER Name
        The Name of the vRA Machine
 
        .PARAMETER WaitForCompletion
        If this flag is added, this function will wait for the power state of the machine to = ON (note: machine may still be completing OS boot procedure when this function is complete)
 
        .PARAMETER CompletionTimeout
        The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
        .PARAMETER Force
        Force this change
 
        .OUTPUTS
        System.Management.Automation.PSObject.
 
        .EXAMPLE
        Start-vRAMachine -Id 'b1dd48e71d74267559bb930934470'
 
        .EXAMPLE
        Start-vRAMachine -Name 'iaas01'
 
        .EXAMPLE
        Start-vRAMachine -Name 'iaas01' -WaitForCompletion
 
        .EXAMPLE
        Start-vRAMachine -Name 'iaas01' -WaitForCompletion -CompletionTimeout 300
 
    #>

    [CmdletBinding(DefaultParameterSetName="PowerOnByName", SupportsShouldProcess, ConfirmImpact="Low")][OutputType('System.Management.Automation.PSObject')]

        Param (

            [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="PowerOnById")]
            [ValidateNotNullOrEmpty()]
            [String[]]$Id,

            [Parameter(Mandatory=$true,ParameterSetName="PowerOnByName")]
            [ValidateNotNullOrEmpty()]
            [String[]]$Name,

            [Parameter()]
            [switch]$WaitForCompletion,

            [Parameter()]
            [int]$CompletionTimeout = 120,

            [Parameter()]
            [switch]$Force

        )
        Begin {

            $APIUrl = "/iaas/api/machines"

            function CalculateOutput {

                if ($WaitForCompletion) {
                    # if the wait for completion flag is given, the output will be different, we will wait here
                    # we will use the built-in function to check status
                    $elapsedTime = 0
                    do {
                        $RequestResponse = Get-vRARequest -RequestId $Response.id
                        if ($RequestResponse.Status -eq "FINISHED") {
                            foreach ($resource in $RequestResponse.Resources) {
                                $Record = Invoke-vRARestMethod -URI "$resource" -Method GET
                                [PSCustomObject]@{
                                    Name = $Record.name
                                    PowerState = $Record.powerState
                                    IPAddress = $Record.address
                                    ExternalRegionId = $Record.externalRegionId
                                    CloudAccountIDs = $Record.cloudAccountIds
                                    ExternalId = $Record.externalId
                                    Id = $Record.id
                                    DateCreated = $Record.createdAt
                                    LastUpdated = $Record.updatedAt
                                    OrganizationId = $Record.organizationId
                                    Properties = $Record.customProperties
                                    RequestId = $Response.id
                                    RequestStatus = "FINISHED"
                                }
                            }
                            break # leave loop as we are done here
                        }
                        $elapsedTime += 5
                        Start-Sleep -Seconds 5
                    } while ($elapsedTime -lt $CompletionTimeout)

                    if ($elapsedTime -gt $CompletionTimeout -or $elapsedTime -eq $CompletionTimeout) {
                        # we have errored out
                        [PSCustomObject]@{
                            Name = $Response.name
                            Progress = $Response.progress
                            Resources = $Response.resources
                            RequestId = $Response.id
                            Message = "We waited for completion, but we hit a timeout at $CompletionTimeout seconds. You may use Get-vRARequest -RequestId $($Response.id) to continue checking status. Here was the original response: $($Response.message)"
                            RequestStatus = $Response.status
                        }
                    }
                } else {
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Resources = $Response.resources
                        RequestId = $Response.id
                        Message = $Response.message
                        RequestStatus = $Response.status
                    }
                }
            }
        }
        Process {

            try {

                    switch ($PsCmdlet.ParameterSetName) {

                        # --- Start the given machine by its id
                        'PowerOnById' {

                            foreach ($machineId in $Id) {
                                if ($Force -or $PsCmdlet.ShouldProcess($machineId)){
                                    $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/power-on" -Method POST
                                    CalculateOutput
                                }
                            }
                            break
                        }

                        # --- Start the given machine by its name
                        'PowerOnByName' {

                            foreach ($machine in $Name) {
                                if ($Force -or $PsCmdlet.ShouldProcess($machine)){
                                    $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machine'`&`$select=id" -Method GET
                                    $machineId = $machineResponse.content[0].Id

                                    $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/power-on" -Method POST
                                    CalculateOutput
                                }
                            }
                            break
                        }

                    }

            }
            catch [Exception]{

                throw
            }
        }
        End {

        }
    }


<#
    - Function: Stop-vRAMachine
#>


function Stop-vRAMachine {
<#
    .SYNOPSIS
    Power-Off a vRA Machine
 
    .DESCRIPTION
    Power-Off a vRA Machine
 
    .PARAMETER Id
    The ID of the vRA Machine
 
    .PARAMETER Name
    The Name of the vRA Machine
 
    .PARAMETER WaitForCompletion
    If this flag is added, this function will wait for the power state of the machine to = OFF
 
    .PARAMETER CompletionTimeout
    The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
    .PARAMETER Force
    Force this change
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Stop-vRAMachine -Id 'b1dd48e71d74267559bb930934470'
 
    .EXAMPLE
    Stop-vRAMachine -Name 'iaas01'
 
    .EXAMPLE
    Stop-vRAMachine -Name 'iaas01' -WaitForCompletion
 
    .EXAMPLE
    Stop-vRAMachine -Name 'iaas01' -WaitForCompletion -CompletionTimeout 300
 
#>

[CmdletBinding(DefaultParameterSetName="PowerOffByName", SupportsShouldProcess, ConfirmImpact='High')][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="PowerOffById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="PowerOffByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name,

        [Parameter()]
        [switch]$WaitForCompletion,

        [Parameter()]
        [int]$CompletionTimeout = 120,

        [Parameter()]
        [switch]$Force

    )
    Begin {

        $APIUrl = "/iaas/api/machines"

        function CalculateOutput {
            if ($WaitForCompletion) {
                # if the wait for completion flag is given, the output will be different, we will wait here
                # we will use the built-in function to check status
                $elapsedTime = 0
                do {
                    $RequestResponse = Get-vRARequest -RequestId $Response.id
                    if ($RequestResponse.Status -eq "FINISHED") {
                        foreach ($resource in $RequestResponse.Resources) {
                            $Record = Invoke-vRARestMethod -URI "$resource" -Method GET
                            [PSCustomObject]@{
                                Name = $Record.name
                                PowerState = $Record.powerState
                                IPAddress = $Record.address
                                ExternalRegionId = $Record.externalRegionId
                                CloudAccountIDs = $Record.cloudAccountIds
                                ExternalId = $Record.externalId
                                Id = $Record.id
                                DateCreated = $Record.createdAt
                                LastUpdated = $Record.updatedAt
                                OrganizationId = $Record.organizationId
                                Properties = $Record.customProperties
                                RequestId = $Response.id
                                RequestStatus = "FINISHED"
                            }
                        }
                        break # leave loop as we are done here
                    }
                    $elapsedTime += 5
                    Start-Sleep -Seconds 5
                } while ($elapsedTime -lt $CompletionTimeout)

                if ($elapsedTime -gt $CompletionTimeout -or $elapsedTime -eq $CompletionTimeout) {
                    # we have errored out
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Resources = $Response.resources
                        RequestId = $Response.id
                        Message = "We waited for completion, but we hit a timeout at $CompletionTimeout seconds. You may use Get-vRARequest -RequestId $($Response.id) to continue checking status. Here was the original response: $($Response.message)"
                        RequestStatus = $Response.status
                    }
                }
            } else {
                [PSCustomObject]@{
                    Name = $Response.name
                    Progress = $Response.progress
                    Resources = $Response.resources
                    RequestId = $Response.id
                    Message = $Response.message
                    RequestStatus = $Response.status
                }
            }
        }
    }
    Process {

        try {

                switch ($PsCmdlet.ParameterSetName) {

                    # --- Stop the given machine by its id
                    'PowerOffById' {

                        foreach ($machineId in $Id) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machineId)){
                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/power-off" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                    # --- Stop the given machine by its name
                    'PowerOffByName' {

                        foreach ($machine in $Name) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machine)){
                                $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machine'`&`$select=id" -Method GET
                                $machineId = $machineResponse.content[0].Id

                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/power-off" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                }
        }
        catch [Exception]{

            throw
        }
    }
    End {

    }
}


<#
    - Function: Stop-vRAMachineGuestOS
#>


function Stop-vRAMachineGuestOS {
<#
    .SYNOPSIS
    Shutdown a vRA Machine
 
    .DESCRIPTION
    Shutdown a vRA Machine
 
    .PARAMETER Id
    The ID of the vRA Machine
 
    .PARAMETER Name
    The Name of the vRA Machine
 
    .PARAMETER WaitForCompletion
    If this flag is added, this function will wait for the power state of the machine to = OFF
 
    .PARAMETER CompletionTimeout
    The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
    .PARAMETER Force
    Force this change
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Stop-vRAMachineGuestOS -Id 'b1dd48e71d74267559bb930934470'
 
    .EXAMPLE
    Stop-vRAMachineGuestOS -Name 'iaas01'
 
    .EXAMPLE
    Stop-vRAMachineGuestOS -Name 'iaas01' -WaitForCompletion
 
    .EXAMPLE
    Stop-vRAMachineGuestOS -Name 'iaas01' -WaitForCompletion -CompletionTimeout 300
 
#>

[CmdletBinding(DefaultParameterSetName="ShutdownByName", SupportsShouldProcess, ConfirmImpact='High')][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ShutdownById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ShutdownByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name,

        [Parameter()]
        [switch]$WaitForCompletion,

        [Parameter()]
        [int]$CompletionTimeout = 120,

        [Parameter()]
        [switch]$Force

    )
    Begin {

        $APIUrl = "/iaas/api/machines"

        function CalculateOutput {

            if ($WaitForCompletion) {
                # if the wait for completion flag is given, the output will be different, we will wait here
                # we will use the built-in function to check status
                $elapsedTime = 0
                do {
                    $RequestResponse = Get-vRARequest -RequestId $Response.id
                    if ($RequestResponse.Status -eq "FINISHED") {
                        foreach ($resource in $RequestResponse.Resources) {
                            $Record = Invoke-vRARestMethod -URI "$resource" -Method GET
                            [PSCustomObject]@{
                                Name = $Record.name
                                PowerState = $Record.powerState
                                IPAddress = $Record.address
                                ExternalRegionId = $Record.externalRegionId
                                CloudAccountIDs = $Record.cloudAccountIds
                                ExternalId = $Record.externalId
                                Id = $Record.id
                                DateCreated = $Record.createdAt
                                LastUpdated = $Record.updatedAt
                                OrganizationId = $Record.organizationId
                                Properties = $Record.customProperties
                                RequestId = $Response.id
                                RequestStatus = "FINISHED"
                            }
                        }
                        break # leave loop as we are done here
                    }
                    $elapsedTime += 5
                    Start-Sleep -Seconds 5
                } while ($elapsedTime -lt $CompletionTimeout)

                if ($elapsedTime -gt $CompletionTimeout -or $elapsedTime -eq $CompletionTimeout) {
                    # we have errored out
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Resources = $Response.resources
                        RequestId = $Response.id
                        Message = "We waited for completion, but we hit a timeout at $CompletionTimeout seconds. You may use Get-vRARequest -RequestId $($Response.id) to continue checking status. Here was the original response: $($Response.message)"
                        RequestStatus = $Response.status
                    }
                }
            } else {
                [PSCustomObject]@{
                    Name = $Response.name
                    Progress = $Response.progress
                    Resources = $Response.resources
                    RequestId = $Response.id
                    Message = $Response.message
                    RequestStatus = $Response.status
                }
            }
        }
    }
    Process {

        try {

                switch ($PsCmdlet.ParameterSetName) {

                    # --- Shutdown the given machine by its id
                    'ShutdownById' {

                        foreach ($machineId in $Id) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machineId)) {
                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/shutdown" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                    # --- Shutdown the given machine by its name
                    'ShutdownByName' {

                        foreach ($machine in $Name) {
                            if ($Force -or $PsCmdlet.ShouldProcess($machine)) {
                                $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machine'`&`$select=id" -Method GET
                                $machineId = $machineResponse.content[0].Id

                                $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/shutdown" -Method POST
                                CalculateOutput
                            }
                        }
                        break
                    }

                }
        }
        catch [Exception]{

            throw
        }
    }
    End {

    }
}


<#
    - Function: Suspend-vRAMachine
#>


function Suspend-vRAMachine {
    <#
        .SYNOPSIS
        Suspend a vRA Machine
 
        .DESCRIPTION
        Suspend a vRA Machine
 
        .PARAMETER Id
        The ID of the vRA Machine
 
        .PARAMETER Name
        The Name of the vRA Machine
 
        .PARAMETER WaitForCompletion
        If this flag is added, this function will wait for the suspend operation to complete
 
        .PARAMETER CompletionTimeout
        The default of this paramter is 2 minutes (120 seconds), but this parameter can be overriden here
 
        .PARAMETER Force
        Force this change
 
        .OUTPUTS
        System.Management.Automation.PSObject.
 
        .EXAMPLE
        Suspend-vRAMachine -Id 'b1dd48e71d74267559bb930934470'
 
        .EXAMPLE
        Suspend-vRAMachine -Name 'iaas01'
 
        .EXAMPLE
        Suspend-vRAMachine -Name 'iaas01' -WaitForCompletion
 
        .EXAMPLE
        Suspend-vRAMachine -Name 'iaas01' -WaitForCompletion -CompletionTimeout 300
 
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High', DefaultParameterSetName="SuspendByName")][OutputType('System.Management.Automation.PSObject')]

        Param (

            [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="SuspendById")]
            [ValidateNotNullOrEmpty()]
            [String[]]$Id,

            [Parameter(Mandatory=$true,ParameterSetName="SuspendByName")]
            [ValidateNotNullOrEmpty()]
            [String[]]$Name,

            [Parameter()]
            [switch]$WaitForCompletion,

            [Parameter()]
            [int]$CompletionTimeout = 120,

            [Parameter()]
            [switch]$Force

        )
        Begin {

            $APIUrl = "/iaas/api/machines"

            function CalculateOutput {

                if ($WaitForCompletion) {
                    # if the wait for completion flag is given, the output will be different, we will wait here
                    # we will use the built-in function to check status
                    $elapsedTime = 0
                    do {
                        $RequestResponse = Get-vRARequest -RequestId $Response.id
                        if ($RequestResponse.Status -eq "FINISHED") {
                            foreach ($resource in $RequestResponse.Resources) {
                                $Record = Invoke-vRARestMethod -URI "$resource" -Method GET
                                [PSCustomObject]@{
                                    Name = $Record.name
                                    PowerState = $Record.powerState
                                    IPAddress = $Record.address
                                    ExternalRegionId = $Record.externalRegionId
                                    CloudAccountIDs = $Record.cloudAccountIds
                                    ExternalId = $Record.externalId
                                    Id = $Record.id
                                    DateCreated = $Record.createdAt
                                    LastUpdated = $Record.updatedAt
                                    OrganizationId = $Record.organizationId
                                    Properties = $Record.customProperties
                                    RequestId = $Response.id
                                    RequestStatus = "FINISHED"
                                }
                            }
                            break # leave loop as we are done here
                        }
                        $elapsedTime += 5
                        Start-Sleep -Seconds 5
                    } while ($elapsedTime -lt $CompletionTimeout)

                    if ($elapsedTime -gt $CompletionTimeout -or $elapsedTime -eq $CompletionTimeout) {
                        # we have errored out
                        [PSCustomObject]@{
                            Name = $Response.name
                            Progress = $Response.progress
                            Resources = $Response.resources
                            RequestId = $Response.id
                            Message = "We waited for completion, but we hit a timeout at $CompletionTimeout seconds. You may use Get-vRARequest -RequestId $($Response.id) to continue checking status. Here was the original response: $($Response.message)"
                            RequestStatus = $Response.status
                        }
                    }
                } else {
                    [PSCustomObject]@{
                        Name = $Response.name
                        Progress = $Response.progress
                        Resources = $Response.resources
                        RequestId = $Response.id
                        Message = $Response.message
                        RequestStatus = $Response.status
                    }
                }
            }
        }
        Process {

            try {


                    switch ($PsCmdlet.ParameterSetName) {

                        # --- Suspend the given machine by its id
                        'SuspendById' {

                            foreach ($machineId in $Id) {
                                if ($Force -or $PsCmdlet.ShouldProcess($machineid)) {
                                    $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/suspend" -Method POST
                                    CalculateOutput
                                }
                            }
                            break
                        }

                        # --- Suspend the given machine by its name
                        'SuspendByName' {

                            foreach ($machine in $Name) {
                                if ($Force -or $PsCmdlet.ShouldProcess($machine)) {
                                    $machineResponse = Invoke-vRARestMethod -URI "$APIUrl`?`$filter=name eq '$machine'`&`$select=id" -Method GET
                                    $machineId = $machineResponse.content[0].Id

                                    $Response = Invoke-vRARestMethod -URI "$APIUrl`/$machineId/operations/suspend" -Method POST
                                    CalculateOutput
                                }
                            }
                            break
                        }

                    }
            }
            catch [Exception]{

                throw
            }
        }
        End {

        }
    }


<#
    - Function: Get-vRAOnboardingDeployment
#>


function Get-vRAOnboardingDeployment {
<#
    .SYNOPSIS
    Get a vRA OnboardingDeployment.
 
    .DESCRIPTION
    Get a vRA OnboardingDeployment.
 
    .PARAMETER Id
    The ID of the OnboardingDeployment
 
    .PARAMETER Name
    The Name of the OnboardingDeployment
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Get-vRAOnboardingDeployment
 
    .EXAMPLE
    Get-vRAOnboardingDeployment -Id '247d9305a4231275581a098553c26'
 
    .EXAMPLE
    Get-vRAOnboardingDeployment -Name 'Test OnboardingDeployment'
 
#>

[CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name
    )

    Begin {
        $APIUrl = '/relocation/onboarding/deployment'

        function CalculateOutput {

            $DocumentSelfLink = $OnboardingDeployment.documentSelfLink
            $OnboardingDeploymentId = ($DocumentSelfLink -split "/")[-1]

            [PSCustomObject] @{

                Name = $OnboardingDeployment.name
                Id = $OnboardingDeploymentId
                PlanLink = $OnboardingDeployment.planLink
                ConsumerDeploymentLink = $OnboardingDeployment.consumerDeploymentLink
                DocumentSelfLink = $DocumentSelfLink
            }
        }
    }

    Process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Onboarding Deployment by id
                'ById' {

                    foreach ($OnboardingDeploymentId in $Id){

                        $URI = "$($APIUrl)/$($OnboardingDeploymentId)"

                        $OnboardingDeployment= Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        CalculateOutput
                    }

                    break
                }
                # --- Get Onboarding Deployment by name
                'ByName' {

                    $URI = "$($APIUrl)?`$expand=true"

                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($OnboardingDeploymentName in $Name){

                        $MatchedOnboardingDeployment = $false

                        foreach ($Document in $Response.documentLinks){

                            $OnboardingDeployment = $Response.documents.$document

                            if ($OnboardingDeployment.name -eq $OnboardingDeploymentName){

                                $MatchedOnboardingDeployment = $true
                                CalculateOutput
                            }
                        }

                        if (!$MatchedOnboardingDeployment) {

                            throw "Could not find Onboarding Deployment with name: $($OnboardingDeploymentName)"
                        }
                    }

                    break
                }
                # --- No parameters passed so return all Onboarding Deployments
                'Standard' {

                    $URI = "$($APIUrl)?`$expand=true"

                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($Document in $Response.documentLinks){

                        $OnboardingDeployment = $Response.documents.$document

                        CalculateOutput
                    }
                }
            }
        }
        catch [Exception]{

            throw
        }
    }

    End {

    }
}

<#
    - Function: Get-vRAOnboardingPlan
#>


function Get-vRAOnboardingPlan {
<#
    .SYNOPSIS
    Get a vRA OnboardingPlan.
 
    .DESCRIPTION
    Get a vRA OnboardingPlan.
 
    .PARAMETER Id
    The ID of the OnboardingPlan
 
    .PARAMETER Name
    The Name of the OnboardingPlan
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Get-vRAOnboardingPlan
 
    .EXAMPLE
    Get-vRAOnboardingPlan -Id '247d9305a4231275581a098553c26'
 
    .EXAMPLE
    Get-vRAOnboardingPlan -Name 'Test OnboardingPlan'
 
#>

[CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name
    )

    Begin {
        $APIUrl = '/relocation/onboarding/plan'

        function CalculateOutput {

            $DocumentSelfLink = $OnboardingPlan.documentSelfLink
            $OnboardingPlanId = ($DocumentSelfLink -split "/")[-1]

            [PSCustomObject] @{

                Name = $OnboardingPlan.name
                Id = $OnboardingPlanId
                Status = $OnboardingPlan.status
                EndpointName = $OnboardingPlan.endpointName
                EndpointId = $OnboardingPlan.endpointId
                EndpointIds = $OnboardingPlan.endpointIds
                ProjectName = $OnboardingPlan.projectName
                ProjectId = $OnboardingPlan.projectId
                CreatedBy = $OnboardingPlan.createdBy
                EnableExtensibilityEvents = $OnboardingPlan.enableExtensibilityEvents
                OrganizationId = $OnboardingPlan.organizationId
                LastRunTimeMicros = $OnboardingPlan.lastRunTimeMicros
                NextRefreshTimeMicros = $OnboardingPlan.nextRefreshTimeMicros
                RefreshIntervalMicros = $OnboardingPlan.refreshIntervalMicros
                DocumentSelfLink = $DocumentSelfLink
            }
        }
    }

    Process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Onboarding Plan by id
                'ById' {

                    foreach ($OnboardingPlanId in $Id){

                        $URI = "$($APIUrl)/$($OnboardingPlanId)"

                        $OnboardingPlan= Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        CalculateOutput
                    }

                    break
                }
                # --- Get Onboarding Plan by name
                'ByName' {

                    $URI = "$($APIUrl)?`$expand=true"

                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($OnboardingPlanName in $Name){

                        $MatchedOnboardingPlan = $false

                        foreach ($Document in $Response.documentLinks){

                            $OnboardingPlan = $Response.documents.$document

                            if ($OnboardingPlan.name -eq $OnboardingPlanName){

                                $MatchedOnboardingPlan = $true
                                CalculateOutput
                            }
                        }

                        if (!$MatchedOnboardingPlan) {

                            throw "Could not find Onboarding Plan with name: $($OnboardingPlanName)"
                        }
                    }

                    break
                }
                # --- No parameters passed so return all Onboarding Plans
                'Standard' {

                    $URI = "$($APIUrl)?`$expand=true"

                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($Document in $Response.documentLinks){

                        $OnboardingPlan = $Response.documents.$document

                        CalculateOutput
                    }
                }
            }
        }
        catch [Exception]{

            throw
        }
    }

    End {

    }
}

<#
    - Function: Get-vRAOnboardingPlanExecution
#>


function Get-vRAOnboardingPlanExecution {
<#
    .SYNOPSIS
    Get a vRA OnboardingPlanExecution
 
    .DESCRIPTION
    Get a vRA OnboardingPlanExecution
 
    .PARAMETER Id
    The ID of the OnboardingPlanExecution
 
    .PARAMETER ExecutionPlanLink
    The Execution Plan Link
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Get-vRAOnboardingPlanExecution -Id 'ig885f86-0e2d-4157-r5d4-8cb42ce6dd84'
 
    .EXAMPLE
    Get-vRAOnboardingPlanExecution -ExecutionPlanLink '/relocation/api/wo/execute-plan/ig885f86-0e2d-4157-r5d4-8cb42ce6dd8'
 
#>

[CmdletBinding(DefaultParameterSetName="ById")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByExecutionPlanLink")]
        [ValidateNotNullOrEmpty()]
        [String[]]$ExecutionPlanLink
    )

    begin {

        function CalculateOutput {

            [PSCustomObject] @{

                ExecutionId = $ExecuteOnboardingPlan.executionId
                DocumentSelfLink = $ExecuteOnboardingPlan.documentSelfLink
                PlanLink = $ExecuteOnboardingPlan.planLink
                TaskInfo = $ExecuteOnboardingPlan.taskInfo
                SubStage = $ExecuteOnboardingPlan.subStage
                PlanValidated = $ExecuteOnboardingPlan.planValidated
                BlueprintsValidated = $ExecuteOnboardingPlan.blueprintsValidated
                DeploymentsValidated = $ExecuteOnboardingPlan.deploymentsValidated
                MachinesValidated = $ExecuteOnboardingPlan.machinesValidated
                DeploymentCount = $ExecuteOnboardingPlan.deploymentCount
                RetryCount = $ExecuteOnboardingPlan.retryCount
                FailedDeploymentCount = $ExecuteOnboardingPlan.failedDeploymentCount
            }
        }
    }

    process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Onboarding Plan Execution by Id
                'ById' {

                    foreach ($OnboardingPlanExecutionId in $Id){

                        $URI = "/relocation/api/wo/execute-plan/$($OnboardingPlanExecutionId)"

                        $ExecuteOnboardingPlan = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        CalculateOutput
                    }

                    break
                }
                # --- Get Onboarding Plan Execution by Name
                'ByExecutionPlanLink' {

                    foreach ($OnboardingPlanExecutionLink in $ExecutionPlanLink){

                        $ExecuteOnboardingPlan = Invoke-vRARestMethod -Method GET -URI $OnboardingPlanExecutionLink -Verbose:$VerbosePreference

                        CalculateOutput
                    }

                    break
                }
            }
        }
        catch [Exception]{

            throw
        }
    }
    end {

    }
}

<#
    - Function: Get-vRAOnboardingResource
#>


function Get-vRAOnboardingResource {
<#
    .SYNOPSIS
    Get a vRA Onboarding Resource
 
    .DESCRIPTION
    Get a vRA Onboarding Resource
 
    .PARAMETER Id
    The ID of the Onboarding Resource
 
    .PARAMETER Name
    The Name of the Onboarding Resource
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Get-vRAOnboardingResource
 
    .EXAMPLE
    Get-vRAOnboardingResource -Id '0b8c2def-b2bc-3fb1-a88f-0621dacdab71'
 
    .EXAMPLE
    Get-vRAOnboardingResource -Name 'Test OnboardingResource'
 
#>

[CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name
    )

    begin {
        $APIUrl = '/relocation/onboarding/resource'

        function CalculateOutput {

            $DocumentSelfLink = $OnboardingResource.documentSelfLink
            $OnboardingResourceId = ($DocumentSelfLink -split "/")[-1]

            [PSCustomObject] @{

                Name = $OnboardingResource.resourceName
                Id = $OnboardingResourceId
                PlanLink = $OnboardingResource.planLink
                ResourceLink = $OnboardingResource.resourceLink
                DeploymentLink = $OnboardingResource.deploymentLink
                TagLinks = $OnboardingResource.tagLinks
                RuleLinks = $OnboardingResource.ruleLinks
                CreatedTimeMicros = $OnboardingResource.createdTimeMicros
                DocumentSelfLink = $DocumentSelfLink
            }
        }
    }

    process {

        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Get Onboarding Resource by Id
                'ById' {

                    foreach ($OnboardingResourceId in $Id){

                        $URI = "$($APIUrl)/$($OnboardingResourceId)"
                        $OnboardingResource= Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                        CalculateOutput
                    }

                    break
                }
                # --- Get Onboarding Resource by Name
                'ByName' {

                    $URI = "$($APIUrl)?`$expand=true"
                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($OnboardingResourceName in $Name){

                        $MatchedOnboardingResource = $false

                        foreach ($Document in $Response.documentLinks){

                            $OnboardingResource = $Response.documents.$document

                            if ($OnboardingResource.resourceName -eq $OnboardingResourceName){

                                $MatchedOnboardingResource = $true
                                CalculateOutput
                            }
                        }

                        if (!$MatchedOnboardingResource) {

                            throw "Could not find Onboarding Resource with name: $($OnboardingResourceName)"
                        }
                    }

                    break
                }
                # --- No parameters passed so return all Onboarding Resources
                'Standard' {

                    $URI = "$($APIUrl)?`$expand=true"
                    $Response = Invoke-vRARestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($Document in $Response.documentLinks){

                        $OnboardingResource = $Response.documents.$document

                        CalculateOutput
                    }
                }
            }
        }
        catch [Exception]{

            throw
        }
    }
    end {

    }
}

<#
    - Function: Invoke-vRAOnboardingPlan
#>


function Invoke-vRAOnboardingPlan {
<#
    .SYNOPSIS
    Execute a vRA Onboarding Plan
 
    .DESCRIPTION
    Execute a vRA Onboarding Plan
 
    .PARAMETER Name
    The Name of the Onboarding Plan
 
    .PARAMETER Id
    The Id of the Onboarding Plan
 
    .PARAMETER PlanLink
    The Link of the Onboarding Plan
 
    .PARAMETER JSON
    A JSON string with the body payload
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Invoke-vRAOnboardingPlan -Name "TestOnboardingPlan"
 
    .EXAMPLE
    Invoke-vRAOnboardingPlan -Id "ecaa2cf0-2f8c-4a79-r4d7-27f13c7d3ee6"
 
    .EXAMPLE
    Invoke-vRAOnboardingPlan -PlanLink "/relocation/onboarding/plan/ecaa2cf0-2f8c-4a79-r4d7-27f13c7d3ee6"
 
    .EXAMPLE
    $JSON = @"
 
        {
            "planLink": "/relocation/onboarding/plan/ecaa2cf0-2f8c-4a79-r4d7-27f13c7d3ee6"
        }
"@
 
    $JSON | Invoke-vRAOnboardingPlan
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low",DefaultParameterSetName="ById")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ById")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Id,

        [Parameter(Mandatory=$true,ParameterSetName="ByName")]
        [ValidateNotNullOrEmpty()]
        [String[]]$Name,

        [Parameter(Mandatory=$true,ParameterSetName="ByPlanLink")]
        [ValidateNotNullOrEmpty()]
        [String[]]$PlanLink,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="JSON")]
        [ValidateNotNullOrEmpty()]
        [String]$JSON

    )

    begin {

        $URI = "/relocation/api/wo/execute-plan"
        function CalculateOutput {

            [PSCustomObject] @{

                ExecutionId = $ExecuteOnboardingPlan.executionId
                DocumentSelfLink = $ExecuteOnboardingPlan.documentSelfLink
                PlanLink = $ExecuteOnboardingPlan.planLink
                TaskInfo = $ExecuteOnboardingPlan.taskInfo
                SubStage = $ExecuteOnboardingPlan.subStage
                PlanValidated = $ExecuteOnboardingPlan.planValidated
                BlueprintsValidated = $ExecuteOnboardingPlan.blueprintsValidated
                DeploymentsValidated = $ExecuteOnboardingPlan.deploymentsValidated
                MachinesValidated = $ExecuteOnboardingPlan.machinesValidated
                DeploymentCount = $ExecuteOnboardingPlan.deploymentCount
                RetryCount = $ExecuteOnboardingPlan.retryCount
                FailedDeploymentCount = $ExecuteOnboardingPlan.failedDeploymentCount
            }
        }
    }

    process {
        try {

            switch ($PsCmdlet.ParameterSetName) {

                # --- Execute Onboarding Plan by Id
                'ById' {

                    foreach ($OnboardingPlanId in $Id){

                        if ($PSCmdlet.ShouldProcess($OnboardingPlanId)){

                            $Body = @"
                            {
                                "planLink": "/relocation/onboarding/plan/$($OnboardingPlanId)"
                            }
"@

                            $ExecuteOnboardingPlan= Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                            CalculateOutput
                        }
                    }

                    break
                }
                # --- Execute Onboarding Plan by Name
                'ByName' {

                    foreach ($OnboardingPlanName in $Name){

                        if ($PSCmdlet.ShouldProcess($OnboardingPlanName)){

                            $OnboardingPlanLink = (Get-vRAOnboardingPlan -Name $OnboardingPlanName).DocumentSelfLink
                            $Body = @"
                            {
                                "planLink": "$($OnboardingPlanLink)"
                            }
"@

                            $ExecuteOnboardingPlan= Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                            CalculateOutput
                        }
                    }
                }
                # --- Execute Onboarding Plan by PlanLink
                'ByPlanLink' {

                    foreach ($OnboardingPlanLink in $PlanLink){

                        if ($PSCmdlet.ShouldProcess($OnboardingPlanLink)){

                            $Body = @"
                            {
                                "planLink": "$($OnboardingPlanLink)"
                            }
"@

                            $ExecuteOnboardingPlan= Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                            CalculateOutput
                        }
                    }
                }
                # --- Execute Onboarding Plan by JSON
                'JSON' {

                    $Data = ($JSON | ConvertFrom-Json)
                    $Body = $JSON
                    $OnboardingPlanLink = $Data.planLink

                    if ($PSCmdlet.ShouldProcess($OnboardingPlanLink)){

                        $ExecuteOnboardingPlan= Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                        CalculateOutput
                    }
                }
            }
        }
        catch [Exception] {

            throw
        }
    }
    end {

    }
}

<#
    - Function: New-vRAOnboardingDeployment
#>


function New-vRAOnboardingDeployment {
<#
    .SYNOPSIS
    Create a vRA Onboarding Deployment
 
    .DESCRIPTION
    Create a vRA Onboarding Deployment
 
    .PARAMETER Name
    The name of the Onboarding Deployment
 
    .PARAMETER OnboardingPlanLink
    Link for the Onboarding Plan to associate with
 
    .PARAMETER JSON
    A JSON string with the body payload
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    New-vRAOnboardingDeployment -Name "TestOnboardingDeployment" -OnboardingPlanLink "/relocation/onboarding/plan/282dd58e8dcfc7559a0d225680a7"
 
    .EXAMPLE
    $JSON = @"
 
        {
            "name": "TestOnboardingDeployment",
            "planLink": "/relocation/onboarding/plan/282dd58e8dcfc7559a0d225680a7"
        }
"@
 
    $JSON | New-vRAOnboardingDeployment
 
 
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low",DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$false,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$OnboardingPlanLink,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="JSON")]
        [ValidateNotNullOrEmpty()]
        [String]$JSON

    )

    begin {
        function CalculateOutput {

            $DocumentSelfLink = $OnboardingDeployment.documentSelfLink
            $OnboardingDeploymentId = ($DocumentSelfLink -split "/")[-1]

            [PSCustomObject] @{

                Name = $OnboardingDeployment.name
                Id = $OnboardingDeploymentId
                PlanLink = $OnboardingDeployment.planLink
                DocumentSelfLink = $DocumentSelfLink
            }
        }
    }

    process {

        if ($PSBoundParameters.ContainsKey("JSON")) {

            $Data = ($JSON | ConvertFrom-Json)

            $Body = $JSON
            $Name = $Data.name
        }
        else {

            $Body = @"
                {
                    "name": "$($Name)",
                    "planLink": "$($OnboardingPlanLink)"
                }
"@

        }

        # --- Create new Onboarding Deployment
        try {
            if ($PSCmdlet.ShouldProcess($Name)){

                $URI = "/relocation/onboarding/deployment"
                $OnboardingDeployment = Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                CalculateOutput
            }
        }
        catch [Exception] {

            throw
        }
    }

    end {

    }
}

<#
    - Function: New-vRAOnboardingPlan
#>


function New-vRAOnboardingPlan {
<#
    .SYNOPSIS
    Create a vRA Onboarding Plan
 
    .DESCRIPTION
    Create a vRA Onboarding Plan
 
    .PARAMETER Name
    The name of the Onboarding Plan
 
    .PARAMETER CloudAccountId
    Cloud Account Id for the Onboarding Plan (Note: vRA Cloud API refers to it as endpointId)
 
    .PARAMETER ProjectId
    Project Id for the Onboarding Plan
 
    .PARAMETER JSON
    A JSON string with the body payload
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    New-vRAOnboardingPlan -Name "TestOnboardingPlan" -CloudAccountId "42fe38765a63bd755921a88814a14" -ProjectId "9f732951-2279-422a-8045-9b254d427100"
 
    .EXAMPLE
    $JSON = @"
 
        {
            "name": "TestOnboardingPlan",
            "endpointId": "42fe38765a63bd755921a88814a14",
            "projectId": "9f732951-2279-422a-8045-9b254d427100"
        }
"@
 
    $JSON | New-vRAOnboardingPlan
 
 
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low",DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$CloudAccountId,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$ProjectId,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="JSON")]
        [ValidateNotNullOrEmpty()]
        [String]$JSON

    )

    Begin {
        function CalculateOutput {

            $DocumentSelfLink = $OnboardingPlan.documentSelfLink
            $OnboardingPlanId = ($DocumentSelfLink -split "/")[-1]

            [PSCustomObject] @{

                Name = $OnboardingPlan.name
                Id = $OnboardingPlanId
                Status = $OnboardingPlan.status
                EndpointId = $OnboardingPlan.endpointId
                EndpointIds = $OnboardingPlan.endpointIds
                ProjectId = $OnboardingPlan.projectId
                CreatedBy = $OnboardingPlan.createdBy
                EnableExtensibilityEvents = $OnboardingPlan.enableExtensibilityEvents
                OrganizationId = $OnboardingPlan.organizationId
                DocumentSelfLink = $DocumentSelfLink
            }
        }
    }

    Process {

        if ($PSBoundParameters.ContainsKey("JSON")) {

            $Data = ($JSON | ConvertFrom-Json)

            $Body = $JSON
            $Name = $Data.name
        }
        else {

            $Body = @"
                {
                    "name": "$($Name)",
                    "endpointId": "$($CloudAccountId)",
                    "projectId": "$($ProjectId)"
                }
"@

        }

        # --- Create new Onboarding Plan
        try {
            if ($PSCmdlet.ShouldProcess($Name)){

                $URI = "/relocation/onboarding/plan"
                $OnboardingPlan = Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                CalculateOutput
            }
        }
        catch [Exception] {

            throw
        }
    }

    End {

    }
}

<#
    - Function: New-vRAOnboardingResource
#>


function New-vRAOnboardingResource {
<#
    .SYNOPSIS
    Create a vRA Onboarding Resource
 
    .DESCRIPTION
    Create a vRA Onboarding Resource
 
    .PARAMETER Name
    The name of the Onboarding Resource
 
    .PARAMETER VMId
    The Id of the IaaS VM to associate the Onboarding Resource with
 
    .PARAMETER DeploymentLink
    Link to the Onboarding Deployment to associate the Onboarding Resource with
 
    .PARAMETER PlanLink
    Link to the Onboarding Plan to associate the Onboarding Resource with
 
    .PARAMETER RuleLinks
    Link(s) to the Onboarding Rule(s) to associate the Onboarding Resource with
 
    .PARAMETER JSON
    A JSON string with the body payload
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    $OnboardingResourceArguments = @{
 
        Name = 'TestOnboardingResource'
        VMId = 'ee7eeed1-b4e4-4143-a437-d3c0622bf9df'
        DeploymentLink = '/relocation/onboarding/deployment/5bc7eb75-r2d2-4c24-93ac-8c3p0d02f7f1'
        PlanLink = '/relocation/onboarding/plan/ecaak2s0-r5d4-4a79-b17b-27f13c7d3ff7'
        RuleLinks = '/relocation/onboarding/rule/include'
    }
 
    New-vRAOnboardingResource @OnboardingResourceArguments
 
    .EXAMPLE
    $JSON = @"
 
        {
            "deploymentLink": "/relocation/onboarding/deployment/5bc7eb75-r2d2-4c24-93ac-8c3p0d02f7f1",
            "planLink": "/relocation/onboarding/plan/ecaak2s0-r5d4-4a79-b17b-27f13c7d3ff7",
            "resourceLink": "/resources/compute/ee7eeed1-b4e4-4143-a437-d3c0622bf9df",
            "resourceName": "TestOnboardingResource",
            "ruleLinks": [
                "/relocation/onboarding/rule/include"
            ]
        }
"@
 
    $JSON | New-vRAOnboardingResource
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low",DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')]

    Param (

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$VMId,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$DeploymentLink,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String]$PlanLink,

        [Parameter(Mandatory=$true,ParameterSetName="Standard")]
        [ValidateNotNullOrEmpty()]
        [String[]]$RuleLinks,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="JSON")]
        [ValidateNotNullOrEmpty()]
        [String]$JSON

    )

    begin {
        function CalculateOutput {

            $DocumentSelfLink = $OnboardingResource.documentSelfLink
            $OnboardingResourceId = ($DocumentSelfLink -split "/")[-1]

            [PSCustomObject] @{

                Name = $OnboardingResource.resourceName
                Id = $OnboardingResourceId
                PlanLink = $OnboardingResource.planLink
                ResourceLink = $OnboardingResource.resourceLink
                DeploymentLink = $OnboardingResource.deploymentLink
                RuleLinks = $OnboardingResource.ruleLinks
                CreatedTimeMicros = $OnboardingResource.createdTimeMicros
                DocumentSelfLink = $DocumentSelfLink
            }
        }
    }

    process {

        if ($PSBoundParameters.ContainsKey("JSON")) {

            $Data = ($JSON | ConvertFrom-Json)

            $Body = $JSON
            $Name = $Data.resourceName
        }
        else {

            # Format RuleLinks with surrounding quotes and join into single string
            $RuleLinksAddQuotes = $RuleLinks | ForEach-Object {"`"$_`""}
            $RuleLinksFormatForBodyText = $RuleLinksAddQuotes -join ","

            $Body = @"
                {
                    "deploymentLink": "$($DeploymentLink)",
                    "planLink": "$($PlanLink)",
                    "resourceLink": "/resources/compute/$($VMId)",
                    "resourceName": "$($Name)",
                    "ruleLinks": [ $($RuleLinksFormatForBodyText) ]
                }
"@

        }

        # --- Create new Onboarding Resource
        try {
            if ($PSCmdlet.ShouldProcess($Name)){

                $URI = "/relocation/onboarding/resource"
                $OnboardingResource = Invoke-vRARestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                CalculateOutput
            }
        }
        catch [Exception] {

            throw
        }
    }
    end {

    }
}

<#
    - Function: Remove-vRAOnboardingDeployment
#>


function Remove-vRAOnboardingDeployment {
    <#
        .SYNOPSIS
        Remove an Onboarding Deployment
 
        .DESCRIPTION
        Remove an Onboarding Deployment
 
        .PARAMETER Id
        The Id of the Onboarding Deployment
 
        .PARAMETER Name
        The name of the Onboarding Deployment
 
        .INPUTS
        System.String
 
        .EXAMPLE
        Remove-vRAOnboardingDeployment -Name OnboardingDeployment1
 
        .EXAMPLE
        Remove-vRAOnboardingDeployment -Id 'b210b3044578447559e3b3bad52de'
 
        .EXAMPLE
        Get-vRAOnboardingDeployment -Name OnboardingDeployment1 | Remove-vRAOnboardingDeployment
 
    #>

    [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High",DefaultParameterSetName="ById")]

    Param (

    [parameter(Mandatory=$true, ValueFromPipelineByPropertyName, ParameterSetName="ById")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$true, ParameterSetName="ByName")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name

    )

    begin {}

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {

                'ById' {

                    foreach ($OnboardingDeploymentId in $Id) {

                        if ($PSCmdlet.ShouldProcess($OnboardingDeploymentId)){

                            $URI = "/relocation/onboarding/deployment/$($OnboardingDeploymentId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }

                'ByName' {

                    foreach ($OnboardingDeploymentName in $Name) {

                        if ($PSCmdlet.ShouldProcess($OnboardingDeploymentName)){

                            $OnboardingDeploymentId = (Get-vRAOnboardingDeployment -Name $OnboardingDeploymentName).id
                            $URI = "/relocation/onboarding/deployment/$($OnboardingDeploymentId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }
            }
        }
        catch [Exception]{

            throw
        }
    }
}

<#
    - Function: Remove-vRAOnboardingPlan
#>


function Remove-vRAOnboardingPlan {
    <#
        .SYNOPSIS
        Remove an Onboarding Plan
 
        .DESCRIPTION
        Remove an Onboarding Plan
 
        .PARAMETER Id
        The id of the Onboarding Plan
 
        .PARAMETER Name
        The name of the Onboarding Plan
 
        .INPUTS
        System.String
 
        .EXAMPLE
        Remove-vRAOnboardingPlan -Name OnboardingPlan1
 
        .EXAMPLE
        Remove-vRAOnboardingPlan -Id 'b210b3044578447559e3b3bad52de'
 
        .EXAMPLE
        Get-vRAOnboardingPlan -Name OnboardingPlan1 | Remove-vRAOnboardingPlan
 
    #>

    [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High",DefaultParameterSetName="ById")]

    Param (

    [parameter(Mandatory=$true, ValueFromPipelineByPropertyName, ParameterSetName="ById")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$true, ParameterSetName="ByName")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name

    )

    begin {}

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {

                'ById' {

                    foreach ($OnboardingPlanId in $Id) {

                        if ($PSCmdlet.ShouldProcess($OnboardingPlanId)){

                            $URI = "/relocation/onboarding/plan/$($OnboardingPlanId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }

                'ByName' {

                    foreach ($OnboardingPlanName in $Name) {

                        if ($PSCmdlet.ShouldProcess($OnboardingPlanName)){

                            $OnboardingPlanId = (Get-vRAOnboardingPlan -Name $OnboardingPlanName).id
                            $URI = "/relocation/onboarding/plan/$($OnboardingPlanId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }
            }
        }
        catch [Exception]{

            throw
        }
    }
}

<#
    - Function: Remove-vRAOnboardingResource
#>


function Remove-vRAOnboardingResource {
    <#
        .SYNOPSIS
        Remove a Onboarding Resource
 
        .DESCRIPTION
        Remove a Onboarding Resource
 
        .PARAMETER Id
        The Id of the Onboarding Resource
 
        .PARAMETER Name
        The Name of the Onboarding Resource
 
        .INPUTS
        System.String
 
        .EXAMPLE
        Remove-vRAOnboardingResource -Name OnboardingResource1
 
        .EXAMPLE
        Remove-vRAOnboardingResource -Id '81289f15-89e4-3580-k2s0-86cd3af25257'
 
        .EXAMPLE
        Get-vRAOnboardingResource -Name OnboardingResource1 | Remove-vRAOnboardingResource
 
    #>

    [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High",DefaultParameterSetName="ById")]

    Param (

    [parameter(Mandatory=$true, ValueFromPipelineByPropertyName, ParameterSetName="ById")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$true, ParameterSetName="ByName")]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name

    )

    begin {}

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {

                'ById' {

                    foreach ($OnboardingResourceId in $Id) {

                        if ($PSCmdlet.ShouldProcess($OnboardingResourceId)){

                            $URI = "/relocation/onboarding/resource/$($OnboardingResourceId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }

                'ByName' {

                    foreach ($OnboardingResourceName in $Name) {

                        if ($PSCmdlet.ShouldProcess($OnboardingResourceName)){

                            $OnboardingResourceId = (Get-vRAOnboardingResource -Name $OnboardingResourceName).id
                            $URI = "/relocation/onboarding/resource/$($OnboardingResourceId)"

                            Invoke-vRARestMethod -Method DELETE -URI "$($URI)" -Verbose:$VerbosePreference | Out-Null
                        }
                    }

                    break
                }
            }
        }
        catch [Exception]{

            throw
        }
    }
}