Public/Deploy/Core/extension/New-CmAzCustomExtension.ps1
function New-CmAzCustomExtension { <# .Synopsis Enables generic deployment of an ARM template as a framework extension. .Description Has following features: * Self-loading deployments using the component: "extension" header value. * A library of reusable templates automatically resolved in a [REPO]/extensions directory. * The ability to plug into useful functionality like the name generator and service locator. * Ability to use keyvault reference for secure strings. .Parameter SettingsFile File path for the settings file to be converted into a settings object. .Parameter SettingsObject Object containing the configuration values required to run this cmdlet. .Parameter TagSettingsFile File path for the tag settings file to be converted into a tag settings object. .Parameter OmitTags Parameter to specify if the cmdlet should handle its own tagging. .Component IaaS .Example New-CmAzCustomExtension -settingsFile "extensions.yml" .Example New-CmAzCustomExtension -settingsObject $extensions #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Medium")] param( [parameter(Mandatory = $true, ParameterSetName = "Settings Yml File")] [String]$SettingsFile, [parameter(Mandatory = $true, ParameterSetName = "Settings Object")] [Object]$SettingsObject ) $ErrorActionPreference = "Stop" try { Write-CommandStatus -CommandName $MyInvocation.MyCommand.Name $SettingsObject = Get-Settings -SettingsFile $SettingsFile -SettingsObject $SettingsObject -CmdletName (Get-CurrentCmdletName -ScriptRoot $PSCommandPath) if ($PSCmdlet.ShouldProcess((Get-CmAzSubscriptionName), "Deploy Custom Extension")) { foreach ($name in $SettingsObject.names.keys) { $SettingsObject.names.$name.generatedName = Get-CmAzResourceName ` -Resource $SettingsObject.names.$name.resource ` -Architecture $SettingsObject.names.$name.architecture ` -Location $SettingsObject.names.$name.location ` -IncludeBuild $SettingsObject.names.$name.includeBuild ` -Name $SettingsObject.names.$name.name } function Resolve-Dependency { param ( [AllowEmptyString()] [String]$Location, [Boolean]$ThrowIfUnavailable, [Boolean]$ThrowIfMultiple, [string]$Service ) if ($Location) { return Get-CmAzService ` -Service $Service ` -ThrowIfUnavailable:$ThrowIfUnavailable ` -ThrowIfMultiple:$ThrowIfMultiple ` -Location $Location } else { return Get-CmAzService ` -Service $Service ` -ThrowIfUnavailable:$ThrowIfUnavailable ` -ThrowIfMultiple:$ThrowIfMultiple } } foreach ($template in $SettingsObject.templates) { $templateParameter = @{} foreach ($parameter in $template.parameters.keys) { $value = $template.parameters.$parameter.value $type = $template.parameters.$parameter.type switch ($type) { "static" { Write-Verbose "Static value: $value..." $templateParameter += @{ $parameter = $value } } "dependency" { Write-Verbose "Dependency value: $value..." $property = $template.parameters.$parameter.property $template.parameters.$parameter.throwIfUnavailable ??= $true $template.parameters.$parameter.throwIfMultiple ??= $true $resolvedDependency = Resolve-Dependency ` -Service $value ` -Location $template.parameters.$parameter.location ` -ThrowIfMultiple $template.parameters.$parameter.throwIfMultiple ` -ThrowIfUnavailable $template.parameters.$parameter.throwIfUnavailable if ($property) { $templateParameter += @{ $parameter = $resolvedDependency.$property } } else { $templateParameter += @{ $parameter = $resolvedDependency } } } "secureDependency" { $secretName = $template.parameters.$parameter.secretName if (!$secretName) { Write-Error "Please provide secret for parameter: $parameter" -Category InvalidArgument -TargetObject $parameter } Write-Verbose "SecureDependency value: $value..." $template.parameters.$parameter.throwIfUnavailable ??= $true $template.parameters.$parameter.throwIfMultiple ??= $true $resolvedDependency = Resolve-Dependency ` -Service $value ` -Location $template.parameters.$parameter.location ` -ThrowIfMultiple $template.parameters.$parameter.throwIfMultiple ` -ThrowIfUnavailable $template.parameters.$parameter.throwIfUnavailable $templateParameter += @{ $parameter = @{ reference = @{ keyVault = @{ id = $resolvedDependency.id }; secretName = $secretName } } } } "name" { Write-Verbose "Name value: $value..." if ($SettingsObject.names.$value.generatedName) { Write-Verbose "Found name: $value..." $templateParameter += @{ $parameter = $SettingsObject.names.$value.generatedName } } else { Write-Error "Invalid name: $value for $parameter..." -Category InvalidArgument -TargetObject $value } } } } if ([System.IO.Path]::IsPathRooted($templatePath)) { $templatePath = $template.name } else { $defaultPath = "$((Get-CmAzContext).projectRoot)/extensions/$($template.name)" if (Test-Path -Path $defaultPath) { Write-Verbose "Template Found in extensions..." $templatePath = $defaultPath } else { $templatePath = Resolve-FilePath -NestedFile $template.name } } if ($template.service.dependencies.resourceGroup) { $resourceGroup = Get-CmAzService -Service $template.service.dependencies.resourceGroup -ThrowIfUnavailable -ThrowIfMultiple -IsResourceGroup $deploymentName = Get-CmAzResourceName -Resource "Deployment" -Architecture "Core" -Location $resourceGroup.location -Name $MyInvocation.MyCommand.Name New-AzResourceGroupDeployment ` -Name $deploymentName ` -ResourceGroupName $resourceGroup.ResourceGroupName ` -TemplateFile $templatePath ` -TemplateParameterObject $templateParameter ` -Force } else { if (!$template.location) { Write-Error "Location is mandatory for subscription scoped deployment..." -Category InvalidType -TargetObject $template.location } $deploymentName = Get-CmAzResourceName -Resource "Deployment" -Architecture "Core" -Location $template.location -Name $MyInvocation.MyCommand.Name New-AzDeployment ` -Name $deploymentName ` -TemplateFile $templatePath ` -TemplateParameterObject $templateParameter ` -Location $template.location ` -Force } } Write-CommandStatus -CommandName $MyInvocation.MyCommand.Name -Start $false } } catch { $PSCmdlet.ThrowTerminatingError($PSItem) } } |