Public/New-VMetricDeployment.ps1

function New-VMetricDeployment {
    <#
    .SYNOPSIS
    Deploys a Bicep template.
 
    .DESCRIPTION
    New-VMetricDeployment runs a deployment template: every resource it declares is created when its name is
    absent and updated when present; resources it does not name are never touched. The engine checks every
    permission first and writes nothing when one is missing.
 
    The template is validated first, and an invalid one is refused with its diagnostics. With -WhatIf the
    engine's what-if shows what the deployment would create and change, property by property, and nothing is
    deployed; -Confirm shows the same and asks.
 
    It waits for the deployment to end, showing its progress operation by operation, and writes the
    deployment (VirtualMetric.Deployment); a failed or canceled one is also reported as an error. -AsJob runs
    it in a background job instead (Receive-Job gives the deployment), and -NoWait returns as soon as it has
    started.
 
    One deployment runs at a time in an organization: while another runs, the module waits up to 30 seconds
    before it gives up.
 
    .PARAMETER TemplateFile
    The Bicep file to deploy. Files can be piped from Get-ChildItem.
 
    .PARAMETER Template
    The Bicep text to deploy.
 
    .PARAMETER TemplateParameterObject
    The template's parameters, such as @{ deviceName = 'syslog-tcp'; port = 1514 }. Give a secure parameter's
    value as a SecureString; it is sent only in the request.
 
    .PARAMETER TemplateParameterFile
    A JSON parameters file: {"parameters": {"name": {"value": ...}}} or a plain object of values. Values in
    -TemplateParameterObject win over the file's.
 
    .PARAMETER Name
    The deployment's name (at most 128 characters). The server names it deploy-YYYYMMDD-HHMMSS otherwise.
 
    .PARAMETER Wait
    Wait for the deployment to end. This is the default; the switch lets a script say so.
 
    .PARAMETER NoWait
    Return as soon as the deployment has started (status running). Follow it with Get-VMetricDeployment -Id.
 
    .PARAMETER AsJob
    Run the deployment in a background thread job and return the job.
 
    .EXAMPLE
    New-VMetricDeployment -TemplateFile ./syslog.bicep -TemplateParameterObject @{ deviceName = 'syslog-tcp' }
 
    .EXAMPLE
    New-VMetricDeployment -TemplateFile ./syslog.bicep -WhatIf
 
    Shows what the deployment would change without deploying.
 
    .EXAMPLE
    $job = New-VMetricDeployment -TemplateFile ./fleet.bicep -Name fleet-rollout -AsJob
    $job | Receive-Job -Wait
 
    .EXAMPLE
    New-VMetricDeployment -TemplateFile ./director.bicep -TemplateParameterObject @{ adminPassword = (Read-Host -AsSecureString) }
 
    .OUTPUTS
    VirtualMetric.Deployment, or a job with -AsJob.
 
    .LINK
    Test-VMetricDeployment
 
    .LINK
    Get-VMetricDeployment
 
    .LINK
    Stop-VMetricDeployment
 
    .LINK
    Export-VMetricTemplate
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'File')]
    [OutputType('VirtualMetric.Deployment')]
    param(
        [Parameter(Mandatory, Position = 0, ParameterSetName = 'File', ValueFromPipelineByPropertyName)]
        [Alias('FullName')]
        [ValidateNotNullOrEmpty()]
        [string] $TemplateFile,

        [Parameter(Mandatory, ParameterSetName = 'Text')]
        [ValidateNotNullOrEmpty()]
        [string] $Template,

        [System.Collections.IDictionary] $TemplateParameterObject,

        [ValidateNotNullOrEmpty()]
        [string] $TemplateParameterFile,

        [ValidateLength(1, 128)]
        [string] $Name,

        [switch] $Wait,

        [switch] $NoWait,

        [switch] $AsJob
    )

    process {
        $deployment = $null
        try {
            if ($Wait -and $NoWait) {
                throw (New-VMetricException -Message '-Wait and -NoWait cannot be used together.' -Code 'InvalidArguments' -Category InvalidArgument)
            }
            if ($AsJob -and $NoWait) {
                throw (New-VMetricException -Message '-AsJob already returns at once; leave out -NoWait.' -Code 'InvalidArguments' -Category InvalidArgument)
            }
            $session = Get-VMetricSession
            $text = Get-VMetricTemplateText -Cmdlet $PSCmdlet -TemplateFile $TemplateFile -Template $Template
            $parameters = Get-VMetricTemplateParameter -Cmdlet $PSCmdlet -ParameterObject $TemplateParameterObject -ParameterFile $TemplateParameterFile
            $secrets = Get-VMetricSecretText -InputObject $parameters
            $null = Assert-VMetricTemplateValid -Cmdlet $PSCmdlet -Template $text -Parameters $parameters -Session $session -Secret $secrets

            $description = if ($TemplateFile) { "Deploy template '$(Split-Path -Path $TemplateFile -Leaf)'" } else { 'Deploy the template' }
            if ($Name) {
                $description += " as '$Name'"
            }
            $impact = Get-VMetricConfirmImpact -Cmdlet $PSCmdlet
            if (Test-VMetricPromptActive -Cmdlet $PSCmdlet -ConfirmImpact $impact) {
                $whatIf = Invoke-VMetricRequest -Method POST -Path '/deployments/what-if' -Session $session `
                    -Body ([ordered]@{ template = $text; parameters = $parameters })
                $refused = Write-VMetricPreviewDiagnostic -Cmdlet $PSCmdlet -Preview $whatIf -Secret $secrets -TargetObject $description
                $lines = Format-VMetricWhatIfText -Result $whatIf -Secret $secrets
                $description = "${description}:" + [Environment]::NewLine + (($lines | ForEach-Object { " $_" }) -join [Environment]::NewLine)
                if ($refused -and -not (Test-VMetricWhatIf -Cmdlet $PSCmdlet)) {
                    return
                }
            }
            if (-not (Test-VMetricShouldProcess -Cmdlet $PSCmdlet -Description $description -Warning "$description$([Environment]::NewLine)Continue?" -Caption 'Deploy')) {
                return
            }

            if ($AsJob) {
                Start-VMetricDeploymentJob -Session $session -Name $Name -Template $text -Parameters $parameters
                return
            }
            $raw = Invoke-VMetricDeploymentRun -Session $session -Name $Name -Template $text -Parameters $parameters -NoWait:$NoWait
            $deployment = ConvertTo-VMetricDeploymentObject -InputObject $raw
        }
        catch {
            if (Test-VMetricFlowControl -ErrorRecord $_) {
                throw
            }
            $record = Hide-VMetricSecretInError -ErrorRecord $_ -Secret (Get-VMetricSecretText -InputObject $TemplateParameterObject)
            Write-VMetricCmdletError -Cmdlet $PSCmdlet -ErrorRecord $record
            return
        }
        Hide-VMetricSecretInObject -InputObject $deployment -Secret $secrets
        $deployment
        Write-VMetricDeploymentOutcome -Cmdlet $PSCmdlet -Deployment $deployment -Secret $secrets
    }
}