From a594ed3fc48c7672676ffd955ab0f8ad50448bd6 Mon Sep 17 00:00:00 2001 From: Guy Pritchard Date: Wed, 29 Mar 2023 22:20:09 +0100 Subject: [PATCH] Adding functionality to modify values before they're set based on simple powershell expressions... --- .../alz-bicep-config/v0.14.1-pre.config.json | 17 ++- .../Edit-ALZConfigurationFilesInPlace.ps1 | 16 +- ...dit-ALZConfigurationFilesInPlace.Tests.ps1 | 143 +++++++++++++++++- 3 files changed, 168 insertions(+), 8 deletions(-) diff --git a/src/ALZ/Assets/alz-bicep-config/v0.14.1-pre.config.json b/src/ALZ/Assets/alz-bicep-config/v0.14.1-pre.config.json index 9e28b513..e30460a4 100644 --- a/src/ALZ/Assets/alz-bicep-config/v0.14.1-pre.config.json +++ b/src/ALZ/Assets/alz-bicep-config/v0.14.1-pre.config.json @@ -183,10 +183,6 @@ "Name": "parAutomationAccountLocation.value", "Destination": "Parameters" }, - { - "Name": "parLogAnalyticsWorkspaceLocation.value", - "Destination": "Parameters" - }, { "Name": "parPolicyAssignmentParameters.value.ascExportResourceGroupLocation.value", "Destination": "Parameters" @@ -320,6 +316,18 @@ ], "Value": "" }, + "LogAnalyticsWorkspaceLocation": { + "Type": "Computed", + "Value": "{%Location%}", + "Process": "($args[0] -eq \"eastus\") ? \"eastus2\" : ($args[0] -eq \"eastus2\") ? \"eastus\" : $args[0]", + "Targets": [ + { + "Name": "parLogAnalyticsWorkspaceLocation.value", + "Destination": "Parameters" + } + ] + }, + "LogAnalyticsResourceId": { "Type": "Computed", "Value": "/subscriptions/{%ManagementSubscriptionId%}/resourcegroups/alz-logging/providers/microsoft.operationalinsights/workspaces/alz-log-analytics", @@ -332,6 +340,7 @@ }, "AllSubscriptionIds": { "Type": "Computed", + "Process": "@($args | Select-Object -Unique)", "Value": [ "{%ManagementSubscriptionId%}", "{%ConnectivitySubscriptionId%}", diff --git a/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 b/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 index 5f64ca6e..1c371165 100644 --- a/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 +++ b/src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1 @@ -67,9 +67,23 @@ function Edit-ALZConfigurationFilesInPlace { foreach($formatString in $configKey.Value.Value) { $formattedValues += Format-TokenizedConfigurationString -tokenizedString $formatString -configuration $configuration } + + if ($null -ne $configKey.Value.Process) { + $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) + $formattedValues = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValues + } + $bicepConfigNode[$leafPropertyName] = $formattedValues } else { - $bicepConfigNode[$leafPropertyName] = Format-TokenizedConfigurationString -tokenizedString $configKey.Value.Value -configuration $configuration + + $formattedValue = Format-TokenizedConfigurationString -tokenizedString $configKey.Value.Value -configuration $configuration + + if ($null -ne $configKey.Value.Process) { + $scriptBlock = [ScriptBlock]::Create($configKey.Value.Process) + $formattedValue = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $formattedValue + } + + $bicepConfigNode[$leafPropertyName] = $formattedValue } } else { $bicepConfigNode[$leafPropertyName] = $configKey.Value.Value diff --git a/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 b/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 index f1234264..7bab2ac8 100644 --- a/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 +++ b/src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1 @@ -34,9 +34,8 @@ InModuleScope 'ALZ' { [Parameter(Mandatory = $true)] [string]$withValue - ) - - return [pscustomobject]@{ + ) + $config = [pscustomobject]@{ Nested = [pscustomobject]@{ Type = "Computed" Description = "A Test Value" @@ -48,6 +47,8 @@ InModuleScope 'ALZ' { }) } } + + return $config } function Format-ExpectedResult { @@ -481,6 +482,142 @@ InModuleScope 'ALZ' { Write-InformationColored $contentStringAfterParsing -ForegroundColor Yellow -InformationAction Continue Should -Invoke -CommandName Out-File -ParameterFilter { $FilePath -eq "test2.parameters.json" -and $InputObject -eq $contentStringAfterParsing } -Scope It } + + It 'Computed, Processed array values replace values correctly' { + $config = [pscustomobject]@{ + Nested = [pscustomobject]@{ + Type = "Computed" + Description = "A Test Value" + Process = '@($args | Select-Object -Unique)' + Value = @( + "1", + "1", + "3" + ) + Targets = @( + [pscustomobject]@{ + Name = "parValue.value" + Destination = "Parameters" + }) + } + } + + $fileContent = '{ + "parameters": { + "parValue": { + "value": [] + } + } + }' + + $expectedContent = '{ + "parameters": { + "parValue": { + "value": [ "1", "3" ] + } + } + }' + + Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { + $fileContent + } + + $expectedContent = Format-ExpectedResult -expectedJson $expectedContent + + Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config + + Should -Invoke -CommandName Out-File ` + -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` + -Scope It + } + + It 'Computed, Processed values replace values correctly' { + $config = [pscustomobject]@{ + Nested = [pscustomobject]@{ + Type = "Computed" + Description = "A Test Value" + Process = '($args[0] -eq "eastus") ? "eastus2" : ($args[0] -eq "eastus2") ? "eastus" : $args[0]' + Value = "eastus" + Targets = @( + [pscustomobject]@{ + Name = "parValue.value" + Destination = "Parameters" + }) + } + } + + $fileContent = '{ + "parameters": { + "parValue": { + "value": "replace_me" + } + } + }' + + $expectedContent = '{ + "parameters": { + "parValue": { + "value": "eastus2" + } + } + }' + + Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { + $fileContent + } + + $expectedContent = Format-ExpectedResult -expectedJson $expectedContent + + Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config + + Should -Invoke -CommandName Out-File ` + -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` + -Scope It + } + + It 'Computed, Processed values replace values correctly' { + $config = [pscustomobject]@{ + Nested = [pscustomobject]@{ + Type = "Computed" + Description = "A Test Value" + Process = '($args[0] -eq "goodbye") ? "Hello" : "Goodbye"' + Value = "goodbye" + Targets = @( + [pscustomobject]@{ + Name = "parValue.value" + Destination = "Parameters" + }) + } + } + + $fileContent = '{ + "parameters": { + "parValue": { + "value": "replace_me" + } + } + }' + + $expectedContent = '{ + "parameters": { + "parValue": { + "value": "Hello" + } + } + }' + + Mock -CommandName Get-Content -ParameterFilter { $Path -eq $testFile1Name } -MockWith { + $fileContent + } + + $expectedContent = Format-ExpectedResult -expectedJson $expectedContent + + Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $config + + Should -Invoke -CommandName Out-File ` + -ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } ` + -Scope It + } } } }