PowervRO.psm1

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


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

    Remove-Variable -Name vROConnection -Force -ErrorAction SilentlyContinue

}
<#
    - Function: Connect-vROServer
#>


function Connect-vROServer {
<#
    .SYNOPSIS
    Connect to a vRO Server
 
    .DESCRIPTION
    Connect to a vRO Server and generate a connection object with Servername, Token etc
 
    .PARAMETER Server
    vRO Server to connect to
 
    .PARAMETER Port
    Optionally specify the server port. Default is 8281
 
    .PARAMETER Username
    Username to connect with
 
    .PARAMETER Password
    Password to connect with
 
    .PARAMETER Credential
    Credential object 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
    System.SecureString
    Management.Automation.PSCredential
    Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Connect-vROServer -Server vro01.domain.local -Credential (Get-Credential)
 
    .EXAMPLE
    $SecurePassword = ConvertTo-SecureString “P@ssword” -AsPlainText -Force
    Connect-vROServer -Server vro01.domain.local -Username TenantAdmin01 -Password $SecurePassword -IgnoreCertRequirements
 
    .EXAMPLE
    Connect-vROServer -Server vro01.domain.local -Port 443 -Credential (Get-Credential)
 
#>

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

    Param (

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

    [Parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [Int]$Port = 8281,

    [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)]
    [Switch]$IgnoreCertRequirements,

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

    )

    # --- Test Connectivity to vRO Server on the given port
    try {

        # --- Test Connection to the vRO Server
        Write-Verbose -Message "Testing connectivity to $($Server):$($Port)"

        $TCPClient = New-Object Net.Sockets.TcpClient
        $TCPClient.Connect($Server, $Port)

        $TCPClient.Close()

    }
    catch [Exception] {

        throw "Could not connect to server $($Server) on port $($Port)"

    }

    # --- 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
    }
    elseif (!$IsCoreCLR) {

        # --- Set the default Security Protocol for Windows PS to be TLS 1.2
        # --- vRO 7.x+ requires this
        $CurrentProtocols = ([System.Net.ServicePointManager]::SecurityProtocol).toString() -split ', '

        if (!($SslProtocol -in $CurrentProtocols)){

            [System.Net.ServicePointManager]::SecurityProtocol += [System.Net.SecurityProtocolType]::Tls12
        }

        $SslProtocolResult = 'Tls12'
    }

    # --- Convert Secure Credentials
    if ($PSBoundParameters.ContainsKey("Credential")){

        $Username = $Credential.UserName
        $ConnectionPassword = $Credential.GetNetworkCredential().Password

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

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

    try {

        # --- Set Encoded Password
        $Auth = $Username + ':' + $ConnectionPassword
        $Encoded = [System.Text.Encoding]::UTF8.GetBytes($Auth)
        $EncodedPassword = [System.Convert]::ToBase64String($Encoded)

        # --- Create Output Object
        $Script:vROConnection = [pscustomobject]@{

            Server = "https://$($Server):$($Port)"
            Username = $Username
            EncodedPassword = $EncodedPassword
            Version = $Null
            APIVersion = $Null
            SignedCertificates = $SignedCertificates
            SslProtocol = $SslProtocolResult
        }

        # --- Update vROConnection with version information
        $VersionInfo = Get-vROVersion
        $Script:vROConnection.Version = $VersionInfo.Version
        $Script:vROConnection.APIVersion = $VersionInfo.APIVersion

        # --- Test the credentials provided
        Write-Verbose -Message "Testing credentials"
        $URI = "/vco/api/server/permissions"
        Invoke-vRORestMethod -Method Get -URI $URI -ErrorAction Stop | Out-Null

        Write-Output $Script:vROConnection
    }
    catch [Exception]{

        Remove-Variable -Name vROConnection -Scope Script -Force -ErrorAction SilentlyContinue
        $PSCmdlet.ThrowTerminatingError($PSitem)
    }
}


<#
    - Function: Disconnect-vROServer
#>


function Disconnect-vROServer {
<#
    .SYNOPSIS
    Disconnect from a vRO server
 
    .DESCRIPTION
    Disconnect from a vRO server by removing the vROConnection script variable from PowerShell
 
    .EXAMPLE
    Disconnect-vROServer
 
    .EXAMPLE
    Disconnect-vROServer -Confirm:$false
#>

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

    Param ()

    # --- Test for existing connection to vRA
    if (-not $Script:vROConnection){

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

    if ($PSCmdlet.ShouldProcess($Script:vROConnection.Server)){

        try {

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

                if (!$IsCoreCLR) {

                    [System.Net.ServicePointManager]::SecurityProtocol -= [System.Net.SecurityProtocolType]::$($Script:vROConnection.SslProtocol)
                }
            }
        }
        catch [Exception]{

            $PSCmdlet.ThrowTerminatingError($PSitem)
        }
        finally {

            # --- Remove the vROConnection script variable
            Write-Verbose -Message "Removing vROConnection script variable"
            Remove-Variable -Name vROConnection -Scope Script -Force -ErrorAction SilentlyContinue
        }
    }
}

<#
    - Function: Invoke-vRORestMethod
#>


function Invoke-vRORestMethod {
<#
    .SYNOPSIS
    Wrapper for Invoke-RestMethod with vRO specifics
 
    .DESCRIPTION
    Wrapper for Invoke-RestMethod with vRO specifics
 
    .PARAMETER Method
    REST Method: GET, POST, PUT or DELETE
 
    .PARAMETER URI
    API URI, e.g. /vco/api/workflows
 
    .PARAMETER Body
    REST Body in JSON format
 
    .PARAMETER Webrequest
    Use Invoke-WebRequest instead of Invoke-RestMethod
 
    .PARAMETER Headers
    Optionally supply custom headers
 
    .PARAMETER OutFile
    Saves the response body in the specified output file
 
    .INPUTS
    System.String
    System.Collections.IDictionary
    Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    Invoke-vRORestMethod -Method GET -URI '/vco/api/workflows'
 
    .EXAMPLE
    $URI = "/vco/api/workflows/$($ID)/executions/"
    $JSON = @"
{"parameters":
    [
        {
            "value": {"string":{ "value": "Apple"}},
            "type": "string",
            "name": "a",
            "scope": "local"
        },
        {
            "value": {"number":{ "value": 20}},
            "type": "number",
            "name": "b",
            "scope": "local"
        }
    ]
}
"@
    $InvokeRequest = Invoke-vRORestMethod -Method POST -URI $URI -Body $Body -WebRequest
#>

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

    Param (

    [parameter(Mandatory=$true)]
    [ValidateSet("GET","POST","PUT","DELETE")]
    [String]$Method,

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

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    $Body,

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

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [System.Collections.IDictionary]$Headers,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$OutFile
    )

# --- Test for existing connection to vRO
if (-not $Script:vROConnection){

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

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

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

        $Headers = @{

            "Accept"="application/json";
            "Content-Type" = "application/json";
            "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
        }
    }

    # --- 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 (!($Script:vROConnection.SignedCertificates) -and ($IsCoreCLR)) {

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

    try {

        # --- Use either Invoke-WebRequest or Invoke-RestMethod

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

            Invoke-WebRequest @Params
        }

        else {

            Invoke-RestMethod @Params
        }
    }
    catch [Exception] {

        $PSCmdlet.ThrowTerminatingError($PSitem)
    }
    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: New-vROParameterDefinition
#>


function New-vROParameterDefinition {
<#
    .SYNOPSIS
    Create a parameter definition for use with workflows such as Invoke-vROWorkflow and Invoke-vROAction
     
    .DESCRIPTION
    Create a parameter definition for use with workflows such as Invoke-vROWorkflow and Invoke-vROAction
 
    .PARAMETER Name
    Name of the workflow or action parameter
 
    .PARAMETER Value
    Value of the workflow or action parameter
 
    .PARAMETER Type
    Type of the workflow or action parameter
     
    .PARAMETER Scope
    Scope of the workflow or action parameter
 
    .INPUTS
    System.String.
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    $Param1 = New-vROParameterDefinition -Name a -Value Apple -Type String -Scope LOCAL
    Invoke-vROWorkflow -Id c0278910-9ae2-46c5-bb45-2292fe88e3ab -Parameters $Param1
 
    .EXAMPLE
    $Param1 = New-vROParameterDefinition -Name Location -Value UK -Type String -Scope LOCAL
    Invoke-vROAction -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133 -Parameters $Param1
#>

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

    Param (

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

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

    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Type,
    
    [parameter(Mandatory=$false)]
    [ValidateSet("LOCAL", "TOKEN")]
    [String]$Scope = "LOCAL"

    )    

    begin {
    
    }
    
    process {

        try {

            if ($PSCmdlet.ShouldProcess("WorkflowParameterDefinition")){

                # --- Define object
                $ParameterDefinition = @"
         
                    {
                        "name": "$($Name)",
                        "type": "$($Type.ToLower())",
                        "scope": "$($Scope.ToLower())",
                        "value": {
                            "$($Type.ToLower())":{ "value": "$($Value)"}
                        }
                    }
"@

            
                $ParameterDefinition | ConvertFrom-Json

            }

        }
        catch [Exception]{

            throw

        }

    }
    end {
        
    }

}

<#
    - Function: Add-vROActionPermission
#>


function Add-vROActionPermission {
<#
    .SYNOPSIS
    Add a Permission to a vRO Action
     
    .DESCRIPTION
    Add a Permission to a vRO Action
     
    .PARAMETER Id
    Action Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .PARAMETER Rights
    Specify the Permission Rights
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
     
    .EXAMPLE
    Add-vROActionPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' -Principal vRO_Users@vrademo.local -Rights 'View','Execute','Inspect'
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal,  
    
    [parameter(Mandatory=$true)]
    [ValidateSet("View","Execute","Inspect","Edit","Admin")]
    [String[]]$Rights

    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
            $Domain = ($Principal -split "@")[1]

        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "\\")[1]
            $Domain = ($Principal -split "\\")[0]

        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"

        }

        # --- Convert Rights to API required digit(s)
        $APIRights = @()

        switch ($Rights)
        {
            "View" {$APIRights += "r"}
            "Execute" {$APIRights += "x"}
            "Inspect" {$APIRights += "i"}
            "Edit" {$APIRights += "c"}
            "Admin" {$APIRights += "a"}

            Default {}

        }

    }

    process {

        foreach ($ActionId in $Id){
                
            try {

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

                    # --- Create JSON Body
                    $Body = @"
                        {
                            "permissions": [
                                {
                                    "permission": {
                                        "principal": "$($Domain)\\$($Username)",
                                        "relations": null,
                                        "rights": "$($APIRights -Join(""))"
                                    }
                                }
                            ]
                        }
"@


                    # --- Send REST call and process results
                    $URI = "/vco/api/actions/$($ActionId)/permissions"

                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Body -Verbose:$VerbosePreference | Out-Null
        
                    # --- Output the Successful Result
                    Get-vROActionPermission -Id $ActionId | Where-Object {$_.Principal -match $Username}

                }

            }
            catch [Exception]{

                throw
            }

        }

    }

    end {

    }
    
}

<#
    - Function: Export-vROAction
#>


function Export-vROAction {
<#
    .SYNOPSIS
    Exports an action by its ID.
 
    .DESCRIPTION
    Exports an action by its ID.
 
    .PARAMETER Id
    The id of the action
 
    .PARAMETER Path
    The resulting path. If this parameter is not passed the action will be exported to
    the current working directory.
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.IO.FileInfo
 
    .EXAMPLE
    Get-vROAction -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133 | Export-vROAction -Path C:\Actions\Test01.action
 
    .EXAMPLE
    Get-vROAction -Name Test01 -Category com.company.test | Export-vROAction
 
#>

[CmdletBinding()][OutputType('System.IO.FileInfo')]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Id,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$Path

    )

    begin {

        if ($IsWindows) {

            $Delimiter = '\'
        }
        else {

            $Delimiter = '/'
        }
    }

    process {

        foreach ($ActionId in $Id){

            try {

                $URI = "/vco/api/actions/$($ActionId)"

                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" ="Application/zip";
                    "Accept-Encoding" = "gzip, deflate";
                    "Content-Type" = "Application/zip;charset=utf-8";

                }

                # --- Run vRO REST Request
                $Request = Invoke-vRORestMethod -Uri $URI -Method Get -Headers $Headers -WebRequest -Verbose:$VerbosePreference

                $Filename = $Request.Headers['Content-Disposition'].Split("=")[1]

                if (!$PSBoundParameters.ContainsKey("Path")) {

                    Write-Verbose -Message "Path parameter not passed, exporting to current directory."
                    $FullPath = "$($(Get-Location).Path)$($Delimiter)$($Filename)"

                }
                else {

                    Write-Verbose -Message "Path parameter passed."

                    if ($Path.EndsWith("$($Delimiter)")) {

                        Write-Verbose -Message "Ends with"

                        $Path = $Path.TrimEnd("$($Delimiter)")

                    }

                    $FullPath = "$($Path)$($Delimiter)$($FileName)"

                }

                Write-Verbose -Message "Exporting action to $($FullPath)"

                # --- PS Core does not have -Encoding Byte. Replaced with new parameter AsByteStream
                if (!$IsCoreCLR) {

                    $Request.Content | Set-Content -Path $FullPath -Encoding Byte -Force
                }
                else {
                    $Request.Content | Set-Content -Path $FullPath -AsByteStream -Force
                }

                # --- Output the result
                Get-ChildItem -Path $FullPath

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}

<#
    - Function: Get-vROAction
#>


function Get-vROAction {
<#
    .SYNOPSIS
    Retrieves a list of all actions
 
    .DESCRIPTION
    Retrieves a list of all actions
 
    .PARAMETER Id
    The id of the action
 
    .PARAMETER Name
    The name of the action
     
    .PARAMETER Category
    The category that the action is in. This must be used with the name parameter
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROAction
 
    .EXAMPLE
    Get-vROAction -Id f2193849-89e9-4136-8607-526eb196ee4c
 
    .EXAMPLE
    Get-vROAction -Name Test01 -Category com.company.test
 
#>

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

    Param(

        [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true,ParameterSetName="Id")]
        [ValidateNotNullOrEmpty()]
        [String]$Id,

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

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

    )

    begin {

    }

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {
                'Id' {

                    $URI = "/vco/api/actions/$($Id)"

                    Write-Verbose -Message "GET : $($URI)"

                    $Response = Invoke-vRORestMethod -Method GET -URI $URI

                    Write-Verbose -Message "SUCCESS"

                    [PSCustomObject]@{

                        Id = $Response.id
                        Name = $Response.name
                        Description = $Response.Description
                        FQN = $Response.fqn
                        Version = $Response.version
                        InputParameters = $Response.'input-parameters'
                        OutputType = $Response.'output-type'
                        Href = $Response.href
                        Relations = $Response.relations

                    }

                    break

                }
                'Name' {

                    $URI = "/vco/api/actions/$($Category)/$Name"

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

                    [PSCustomObject]@{

                        Id = $Response.id
                        Name = $Response.name
                        Description = $Response.Description
                        FQN = $Response.fqn
                        Version = $Response.version
                        InputParameters = $Response."input-parameters"
                        OutputType = $Response."output-type"
                        Href = $Response.href
                        Relations = $Response.relations

                    }

                    break

                }
                'All' {

                    $URI = "/vco/api/actions"
                    
                    $Response = Invoke-vRORestMethod -Method GET -URI $URI -Verbose:$VerbosePreference

                    foreach ($Action in $Response.link) {
                        
                        [PSCustomObject]@{

                            Id = ($Action.attributes | Where-Object {$_.name -eq "id"}).value
                            Name = ($Action.attributes | Where-Object {$_.name -eq "name"}).value
                            Description = ($Action.attributes | Where-Object {$_.name -eq "description"}).value
                            FQN = ($Action.attributes | Where-Object {$_.name -eq "fqn"}).value
                            Version = ($Action.attributes | Where-Object {$_.name -eq "version"}).value
                            InputParameters = $null
                            OutputType = $null
                            Href = $null
                            Relations = $null

                        }                

                    }

                    break

                }

            }

        }
        catch [Exception]{
        
            throw
        }

    }

    end {

    }

}

<#
    - Function: Get-vROActionPermission
#>


function Get-vROActionPermission {
<#
    .SYNOPSIS
    Get vRO Action Permissions
 
    .DESCRIPTION
    Get vRO Action Permissions
 
    .PARAMETER Id
    Action Id
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROActionPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea'
 
    .EXAMPLE
    Get-vROAction -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' | Get-vROActionPermission
 
#>

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

    Param
    (   
    
    [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id

    )

    begin {

    }

    process {

        try {

            foreach ($ActionId in $Id){

                # --- Send REST call and process results
                $URI = "/vco/api/actions/$($ActionId)/permissions"

                $Action = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

                foreach ($Permission in $Action.permissions){

                    $Rights = @()

                    switch -regex ($Permission.permission.rights)
                    {
                        "[r]" {$Rights += "View"}
                        "[x]" {$Rights += "Execute"}
                        "[i]" {$Rights += "Inspect"}
                        "[c]" {$Rights += "Edit"}
                        "[a]" {$Rights += "Admin"}

                        Default {}

                    }

                    # --- Get the permission href
                    [System.Uri]$Href = $permission.permission.href

                    [PSCustomObject]@{                
                    
                        Id = $href.segments[6].Trim("/")
                        Principal = $Permission.permission.principal
                        Rights = $Rights
                        ActionId = $ActionId

                    }

                }

            }

        }
        catch [Exception]{
        
            throw
        }

    }

    end {

    }

}

<#
    - Function: Import-vROAction
#>


function Import-vROAction {
<#
    .SYNOPSIS
    Imports an action in a given category.
 
    .DESCRIPTION
    Imports an action in a given category.
 
    .PARAMETER CategoryName
    The name of the action category
 
    .PARAMETER File
    The action file
 
    .PARAMETER Overwrite
    Overwrite an existing action
 
    .INPUTS
    System.String
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Import-vROAction -File C:\Actions\test01.action -CategoryName "com.company.package" -Confirm:$false
 
    .EXAMPLE
    Get-ChildItem -Path C:\Actions\*.action | Import-vROAction -CategoryName "com.company.package" -Confirm:$false
 
#>

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

    Param (

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

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$File,

    [parameter(Mandatory=$false)]
    [Switch]$Overwrite

    )

    begin {

        #Set Set Line Feed
        $LF = "`r`n"

    }

    process {

        foreach ($FilePath in $File){

            try {

                # --- Resolve the file path
                $FileInfo = [System.IO.FileInfo](Resolve-Path $FilePath).Path

                # --- Create the multi-part form
                $Boundary = [guid]::NewGuid().ToString()
                $FileBin = [System.IO.File]::ReadAllBytes($FileInfo.FullName)
                $Encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")
                $EncodedFile = $Encoding.GetString($FileBin)

                $Form = (
                    "--$($Boundary)",
                    "Content-Disposition: form-data; name=`"file`"; filename=`"$($FileInfo.Name)`"",
                    "Content-Type:application/octet-stream$($LF)",
                    $EncodedFile,
                    "--$($Boundary)--$($LF)"
                ) -join $LF

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

                    $URI = "/vco/api/actions?categoryName=$($CategoryName)&overwrite=true"

                }
                else {

                    $URI = "/vco/api/actions?categoryName=$($CategoryName)"

                }

                # --- Set custom headers for the request
                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" = "Application/json"
                    "Accept-Encoding" = "gzip,deflate,sdch";
                    "Content-Type" = "multipart/form-data; boundary=$($Boundary)"
                }

                if ($PSCmdlet.ShouldProcess($FileInfo.FullName)){

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Form -Headers $Headers -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}


<#
    - Function: Invoke-vROAction
#>


function Invoke-vROAction {
<#
    .SYNOPSIS
    Invoke a vRO Action
 
    .DESCRIPTION
    Invoke a vRO Action
 
    .PARAMETER Id
    The id of the action requesting an action by id will return additional information
 
    .PARAMETER Name
    The name of the action
     
    .PARAMETER Category
    The category that the action is in. This must be used with the name parameter
 
    .PARAMETER Parameters
    The parameters, if any, that the action expects. The input expects an array of New-vROParameterDefinition
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    $Param1 = New-vROParameterDefinition -Name Location -Value UK -Type String -Scope LOCAL
    Invoke-vROAction -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133 -Parameters $Param1
 
    .EXAMPLE
    $Param1 = New-vROParameterDefinition -Name Location -Value UK -Type String -Scope LOCAL
    Invoke-vROAction -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133 -Parameters $Param1 | ConvertTo-Json
 
    .EXAMPLE
    Invoke-vROACtion -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133
 
#>

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

    Param(

        [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true,ParameterSetName="Id")]
        [ValidateNotNullOrEmpty()]
        [String]$Id,

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

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

        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [PSCustomObject[]]$Parameters

    )

    begin {

    }

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {

                'Id' {

                    $URI = "/vco/api/actions/$($Id)/executions"

                    break

                }
                'Name' {

                    $URI = "/vco/api/actions/$($Category)/$Name/executions"

                    break

                }

            }

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

                $Object = [PSCustomObject]@{

                    parameters = @()

                }

                foreach ($Parameter in $Parameters) {

                    $Object.parameters += $Parameter
                    
                }

                $Body = $Object | ConvertTo-Json -Depth 100

            }
            else {

                $Body = "{}"

            }

            $Response = Invoke-vRORestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

            if ($Response) {

                [PSCustomObject]@{

                    Type = $Response.type
                    Value = $Response.value

                }

            }

        }
        catch [Exception]{
        
            throw
            
        }

    }

    end {

    }

}

<#
    - Function: Remove-vROAction
#>


function Remove-vROAction {
<#
    .SYNOPSIS
    Remove a vRO Action
     
    .DESCRIPTION
    Remove a vRO Action
     
    .PARAMETER Id
    Action ID
 
    .PARAMETER Force
    If the action is referenced by some workflows, it is considered to be 'in use'and the delete operation will fail, unless the 'force' option is provided.
 
    .INPUTS
    System.String.
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Remove-vROAction -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea"
 
    .EXAMPLE
    Get-vROAction -Name Test01 -Category com.company.test | Remove-vROAction -Confirm:$false
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$false)]
    [Switch]$Force

    )    

    begin {
    
    }
    
    process {    

        foreach ($ActionId in $Id){

            try {    
                
                if ($PSBoundParameters.ContainsKey("Force")) {
                
                    $URI = "/vco/api/actions/$($ActionId)?force=true"
                    
                }
                else {

                    $URI = "/vco/api/actions/$($ActionId)"

                }

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

                    # --- Run vRO REST Request

                    Invoke-vRORestMethod -Uri $URI -Method DELETE -Verbose:$VerbosePreference | Out-Null


                }

            }
            catch [Exception]{

                throw

            }

        }

    }
    end {
        
    }

}

<#
    - Function: Remove-vROActionPermission
#>


function Remove-vROActionPermission {
<#
    .SYNOPSIS
    Remove a Permission from a vRO Action
     
    .DESCRIPTION
    Remove a Permission from a vRO Action
     
    .PARAMETER Id
    Action Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .INPUTS
    System.String
 
    .OUTPUTS
    None
     
    .EXAMPLE
    Remove-vROActionPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' -Principal vRO_Users@vrademo.local
 
    .EXAMPLE
    Get-vROAction -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' | Remove-vROActionPermission -Principal vRO_Users@vrademo.local
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal

    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]

        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "@")[1]

        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"

        }

    }

    process {

        foreach ($ActionId in $Id){
                
            try {

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

                    # --- Get Permission Rule
                    $Permission = Get-vROActionPermission -Id $ActionId | Where-Object {$_.Principal -match $Username}
                    
                    if (!$Permission){

                        throw "Unable to find Permission with Principal $($Principal)"
                    }
                    else {
                        
                        $URI = "/vco/api/actions/$($ActionId)/permissions/$($Permission.Id)"

                    }

                    # --- Send REST call and process results
                    Invoke-vRORestMethod -Method DELETE -Uri $URI -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}

<#
    - Function: Add-vROCategoryPermission
#>


function Add-vROCategoryPermission {
<#
    .SYNOPSIS
    Add a Permission to a vRO Category
     
    .DESCRIPTION
    Add a Permission to a vRO Category
     
    .PARAMETER Id
    Category Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .PARAMETER Rights
    Specify the Permission Rights
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
     
    .EXAMPLE
    Add-vROCategoryPermission -Id '40281e8654ddec6201553af63677146e' -Principal vRO_Users@vrademo.local -Rights 'View','Execute','Inspect'
 
    .EXAMPLE
    $Permissions = Get-vROCategoryPermission -Id '40281e8654ddec6201553af63677146e'
    Get-vROCategory -Id '40281e8654ddec6201554f5836651514' | Add-vROCategoryPermission -Principal $Permissions[0].Principal -Rights $Permissions[0].Rights
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal,  
    
    [parameter(Mandatory=$true)]
    [ValidateSet("View","Execute","Inspect","Edit","Admin")]
    [String[]]$Rights
    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
            $Domain = ($Principal -split "@")[1]
        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "\\")[1]
            $Domain = ($Principal -split "\\")[0]
        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"
        }

        # --- Convert Rights to API required digit(s)
        $APIRights = @()

        switch ($Rights)
        {
            "View" {$APIRights += "r"}
            "Execute" {$APIRights += "x"}
            "Inspect" {$APIRights += "i"}
            "Edit" {$APIRights += "c"}
            "Admin" {$APIRights += "a"}

            Default {}
        }
    }

    process {

        foreach ($CategoryId in $Id){
                
            try {

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

                    # --- Create JSON Body
                    $Body = @"
    {
      "permissions": [
        {
          "permission": {
            "principal": "$($Domain)\\$($Username)",
            "rights": "$($APIRights -join "")"
          }
        }
      ]
    }
"@

                    # --- Send REST call and process results
                    $URI = "/vco/api/categories/$($CategoryId)/permissions"

                    $Request = Invoke-vRORestMethod -Method POST -Uri $URI -Body $Body -Verbose:$VerbosePreference
        
                    # --- Output the Successful Result
                    foreach ($Permission in $Request.permissions){

                        $Rights = @()

                        switch -regex ($Permission.permission.rights)
                        {
                            "[r]" {$Rights += "View"}
                            "[x]" {$Rights += "Execute"}
                            "[i]" {$Rights += "Inspect"}
                            "[c]" {$Rights += "Edit"}
                            "[a]" {$Rights += "Admin"}

                            Default {}
                        }

                        [pscustomobject]@{                
                    
                            Principal = $Permission.permission.principal
                            Rights = $Rights
                            CategoryID = $CategoryId
                            CategoryHref = $Permission.permission.href
                        }
                    }
                }
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Get-vROCategory
#>


function Get-vROCategory {
<#
    .SYNOPSIS
    Get vRO Categories
 
    .DESCRIPTION
    Get vRO Categories
 
    .PARAMETER CategoryType
    Retrieve Category by CategoryType
 
    .PARAMETER Id
    Retrieve Category by Id
 
    .PARAMETER Root
    Retrieve only Categories in the top-level folder root
 
    .INPUTS
    System.String
    System.Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROCategory
 
    .EXAMPLE
    Get-vROCategory -CategoryType Workflow
 
    .EXAMPLE
    Get-vROCategory -Id '40281e8b555889520155588bc4c10f1c'
 
    .EXAMPLE
    Get-vROCategory -CategoryType ResourceElement -Root
#>

[CmdletBinding(DefaultParametersetName="All")][OutputType('System.Management.Automation.PSObject')]

    Param
    (   
    
    [parameter(Mandatory=$true,ParameterSetName="CategoryType")]
    [ValidateSet("WorkflowCategory","ScriptModuleCategory","ConfigurationElementCategory","ResourceElementCategory")]
    [String]$CategoryType,

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

    [parameter(Mandatory=$false,ParameterSetName="All")]
    [parameter(Mandatory=$false,ParameterSetName="CategoryType")]
    [Switch]$Root

    )

    try {

        # --- Send REST call and process results
        switch ($PsCmdlet.ParameterSetName) {

            "All"  { 
                
                if ($PSBoundParameters.ContainsKey("Root")) {

                    $URI = "/vco/api/categories?isRoot=true"
                }
                else {

                    $URI = "/vco/api/categories"
                }

                break
            }

            "CategoryType"  {

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

                    $URI = "/vco/api/categories?categoryType=$($CategoryType)&isRoot=true"
                }
                else {

                    $URI = "/vco/api/categories?categoryType=$($CategoryType)"
                }

                break
            }

            "Id"  {
            
                $URI = "/vco/api/categories/$($Id)"
                break
            }
        }

        if ($PsCmdlet.ParameterSetName -eq 'Id'){

            $Category = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

            [pscustomobject]@{                        
                    
                Name = $Category.name
                ID = $Category.id
                Description = $Category.description
                Type = $Category.type
                Path = $Category.path
                Href = $Category.href
           }
        }
        else {
         
            $Categories = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

            foreach ($Category in $Categories.link){

                [pscustomobject]@{                        
                    
                    Name = ($Category.attributes | Where-Object {$_.name -eq 'name'}).value
                    ID = ($Category.attributes | Where-Object {$_.name -eq 'id'}).value
                    Description = ($Category.attributes | Where-Object {$_.name -eq 'description'}).value
                    Type = ($Category.attributes | Where-Object {$_.name -eq 'type'}).value
                    Path = $null
                    Href = $Category.href
                }
            }
        } 
    }
    catch [Exception]{
        
        throw
    }
}

<#
    - Function: Get-vROCategoryPermission
#>


function Get-vROCategoryPermission {
<#
    .SYNOPSIS
    Get vRO Category Permissions
 
    .DESCRIPTION
    Get vRO Category Permissions
 
    .PARAMETER Id
    Category Id
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROCategoryPermission -Id '40281e8654ddec6201553af63677146e'
 
    .EXAMPLE
    Get-vROCategory -Id '40281e8654ddec6201553af63677146e' | Get-vROCategoryPermission
#>

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

    Param
    (   
    
    [parameter(Mandatory=$true,ValueFromPipeline,ValueFromPipelinebyPropertyName=$true)]
    [String[]]$Id

    )

    begin {

    }

    process{

        try {

            foreach ($CategoryId in $Id){

                # --- Send REST call and process results
                $URI = "/vco/api/categories/$($CategoryId)/permissions"

                $Category = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

                foreach ($Permission in $Category.permissions){

                    $Rights = @()

                    switch -regex ($Permission.permission.rights)
                    {
                        "[r]" {$Rights += "View"}
                        "[x]" {$Rights += "Execute"}
                        "[i]" {$Rights += "Inspect"}
                        "[c]" {$Rights += "Edit"}
                        "[a]" {$Rights += "Admin"}

                        Default {}
                    }

                    [pscustomobject]@{                
                    
                        Principal = $Permission.permission.principal
                        Rights = $Rights
                        CategoryID = $CategoryId
                        CategoryHref = $Permission.permission.href
                    }
                }
            }
        }
        catch [Exception]{
        
            throw
        }
    }

    end {

    }
}

<#
    - Function: New-vROCategory
#>


function New-vROCategory {
<#
    .SYNOPSIS
    Create a vRO Category
     
    .DESCRIPTION
    Create a vRO Category
         
    .PARAMETER Name
    Category Name
     
    .PARAMETER Description
    Category Description
 
    .PARAMETER CategoryType
    CategoryType
 
    .PARAMETER CategoryId
    Id of the Category to create the new Category in - default is the root Category
 
    .PARAMETER JSON
    Body text to send in JSON format
 
    .INPUTS
    System.String.
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .EXAMPLE
    New-vROCategory -Name Category01 -Description "This is Category01" -CategoryType WorkflowCategory
 
    .EXAMPLE
    Get-vROCategory -Id '40281e8654ddec6201553af63677146e' | New-vROCategory -Name "Category01" -Description "This is Category01"
     
    .EXAMPLE
    $JSON = @"
    {
       "type":"WorkflowCategory",
       "name":"Category01",
       "description":"This is Category01"
    }
    "@
    $JSON | New-vROCategory -CategoryId "40281e8654ddec6201553af63677146e"
#>

[CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low",DefaultParameterSetName="JSON")][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,ValueFromPipelineByPropertyName=$true,ParameterSetName="Standard")]
    [ValidateSet("WorkflowCategory","ScriptModuleCategory","ConfigurationElementCategory","ResourceElementCategory")]
    [alias("Type")]
    [String]$CategoryType,

    [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName="Standard")]
    [parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,ParameterSetName="JSON")]
    [alias("Id")]
    [ValidateNotNullOrEmpty()]
    [String]$CategoryId,

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

    begin {
    
    }
    
    process {
    
        # --- Set Body for REST request depending on ParameterSet
        if ($PSBoundParameters.ContainsKey("JSON")){
        
            $Data = ($JSON | ConvertFrom-Json)
            
            $Body = $JSON
            $Name = $Data.name     
        }
        else {
        
            $Body = @"
            {
                "type": "$($CategoryType)",
                "name": "$($Name)",
                "description": "$($Description)"
            }
"@

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

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

                    $URI = "/vco/api/categories/$($CategoryId)"
                }
                else {

                    $URI = "/vco/api/categories"
                }

                # --- Run vRO REST Request
                $Category = Invoke-vRORestMethod -Method POST -URI $URI -Body $Body -Verbose:$VerbosePreference

                # --- Output the Successful Result
                [pscustomobject]@{                        
                    
                    Name = $Category.name
                    ID = $Category.id
                    Description = $Category.description
                    Type = $Category.type
                    Path = $Category.path
                    Href = $null
               }
            }
        }
        catch [Exception]{

            throw
        }
    }
    end {
        
    }
}

<#
    - Function: Remove-vROCategory
#>


function Remove-vROCategory {
<#
    .SYNOPSIS
    Remove a vRO Category
     
    .DESCRIPTION
    Remove a vRO Category
     
    .PARAMETER Id
    Category ID
 
    .PARAMETER Force
    If the contains any content such as Workflows, Actions, Resource Elements or Configuration Elements the delete operation will fail, unless the 'force' option is provided. USE WITH CAUTION!
 
    .INPUTS
    System.String.
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Remove-vROCategory -Id "40281e8654ddec620155df5563fc1800"
 
    .EXAMPLE
    Get-vROCategory -Id '40281e8b555889520155588bc4c10f1c' | Remove-vROCategory -Confirm:$false
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$false)]
    [Switch]$Force
    )    

    begin {
    
    }
    
    process {    

        foreach ($CategoryId in $Id){

            try {    
                
                if ($PSBoundParameters.ContainsKey("Force")) {
                
                    $URI = "/vco/api/categories/$($CategoryId)?deleteNonEmptyContent=true"
                }
                else {

                    $URI = "/vco/api/categories/$($CategoryId)"
                }

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

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Uri $URI -Method DELETE -Verbose:$VerbosePreference
                }
            }
            catch [Exception]{

                throw
            }
        }
    }
    end {
        
    }
}

<#
    - Function: Remove-vROCategoryPermission
#>


function Remove-vROCategoryPermission {
<#
    .SYNOPSIS
    Remove a Permission from a vRO Category
     
    .DESCRIPTION
    Remove a Permission from a vRO Category
     
    .PARAMETER Id
    Category Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .INPUTS
    System.String
 
    .OUTPUTS
    None
     
    .EXAMPLE
    Remove-vROCategoryPermission -Id '40281e8654ddec6201553af63677146e' -Principal vRO_Users@vrademo.local
 
    .EXAMPLE
    Get-vROCategory -Id '40281e8654ddec6201553af63677146e' | Remove-vROWorkflowPermission -Principal vRO_Users@vrademo.local
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal
    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "@")[1]
        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"
        }
    }

    process {

        foreach ($CategoryId in $Id){
                
            try {

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

                    # --- Get Permission Rule
                    $CategoryPermission = Get-vROCategoryPermission -Id $CategoryId | Where-Object {$_.Principal -match $Username}
                    
                    if (!$CategoryPermission){

                        throw "Unable to find Category Permission with Principal $($Principal)"
                    }
                    else {
                        
                        $Index = $CategoryPermission.CategoryHref.IndexOf("/vco")
                        $URI = $CategoryPermission.CategoryHref.Substring($Index)
                    }

                    # --- Send REST call and process results
                    Invoke-vRORestMethod -Method DELETE -Uri $URI -Verbose:$VerbosePreference | Out-Null        
                }
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Add-vROConfigurationElementPermission
#>


function Add-vROConfigurationElementPermission {
<#
    .SYNOPSIS
    Add a Permission to a vRO Configuration Element
     
    .DESCRIPTION
    Add a Permission to a vRO Configuration Element
     
    .PARAMETER Id
    Configuration Element Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .PARAMETER Rights
    Specify the Permission Rights
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
     
    .EXAMPLE
    Add-vROConfigurationElementPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' -Principal vRO_Users@vrademo.local -Rights 'View','Execute','Inspect'
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal,  
    
    [parameter(Mandatory=$true)]
    [ValidateSet("View","Execute","Inspect","Edit","Admin")]
    [String[]]$Rights

    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
            $Domain = ($Principal -split "@")[1]

        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "\\")[1]
            $Domain = ($Principal -split "\\")[0]

        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"

        }

        # --- Convert Rights to API required digit(s)
        $APIRights = @()

        switch ($Rights)
        {
            "View" {$APIRights += "r"}
            "Execute" {$APIRights += "x"}
            "Inspect" {$APIRights += "i"}
            "Edit" {$APIRights += "c"}
            "Admin" {$APIRights += "a"}

            Default {}

        }

    }

    process {

        foreach ($ConfigurationId in $Id){
                
            try {

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

                    # --- Create JSON Body
                    $Body = @"
                        {
                            "permissions": [
                                {
                                    "permission": {
                                        "principal": "$($Domain)\\$($Username)",
                                        "relations": null,
                                        "rights": "$($APIRights -Join(""))"
                                    }
                                }
                            ]
                        }
"@


                    # --- Send REST call and process results
                    $URI = "/vco/api/configurations/$($ConfigurationId)/permissions"

                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Body -Verbose:$VerbosePreference | Out-Null
        
                    # --- Output the Successful Result
                    Get-vROConfigurationElementPermission -Id $ConfigurationId | Where-Object {$_.Principal -match $Username}

                }

            }
            catch [Exception]{

                throw
            }

        }

    }

    end {

    }
    
}

<#
    - Function: Export-vROConfigurationElement
#>


function Export-vROConfigurationElement {
<#
    .SYNOPSIS
    Exports a configuration element by its ID.
 
    .DESCRIPTION
    Exports a configuration element by its ID.
 
    .PARAMETER Id
    The id of the action
 
    .PARAMETER Path
    The path of the exported file. If this parameter is not passed, the resource element
    will be exported to the current working directory.
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.IO.FileInfo
 
    .EXAMPLE
    Get-vROConfigurationElement -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133 | Export-vROConfigurationElement -Path C:\Configurations
 
    .EXAMPLE
    Export-vROConfigurationElement -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133
 
#>

[CmdletBinding()][OutputType('System.IO.FileInfo')]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Id,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$Path

    )

    begin {

    }

    process {

        foreach ($ConfigurationId in $Id){

            try {

                $URI = "/vco/api/configurations/$($ConfigurationId)"

                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" ="application/vcoobject+xml";
                    "Accept-Encoding" = "gzip, deflate";
                    "Content-Type" = "Application/vcoobject+xml;charset=utf-8";

                }

                # --- Run vRO REST Request
                $Request = Invoke-vRORestMethod -Uri $URI -Method Get -Headers $Headers -WebRequest -Verbose:$VerbosePreference

                # --- Get the displayname of the Configuration element and set filename
                $XMLContent = [XML]$Request.Content
                $DisplayName = $XMLContent.'config-element'.'display-name'.'#cdata-section'
                $FileName = "$($DisplayName).vsoconf"

                if (!$PSBoundParameters.ContainsKey("Path")) {

                    Write-Verbose -Message "Path parameter not passed, exporting to current directory."
                    $FullPath = "$($(Get-Location).Path)\$($Filename)"

                }
                else {

                    Write-Verbose -Message "Path parameter passed."

                    if ($Path.EndsWith("\")) {

                        Write-Verbose -Message "Ends with"

                        $Path = $Path.TrimEnd("\")

                    }

                    $FullPath = "$($Path)\$($FileName)"

                }

                Write-Verbose -Message "Exporting configuration element to $($FullPath)"
                $Request.Content | Set-Content -Path $FullPath -Force

                # --- Output the result
                Get-ChildItem -Path $FullPath

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}

<#
    - Function: Get-vROConfigurationElement
#>


function Get-vROConfigurationElement {
<#
    .SYNOPSIS
    Retrieves a list of all configuration elements
 
    .DESCRIPTION
    Retrieves a list of all configuration elements
 
    .PARAMETER Id
    The id of the configuration elements
 
    .PARAMETER WithAttributes
    By default when listing all configuration elements attributes are not returned.
    Using this parameter will return attributes for each configuration element found. It
    could potentially be an expensive operation depending on the number of elements returned.
 
    .INPUTS
    System.String
    System.Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROConfigurationElement
 
    .EXAMPLE
    Get-vROConfigurationElement -Id f2193849-89e9-4136-8607-526eb196ee4c
 
#>

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

    Param(

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

        [Parameter(Mandatory=$false,ParameterSetName="All")]
        [Switch]$WithAttributes

    )

    begin {

    }

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {

                'Id' {

                    foreach ($ConfigurationId in $Id) {

                        $Response = Invoke-vRORestMethod -Method Get -URI "/vco/api/configurations/$($ConfigurationId)" -Verbose:$VerbosePreference
                        
                        [PSCustomObject]@{

                            Id = $Response.id
                            Name = $Response.name
                            Description = $Response.description
                            Version = $Response.version
                            Attributes = $Response.attributes
                            Href = $Response.href

                        }                        

                    }

                    break

                }
                'All' {

                    $URI = "/vco/api/configurations"

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

                    if ($WithAttributes) {

                        foreach ($Item in $Response.link) {

                            [URI]$Href = $Item.href
                            $Id = $Href.Segments[-1].Trim("/")
                            
                            getConfiguration($Id)

                        }

                    }
                    else {

                        foreach ($Item in $Response.link) {

                            [PSCustomObject]@{

                                Id = ($Item.attributes | Where-Object {$_.Name -eq "id"}).value
                                Name = ($Item.attributes | Where-Object {$_.Name -eq "name"}).value
                                Description = ($Item.attributes | Where-Object {$_.Name -eq "description"}).value
                                Version = ($Item.attributes | Where-Object {$_.Name -eq "version"}).value
                                Attributes = $null
                                Href = $Item.href

                            }

                        }

                    }

                }

            }

        }
        catch [Exception]{
        
            throw
        }

    }

    end {

    }

}

function getConfiguration($Id){
<#
    Private function for retrieving configurations elements
#>
    

    $Response = Invoke-vRORestMethod -Method Get -URI "/vco/api/configurations/$($Id)" -Verbose:$VerbosePreference

    $Object = [PSCustomObject]@{

        Id = $Response.id
        Name = $Response.name
        Description = $Response.description
        Version = $Response.version
        Attributes = $Response.attributes
        Href = $Response.href

    }

    return $Object

}

<#
    - Function: Get-vROConfigurationElementPermission
#>


function Get-vROConfigurationElementPermission {
<#
    .SYNOPSIS
    Get vRO Configuration Element Permissions
 
    .DESCRIPTION
    Get vRO Configuration Element Permissions
 
    .PARAMETER Id
    Configuration Element Id
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROConfigurationElementPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea'
 
    .EXAMPLE
    Get-vROConfigurationElement -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' | Get-vROConfigurationElementPermission
 
#>

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

    Param
    (   
    
    [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id

    )

    begin {

    }

    process {

        try {

            foreach ($ConfigurationId in $Id){

                # --- Send REST call and process results
                $URI = "/vco/api/configurations/$($ConfigurationId)/permissions"

                $Response = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

                foreach ($Permission in $Response.permissions){

                    $Rights = @()

                    switch -regex ($Permission.permission.rights)
                    {
                        
                        "[r]" {$Rights += "View"}
                        "[x]" {$Rights += "Execute"}
                        "[i]" {$Rights += "Inspect"}
                        "[c]" {$Rights += "Edit"}
                        "[a]" {$Rights += "Admin"}

                        Default {}

                    }

                    # --- Get the permission href
                    [System.Uri]$Href = $permission.permission.href

                    [PSCustomObject]@{                
                    
                        Id = $Href.segments[-1].Trim("/")
                        Principal = $Permission.permission.principal
                        Rights = $Rights
                        ConfigurationId = $ConfigurationId

                    }

                }

            }

        }
        catch [Exception]{
        
            throw
        }

    }

    end {

    }

}

<#
    - Function: Import-vROConfigurationElement
#>


function Import-vROConfigurationElement {
<#
    .SYNOPSIS
    Imports a configuration element in a given category.
 
    .DESCRIPTION
    Imports a configuration element in a given category.
 
    .PARAMETER CategoryId
    The name of the configuration element category
 
    .PARAMETER File
    The configuraiton file
 
    .INPUTS
    System.String
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Get-ChildItem -Path C:\Configurations\*.vsoconfig | Import-vROConfigurationElement -CategoryId "36cd783f-e858-4783-9273-06d11defc8b0" -Confirm:$false
 
#>

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

    Param (

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

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$File

    )

    begin {

        #Set Set Line Feed
        $LF = "`r`n"

    }

    process {

        foreach ($FilePath in $File){

            $FileInfo = [System.IO.FileInfo](Resolve-Path $FilePath).Path

            try {

                # --- Create the multi-part form
                $Boundary = [guid]::NewGuid().ToString()
                $FileBin = [System.IO.File]::ReadAllBytes($FileInfo.FullName)
                $Encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")
                $EncodedFile = $Encoding.GetString($FileBin)

                $Form = (
                    "--$($Boundary)",
                    "Content-Disposition: form-data; name=`"file`"; filename=`"$($FileInfo.Name)`"",
                    "Content-Type:application/octet-stream$($LF)",
                    $EncodedFile,
                    "--$($Boundary)--$($LF)"
                ) -join $LF

                $URI = "/vco/api/configurations?categoryId=$($CategoryId)"

                # --- Set custom headers for the request
                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" = "Application/json"
                    "Accept-Encoding" = "gzip,deflate,sdch";
                    "Content-Type" = "multipart/form-data; boundary=$($Boundary)"
                }

                if ($PSCmdlet.ShouldProcess($FileInfo.FullName)){

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Form -Headers $Headers -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}


<#
    - Function: Remove-vROConfigurationElement
#>


function Remove-vROConfigurationElement {
<#
    .SYNOPSIS
    Remove a vRO Configuration Element
     
    .DESCRIPTION
    Remove a vRO Configuration Element
     
    .PARAMETER Id
    Action ID
 
    .PARAMETER Force
    If the configuration element is referenced by some workflows, it is considered to be 'in use'and the delete operation will fail, unless the 'force' option is provided.
 
    .INPUTS
    System.String.
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Remove-vROConfigurationElement -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea"
 
    .EXAMPLE
    Get-vROConfigurationElement -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea" | Remove-vROConfigurationElement
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$false)]
    [Switch]$Force

    )    

    begin {
    
    }
    
    process {    

        foreach ($ConfigurationId in $Id){

            try {    
                
                if ($PSBoundParameters.ContainsKey("Force")) {
                
                    $URI = "/vco/api/configurations/$($ConfigurationId)?force=true"
                    
                }
                else {

                    $URI = "/vco/api/configurations/$($ConfigurationId)"

                }

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

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Uri $URI -Method DELETE -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }
    end {
        
    }

}

<#
    - Function: Remove-vROConfigurationElementPermission
#>


function Remove-vROConfigurationElementPermission {
<#
    .SYNOPSIS
    Remove a Permission from a vRO Configuration Element
     
    .DESCRIPTION
    Remove a Permission from a vRO Configuration Element
     
    .PARAMETER Id
    Configuration Element Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .INPUTS
    System.String
 
    .OUTPUTS
    None
     
    .EXAMPLE
    Remove-vROConfigurationElementPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' -Principal vRO_Users@vrademo.local
 
    .EXAMPLE
    Get-vROConfigurationElement -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' | Remove-vROConfigurationElementPermission -Principal vRO_Users@vrademo.local
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal

    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]

        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "@")[1]

        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"

        }

    }

    process {

        foreach ($ConfigurationId in $Id){
                
            try {

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

                    # --- Get Permission Rule
                    $Permission = Get-vROConfigurationElementPermission -Id $ConfigurationId | Where-Object {$_.Principal -match $Username}
                    
                    if (!$Permission){

                        throw "Unable to find Permission with Principal $($Principal)"
                    }
                    else {
                        
                        $URI = "/vco/api/configurations/$($ConfigurationId)/permissions/$($Permission.Id)"

                    }

                    # --- Send REST call and process results
                    Invoke-vRORestMethod -Method DELETE -Uri $URI -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}

<#
    - Function: Add-vROPackagePermission
#>


function Add-vROPackagePermission {
<#
    .SYNOPSIS
    Add a Permission to a vRO Package
     
    .DESCRIPTION
    Add a Permission to a vRO Package
     
    .PARAMETER Name
    Package Name
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .PARAMETER Rights
    Specify the Permission Rights
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
     
    .EXAMPLE
    Add-vROPackagePermission -Name "net.powervro.tests" -Principal vRO_Users@vrademo.local -Rights 'View','Inspect'
 
    .EXAMPLE
    $Permissions = Get-vROPackagePermission -Name "net.powervro.tests"
    Get-vROPackage -Name "net.powervro.tests2" | Add-vROWorkflowPermission -Principal $Permissions[0].Principal -Rights $Permissions[0].Rights
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal,  
    
    [parameter(Mandatory=$true)]
    [ValidateSet("View","Inspect","Edit","Admin")]
    [String[]]$Rights
    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
            $Domain = ($Principal -split "@")[1]
        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "\\")[1]
            $Domain = ($Principal -split "\\")[0]
        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"
        }

        # --- Convert Rights to API required digit(s)
        $APIRights = @()

        switch ($Rights)
        {
            "View" {$APIRights += "r"}
            "Inspect" {$APIRights += "i"}
            "Edit" {$APIRights += "c"}
            "Admin" {$APIRights += "a"}

            Default {}
        }
    }

    process {

        foreach ($PackageName in $Name){
                
            try {

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

                    # --- Create JSON Body
                    $Body = @"
    {
      "permissions": [
        {
          "permission": {
            "principal": "$($Domain)\\$($Username)",
            "rights": "$($APIRights -join "")"
          }
        }
      ]
    }
"@

                    # --- Send REST call and process results
                    $URI = "/vco/api/packages/$($PackageName)/permissions"

                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Body -Verbose:$VerbosePreference | Out-Null
        
                    # --- Output the Successful Result
                    Get-vROPackagePermission -Name $PackageName | Where-Object {$_.Principal -match $Username}
                }
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Export-vROPackage
#>


function Export-vROPackage {
<#
    .SYNOPSIS
    Export a vRO Package to a .package file
 
    .DESCRIPTION
    Export a vRO Package to a .package file
 
    .PARAMETER Name
    Specify the Name of the vRO Package
 
    .PARAMETER DontExportConfigurationAttributeValues
    Don't Export Configuration Attribute Values
 
    .PARAMETER DontExportGlobalTags
    Don't Export Global Tags
 
    .PARAMETER File
    Specify the Filename to export to - should be a .package file
 
    .INPUTS
    System.String
    Switch
 
    .OUTPUTS
    System.IO.FileInfo
 
    .NOTES
    Thanks to @burkeazbill for a few hints with this one https://github.com/burkeazbill/vroClientScripts
 
    .EXAMPLE
    Export-vROPackage -Name "net.powervro.tests" -File C:\Packages\net.powervro.tests.package
 
    .EXAMPLE
    Get-vROPackage -Name 'net.powervro.tests' | Export-vROPackage -File C:\Packages\net.powervro.tests.package -DontExportConfigurationAttributeValues
#>

[CmdletBinding()][OutputType('System.IO.FileInfo')]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Name,

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

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

    [parameter(Mandatory=$false)]
    [Switch]$DontExportGlobalTags

    )

    begin {

        $Headers = @{

            "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
            "Accept" ="Application/zip";
            "Accept-Encoding" = "gzip, deflate";
            "Content-Type" = "Application/zip;charset=utf-8";
        }

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

            $ExportConfigurationAttributeValues = 'false'
        }
        else {

            $ExportConfigurationAttributeValues = 'true'
        }
        if ($PSBoundParameters.ContainsKey('DontExportGlobalTags')){

            $ExportGlobalTags = 'false'
        }
        else {

            $ExportGlobalTags = 'true'
        }
    }

    process {

        foreach ($PackageName in $Name){

            try {

                $URI = "/vco/api/packages/$($PackageName)/?exportConfigurationAttributeValues=$($ExportConfigurationAttributeValues)&exportGlobalTags=$($ExportGlobalTags)"

                # --- Run vRO REST Request
                $Request = Invoke-vRORestMethod -Uri $URI -Method Get -Headers $Headers -WebRequest -Verbose:$VerbosePreference

                # --- PS Core does not have -Encoding Byte. Replaced with new parameter AsByteStream
                if (!$IsCoreCLR) {

                    $Request.Content | Set-Content -Path $File -Encoding Byte -Force
                }
                else {
                    $Request.Content | Set-Content -Path $File -AsByteStream -Force
                }

                # --- Output the result
                Get-ChildItem -Path $File
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Get-vROPackage
#>


function Get-vROPackage {
<#
    .SYNOPSIS
    Get vRO Packages
 
    .DESCRIPTION
    Get vRO Packages
 
    .PARAMETER Name
    Retrieve Package by Name
 
    .INPUTS
    System.String
    System.Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROPackage
 
    .EXAMPLE
    Get-vROPackage -Name 'com.vmware.library.powershell'
#>

[CmdletBinding(DefaultParametersetName="All")][OutputType('System.Management.Automation.PSObject')]

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

    )

    try {

        # --- Send REST call and process results
        switch ($PsCmdlet.ParameterSetName) {

            "All"  { 
                
                $URI = "/vco/api/packages"

                $Packages = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

                foreach ($Package in $Packages.link){

                    [pscustomobject]@{                        
                    
                        Name = ($Package.attributes | Where-Object {$_.name -eq 'name'}).value
                        ID = ($Package.attributes | Where-Object {$_.name -eq 'id'}).value
                        Description = ($Package.attributes | Where-Object {$_.name -eq 'description'}).value
                        Href = $Package.href
                        Workflows = $null
                        Actions = $null
                    }
                }

                break
            }

            "Name"  {
            
                $URI = "/vco/api/packages/$($Name)/"

                $Package = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

                [pscustomobject]@{                        
                    
                    Name = $Package.name
                    ID = $Package.id
                    Description = $Package.description
                    Href = $Package.href
                    Workflows = $Package.workflows
                    Actions = $Package.actions
               }

               break
            }
        }
    }
    catch [Exception]{
        
        throw
    }
}

<#
    - Function: Get-vROPackagePermission
#>


function Get-vROPackagePermission {
<#
    .SYNOPSIS
    Get vRO Package Permissions
 
    .DESCRIPTION
    Get vRO Package Permissions
 
    .PARAMETER Name
    Package Name
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROPackagePermission -Name "net.powervro.tests"
 
    .EXAMPLE
    Get-vROPackage -Name "net.powervro.tests" | Get-vROPackagePermission
#>

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

    Param
    (   
    
    [parameter(Mandatory=$true,ValueFromPipeline,ValueFromPipelinebyPropertyName=$true)]
    [String[]]$Name

    )

    begin {

    }

    process {

        try {

            foreach ($PackageName in $Name){

                # --- Send REST call and process results
                $URI = "/vco/api/packages/$($PackageName)/permissions"

                $Package= Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

                foreach ($Permission in $Package.permissions){

                    $Rights = @()

                    switch -regex ($Permission.permission.rights)
                    {
                        "[r]" {$Rights += "View"}
                        "[i]" {$Rights += "Inspect"}
                        "[c]" {$Rights += "Edit"}
                        "[a]" {$Rights += "Admin"}

                        Default {}
                    }

                    [pscustomobject]@{                
                    
                        Principal = $Permission.permission.principal
                        Rights = $Rights
                        Package = $PackageName
                        PackageHref = $Permission.permission.href
                    }
                }
            }
        }
        catch [Exception]{
        
            throw
        }
    }

    end {

    }
}

<#
    - Function: Import-vROPackage
#>


function Import-vROPackage {
<#
    .SYNOPSIS
    Imports a vRO Package
 
    .DESCRIPTION
    Imports a vRO Package
 
    .PARAMETER File
    The action file
 
    .PARAMETER Overwrite
    Overwrite an existing Package
 
    .PARAMETER ImportConfigurationAttributeValues
    Import Configuration Attribute Values
 
    .PARAMETER TagImportMode
    Tag Import Mode
 
    .INPUTS
    System.String
    System.IO.FileInfo
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Import-vROPackage -File C:\Packages\net.powervro.tests.package -Overwrite
 
    .EXAMPLE
    Get-ChildItem -Path C:\Packages\net.powervro.tests.package | Import-vROPackage -Confirm:$false
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$File,

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

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

    [parameter(Mandatory=$false)]
    [ValidateSet("Dont","ImportOverwrite","ImportPreserve")]
    [String]$TagImportMode = "Dont"

    )

    begin {

        # --- Set Set Line Feed
        $LF = "`r`n"

        # --- Set options
        if ($PSBoundParameters.ContainsKey("Overwrite")) {

            $OverwriteParam = 'true'

        }
        else {

            $OverwriteParam = 'false'
        }

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

            $ImportConfigurationAttributeValuesParam = 'true'

        }
        else {

            $ImportConfigurationAttributeValuesParam = 'false'
        }

        switch ($TagImportMode){

            “Dont”  {

                $TagImportModeParam = 'DoNotImport';
                break
            }

            “ImportOverwrite”  {

                $TagImportModeParam = 'ImportAndOverwriteExistingValue';
                break
            }
            “ImportPreserve”  {

                $TagImportModeParam = 'ImportButPreserveExistingValue';
                break
            }

        }

    }

    process {

        foreach ($FilePath in $File){

            try {

                # --- Resolve the file path
                $FileInfo = [System.IO.FileInfo](Resolve-Path $FilePath).Path

                # --- Create the multi-part form
                $Boundary = [guid]::NewGuid().ToString()
                $FileBin = [System.IO.File]::ReadAllBytes($FileInfo.FullName)
                $Encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")
                $EncodedFile = $Encoding.GetString($FileBin)

                $Form = (
                    "--$($Boundary)",
                    "Content-Disposition: form-data; name=`"file`"; filename=`"$($FileInfo.Name)`"",
                    "Content-Type:application/octet-stream$($LF)",
                    $EncodedFile,
                    "--$($Boundary)--$($LF)"
                ) -join $LF

                $URI = "/vco/api/packages?overwrite=$($OverwriteParam)&importConfigurationAttributeValues=$($ImportConfigurationAttributeValuesParam)&tagImportMode=$($TagImportModeParam)"

                # --- Set custom headers for the request
                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" = "Application/json"
                    "Accept-Encoding" = "gzip,deflate,sdch";
                    "Content-Type" = "multipart/form-data; boundary=$($Boundary)"
                }

                if ($PSCmdlet.ShouldProcess($FileInfo.FullName)){

                    # --- Run vRO REST Request
                    Write-Verbose -Message "POST : $($URI)"

                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Form -Headers $Headers -Verbose:$VerbosePreference

                    Write-Verbose -Message "SUCCESS"

                    # --- Output the result
                    Get-vROPackage -Name $FileInfo.BaseName
                }

            }
            catch [Exception]{

                throw

            }
        }
    }

    end {

    }
}

<#
    - Function: Remove-vROPackage
#>


function Remove-vROPackage {
<#
    .SYNOPSIS
    Remove a vRO Package
 
    .DESCRIPTION
    Remove a vRO Package
 
    .PARAMETER Name
    Package Name
 
    .PARAMETER DeletePackageWithContent
    Deletes the package along with the content. If other packages share elements with this package, they will be deleted
 
    .PARAMETER DeletePackageKeepingShared
    Deletes the package along with the content. If other packages share elements with this package, the elements will not be removed.
 
    .INPUTS
    System.String.
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Remove-vROPackage -Name "net.powervro.tests"
 
    .EXAMPLE
    Get-vROPackage -Name "net.powervro.tests" | Remove-vROPackage -Confirm:$false
#>

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

[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name,

    [parameter(Mandatory=$false,ParametersetName="DeletePackageWithContent")]
    [Switch]$DeletePackageWithContent,

    [parameter(Mandatory=$false,ParametersetName="DeletePackageKeepingShared")]
    [Switch]$DeletePackageKeepingShared
    )

    begin {

    }

    process {

        foreach ($PackageName in $Name){

            try {

                switch ($PsCmdlet.ParameterSetName){

                    “DeletePackage”  {

                        $URI = "/vco/api/packages/$($PackageName)/";
                        break
                    }

                    “DeletePackageWithContent”  {

                        $URI = "/vco/api/packages/$($PackageName)/?option=deletePackageWithContent";
                        break
                    }
                    “DeletePackage”  {

                        $URI = "/vco/api/packages/$($PackageName)/?option=deletePackageKeepingShared";
                        break
                    }

                }

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

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Uri $URI -Method DELETE -Verbose:$VerbosePreference
                }
            }
            catch [Exception]{

                throw
            }
        }
    }
    end {

    }
}

<#
    - Function: Remove-vROPackagePermission
#>


function Remove-vROPackagePermission {
<#
    .SYNOPSIS
    Remove a Permission from a vRO Package
     
    .DESCRIPTION
    Remove a Permission from a vRO Package
     
    .PARAMETER Name
    Package Name
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .INPUTS
    System.String
 
    .OUTPUTS
    None
     
    .EXAMPLE
    Remove-vROPackagePermission -Name "net.powervro.tests" -Principal vRO_Users@vrademo.local
 
    .EXAMPLE
    Get-vROPackage -Name "net.powervro.tests" | Remove-vROPackagePermission -Principal vRO_Users@vrademo.local
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal
    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "@")[1]
        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"
        }
    }

    process {

        foreach ($PackageName in $Name){
                
            try {

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

                    # --- Get Permission Rule
                    $PackagePermission = Get-vROPackagePermission -Name $PackageName | Where-Object {$_.Principal -match $Username}
                    
                    if (!$PackagePermission){

                        throw "Unable to find Workflow Permission with Principal $($Principal)"
                    }
                    else {
                        
                        $Index = $PackagePermission.PackageHref.IndexOf("/vco")
                        $URI = $PackagePermission.PackageHref.Substring($Index)
                    }

                    # --- Send REST call and process results
                    Invoke-vRORestMethod -Method DELETE -Uri $URI -Verbose:$VerbosePreference | Out-Null        
                }
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Export-vROPlugin
#>


function Export-vROPlugin {
<#
    .SYNOPSIS
    Exports a plugin.
 
    .DESCRIPTION
    Exports a plugin.
 
    .PARAMETER Name
    The name of the plugin
 
    .PARAMETER Path
    The path of the exported file. If this parameter is not passed, the plugin
    will be exported to the current working directory.
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.IO.FileInfo
 
    .EXAMPLE
    Export-vROPlugin -Name ExamplePlugin
 
    .EXAMPLE
    Export-vROPlugin -Name ExamplePlugin -Path C:\plugins
 
#>

[CmdletBinding()][OutputType('System.IO.FileInfo')]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Name,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$Path

    )

    begin {

        if ($IsWindows) {

            $Delimiter = '\'
        }
        else {

            $Delimiter = '/'
        }
    }

    process {

        foreach ($PluginName in $Name){

            try {

                $URI = "/vco/api/plugins/$($PluginName)"

                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" ="Application/json";
                    "Content-Type" = "application/zip;charset=UTF-8";

                }

                # --- Run vRO REST Request
                Write-Verbose -Message "Receiving response. This may take some time depending on the size of the plugin.."
                $Request = Invoke-vRORestMethod -Uri $URI -Method Get -Headers $Headers -WebRequest -Verbose:$VerbosePreference

                # --- Get the name of the plugin
                $Filename = $Request.Headers['Content-Disposition'].Split("=")[1]

                if (!$PSBoundParameters.ContainsKey("Path")) {


                    Write-Verbose -Message "Path parameter not passed, exporting to current directory."
                    $FullPath = "$($(Get-Location).Path)$($Delimiter)$($Filename)"

                }
                else {

                    Write-Verbose -Message "Path parameter passed."

                    if ($Path.EndsWith("$($Delimiter)")) {

                        Write-Verbose -Message "Ends with"

                        $Path = $Path.TrimEnd("$($Delimiter)")

                    }

                    $FullPath = "$($Path)$($Delimiter)$($FileName)"

                }

                Write-Verbose -Message "Exporting plugin to $($FullPath)"
                [System.IO.File]::WriteAllBytes($FullPath, $Request.Content)

                # --- Get the exported file
                Get-ChildItem -Path $FullPath

            }
            catch [Exception]{

                throw

            }
            finally {

                # --- Set request variable to null to avoid the content staying in memory
                $Request = $null

            }

        }

    }

    end {

    }

}

<#
    - Function: Get-vROPlugin
#>


function Get-vROPlugin {
<#
    .SYNOPSIS
    Retrieves a list of all installed plugins
 
    .DESCRIPTION
    Retrieves a list of all installed plugins
 
    .INPUTS
    None.
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROPlugin
 
#>

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

    Param()

    begin {

    }

    process {

        try {

            $URI = "/vco/api/plugins"

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

            foreach ($Item in $Response.plugin) {

                [PSCustomObject]@{

                    Name = $Item.moduleName
                    DisplayName = $Item.displayName
                    Enabled = $Item.enabled
                    URL = $Item.url
                    Version = $Item.version
                    BuildNumber = $Item.buildNumber
                    InfoText = $Item.infoText
                    HasValidation = $Item.hasValidation
                    Configurable = $Item.configurable
                    HasInstallActions = $Item.hasInstallActions

                }

            }

        }
        catch [Exception]{
        
            throw
        }

    }

    end {

    }

}

<#
    - Function: Import-vROPlugin
#>


function Import-vROPlugin {
<#
    .SYNOPSIS
    Imports a resource element in a given category.
 
    .DESCRIPTION
    Imports a resource element in a given category.
 
    .PARAMETER File
    The plugin file
 
    .PARAMETER Format
    The format of the plugin. It can be either dar or vmoapp
 
    .PARAMETER Overwrite
    Overwrite an installed plugin
 
    .INPUTS
    System.String
    System.IO.FileInfo
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Get-ChildItem -Path C:\Resources\* | Import-vROResourceElement -CategoryId "36cd783f-e858-4783-9273-06d11defc8b0" -Confirm:$false
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [System.IO.FileInfo]$File,

    [parameter(Mandatory=$true)]
    [ValidateSet("dar","vmoapp")]
    [String]$Format,

    [parameter(Mandatory=$false)]
    [Switch]$Overwrite

    )

    begin {

        #Set Set Line Feed
        $LF = "`r`n"

    }

    process {

        $FileInfo = [System.IO.FileInfo](Resolve-Path $File).Path

        try {

            # --- Create the multi-part form
            $Boundary = [guid]::NewGuid().ToString()
            $FileBin = [System.IO.File]::ReadAllBytes($FileInfo.FullName)
            $Encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")
            $EncodedFile = $Encoding.GetString($FileBin)

            $Form = (
                "--$($Boundary)",
                "Content-Disposition: form-data; name=`"file`"; filename=`"$($FileInfo.Name)`"",
                "Content-Type:application/octet-stream$($LF)",
                $EncodedFile,
                "--$($Boundary)--$($LF)"
            ) -join $LF

            $URI = "/vco/api/plugins?format=$($Format)&overwrite=$($Overwrite.ToString().ToLower())"

            # --- Set custom headers for the request
            $Headers = @{

                "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                "Accept" = "Application/json"
                "Accept-Encoding" = "gzip,deflate,sdch";
                "Content-Type" = "multipart/form-data; boundary=$($Boundary)"
            }

            if ($PSCmdlet.ShouldProcess($FileInfo.FullName)){

                # --- Run vRO REST Request
                Invoke-vRORestMethod -Method POST -Uri $URI -Body $Form -Headers $Headers -Verbose:$VerbosePreference | Out-Null

            }

        }
        catch [Exception]{

            throw

        }

    }

    end {

    }

}


<#
    - Function: Set-vROPluginState
#>


function Set-vROPluginState {
<#
    .SYNOPSIS
    Sets the state of a vRO plugin
     
    .DESCRIPTION
    Sets the state of a vRO plugin
     
    .PARAMETER Name
    The name of the plugin
 
    .PARAMETER Enabled
    A boolean value to decide whether or not the plugin is enabled
 
    .INPUTS
    System.String.
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Remove-vROPlugin -Name ExamplePlugin -Enabled:$True
 
    .EXAMPLE
    Remove-vROPlugin -Name ExamplePlugin -Enabled:$False
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Name,

    [parameter(Mandatory=$true)]
    [bool]$Enabled

    )    

    begin {
    
    }
    
    process {    

        foreach ($PluginName in $Name){

            $URI = "/vco/api/plugins/$($PluginName)/state"

            try {

                $Body = @"
 
                    {
 
                        "enabled": $($Enabled.toString().toLower())
 
                    }
 
"@


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

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Uri $URI -Method PUT -Body $Body -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }
    end {
        
    }

}

<#
    - Function: Add-vROResourceElementPermission
#>


function Add-vROResourceElementPermission {
<#
    .SYNOPSIS
    Add a Permission to a vRO Resource Element
     
    .DESCRIPTION
    Add a Permission to a vRO Resource Element
     
    .PARAMETER Id
    Resource Element Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .PARAMETER Rights
    Specify the Permission Rights
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
     
    .EXAMPLE
    Add-vROResourceElementPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' -Principal vRO_Users@vrademo.local -Rights 'View','Execute','Inspect'
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal,  
    
    [parameter(Mandatory=$true)]
    [ValidateSet("View","Execute","Inspect","Edit","Admin")]
    [String[]]$Rights

    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
            $Domain = ($Principal -split "@")[1]

        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "\\")[1]
            $Domain = ($Principal -split "\\")[0]

        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"

        }

        # --- Convert Rights to API required digit(s)
        $APIRights = @()

        switch ($Rights)
        {
            "View" {$APIRights += "r"}
            "Execute" {$APIRights += "x"}
            "Inspect" {$APIRights += "i"}
            "Edit" {$APIRights += "c"}
            "Admin" {$APIRights += "a"}

            Default {}

        }

    }

    process {

        foreach ($ResourceId in $Id){
                
            try {

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

                    # --- Create JSON Body
                    $Body = @"
                        {
                            "permissions": [
                                {
                                    "permission": {
                                        "principal": "$($Domain)\\$($Username)",
                                        "relations": null,
                                        "rights": "$($APIRights -Join(""))"
                                    }
                                }
                            ]
                        }
"@


                    # --- Send REST call and process results
                    $URI = "/vco/api/resources/$($ResourceId)/permissions"

                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Body -Verbose:$VerbosePreference | Out-Null
        
                    # --- Output the Successful Result
                    Get-vROResourceElementPermission -Id $ResourceId | Where-Object {$_.Principal -match $Username}

                }

            }
            catch [Exception]{

                throw
            }

        }

    }

    end {

    }
    
}

<#
    - Function: Export-vROResourceElement
#>


function Export-vROResourceElement {
<#
    .SYNOPSIS
    Exports a resource element by its ID.
 
    .DESCRIPTION
    Exports a resource element by its ID.
 
    .PARAMETER Id
    The id of the resource element
 
    .PARAMETER Path
    The path of the exported file. If this parameter is not passed, the resource element
    will be exported to the current working directory.
 
    .PARAMETER Encoding
    Encoding of the output file
    Windows PS Default = UTF8
    PS Core Default = UTF8NoBOM
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.IO.FileInfo
 
    .EXAMPLE
    Get-vROResourceElement -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133 | Export-vROResourceElement -Path C:\Resources
 
    .EXAMPLE
    Export-vROResourceElement -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133
 
    .EXAMPLE
    Export-vROResourceElement -Id 92768e86-d7bc-400d-bb6d-11e6e10eb133 -Encoding Ascii
 
#>

[CmdletBinding()][OutputType('System.IO.FileInfo')]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Id,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$Path,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$Encoding

    )

    begin {
        if (!$PSBoundParameters.ContainsKey('Encoding')){

            if (!$IsCoreCLR){

                $Encoding = 'UTF8'
            }
            else {
                $Encoding = 'UTF8NoBOM'
            }
        }
    }

    process {

        foreach ($ResourceId in $Id){

            try {

                $URI = "/vco/api/resources/$($ResourceId)"

                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" =" application/octet-stream";

                }

                # --- Run vRO REST Request
                $Request = Invoke-vRORestMethod -Uri $URI -Method Get -Headers $Headers -WebRequest -Verbose:$VerbosePreference

                # --- Get the name of the resource element
                $FileName = (Get-vROResourceElement -Id $ResourceId).Name

                if (!$PSBoundParameters.ContainsKey("Path")) {

                    Write-Verbose -Message "Path parameter not passed, exporting to current directory."
                    $FullPath = "$($(Get-Location).Path)\$($Filename)"

                }
                else {

                    Write-Verbose -Message "Path parameter passed."

                    if ($Path.EndsWith("\")) {

                        Write-Verbose -Message "Ends with"

                        $Path = $Path.TrimEnd("\")

                    }

                    $FullPath = "$($Path)\$($FileName)"

                }

                Write-Verbose -Message "Exporting resource element to $($FullPath)"
                $Request.Content | Set-Content -Path $FullPath -Encoding $Encoding -Force

                # --- Output the result
                Get-ChildItem -Path $FullPath

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}

<#
    - Function: Get-vROResourceElement
#>


function Get-vROResourceElement {
<#
    .SYNOPSIS
    Retrieves a list of all resource elements
 
    .DESCRIPTION
    Retrieves a list of all resource elements
 
    .PARAMETER Id
    The id of the resource element
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROResourceElement
 
    .EXAMPLE
    Get-vROResourceElement -Id f2193849-89e9-4136-8607-526eb196ee4c
 
#>

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

    Param(

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

    )

    begin {

    }

    process {

        try {

            switch ($PSCmdlet.ParameterSetName) {

                'Id' {

                    foreach ($ResourceId in $Id) {

                        $Response = Invoke-vRORestMethod -Method Get -URI "/vco/api/resources/$($ResourceId)" -Verbose:$VerbosePreference
                        
                        [PSCustomObject]@{

                            Id = $Response.id
                            Name = $Response.name
                            Description = $Response.description
                            Version = $Response.version
                            MimeType = $Response."mime-type"
                            Href = $Response.href

                        }                        

                    }

                    break

                }
                'All' {

                    $URI = "/vco/api/resources"

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

                    foreach ($Item in $Response.link) {

                        [PSCustomObject]@{

                            Id = ($Item.attributes | Where-Object {$_.Name -eq "id"}).value
                            Name = ($Item.attributes | Where-Object {$_.Name -eq "name"}).value
                            Description = ($Item.attributes | Where-Object {$_.Name -eq "description"}).value
                            Version = ($Item.attributes | Where-Object {$_.Name -eq "version"}).value
                            MimeType = ($Item.attributes | Where-Object {$_.Name -eq "mime-type"}).value
                            Href = $Item.href

                        }

                    }

                }

            }

        }
        catch [Exception]{
        
            throw
        }

    }

    end {

    }

}

<#
    - Function: Get-vROResourceElementPermission
#>


function Get-vROResourceElementPermission {
<#
    .SYNOPSIS
    Get vRO Resource Element Permissions
 
    .DESCRIPTION
    Get vRO Resource Element Permissions
 
    .PARAMETER Id
    Resource Element Id
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROResourceElementPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea'
 
    .EXAMPLE
    Get-vROResourceElement -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' | Get-vROResourceElementPermission
 
#>

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

    Param
    (   
    
    [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id

    )

    begin {

    }

    process {

        try {

            foreach ($ResourceId in $Id){

                # --- Send REST call and process results
                $URI = "/vco/api/resources/$($ResourceId)/permissions"

                $Response = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

                foreach ($Permission in $Response.permissions){

                    $Rights = @()

                    switch -regex ($Permission.permission.rights)
                    {
                        "[r]" {$Rights += "View"}
                        "[x]" {$Rights += "Execute"}
                        "[i]" {$Rights += "Inspect"}
                        "[c]" {$Rights += "Edit"}
                        "[a]" {$Rights += "Admin"}

                        Default {}

                    }

                    # --- Get the permission href
                    [System.Uri]$Href = $permission.permission.href

                    [PSCustomObject]@{                
                    
                        Id = $href.segments[-1].Trim("/")
                        Principal = $Permission.permission.principal
                        Rights = $Rights
                        ResourceId = $ResourceId

                    }

                }

            }

        }
        catch [Exception]{
        
            throw
        }

    }

    end {

    }

}

<#
    - Function: Import-vROResourceElement
#>


function Import-vROResourceElement {
<#
    .SYNOPSIS
    Imports a resource element in a given category.
 
    .DESCRIPTION
    Imports a resource element in a given category.
 
    .PARAMETER CategoryId
    The name of the resource element category
 
    .PARAMETER File
    The resouce file
 
    .INPUTS
    System.String
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Get-ChildItem -Path C:\Resources\* | Import-vROResourceElement -CategoryId "36cd783f-e858-4783-9273-06d11defc8b0" -Confirm:$false
 
#>

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

    Param (

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

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$File

    )

    begin {

        #Set Set Line Feed
        $LF = "`r`n"

    }

    process {

        foreach ($FilePath in $File){

            $FileInfo = [System.IO.FileInfo](Resolve-Path $FilePath).Path

            try {

                # --- Create the multi-part form
                $Boundary = [guid]::NewGuid().ToString()
                $FileBin = [System.IO.File]::ReadAllBytes($FileInfo.FullName)
                $Encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")
                $EncodedFile = $Encoding.GetString($FileBin)

                $Form = (
                    "--$($Boundary)",
                    "Content-Disposition: form-data; name=`"file`"; filename=`"$($FileInfo.Name)`"",
                    "Content-Type:application/octet-stream$($LF)",
                    $EncodedFile,
                    "--$($Boundary)--$($LF)"
                ) -join $LF

                $URI = "/vco/api/resources?categoryId=$($CategoryId)"

                # --- Set custom headers for the request
                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" = "Application/json"
                    "Accept-Encoding" = "gzip,deflate,sdch";
                    "Content-Type" = "multipart/form-data; boundary=$($Boundary)"
                }

                if ($PSCmdlet.ShouldProcess($FileInfo.FullName)){

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Form -Headers $Headers -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}


<#
    - Function: Remove-vROResourceElement
#>


function Remove-vROResourceElement {
<#
    .SYNOPSIS
    Remove a vRO Resource Element
     
    .DESCRIPTION
    Remove a vRO Resource Element
     
    .PARAMETER Id
    Action ID
 
    .PARAMETER Force
    If the resource element is referenced by some workflows, it is considered to be 'in use'and the delete operation will fail, unless the 'force' option is provided.
 
    .INPUTS
    System.String.
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Remove-vROResourceElement -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea"
 
    .EXAMPLE
    Get-vROResourceElement -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea" | Remove-vROResourceElement
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$false)]
    [Switch]$Force

    )    

    begin {
    
    }
    
    process {    

        foreach ($ResourceId in $Id){

            try {    
                
                if ($PSBoundParameters.ContainsKey("Force")) {
                
                    $URI = "/vco/api/resources/$($ResourceId)?force=true"
                    
                }
                else {

                    $URI = "/vco/api/resources/$($ResourceId)"

                }

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

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Uri $URI -Method DELETE -Verbose:$VerbosePreference | Out-Null


                }

            }
            catch [Exception]{

                throw

            }

        }

    }
    end {
        
    }

}

<#
    - Function: Remove-vROResourceElementPermission
#>


function Remove-vROResourceElementPermission {
<#
    .SYNOPSIS
    Remove a Permission from a vRO Resource Element
     
    .DESCRIPTION
    Remove a Permission from a vRO Resource Element
     
    .PARAMETER Id
    Resource Element Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .INPUTS
    System.String
 
    .OUTPUTS
    None
     
    .EXAMPLE
    Remove-vROResourceElementPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' -Principal vRO_Users@vrademo.local
 
    .EXAMPLE
    Get-vROResourceElement -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' | Remove-vROResourceElementPermission -Principal vRO_Users@vrademo.local
 
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal

    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]

        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "@")[1]

        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"

        }

    }

    process {

        foreach ($ResourceId in $Id){
                
            try {

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

                    # --- Get Permission Rule
                    $Permission = Get-vROResourceElementPermission -Id $ResourceId | Where-Object {$_.Principal -match $Username}
                    
                    if (!$Permission){

                        throw "Unable to find Permission with Principal $($Principal)"
                    }
                    else {
                        
                        $URI = "/vco/api/resources/$($ResourceId)/permissions/$($Permission.Id)"

                    }

                    # --- Send REST call and process results
                    Invoke-vRORestMethod -Method DELETE -Uri $URI -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}

<#
    - Function: Set-vROResourceElement
#>


function Set-vROResourceElement {
<#
    .SYNOPSIS
    Updates a resource element based off the resource ID.
 
    .DESCRIPTION
    Updates a resource element based off the resource ID.
 
    .PARAMETER Id
    The ID of the Resource
 
    .PARAMETER File
    The resource file
 
    .INPUTS
    System.String
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Get-ChildItem -Path "C:\Resources\$file" | Set-vROResourceElement -Id $resource.Id -Confirm:$false
 
#>

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

    Param (

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

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$File

    )

    begin {

        #Set Set Line Feed
        $LF = "`r`n"

    }

    process {

        foreach ($FilePath in $File){

            $FileInfo = [System.IO.FileInfo](Resolve-Path $FilePath).Path

            try {

                # --- Create the multi-part form
                $Boundary = [guid]::NewGuid().ToString()
                $FileBin = [System.IO.File]::ReadAllBytes($FileInfo.FullName)
                $Encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")
                $EncodedFile = $Encoding.GetString($FileBin)

                $Form = (
                    "--$($Boundary)",
                    "Content-Disposition: form-data; name=`"file`"; filename=`"$($FileInfo.Name)`"",
                    "Content-Type:application/octet-stream$($LF)",
                    $EncodedFile,
                    "--$($Boundary)--$($LF)"
                ) -join $LF

                $URI = "/vco/api/resources/$($Id)"

                # --- Set custom headers for the request
                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" = "Application/json"
                    "Accept-Encoding" = "gzip,deflate,sdch";
                    "Content-Type" = "multipart/form-data; boundary=$($Boundary)"
                }

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

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Form -Headers $Headers -Verbose:$VerbosePreference | Out-Null

                }

            }
            catch [Exception]{

                throw

            }

        }

    }

    end {

    }

}


<#
    - Function: Get-vROAPIEndpoint
#>


function Get-vROAPIEndpoint {
<#
    .SYNOPSIS
    Lists the available top-level service entry points.
     
    .DESCRIPTION
    Lists the available top-level service entry points.
 
    .INPUTS
    None
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROApiServiceEntryPoint
#>

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

    Param ()
                
    try {
    
        $URI = "/vco/api/"
        $Response = Invoke-vRORestMethod -URI $URI -Method GET

        foreach ($Service in $Response.service) {

            [pscustomobject] @{

                Href = $Service.href
                Description = $Service.description

            }

        }

    }
    catch [Exception]{

        throw $_.Exception.Message

    }

}

<#
    - Function: Get-vROVersion
#>


function Get-vROVersion {
<#
    .SYNOPSIS
    Retrieve vRO version information
     
    .DESCRIPTION
    Retrieve vRO version information
 
    .INPUTS
    None
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROVersion
#>

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

    Param ()
                
    try {

        $URI = "/vco/api/about"
        $Response = Invoke-vRORestMethod -Method GET -URI $URI

        if ($Response.version.StartsWith("6")){

            $Version = ($Response.version -split " ")[0]
        }
        else {

            $Version = $Response.version
        }

        [pscustomobject] @{

            Version = $Version
            BuildNumber = $Response."build-number"
            BuildDate = $Response."build-date"
            APIVersion = $Response."api-version"

        }

    }
    catch [Exception]{

        throw $_.Exception.Message

    }

}

<#
    - Function: Get-vROUser
#>


function Get-vROUser {
<#
    .SYNOPSIS
    Returns the solution user and whether the current user has admin rights as well as its member groups
 
    .DESCRIPTION
    Returns the solution user and whether the current user has admin rights as well as its member groups
 
    .INPUTS
    None
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROUser
#>

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

    Param()

    begin {

    }

    process {

        try {

            $URI = "/vco/api/users"
            
            Write-Verbose -Message "GET : $($URI)"

            $Response = Invoke-vRORestMethod -Method GET -URI $URI

            Write-Verbose -Message "SUCCESS"

            [PSCustomObject]@{

                AdminRights = $Response."admin-rights"
                SolutionUser = $Response."solution-user"
                MemberGroups = $Response."member-groups"

            }

        }
        catch [Exception]{
        
            throw
        }
    }

    end {

    }
}

<#
    - Function: Get-vROWorkflowExecution
#>


function Get-vROWorkflowExecution {
<#
    .SYNOPSIS
    Get vRO Workflow Executions
 
    .DESCRIPTION
    Get vRO Workflow Executions
 
    .PARAMETER Id
    Retrieve workflow by Id
 
    .PARAMETER Name
    Retrieve workflow by Name
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROWorkflowExecution -Id xxxxxxxxxxxxxxxxxxxxxx
 
    .EXAMPLE
    Get-vROWorkflowExecution -Name 'Test01'
 
    .EXAMPLE
    Get-vROWorkflow -Name 'Test01' | Get-vROWorkflowExecution
#>

[CmdletBinding(DefaultParametersetName="Name")][OutputType('System.Management.Automation.PSObject')]

    Param (   
        [Parameter(Mandatory=$true, ValueFromPipelinebyPropertyName=$true, ParameterSetName="Id")]
        [String]$Id,

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

    begin {

    }

    process {

        try {

            if ($PSCmdlet.ParameterSetName -eq "Name") {

                $Id = (Get-vROWorkflow -Name $Name).Id
            }
    
            $URI = "/vco/api/workflows/$($Id)/executions"

            $Executions = Invoke-vRORestMethod -Method GET -URI $URI  -Verbose:$VerbosePreference

            $Data = $Executions.relations.link | Where-Object {$_.attributes}

            foreach ($Execution in $Data){

                [PSCustomObject]@{                        
        
                    Name = ($Execution.attributes | Where-Object {$_.name -eq 'name'}).value
                    ID = ($Execution.attributes | Where-Object {$_.name -eq 'id'}).value
                    Execution = "$URI/$(($Execution.attributes | Where-Object {$_.name -eq 'id'}).value)/"
                    State = ($Execution.attributes | Where-Object {$_.name -eq 'state'}).value
                    StartedBy = ($Execution.attributes | Where-Object {$_.name -eq 'startedBy'}).value
                    StartDate = ($Execution.attributes | Where-Object {$_.name -eq 'StartDate'}).value
                    EndDate = ($Execution.attributes | Where-Object {$_.name -eq 'EndDate'}).value
                }
            }
        }
        catch [Exception]{
        
            throw
        }
    }

    end {

    }
}

<#
    - Function: Get-vROWorkflowExecutionResult
#>


function Get-vROWorkflowExecutionResult {
<#
    .SYNOPSIS
    Get vRO Workflow Execution Result
 
    .DESCRIPTION
    Get vRO Workflow Execution Result
 
    .PARAMETER ExecutionRef
    vRO Workflow Execution Reference
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROWorkflowExecutionResult -ExecutionRef /vco/api/workflows/565b2c35-3607-4ab9-ace7-9102c1391808/executions/402880244ae8e2a6014b045ea9290213
 
    .EXAMPLE
    Get-vROWorkflow -Name Test04 | Get-vROWorkflowExecution | Select-Object -Last 1 | Get-vROWorkflowExecutionResult
#>

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

    Param
    (   

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [Alias("Execution")]
    [ValidateNotNullOrEmpty()]
    [String]$ExecutionRef 
    )
    
    begin {

    }

    process {  

        try {

            foreach ($Reference in $ExecutionRef){   
    
                # --- Send REST call and process results

                $Result = Invoke-vRORestMethod -Method GET -Uri $Reference -WebRequest -Verbose:$VerbosePreference

                $JSON = $Result.Content | ConvertFrom-Json

                foreach ($OutputParameter in $JSON.'output-parameters'){

                    $Type = $OutputParameter.type

                    [pscustomobject]@{                          
            
                        ExecutionRef = $Reference      
                        Name = $OutputParameter.name
                        Scope = $OutputParameter.scope
                        Type = $OutputParameter.type
                        Value = $OutputParameter.value.$Type.value
                    }
                } 
            }
        }
        catch [Exception]{
        
            throw
        }
    }

    end {

    }
}

<#
    - Function: Get-vROWorkflowExecutionState
#>


function Get-vROWorkflowExecutionState {
<#
    .SYNOPSIS
    Get vRO Workflow Execution State
 
    .DESCRIPTION
    Get vRO Workflow Execution State
 
    .PARAMETER ExecutionStateRef
    vRO Workflow Execution Reference
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROWorkflowExecutionState -ExecutionStateRef '/vco/api/workflows/565b2c35-3607-4ab9-ace7-9102c1391808/executions/402880244ae8e2a6014b045ea9290213'
 
    .EXAMPLE
    Get-vROWorkflowExecution -Id 3f92d2dc-a9fa-4323-900b-ef97196184ea | Select-Object -Last 1 | Get-vROWorkflowExecutionState
#>

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

    Param
    (   
    
    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [Alias("Execution")]
    [ValidateNotNullOrEmpty()]
    [String]$ExecutionStateRef
      
    )    

    begin {

    }

    process {

        try {

            foreach ($Reference in $ExecutionStateRef){
    
                # --- Send REST call and process results

                $URI = $Reference + "state"
                $State = Invoke-vRORestMethod -Method GET -Uri $URI -WebRequest -Verbose:$VerbosePreference

                [pscustomobject]@{                                             
        
                    ExecutionStateRef = $Reference         
                    StatusCode = $State.StatusCode
                    StatusDescription = $State.StatusDescription
                    Execution = ($State.Content | ConvertFrom-Json).Value
                }
            }
        }
        catch [Exception]{
        
            throw
        }
    }

    end {

    }
}

<#
    - Function: Invoke-vROWorkflow
#>


function Invoke-vROWorkflow {
<#
    .SYNOPSIS
    Invoke a vRO Workflow
 
    .DESCRIPTION
    Invoke a vRO Workflow
 
    .PARAMETER Id
    vRO Workflow Id
 
    .PARAMETER ParameterName
    Supply a single parameter to the workflow
 
    .PARAMETER ParameterValue
    Supply the value of the single parameter
 
    .PARAMETER ParameterType
    Supply the type of the single parameter
 
    .PARAMETER Parameters
    Supply workflow parameters via JSON or New-vROParameterDefinition
 
    .INPUTS
    System.String
    System.Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Invoke-vROWorkflow -ID c0278910-9ae2-46c5-bb45-2292fe88e3ab
 
    .EXAMPLE
    Invoke-vROWorkflow -ID c0278910-9ae2-46c5-bb45-2292fe88e3ab -ParameterName 'text' -ParameterValue 'Apple' -ParameterType 'String'
 
    .EXAMPLE
    $Parameters = @"
{"parameters":
    [
        {
            "value": {"string":{ "value": "Apple"}},
            "type": "string",
            "name": "a",
            "scope": "local"
        },
        {
            "value": {"number":{ "value": 20}},
            "type": "number",
            "name": "b",
            "scope": "local"
        }
    ]
}
"@
    Invoke-vROWorkflow -ID c0278910-9ae2-46c5-bb45-2292fe88e3ab -Parameters ($Parameters | ConvertFrom-Json).parameters
 
    .EXAMPLE
    $Param1 = New-vROParameterDefinition -Name a -Value Apple -Type String -Scope LOCAL
    Invoke-vROWorkflow -Id c0278910-9ae2-46c5-bb45-2292fe88e3ab -Parameters $Param1
 
    .EXAMPLE
    Get-vROWorkflow -Name 'Test-Workflow' | Invoke-vROWorkflow -ParameterName a -ParameterValue 'Nature' -ParameterType String
#>

[CmdletBinding(DefaultParametersetName="A")][OutputType('System.Management.Automation.PSObject')]

    Param
    (

        [Parameter(Mandatory=$true,ValueFromPipelinebyPropertyName=$true,ParameterSetName="A")]
        [parameter(Mandatory=$true,ParameterSetName="B")]
        [ValidateNotNullOrEmpty()]
        [String]$Id,

        [Parameter(Mandatory=$false,ParameterSetName="A")]
        [parameter(ParameterSetName="C")]
        [ValidateNotNullOrEmpty()]
        [String]$ParameterName,

        [Parameter(Mandatory=$false,ParameterSetName="A")]
        [parameter(ParameterSetName="C")]
        [String]$ParameterValue,

        [Parameter(Mandatory=$false,ParameterSetName="A")]
        [parameter(ParameterSetName="C")]
        [ValidateNotNullOrEmpty()]
        [String]$ParameterType,

        [Parameter(Mandatory=$false,ParameterSetName="B")]
        [parameter(ParameterSetName="D")]
        [ValidateNotNullOrEmpty()]
        [PSCustomObject[]]$Parameters
    )

    begin {}

    process {

        try {

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

                $ParameterType = $ParameterType.ToLower()

                $Body = @"
{"parameters":
    [
        {
            "value": {"$($ParameterType)":{ "value": "$($ParameterValue)"}},
            "type": "$($ParameterType)",
            "name": "$($ParameterName)",
            "scope": "local"
        }
    ]
}
"@

            }

            elseif ($PSBoundParameters.ContainsKey('Parameters')){

                $Object = [PSCustomObject]@{

                    parameters = @()

                }

                foreach ($Parameter in $Parameters) {

                    $Object.parameters += $Parameter

                }

                $Body = $Object | ConvertTo-Json -Depth 100
            }

            else {

                $Body = @"
{"parameters":
    [
 
    ]
}
"@

            }

            $URI = "/vco/api/workflows/$($Id)/executions/"

            $InvokeRequest = Invoke-vRORestMethod -Method POST -URI $URI -Body $Body -WebRequest -Verbose:$VerbosePreference

            # --- System.Uri gives different output type in Windows PS vs PS Core
            if ($IsCoreCLR) {

                [pscustomobject]@{

                    StatusCode = $InvokeRequest.StatusCode
                    StatusDescription = $InvokeRequest.StatusDescription
                    Execution = ([System.Uri]$InvokeRequest.Headers.Location[0]).LocalPath
                }
            }
            else {

                [pscustomobject]@{

                    StatusCode = $InvokeRequest.StatusCode
                    StatusDescription = $InvokeRequest.StatusDescription
                    Execution = ([System.Uri]$InvokeRequest.Headers.Location).LocalPath
                }
            }
        }
        catch [Exception]{

            throw
        }
    }
}


<#
    - Function: Add-vROWorkflowPermission
#>


function Add-vROWorkflowPermission {
<#
    .SYNOPSIS
    Add a Permission to a vRO Workflow
     
    .DESCRIPTION
    Add a Permission to a vRO Workflow
     
    .PARAMETER Id
    Workflow Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .PARAMETER Rights
    Specify the Permission Rights
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
     
    .EXAMPLE
    Add-vROWorkflowPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' -Principal vRO_Users@vrademo.local -Rights 'View','Execute','Inspect'
 
    .EXAMPLE
    $Permissions = Get-vROWorkflowPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea'
    Get-vROWorkflow -Id '5af6c1fd-3d12-4418-8542-0afad165cc08' | Add-vROWorkflowPermission -Principal $Permissions[0].Principal -Rights $Permissions[0].Rights
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal,  
    
    [parameter(Mandatory=$true)]
    [ValidateSet("View","Execute","Inspect","Edit","Admin")]
    [String[]]$Rights
    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
            $Domain = ($Principal -split "@")[1]
        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "\\")[1]
            $Domain = ($Principal -split "\\")[0]
        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"
        }

        # --- Convert Rights to API required digit(s)
        $APIRights = @()

        switch ($Rights)
        {
            "View" {$APIRights += "r"}
            "Execute" {$APIRights += "x"}
            "Inspect" {$APIRights += "i"}
            "Edit" {$APIRights += "c"}
            "Admin" {$APIRights += "a"}

            Default {}
        }
    }

    process {

        foreach ($WorkflowId in $Id){
                
            try {

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

                    # --- Create JSON Body
                    $Body = @"
    {
      "permissions": [
        {
          "permission": {
            "principal": "$($Domain)\\$($Username)",
            "rights": "$($APIRights -join "")"
          }
        }
      ]
    }
"@

                    # --- Send REST call and process results
                    $URI = "/vco/api/workflows/$($WorkflowId)/permissions"

                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Body -Verbose:$VerbosePreference | Out-Null
        
                    # --- Output the Successful Result
                    Get-vROWorkflowPermission -Id $WorkflowId | Where-Object {$_.Principal -match $Username}
                }
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Export-vROWorkflow
#>


function Export-vROWorkflow {
<#
    .SYNOPSIS
    Export a vRO Workflow to a .workflow file
 
    .DESCRIPTION
    Export a vRO Workflow to a .workflow file
 
    .PARAMETER Id
    Specify the ID of the vRO Workfow
 
    .PARAMETER File
    Specify the Filename to export to - should be a .workflow file
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.IO.FileInfo
 
    .NOTES
    Thanks to @burkeazbill for a few hints with this one https://github.com/burkeazbill/vroClientScripts
 
    .EXAMPLE
    Export-vROWorkflow -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea" -File C:\Workflows\Test01.workflow
 
    .EXAMPLE
    Get-vROWorkflow -Name Test01 | Export-vROWorkflow -File C:\Workflows\Test01.workflow
#>

[CmdletBinding()][OutputType('System.IO.FileInfo')]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Id,

    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$File
    )

    begin {

        $Headers = @{

            "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
            "Accept" ="Application/zip";
            "Accept-Encoding" = "gzip, deflate";
            "Content-Type" = "Application/zip;charset=utf-8";
        }
    }

    process {

        foreach ($WorkflowId in $Id){

            try {

                $URI = "/vco/api/workflows/$($WorkflowId)"

                # --- Run vRO REST Request
                $Request = Invoke-vRORestMethod -Uri $URI -Method Get -Headers $Headers -WebRequest -Verbose:$VerbosePreference

                # --- PS Core does not have -Encoding Byte. Replaced with new parameter AsByteStream
                if (!$IsCoreCLR) {

                    $Request.Content | Set-Content -Path $File -Encoding Byte -Force
                }
                else {
                    $Request.Content | Set-Content -Path $File -AsByteStream -Force
                }

                # --- Output the result
                Get-ChildItem -Path $File
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Export-vROWorkflowIcon
#>


function Export-vROWorkflowIcon {
<#
    .SYNOPSIS
    Export a vRO Workflow Icon as a PNG file
 
    .DESCRIPTION
    Export a vRO Workflow Icon as a PNG file
 
    .PARAMETER Id
    Specify the ID of the vRO Workfow
 
    .PARAMETER File
    Specify the Filename to export to - should be a PNG file
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.IO.FileInfo
 
    .EXAMPLE
    Export-vROWorkflowIcon -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea" -File C:\Icons\Test01.png
 
    .EXAMPLE
    Get-vROWorkflow -Name Test01 | Export-vROWorkflowIcon -File C:\Icons\Test01.png
#>

[CmdletBinding()][OutputType('System.IO.FileInfo')]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Id,

    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$File
    )

    begin {

    }

    process {

        foreach ($WorkflowId in $Id){

            try {

                $URI = "/vco/api/workflows/$($WorkflowId)/icon"

                $Headers = @{

                    "Content-Type" = "image/png";
                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                }

                # --- Run vRO REST Request
                Invoke-vRORestMethod -Method GET -Headers $Headers -URI $URI -OutFile $File -Verbose:$VerbosePreference

                # --- Output the result
                Get-ChildItem -Path $File
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Export-vROWorkflowSchema
#>


function Export-vROWorkflowSchema {
<#
    .SYNOPSIS
    Export a vRO Workflow Schema as a PNG file
 
    .DESCRIPTION
    Export a vRO Workflow Schema as a PNG file
 
    .PARAMETER Id
    Specify the ID of the vRO Workfow
 
    .PARAMETER File
    Specify the Filename to export to - should be a PNG file
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.IO.FileInfo
 
    .EXAMPLE
    Export-vROWorkflowSchema -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea" -File C:\Schemata\Test01.png
 
    .EXAMPLE
    Get-vROWorkflow -Name Test01 | Export-vROWorkflowSchema -File C:\Schemata\Test01.png
#>

[CmdletBinding()][OutputType('System.IO.FileInfo')]

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Id,

    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$File
    )

    begin {

    }

    process {

        foreach ($WorkflowId in $Id){

            try {

                $URI = "/vco/api/workflows/$($WorkflowId)/schema"

                $Headers = @{

                    "Content-Type" = "image/png";
                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                }

                # --- Run vRO REST Request
                Invoke-vRORestMethod -Method GET -Headers $Headers -URI $URI -OutFile $File -Verbose:$VerbosePreference

                # --- Output the result
                Get-ChildItem -Path $File
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Get-vROWorkflow
#>


function Get-vROWorkflow {
<#
    .SYNOPSIS
    Get vRO Workflows
 
    .DESCRIPTION
    Get vRO Workflows
 
    .PARAMETER CategoryName
    Retrieve workflow by Category Name
 
    .PARAMETER CategoryId
    Retrieve workflow by Category Id
 
    .PARAMETER Id
    Retrieve workflow by Id
 
    .PARAMETER Name
    Retrieve workflow by Name
 
    .PARAMETER Wildcard
    Perform a wildcard search when using the Name parameter
 
    .PARAMETER Tag
    Retrieve workflow by Tag
 
    .INPUTS
    System.String
    System.Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROWorkflow
 
    .EXAMPLE
    Get-vROWorkflow -CategoryName Dev
 
    .EXAMPLE
    Get-vROWorkflow -CategoryId 2c94c8b464fa5d6e0164ff48ac54070a
 
    .EXAMPLE
    Get-vROWorkflow -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea'
 
    .EXAMPLE
    Get-vROWorkflow -Name 'New-DRSRule'
 
    .EXAMPLE
    Get-vROWorkflow -Name 'New' -Wildcard
 
    .EXAMPLE
    Get-vROWorkflow -Tag 'vCenter'
#>

[CmdletBinding(DefaultParametersetName="All")][OutputType('System.Management.Automation.PSObject')]

    Param
    (

    [parameter(Mandatory=$false,ParameterSetName="CategoryName")]
    [Alias("Category")]
    [String]$CategoryName,

    [parameter(Mandatory=$false,ParameterSetName="CategoryId")]
    [String]$CategoryId,

    [parameter(Mandatory=$false,ParameterSetName="Id")]
    [String]$Id,

    [parameter(Mandatory=$false,ParameterSetName="Name")]
    [String]$Name,

    [parameter(Mandatory=$false,ParameterSetName="Name")]
    [Switch]$Wildcard,

    [parameter(Mandatory=$false,ParameterSetName="All")]
    [parameter(Mandatory=$false,ParameterSetName="CategoryName")]
    [parameter(Mandatory=$false,ParameterSetName="Category")]
    [String[]]$Tag

    )

    begin {

        # --- Verify vRO version supports tagging
        if ($PSBoundParameters.ContainsKey('Tag') -and $Script:vROConnection.Version -like '7.*') {

            throw "Tagging is not supported with vRO $($Script:vroConnection.Version)."
        }
    }

    process {

        try {

            # --- Send REST call and process results
            switch ($PsCmdlet.ParameterSetName){
    
                "All" {
    
                    $URI = "/vco/api/workflows"
                    break
                }
    
                "CategoryName" {
    
                    $URI = "/vco/api/workflows/?conditions=categoryName=$($CategoryName)"
                    break
                }
    
                "CategoryId" {
    
                    $URI = "/vco/api/catalog/System/WorkflowCategory/$($CategoryId)/workflows"
                    break
                }
    
                "Id" {
    
                    $URI = "/vco/api/workflows/$($Id)"
                    break
    
                }
    
                "Name" {
    
                    if ($PSBoundParameters.ContainsKey('Wildcard')){
    
                        $URI = "/vco/api/workflows/?conditions=name~$($Name)"
                    }
                    else {
    
                        $URI = "/vco/api/workflows/?conditions=name=$($Name)"
                    }
                    break
                }
            }

            # filter by tag
            if ($PSBoundParameters.ContainsKey('Tag')) {
                $URI += if ($PSCmdlet.ParameterSetName -eq 'All') { '?' } else { '&' }
    
                $newParams = @()
                foreach ($tagAttr in $Tag) {
                    $newParams += "tags=$($tagAttr)"
                }
    
                $URI += $newParams -join '&'
            }
    
            switch ($PsCmdlet.ParameterSetName){
    
                "Id" {
    
                    $Workflow = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference
    
                    [pscustomobject]@{
    
                        Name = $Workflow.name
                        ID = $Workflow.id
                        Description = $Workflow.description
                        ItemHref = $Workflow.href
                        Version = $Workflow.version
                        CategoryName = $null
                        CategoryHref = $null
                        CustomIcon = $Workflow.'customized-icon'
                        CanExecute = $null
                        CanEdit = $null
                    }
                }
    
                "CategoryId" {
    
                    $Workflows = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference
    
                    foreach ($Workflow in $Workflows.link){
    
                        $returnObject = @{
    
                            Name = ($Workflow.attributes | Where-Object {$_.name -eq 'name'}).value
                            ID = ($Workflow.attributes | Where-Object {$_.name -eq 'id'}).value
                            Description = ($Workflow.attributes | Where-Object {$_.name -eq 'description'}).value
                            ItemHref = $Workflow.href
                            Version = ($Workflow.attributes | Where-Object {$_.name -eq 'version'}).value
                            CategoryName = ($Workflow.attributes | Where-Object {$_.name -eq 'categoryName'}).value
                            CategoryHref = ($Workflow.attributes | Where-Object {$_.name -eq 'categoryHref'}).value
                            CustomIcon = ($Workflow.attributes | Where-Object {$_.name -eq 'customIcon'}).value
                            CanExecute = ($Workflow.attributes | Where-Object {$_.name -eq 'canExecute'}).value
                            CanEdit = ($Workflow.attributes | Where-Object {$_.name -eq 'canEdit'}).value
                        }

                        # add tags if appropriate
                        $tags = $Workflow.attributes | Where-Object {$_.name -eq 'globalTags'} | Select-Object -ExpandProperty 'value'
                        if ($tags) {

                            $tagsArray = ($tags -replace ':__SYSTEM_TAG__|.$', '').Split(' ')
                            $returnObject.Add('Tags', $tagsArray)
                        }

                        [PSCustomObject]$returnObject
                    }
                }
    
                default {
    
                    $Workflows = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference
    
                    foreach ($Workflow in $Workflows.link){
    
                        $returnObject = @{
    
                            Name = ($Workflow.attributes | Where-Object {$_.name -eq 'name'}).value
                            ID = ($Workflow.attributes | Where-Object {$_.name -eq 'id'}).value
                            Description = ($Workflow.attributes | Where-Object {$_.name -eq 'description'}).value
                            ItemHref = ($Workflow.attributes | Where-Object {$_.name -eq 'itemHref'}).value
                            Version = ($Workflow.attributes | Where-Object {$_.name -eq 'version'}).value
                            CategoryName = ($Workflow.attributes | Where-Object {$_.name -eq 'categoryName'}).value
                            CategoryHref = ($Workflow.attributes | Where-Object {$_.name -eq 'categoryHref'}).value
                            CustomIcon = ($Workflow.attributes | Where-Object {$_.name -eq 'customIcon'}).value
                            CanExecute = ($Workflow.attributes | Where-Object {$_.name -eq 'canExecute'}).value
                            CanEdit = ($Workflow.attributes | Where-Object {$_.name -eq 'canEdit'}).value
                        }

                        # add tags if appropriate
                        $tags = $Workflow.attributes | Where-Object {$_.name -eq 'globalTags'} | Select-Object -ExpandProperty 'value'
                        if ($tags) {

                            $tagsArray = ($tags -replace ':__SYSTEM_TAG__|.$', '').Split(' ')
                            $returnObject.Add('Tags', $tagsArray)
                        }

                        [PSCustomObject]$returnObject
                    }
                }
            }
        }
        catch [Exception]{
    
            throw
        }
    }
}

<#
    - Function: Get-vROWorkflowPermission
#>


function Get-vROWorkflowPermission {
<#
    .SYNOPSIS
    Get vRO Workflow Permissions
 
    .DESCRIPTION
    Get vRO Workflow Permissions
 
    .PARAMETER Id
    Workflow Id
 
    .INPUTS
    System.String
 
    .OUTPUTS
    System.Management.Automation.PSObject.
 
    .EXAMPLE
    Get-vROWorkflowPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea'
 
    .EXAMPLE
    Get-vROWorkflow -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' | Get-vROWorkflowPermission
#>

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

    Param
    (   
    
    [parameter(Mandatory=$true,ValueFromPipeline,ValueFromPipelinebyPropertyName=$true)]
    [String[]]$Id

    )

    begin {

    }

    process {

        try {

            foreach ($WorkflowId in $Id){

                # --- Send REST call and process results
                $URI = "/vco/api/workflows/$($WorkflowId)/permissions"

                $Workflow = Invoke-vRORestMethod -Method Get -Uri $URI -Verbose:$VerbosePreference

                foreach ($Permission in $Workflow.permissions){

                    $Rights = @()

                    switch -regex ($Permission.permission.rights)
                    {
                        "[r]" {$Rights += "View"}
                        "[x]" {$Rights += "Execute"}
                        "[i]" {$Rights += "Inspect"}
                        "[c]" {$Rights += "Edit"}
                        "[a]" {$Rights += "Admin"}

                        Default {}
                    }

                    [pscustomobject]@{                
                    
                        Principal = $Permission.permission.principal
                        Rights = $Rights
                        WorkflowID = $WorkflowId
                        WorkflowHref = $Permission.permission.href
                    }
                }
            }
        }
        catch [Exception]{
        
            throw
        }
    }

    end {

    }
}

<#
    - Function: Import-vROWorkflow
#>


function Import-vROWorkflow {
<#
    .SYNOPSIS
    Import a vRO Workflow from a .workflow file
 
    .DESCRIPTION
    Import a vRO Workflow from a .workflow file
 
    .PARAMETER CategoryId
    Specify the ID of the vRO Category to import the Workfow to
 
    .PARAMETER File
    Specify the Filename to import from - should be a .workflow file
 
    .PARAMETER Overwrite
    Overwrite an existing vRO Workflow
 
    .PARAMETER PassThru
    If the name of the import file matches the name of the workflow then return imported workflow, e.g. if Test01.workflow matches a workflow name of Test01
 
    .INPUTS
    System.String
    System.IO.FileInfo
    Switch
 
    .OUTPUTS
    System.Management.Automation.PSObject
 
    .NOTES
    Thanks to @burkeazbill for a few hints with this one https://github.com/burkeazbill/vroClientScripts
 
    .EXAMPLE
    Import-vROWorkflow -CategoryId "40281e8654ddec6201553af63677146e" -File C:\Workflows\Test01.workflow -Overwrite
 
    .EXAMPLE
    Import-vROWorkflow -CategoryId "40281e8654ddec6201553af63677146e" -File C:\Workflows\Test01.workflow -PassThru -Confirm:$false
 
    .EXAMPLE
    Get-ChildItem -Path C:\Workflows\*.workflow | Import-vROWorkflow -CategoryId "40281e8654ddec6201553af63677146e" -Confirm:$false
#>

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

    Param (

    [parameter(Mandatory=$true)]
    [Alias("Id")]
    [ValidateNotNullOrEmpty()]
    [String]$CategoryId,

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$File,

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

    [parameter(Mandatory=$false)]
    [Switch]$PassThru
    )

    begin {

        # --- Set Set Line Feed
        $LF = "`r`n"
    }

    process {

        foreach ($FilePath in $File){

            try {

                # --- Resolve the file path
                $FileInfo = [System.IO.FileInfo](Resolve-Path $FilePath).Path

                # --- Create the multi-part form
                $Boundary = [guid]::NewGuid().ToString()
                $FileBin = [System.IO.File]::ReadAllBytes($FileInfo.FullName)
                $Encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")
                $EncodedFile = $Encoding.GetString($FileBin)

                $Form = (
                    "--$($Boundary)",
                    "Content-Disposition: form-data; name=`"file`"; filename=`"$($FileInfo.Name)`"",
                    "Content-Type:application/octet-stream$($LF)",
                    $EncodedFile,
                    "--$($Boundary)--$($LF)"
                ) -join $LF

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

                    $URI = "/vco/api/workflows?categoryId=$($categoryId)&overwrite=true"
                }
                else {

                    $URI = "/vco/api/workflows?categoryId=$($categoryId)"
                }

                $Headers = @{

                    "Authorization" = "Basic $($Script:vROConnection.EncodedPassword)";
                    "Accept" = "Application/json"
                    "Accept-Encoding" = "gzip,deflate,sdch";
                    "Content-Type" = "multipart/form-data; boundary=$($Boundary)"
                }

                if ($PSCmdlet.ShouldProcess($FileInfo.FullName)){

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Method POST -Uri $URI -Body $Form -Headers $Headers -Verbose:$VerbosePreference

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

                        # --- Output the result
                        $WorkflowName = ($FileInfo.Name -split "\.")[0]
                        Get-vROWorkflow -Name $WorkflowName
                    }
                }
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}

<#
    - Function: Remove-vROWorkflow
#>


function Remove-vROWorkflow {
<#
    .SYNOPSIS
    Remove a vRO Workflow
     
    .DESCRIPTION
    Remove a vRO Workflow
     
    .PARAMETER Id
    Workflow ID
 
    .PARAMETER Force
    If the workflow is referenced by some other workflows, or is running, it is considered to be 'in use' and the delete operation will fail, unless the 'force' option is provided.
 
    .INPUTS
    System.String.
    Switch
 
    .OUTPUTS
    None
 
    .EXAMPLE
    Remove-vROWorkflow -Id "3f92d2dc-a9fa-4323-900b-ef97196184ea"
 
    .EXAMPLE
    Get-vROWorkflow -Name Test01 | Remove-vROWorkflow -Confirm:$false
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelinebyPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,

    [parameter(Mandatory=$false)]
    [Switch]$Force
    )    

    begin {
    
    }
    
    process {    

        foreach ($WorkflowId in $Id){

            try {    
                
                if ($PSBoundParameters.ContainsKey("Force")) {
                
                    $URI = "/vco/api/workflows/$($WorkflowId)?force=true"
                }
                else {

                    $URI = "/vco/api/workflows/$($WorkflowId)"
                }

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

                    # --- Run vRO REST Request
                    Invoke-vRORestMethod -Uri $URI -Method DELETE -Verbose:$VerbosePreference
                }
            }
            catch [Exception]{

                throw
            }
        }
    }
    end {
        
    }
}

<#
    - Function: Remove-vROWorkflowPermission
#>


function Remove-vROWorkflowPermission {
<#
    .SYNOPSIS
    Remove a Permission from a vRO Workflow
     
    .DESCRIPTION
    Remove a Permission from a vRO Workflow
     
    .PARAMETER Id
    Workflow Id
 
    .PARAMETER Principal
    Specify the Permission Principal. Needs to be in the format user@domain or domain\user
 
    .INPUTS
    System.String
 
    .OUTPUTS
    None
     
    .EXAMPLE
    Remove-vROWorkflowPermission -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' -Principal vRO_Users@vrademo.local
 
    .EXAMPLE
    Get-vROWorkflow -Id '3f92d2dc-a9fa-4323-900b-ef97196184ea' | Remove-vROWorkflowPermission -Principal vRO_Users@vrademo.local
#>

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

    Param (

    [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Id,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$Principal
    )

    begin {

        # --- Break out the Username and Domain from the Principal
        if ($Principal -match "@"){

            $Username = ($Principal -split "@")[0]
        }
        elseif ($Principal -match "\\"){

            $Username = ($Principal -split "@")[1]
        }
        else {

            throw "Principal needs to be in the format user@domain or domain\user"
        }
    }

    process {

        foreach ($WorkflowId in $Id){
                
            try {

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

                    # --- Get Permission Rule
                    $WorkflowPermission = Get-vROWorkflowPermission -Id $WorkflowId | Where-Object {$_.Principal -match $Username}
                    
                    if (!$WorkflowPermission){

                        throw "Unable to find Workflow Permission with Principal $($Principal)"
                    }
                    else {
                        
                        $Index = $WorkflowPermission.WorkflowHref.IndexOf("/vco")
                        $URI = $WorkflowPermission.WorkflowHref.Substring($Index)
                    }

                    # --- Send REST call and process results
                    Invoke-vRORestMethod -Method DELETE -Uri $URI -Verbose:$VerbosePreference | Out-Null        
                }
            }
            catch [Exception]{

                throw
            }
        }
    }

    end {

    }
}