Public/system-vm-router.ps1

function Set-CSSystemVMServiceOffering {
    <#
    .SYNOPSIS
        Changes the service offering for a stopped system VM.

    .DESCRIPTION
        Wraps changeServiceForSystemVm. The system VM (console proxy or secondary
        storage VM) must be stopped first. -Details supplies custom sizing when the
        offering is a custom one. Accepts system VM objects on the pipeline.

    .PARAMETER Id
        The system VM to reconfigure. Binds from a piped system VM's id.

    .PARAMETER ServiceOfferingId
        The service offering to apply

    .PARAMETER Details
        Custom sizing (for example @{ cpuNumber = 2; memory = 4096 }) for a custom offering

    .EXAMPLE
        Set-CSSystemVMServiceOffering -Id 'system-vm-uuid' -ServiceOfferingId 'offering-uuid'
        Applies the selected service offering to the stopped system VM.

    .EXAMPLE
        Get-CSSystemVM -Id 'system-vm-uuid' | Set-CSSystemVMServiceOffering -ServiceOfferingId 'offering-uuid'
        Passes the listed system VM's Id property through the pipeline.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id,
        [Parameter(Mandatory=$true)][string]$ServiceOfferingId,
        [hashtable]$Details
    )
    process {
        $apiParams = @{ id = $Id; serviceofferingid = $ServiceOfferingId }
        if ($Details) {
            $index = 0
            foreach ($key in $Details.Keys) {
                $apiParams["details[$index].name"] = $key
                $apiParams["details[$index].value"] = $Details[$key]
                $index++
            }
        }
        Invoke-CSApiRequest -Command 'changeServiceForSystemVm' -Parameters $apiParams
    }
}

function Remove-CSSystemVM {
    <#
    .SYNOPSIS
        Destroys a CloudStack system VM.

    .DESCRIPTION
        Wraps destroySystemVm. Destruction affects a console proxy or secondary
        storage VM; CloudStack recreates such system VMs automatically as needed.
        Uses ShouldProcess, so -WhatIf previews and -Confirm prompts. Accepts system
        VM objects on the pipeline.

    .PARAMETER Id
        The system VM to destroy. Binds from a piped system VM's id.

    .EXAMPLE
        Remove-CSSystemVM -Id 'system-vm-uuid' -WhatIf
        Previews destruction of the selected system VM.

    .EXAMPLE
        Get-CSSystemVM -Id 'system-vm-uuid' | Remove-CSSystemVM -WhatIf
        Previews destruction using a system VM object from the pipeline.
    #>

    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id)
    process {
        if ($PSCmdlet.ShouldProcess("system VM $Id", 'Destroy')) {
            Invoke-CSApiRequest -Command 'destroySystemVm' -Parameters @{ id = $Id }
        }
    }
}

function Get-CSSystemVM {
    <#
    .SYNOPSIS
        Lists CloudStack system VMs with optional filters.

    .DESCRIPTION
        Wraps listSystemVms, returning console proxy and secondary storage VMs.
        Filter by type, state, zone, pod, host, or storage. Accepts a system VM id
        on the pipeline.

    .PARAMETER HostId
        Filter by the host the system VM runs on

    .PARAMETER Id
        Filter by system VM ID. Binds from a piped system VM's id.

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Name
        Filter by system VM name

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .PARAMETER PodId
        Filter by pod ID

    .PARAMETER State
        Filter by state (for example Running, Stopped)

    .PARAMETER StorageId
        Filter by the storage pool the system VM uses

    .PARAMETER SystemVMType
        Filter by type: consoleproxy or secondarystoragevm

    .PARAMETER ZoneId
        Filter by zone ID

    .EXAMPLE
        Get-CSSystemVM -SystemVMType secondarystoragevm -ZoneId 'zone-uuid'
        Lists secondary storage VMs in the specified zone.

    .EXAMPLE
        Get-CSSystemVM -State Running -PodId 'pod-uuid'
        Lists running system VMs in a pod.
    #>

    [CmdletBinding()]
    param(
        [string]$HostId,
        [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id,
        [string]$Keyword,
        [string]$Name,
        [int]$Page,
        [int]$PageSize,
        [string]$PodId,
        [string]$State,
        [string]$StorageId,
        [ValidateSet('consoleproxy','secondarystoragevm')][string]$SystemVMType,
        [string]$ZoneId
    )
    process {
        $apiParams = @{}
        $parameterMap = @{
            HostId='hostid'; Id='id'; Keyword='keyword'; Name='name'; Page='page'; PageSize='pagesize';
            PodId='podid'; State='state'; StorageId='storageid'; SystemVMType='systemvmtype'; ZoneId='zoneid'
        }
        foreach ($parameter in $parameterMap.Keys) {
            if ($PSBoundParameters.ContainsKey($parameter)) {
                $apiParams[$parameterMap[$parameter]] = Get-Variable -Name $parameter -ValueOnly
            }
        }
        $response = Invoke-CSApiRequest -Command 'listSystemVms' -Parameters $apiParams
        if ($response.listsystemvmsresponse.systemvm) { return $response.listsystemvmsresponse.systemvm }
    }
}

function Get-CSSystemVMUsageHistory {
    <#
    .SYNOPSIS
        Lists usage statistics for one or more system VMs.

    .DESCRIPTION
        Wraps listSystemVmsUsageHistory. Use -Id (or a piped system VM) for a single
        VM or -Ids for several; the two are mutually exclusive. -StartDate/-EndDate
        are DateTime values, sent as 'yyyy-MM-dd HH:mm:ss'.

    .PARAMETER EndDate
        End of the reporting period, as a DateTime

    .PARAMETER Id
        A single system VM ID. Binds from a piped system VM's id. Mutually exclusive with -Ids.

    .PARAMETER Ids
        Several system VM IDs. Mutually exclusive with -Id.

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Name
        Filter by system VM name

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .PARAMETER StartDate
        Start of the reporting period, as a DateTime

    .EXAMPLE
        Get-CSSystemVMUsageHistory -Id 'system-vm-uuid' -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date)
        Retrieves the selected system VM's usage history for the past week.

    .EXAMPLE
        Get-CSSystemVMUsageHistory -Ids @('system-vm-a','system-vm-b')
        Retrieves usage history for multiple system VMs.
    #>

    [CmdletBinding()]
    param(
        [datetime]$EndDate,
        [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id,
        [string[]]$Ids,
        [string]$Keyword,
        [string]$Name,
        [int]$Page,
        [int]$PageSize,
        [datetime]$StartDate
    )
    process {
        if ($PSBoundParameters.ContainsKey('Id') -and $PSBoundParameters.ContainsKey('Ids')) {
            throw 'Specify Id or Ids, not both.'
        }
        $apiParams = @{}
        foreach ($parameter in @('Id','Keyword','Name','Page','PageSize')) {
            if ($PSBoundParameters.ContainsKey($parameter)) {
                $apiParams[$parameter.ToLowerInvariant()] = Get-Variable -Name $parameter -ValueOnly
            }
        }
        if ($PSBoundParameters.ContainsKey('Ids')) { $apiParams['ids'] = $Ids -join ',' }
        foreach ($parameter in @('StartDate','EndDate')) {
            if ($PSBoundParameters.ContainsKey($parameter)) {
                $apiParams[$parameter.ToLowerInvariant()] = (Get-Variable -Name $parameter -ValueOnly).ToString('yyyy-MM-dd HH:mm:ss')
            }
        }
        $response = Invoke-CSApiRequest -Command 'listSystemVmsUsageHistory' -Parameters $apiParams
        if ($response.listsystemvmsusagehistoryresponse.systemvm) { return $response.listsystemvmsusagehistoryresponse.systemvm }
    }
}

function Move-CSSystemVM {
    <#
    .SYNOPSIS
        Migrates a system VM to a destination host and optionally storage pool.

    .DESCRIPTION
        Wraps migrateSystemVm. Provide -HostId, or use -AutoSelect to let CloudStack
        choose a host; the two are mutually exclusive. -StorageId can be supplied to
        migrate the VM's volumes. Accepts a system VM object on the pipeline.

    .PARAMETER VirtualMachineId
        The system VM to migrate. Binds from a piped system VM's id.

    .PARAMETER AutoSelect
        Let CloudStack choose the destination host. Mutually exclusive with -HostId.

    .PARAMETER HostId
        The destination host

    .PARAMETER StorageId
        The destination storage pool for the VM's volumes

    .EXAMPLE
        Move-CSSystemVM -VirtualMachineId 'system-vm-uuid' -HostId 'host-uuid'
        Migrates the system VM to a selected host without storage migration.

    .EXAMPLE
        Move-CSSystemVM -VirtualMachineId 'system-vm-uuid' -AutoSelect -StorageId 'pool-uuid'
        Lets CloudStack choose a host and migrates the VM's volumes to the selected pool.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][Alias('Id')][string]$VirtualMachineId,
        [switch]$AutoSelect,
        [string]$HostId,
        [string]$StorageId
    )
    process {
        if ($AutoSelect -and $PSBoundParameters.ContainsKey('HostId')) { throw 'AutoSelect cannot be combined with HostId.' }
        if (-not $AutoSelect -and -not $PSBoundParameters.ContainsKey('HostId') -and -not $PSBoundParameters.ContainsKey('StorageId')) {
            throw 'Specify HostId, StorageId, or AutoSelect.'
        }
        $apiParams = @{ virtualmachineid = $VirtualMachineId }
        if ($AutoSelect) { $apiParams['autoselect'] = 'true' }
        if ($PSBoundParameters.ContainsKey('HostId')) { $apiParams['hostid'] = $HostId }
        if ($PSBoundParameters.ContainsKey('StorageId')) { $apiParams['storageid'] = $StorageId }
        Invoke-CSApiRequest -Command 'migrateSystemVm' -Parameters $apiParams
    }
}

function Update-CSSystemVMScripts {
    <#
    .SYNOPSIS
        Patches scripts on CloudStack system VMs.

    .DESCRIPTION
        Wraps patchSystemVm. With -Id omitted, CloudStack applies the patch operation
        to system VMs according to its API behavior. -Forced (which restarts the
        agent) is supported only together with a specific -Id. Accepts a system VM id
        on the pipeline.

    .PARAMETER Id
        The system VM to patch. Binds from a piped system VM's id.

    .PARAMETER Forced
        Force script synchronization and agent restart (requires -Id)

    .EXAMPLE
        Update-CSSystemVMScripts -Id 'system-vm-uuid' -Forced
        Forces script synchronization and agent restart for one system VM.

    .EXAMPLE
        Get-CSSystemVM -SystemVMType consoleproxy | Update-CSSystemVMScripts
        Patches each console proxy returned by the query.
    #>

    [CmdletBinding()]
    param([Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [switch]$Forced)
    process {
        if ($Forced -and -not $PSBoundParameters.ContainsKey('Id')) { throw 'Forced requires Id.' }
        $apiParams = @{}
        if ($PSBoundParameters.ContainsKey('Id')) { $apiParams['id'] = $Id }
        if ($Forced) { $apiParams['forced'] = 'true' }
        Invoke-CSApiRequest -Command 'patchSystemVm' -Parameters $apiParams
    }
}

function Restart-CSSystemVM {
    <#
    .SYNOPSIS
        Reboots a CloudStack system VM.

    .DESCRIPTION
        Wraps rebootSystemVm. -Forced performs a hard stop-and-start. Accepts system
        VM objects on the pipeline, so a filtered list can be rebooted in one call.

    .PARAMETER Id
        The system VM to reboot. Binds from a piped system VM's id.

    .PARAMETER Forced
        Force-stop and start the VM as part of the reboot

    .EXAMPLE
        Restart-CSSystemVM -Id 'system-vm-uuid'
        Reboots the selected system VM.

    .EXAMPLE
        Restart-CSSystemVM -Id 'system-vm-uuid' -Forced
        Force-stops and starts the system VM as part of the reboot.

    .EXAMPLE
        Get-CSSystemVM -SystemVMType consoleproxy -State Running | Restart-CSSystemVM
        Reboots each running console proxy returned by the query.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [switch]$Forced)
    process {
        $apiParams = @{ id = $Id }
        if ($Forced) { $apiParams['forced'] = 'true' }
        Invoke-CSApiRequest -Command 'rebootSystemVm' -Parameters $apiParams
    }
}

function Set-CSSystemVMSize {
    <#
    .SYNOPSIS
        Scales a stopped system VM to a service offering or custom sizing.

    .DESCRIPTION
        Wraps scaleSystemVm. The system VM must be stopped. -Details supplies custom
        CPU/memory values when the offering is a custom one. Accepts a system VM id on
        the pipeline.

    .PARAMETER Id
        The system VM to scale. Binds from a piped system VM's id.

    .PARAMETER ServiceOfferingId
        The service offering to scale to

    .PARAMETER Details
        Custom sizing (for example @{ cpunumber = 4; memory = 8192 }) for a custom offering

    .EXAMPLE
        Set-CSSystemVMSize -Id 'system-vm-uuid' -ServiceOfferingId 'offering-uuid'
        Scales the stopped system VM to the selected offering.

    .EXAMPLE
        Set-CSSystemVMSize -Id 'system-vm-uuid' -ServiceOfferingId 'custom-offering' -Details @{ cpunumber = 4; memory = 8192 }
        Supplies custom CPU and memory values alongside the offering.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [Parameter(Mandatory=$true)][string]$ServiceOfferingId, [hashtable]$Details)
    process {
        $apiParams = @{ id = $Id; serviceofferingid = $ServiceOfferingId }
        if ($Details) {
            $index = 0
            foreach ($key in $Details.Keys) {
                $apiParams["details[$index].name"] = $key
                $apiParams["details[$index].value"] = $Details[$key]
                $index++
            }
        }
        Invoke-CSApiRequest -Command 'scaleSystemVm' -Parameters $apiParams
    }
}

function Start-CSSystemVM {
    <#
    .SYNOPSIS
        Starts a CloudStack system VM.

    .DESCRIPTION
        Wraps startSystemVm. Accepts a system VM id on the pipeline.

    .PARAMETER Id
        The system VM to start. Binds from a piped system VM's id.

    .EXAMPLE
        Start-CSSystemVM -Id 'system-vm-uuid'
        Starts the selected system VM.

    .EXAMPLE
        Get-CSSystemVM -State Stopped | Start-CSSystemVM
        Starts each stopped system VM returned by the query.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id)
    process { Invoke-CSApiRequest -Command 'startSystemVm' -Parameters @{ id = $Id } }
}

function Stop-CSSystemVM {
    <#
    .SYNOPSIS
        Stops a CloudStack system VM.

    .DESCRIPTION
        Wraps stopSystemVm. -Forced performs a hard stop. Accepts a system VM id on
        the pipeline.

    .PARAMETER Id
        The system VM to stop. Binds from a piped system VM's id.

    .PARAMETER Forced
        Force-stop the system VM

    .EXAMPLE
        Stop-CSSystemVM -Id 'system-vm-uuid'
        Stops the selected system VM.

    .EXAMPLE
        Stop-CSSystemVM -Id 'system-vm-uuid' -Forced
        Force-stops the system VM when the caller knows it is already stopped.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [switch]$Forced)
    process {
        $apiParams = @{ id = $Id }
        if ($Forced) { $apiParams['forced'] = 'true' }
        Invoke-CSApiRequest -Command 'stopSystemVm' -Parameters $apiParams
    }
}

function Set-CSRouterServiceOffering {
    <#
    .SYNOPSIS
        Changes the service offering of a domain router.

    .DESCRIPTION
        Wraps changeServiceForRouter. The router must be stopped before its offering
        can be changed. Accepts a router object on the pipeline.

    .PARAMETER Id
        The router to reconfigure. Binds from a piped router's id.

    .PARAMETER ServiceOfferingId
        The service offering to apply

    .EXAMPLE
        Set-CSRouterServiceOffering -Id 'router-uuid' -ServiceOfferingId 'offering-uuid'
        Applies the selected offering to the router.

    .EXAMPLE
        Get-CSRouter -Id 'router-uuid' | Set-CSRouterServiceOffering -ServiceOfferingId 'offering-uuid'
        Passes the router's Id property from the pipeline.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [Parameter(Mandatory=$true)][string]$ServiceOfferingId)
    process { Invoke-CSApiRequest -Command 'changeServiceForRouter' -Parameters @{ id = $Id; serviceofferingid = $ServiceOfferingId } }
}

function Set-CSVirtualRouterElement {
    <#
    .SYNOPSIS
        Enables or disables a virtual router provider element.

    .DESCRIPTION
        Wraps configureVirtualRouterElement, toggling whether the virtual router
        provider element is enabled. Accepts a provider element object on the
        pipeline.

    .PARAMETER Id
        The virtual router element to configure. Binds from a piped element's id.

    .PARAMETER Enabled
        $true to enable the element, $false to disable it

    .EXAMPLE
        Set-CSVirtualRouterElement -Id 'provider-uuid' -Enabled:$true
        Enables the virtual router provider.

    .EXAMPLE
        Set-CSVirtualRouterElement -Id 'provider-uuid' -Enabled:$false
        Disables the virtual router provider.

    .EXAMPLE
        Get-CSVirtualRouterElement -Id 'provider-uuid' | Set-CSVirtualRouterElement -Enabled:$true
        Enables the provider element returned by the query.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [Parameter(Mandatory=$true)][bool]$Enabled)
    process { Invoke-CSApiRequest -Command 'configureVirtualRouterElement' -Parameters @{ id = $Id; enabled = $Enabled.ToString().ToLowerInvariant() } }
}

function New-CSVirtualRouterElement {
    <#
    .SYNOPSIS
        Creates a virtual router provider element for a network service provider.

    .DESCRIPTION
        Wraps createVirtualRouterElement, adding a VirtualRouter or VPCVirtualRouter
        element under a network service provider. Accepts the provider id on the
        pipeline.

    .PARAMETER NetworkServiceProviderId
        The network service provider to add the element to. Binds from a piped provider's id.

    .PARAMETER ProviderType
        The element type: VirtualRouter or VPCVirtualRouter

    .EXAMPLE
        New-CSVirtualRouterElement -NetworkServiceProviderId 'nsp-uuid' -ProviderType VirtualRouter
        Creates a standard virtual router element.

    .EXAMPLE
        New-CSVirtualRouterElement -NetworkServiceProviderId 'nsp-uuid' -ProviderType VPCVirtualRouter
        Creates a VPC virtual router element.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][Alias('NspId')][string]$NetworkServiceProviderId,
        [ValidateSet('VirtualRouter','VPCVirtualRouter')][string]$ProviderType
    )
    process {
        $apiParams = @{ nspid = $NetworkServiceProviderId }
        if ($PSBoundParameters.ContainsKey('ProviderType')) { $apiParams['providertype'] = $ProviderType }
        Invoke-CSApiRequest -Command 'createVirtualRouterElement' -Parameters $apiParams
    }
}

function Remove-CSRouter {
    <#
    .SYNOPSIS
        Destroys a CloudStack router.

    .DESCRIPTION
        Wraps destroyRouter. Uses ShouldProcess, so -WhatIf previews and -Confirm
        prompts. Accepts a router object on the pipeline.

    .PARAMETER Id
        The router to destroy. Binds from a piped router's id.

    .EXAMPLE
        Remove-CSRouter -Id 'router-uuid' -WhatIf
        Previews destruction of the router.

    .EXAMPLE
        Get-CSRouter -Id 'router-uuid' | Remove-CSRouter -WhatIf
        Previews router destruction using pipeline input.
    #>

    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id)
    process {
        if ($PSCmdlet.ShouldProcess("router $Id", 'Destroy')) {
            Invoke-CSApiRequest -Command 'destroyRouter' -Parameters @{ id = $Id }
        }
    }
}

function Get-CSRouterHealthCheckResult {
    <#
    .SYNOPSIS
        Gets the most recent health check results for a router.

    .DESCRIPTION
        Wraps getRouterHealthCheckResults. By default it returns the previously
        recorded results; -PerformFreshChecks runs the checks on the router now before
        returning. Accepts a router object on the pipeline.

    .PARAMETER RouterId
        The router to query. Binds from a piped router's id.

    .PARAMETER PerformFreshChecks
        Run the health checks now instead of returning the last recorded results

    .EXAMPLE
        Get-CSRouterHealthCheckResult -RouterId 'router-uuid'
        Returns the previously recorded health check results.

    .EXAMPLE
        Get-CSRouterHealthCheckResult -RouterId 'router-uuid' -PerformFreshChecks
        Runs health checks now and returns their results.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][Alias('Id')][string]$RouterId, [switch]$PerformFreshChecks)
    process {
        $apiParams = @{ routerid = $RouterId }
        if ($PerformFreshChecks) { $apiParams['performfreshchecks'] = 'true' }
        Invoke-CSApiRequest -Command 'getRouterHealthCheckResults' -Parameters $apiParams
    }
}

function Get-CSRouter {
    <#
    .SYNOPSIS
        Lists domain routers with optional filters.

    .DESCRIPTION
        Wraps listRouters. Filter by owner, location (zone/pod/cluster/host),
        network, VPC, state, or version. -FetchHealthCheckResults includes each
        router's last health check. -Account requires -DomainId. Accepts a router id
        on the pipeline.

    .PARAMETER Account
        Filter by account name. Must be used with -DomainId.

    .PARAMETER ClusterId
        Filter by cluster ID

    .PARAMETER DomainId
        Filter by domain ID

    .PARAMETER FetchHealthCheckResults
        Include each router's last health check results

    .PARAMETER ForVpc
        Only list VPC routers

    .PARAMETER HealthChecksFailed
        Filter to routers whose health checks have failed

    .PARAMETER HostId
        Filter by the host the router runs on

    .PARAMETER Id
        Filter by router ID. Binds from a piped router's id.

    .PARAMETER IsRecursive
        With -DomainId, include routers in subdomains

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER ListAll
        List every router the caller is allowed to see

    .PARAMETER Name
        Filter by router name

    .PARAMETER NetworkId
        Filter by the network the router serves

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .PARAMETER PodId
        Filter by pod ID

    .PARAMETER ProjectId
        Filter by project ID

    .PARAMETER State
        Filter by state (for example Running, Stopped)

    .PARAMETER Version
        Filter by router template version

    .PARAMETER VpcId
        Filter by the VPC the router serves

    .PARAMETER ZoneId
        Filter by zone ID

    .EXAMPLE
        Get-CSRouter -ZoneId 'zone-uuid' -State Running -FetchHealthCheckResults
        Lists routers in a zone and includes their last health check results.

    .EXAMPLE
        Get-CSRouter -NetworkId 'network-uuid' -ForVpc
        Lists VPC routers for the specified network.
    #>

    [CmdletBinding()]
    param(
        [string]$Account,
        [string]$ClusterId,
        [string]$DomainId,
        [switch]$FetchHealthCheckResults,
        [switch]$ForVpc,
        [bool]$HealthChecksFailed,
        [string]$HostId,
        [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id,
        [switch]$IsRecursive,
        [string]$Keyword,
        [switch]$ListAll,
        [string]$Name,
        [string]$NetworkId,
        [int]$Page,
        [int]$PageSize,
        [string]$PodId,
        [string]$ProjectId,
        [string]$State,
        [string]$Version,
        [string]$VpcId,
        [string]$ZoneId
    )
    process {
        if ($PSBoundParameters.ContainsKey('Account') -and -not $PSBoundParameters.ContainsKey('DomainId')) {
            throw 'DomainId is required when Account is specified.'
        }
        $apiParams = @{}
        $parameterMap = @{
            Account='account'; ClusterId='clusterid'; DomainId='domainid'; HealthChecksFailed='healthchecksfailed';
            HostId='hostid'; Id='id'; Keyword='keyword'; Name='name'; NetworkId='networkid'; Page='page';
            PageSize='pagesize'; PodId='podid'; ProjectId='projectid'; State='state'; Version='version';
            VpcId='vpcid'; ZoneId='zoneid'
        }
        foreach ($parameter in $parameterMap.Keys) {
            if ($PSBoundParameters.ContainsKey($parameter)) {
                $value = Get-Variable -Name $parameter -ValueOnly
                if ($value -is [bool]) { $value = $value.ToString().ToLowerInvariant() }
                $apiParams[$parameterMap[$parameter]] = $value
            }
        }
        if ($FetchHealthCheckResults) { $apiParams['fetchhealthcheckresults'] = 'true' }
        if ($ForVpc) { $apiParams['forvpc'] = 'true' }
        if ($IsRecursive) { $apiParams['isrecursive'] = 'true' }
        if ($ListAll) { $apiParams['listall'] = 'true' }
        $response = Invoke-CSApiRequest -Command 'listRouters' -Parameters $apiParams
        if ($response.listroutersresponse.router) { return $response.listroutersresponse.router }
    }
}

function Get-CSVirtualRouterElement {
    <#
    .SYNOPSIS
        Lists virtual router provider elements.

    .DESCRIPTION
        Wraps listVirtualRouterElements. Filter by enabled state, network service
        provider, or element id. Accepts an element id on the pipeline.

    .PARAMETER Enabled
        Filter to enabled ($true) or disabled ($false) elements

    .PARAMETER Id
        Filter by element ID. Binds from a piped element's id.

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER NetworkServiceProviderId
        Filter by the network service provider the element belongs to

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSVirtualRouterElement -Enabled:$true
        Lists enabled virtual router elements.

    .EXAMPLE
        Get-CSVirtualRouterElement -NetworkServiceProviderId 'nsp-uuid'
        Lists virtual router elements associated with a network service provider.
    #>

    [CmdletBinding()]
    param([bool]$Enabled, [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [string]$Keyword, [string]$NetworkServiceProviderId, [int]$Page, [int]$PageSize)
    process {
        $apiParams = @{}
        $parameterMap = @{ Enabled='enabled'; Id='id'; Keyword='keyword'; NetworkServiceProviderId='nspid'; Page='page'; PageSize='pagesize' }
        foreach ($parameter in $parameterMap.Keys) {
            if ($PSBoundParameters.ContainsKey($parameter)) {
                $value = Get-Variable -Name $parameter -ValueOnly
                if ($value -is [bool]) { $value = $value.ToString().ToLowerInvariant() }
                $apiParams[$parameterMap[$parameter]] = $value
            }
        }
        $response = Invoke-CSApiRequest -Command 'listVirtualRouterElements' -Parameters $apiParams
        if ($response.listvirtualrouterelementsresponse.virtualrouter) { return $response.listvirtualrouterelementsresponse.virtualrouter }
    }
}

function Restart-CSRouter {
    <#
    .SYNOPSIS
        Reboots a CloudStack router.

    .DESCRIPTION
        Wraps rebootRouter. -Forced performs a hard stop-and-start. Accepts a router
        object on the pipeline.

    .PARAMETER Id
        The router to reboot. Binds from a piped router's id.

    .PARAMETER Forced
        Force-stop and start the router during the reboot

    .EXAMPLE
        Restart-CSRouter -Id 'router-uuid'
        Reboots the selected router.

    .EXAMPLE
        Restart-CSRouter -Id 'router-uuid' -Forced
        Force-stops and starts the router during the reboot.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [switch]$Forced)
    process {
        $apiParams = @{ id = $Id }
        if ($Forced) { $apiParams['forced'] = 'true' }
        Invoke-CSApiRequest -Command 'rebootRouter' -Parameters $apiParams
    }
}

function Start-CSRouter {
    <#
    .SYNOPSIS
        Starts a CloudStack router.

    .DESCRIPTION
        Wraps startRouter. Accepts a router object on the pipeline.

    .PARAMETER Id
        The router to start. Binds from a piped router's id.

    .EXAMPLE
        Start-CSRouter -Id 'router-uuid'
        Starts the selected router.

    .EXAMPLE
        Get-CSRouter -State Stopped | Start-CSRouter
        Starts each stopped router returned by the query.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id)
    process { Invoke-CSApiRequest -Command 'startRouter' -Parameters @{ id = $Id } }
}

function Stop-CSRouter {
    <#
    .SYNOPSIS
        Stops a CloudStack router.

    .DESCRIPTION
        Wraps stopRouter. -Forced performs a hard stop. Accepts a router object on the
        pipeline.

    .PARAMETER Id
        The router to stop. Binds from a piped router's id.

    .PARAMETER Forced
        Force-stop the router

    .EXAMPLE
        Stop-CSRouter -Id 'router-uuid'
        Stops the selected router.

    .EXAMPLE
        Stop-CSRouter -Id 'router-uuid' -Forced
        Force-stops the router when the caller knows the VM is already stopped.

    .EXAMPLE
        Get-CSRouter -Id 'router-uuid' | Stop-CSRouter
        Stops the router returned by the query.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)][string]$Id, [switch]$Forced)
    process {
        $apiParams = @{ id = $Id }
        if ($Forced) { $apiParams['forced'] = 'true' }
        Invoke-CSApiRequest -Command 'stopRouter' -Parameters $apiParams
    }
}