From a784c2ffc586b8a9bcdd6b380641780d7ac4651c Mon Sep 17 00:00:00 2001 From: Jesper Fajers Date: Sat, 26 Nov 2022 00:19:19 +0000 Subject: [PATCH 1/7] Update Class Logic --- src/internal/classes/AzOpsScope.ps1 | 16 ++++--- .../functions/New-AzOpsDeployment.ps1 | 45 ++++++++++++++++++- src/localized/en-us/Strings.psd1 | 8 +++- 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/internal/classes/AzOpsScope.ps1 b/src/internal/classes/AzOpsScope.ps1 index 1193887e..d71492a0 100644 --- a/src/internal/classes/AzOpsScope.ps1 +++ b/src/internal/classes/AzOpsScope.ps1 @@ -390,7 +390,6 @@ return $null } [string] IsResource() { - if ($this.Scope -match $this.regex_managementgroupResource) { return ($this.regex_managementgroupResource.Split($this.Scope) | Select-Object -last 1) } @@ -409,13 +408,18 @@ Should Return Management Group Name #> [string] GetManagementGroup() { - if ($this.GetManagementGroupName()) { foreach ($mgmt in $script:AzOpsAzManagementGroup) { if ($mgmt.Name -eq $this.GetManagementGroupName()) { + $private:mgmtHit = $true return $mgmt.Name } } + if (-not $private:mgmtHit) { + $mgId = $this.Scope -split $this.regex_managementgroupExtract -split '/' | Where-Object { $_ } | Select-Object -First 1 + Write-PSFMessage -Level Debug -String 'AzOpsScope.GetManagementGroup.NotFound' -StringValues $mgId -FunctionName AzOpsScope -ModuleName AzOps + return $mgId + } } if ($this.Subscription) { foreach ($mgmt in $script:AzOpsAzManagementGroup) { @@ -445,7 +449,8 @@ } else { Write-PSFMessage -Level Warning -Tag error -String 'AzOpsScope.GetAzOpsManagementGroupPath.NotFound' -StringValues $managementgroupName -FunctionName AzOpsScope -ModuleName AzOps - throw "Management Group not found: $managementgroupName" + $assumenewresource = "azopsscope-assume-new-resource_$managementgroupName" + return $assumenewresource.ToLower() } } @@ -455,11 +460,10 @@ [string] GetManagementGroupName() { if ($this.Scope -match $this.regex_managementgroupExtract) { $mgId = $this.Scope -split $this.regex_managementgroupExtract -split '/' | Where-Object { $_ } | Select-Object -First 1 - if ($mgId) { $mgDisplayName = ($script:AzOpsAzManagementGroup | Where-Object Name -eq $mgId).Name if ($mgDisplayName) { - #Write-PSFMessage -Level Debug -String 'AzOpsScope.GetManagementGroupName.Found.Azure' -StringValues $mgDisplayName -FunctionName AzOpsScope -ModuleName AzOps + Write-PSFMessage -Level Debug -String 'AzOpsScope.GetManagementGroupName.Found.Azure' -StringValues $mgDisplayName -FunctionName AzOpsScope -ModuleName AzOps return $mgDisplayName } else { @@ -560,4 +564,4 @@ throw "Unable to determine Resource Scope for: $($this.Scope)" } #endregion Data Accessors -} +} \ No newline at end of file diff --git a/src/internal/functions/New-AzOpsDeployment.ps1 b/src/internal/functions/New-AzOpsDeployment.ps1 index 0f6c759b..2d41ef5f 100644 --- a/src/internal/functions/New-AzOpsDeployment.ps1 +++ b/src/internal/functions/New-AzOpsDeployment.ps1 @@ -109,7 +109,7 @@ $deploymentCommand = 'New-AzSubscriptionDeployment' } # Management Groups - elseif ($scopeObject.managementGroup) { + elseif ($scopeObject.managementGroup -and (-not ($scopeObject.StatePath).StartsWith('azopsscope-assume-new-resource_'))) { Write-PSFMessage -Level Verbose -String 'New-AzOpsDeployment.ManagementGroup.Processing' -StringValues $defaultDeploymentRegion, $scopeObject -Target $scopeObject $parameters.ManagementGroupId = $scopeObject.managementgroup $whatIfCommand = 'Get-AzManagementGroupDeploymentWhatIfResult' @@ -121,6 +121,49 @@ $whatIfCommand = 'Get-AzTenantDeploymentWhatIfResult' $deploymentCommand = 'New-AzTenantDeployment' } + # If Management Group resource was not found, validate and prepare for first time deployment of resource + elseif (($scopeObject.StatePath).StartsWith('azopsscope-assume-new-resource_')) { + $resourceScopeFileContent = Get-Content -Path $addition | ConvertFrom-Json -Depth 100 + $resource = ($resourceScopeFileContent.resources | Where-Object {$_.type -eq 'Microsoft.Management/managementGroups'} | Select-Object -First 1) + $filename = (Get-Item -Path $addition).Name + $pathDir = (Get-Item -Path $addition).Directory | Resolve-Path -Relative + if ((Get-PSFConfigValue -FullName 'AzOps.Core.AutoGeneratedTemplateFolderPath') -ne '.') { + $pathDir = Split-Path -Path $pathDir -Parent + } + $pathDirName = (Get-Item -Path $pathDir).Name + $parentDir = Split-Path -Path $pathDir -Parent + $parentDirScopeObject = New-AzOpsScope -Path $parentDir | Where-Object {(-not ($_.StatePath).StartsWith('azopsscope-assume-new-resource_'))} + $parentId = ($resource).properties.details.parent.id + $parentId = New-AzOpsScope -Scope $parentId | Where-Object {(-not ($_.StatePath).StartsWith('azopsscope-assume-new-resource_'))} + $expectedDirName = "$($resource.properties.displayName) ($($resource.name))" + $expectedFileName = ("$($scopeObject.ResourceProvider)_$($scopeObject.Resource)-$($resource.name)" + $(Get-PSFConfigValue -FullName 'AzOps.Core.TemplateParameterFileSuffix')).ToLower() + # Validate parent existence with content parent scope, statepath and name match, determines file location match deployment scope + if ($parentDirScopeObject -and $parentId -and $parentDirScopeObject.Scope -eq $parentId.Scope -and $parentDirScopeObject.StatePath -eq $parentId.StatePath -and $parentDirScopeObject.Name -eq $parentId.Name) { + # Validate directory and file name matches resource information + if ($pathDirName -eq $expectedDirName -and $filename -eq $expectedFileName) { + # Validate file content metadata matches AzOps + if ($resourceScopeFileContent.metadata._generator.name -eq 'AzOps') { + Write-PSFMessage -Level Verbose -String 'New-AzOpsDeployment.Root.Processing' -StringValues $defaultDeploymentRegion, $scopeObject -Target $scopeObject + $whatIfCommand = 'Get-AzTenantDeploymentWhatIfResult' + $deploymentCommand = 'New-AzTenantDeployment' + } + else { + Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Metadata.Failed' -Target $scopeObject -Tag Error -StringValues $scopeObject + throw + } + } + # Invalid directory or file name + else { + Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Directory.NotFound' -Target $scopeObject -Tag Error -StringValues $pathDirName, $expectedDirName, $filename, $expectedFileName + throw + } + } + # Parent missing + else { + Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Parent.NotFound' -Target $scopeObject -Tag Error -StringValues $parentDir, $addition + throw + } + } else { Write-PSFMessage -Level Warning -String 'New-AzOpsDeployment.Scope.Unidentified' -Target $scopeObject -StringValues $scopeObject $scopeFound = $false diff --git a/src/localized/en-us/Strings.psd1 b/src/localized/en-us/Strings.psd1 index 3d63d2df..93a6cb44 100644 --- a/src/localized/en-us/Strings.psd1 +++ b/src/localized/en-us/Strings.psd1 @@ -17,11 +17,12 @@ 'Assert-AzOpsBicepDependency.Success' = 'Bicep found in current path' # 'Assert-AzOpsBicepDependency.NotFound' = 'Unable to locate bicep binary. Will not be able to deploy bicep templates.' # - 'AzOpsScope.GetAzOpsManagementGroupPath.NotFound' = 'Management Group not found: {0}' # $managementgroupName + 'AzOpsScope.GetAzOpsManagementGroupPath.NotFound' = 'Management Group path not found: {0}' # $managementgroupName 'AzOpsScope.GetAzOpsResourcePath.NotFound' = 'Unable to determine Resource Scope for: {0}' # $this.Scope 'AzOpsScope.GetAzOpsResourcePath.Retrieving' = 'Getting Resource path for: {0}' # $this.Scope 'AzOpsScope.GetManagementGroupName.Found.Azure' = 'Management Group found in Azure: {0}' # $mgDisplayName - 'AzOpsScope.GetManagementGroupName.NotFound' = 'Management Group not found in Azure. Using directory name instead: {0}' # $mgId + 'AzOpsScope.GetManagementGroup.NotFound' = 'Management Group does not match any existing in Azure. Assume new resource, using directory name: {0}' # $mgId + 'AzOpsScope.GetManagementGroupName.NotFound' = 'Management Group not found in Azure. Trying with directory name instead: {0}' # $mgId 'AzOpsScope.GetSubscription.Found' = 'SubscriptionId found in Azure: {0}' # $sub.Id 'AzOpsScope.GetSubscription.NotFound' = 'SubscriptionId not found in Azure. Using directory name instead: {0}' # $subId 'AzOpsScope.GetSubscriptionDisplayName.Found' = 'Subscription DisplayName found in Azure: {0}' # $sub.displayName @@ -223,6 +224,9 @@ 'New-AzOpsDeployment.WhatIfResults' = 'WhatIf Results: {0}' # $TemplateFilePath 'New-AzOpsDeployment.WhatIfFile' = 'Creating WhatIf Results file' 'New-AzOpsDeployment.SkipDueToWhatIf' = 'Skipping deployment due to WhatIf' # + 'New-AzOpsDeployment.Parent.NotFound' = 'Failed to find parent {0} for template {1}' # $parentDir, $addition + 'New-AzOpsDeployment.Directory.NotFound' = 'Directory name {0} does not match expected {1} or file name {2} does not match expected {3}' # $pathDirName, $expectedDirName, $filename, $expectedFileName + 'New-AzOpsDeployment.Metadata.Failed' = 'Detected custom template: {0}. Please align formatting based on AzOps generated templates.' #$scopeObject 'New-AzOpsStateDeployment.EnrollmentAccount.First' = 'No enrollment account defined, using the first account found: {0}' # @($enrollmentAccounts)[0].PrincipalName 'New-AzOpsStateDeployment.EnrollmentAccount.Selected' = 'Using the defined enrollment account {0}' # $cfgEnrollmentAccount From 2786171ddc6ea434769b0cedb57416977d117c0b Mon Sep 17 00:00:00 2001 From: Jesper Fajers Date: Mon, 28 Nov 2022 15:42:56 +0000 Subject: [PATCH 2/7] Update --- .../functions/New-AzOpsDeployment.ps1 | 23 +++------- src/localized/en-us/Strings.psd1 | 3 +- src/tests/integration/Repository.Tests.ps1 | 26 ++++++++++- ...ment_managementgroups-pushmgmttest1id.json | 46 +++++++++++++++++++ 4 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 src/tests/templates/pushmgmttest1displayname (pushmgmttest1id)/microsoft.management_managementgroups-pushmgmttest1id.json diff --git a/src/internal/functions/New-AzOpsDeployment.ps1 b/src/internal/functions/New-AzOpsDeployment.ps1 index 2d41ef5f..478d4735 100644 --- a/src/internal/functions/New-AzOpsDeployment.ps1 +++ b/src/internal/functions/New-AzOpsDeployment.ps1 @@ -125,7 +125,6 @@ elseif (($scopeObject.StatePath).StartsWith('azopsscope-assume-new-resource_')) { $resourceScopeFileContent = Get-Content -Path $addition | ConvertFrom-Json -Depth 100 $resource = ($resourceScopeFileContent.resources | Where-Object {$_.type -eq 'Microsoft.Management/managementGroups'} | Select-Object -First 1) - $filename = (Get-Item -Path $addition).Name $pathDir = (Get-Item -Path $addition).Directory | Resolve-Path -Relative if ((Get-PSFConfigValue -FullName 'AzOps.Core.AutoGeneratedTemplateFolderPath') -ne '.') { $pathDir = Split-Path -Path $pathDir -Parent @@ -136,25 +135,15 @@ $parentId = ($resource).properties.details.parent.id $parentId = New-AzOpsScope -Scope $parentId | Where-Object {(-not ($_.StatePath).StartsWith('azopsscope-assume-new-resource_'))} $expectedDirName = "$($resource.properties.displayName) ($($resource.name))" - $expectedFileName = ("$($scopeObject.ResourceProvider)_$($scopeObject.Resource)-$($resource.name)" + $(Get-PSFConfigValue -FullName 'AzOps.Core.TemplateParameterFileSuffix')).ToLower() # Validate parent existence with content parent scope, statepath and name match, determines file location match deployment scope if ($parentDirScopeObject -and $parentId -and $parentDirScopeObject.Scope -eq $parentId.Scope -and $parentDirScopeObject.StatePath -eq $parentId.StatePath -and $parentDirScopeObject.Name -eq $parentId.Name) { - # Validate directory and file name matches resource information - if ($pathDirName -eq $expectedDirName -and $filename -eq $expectedFileName) { - # Validate file content metadata matches AzOps - if ($resourceScopeFileContent.metadata._generator.name -eq 'AzOps') { - Write-PSFMessage -Level Verbose -String 'New-AzOpsDeployment.Root.Processing' -StringValues $defaultDeploymentRegion, $scopeObject -Target $scopeObject - $whatIfCommand = 'Get-AzTenantDeploymentWhatIfResult' - $deploymentCommand = 'New-AzTenantDeployment' - } - else { - Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Metadata.Failed' -Target $scopeObject -Tag Error -StringValues $scopeObject - throw - } + # Validate directory name match resource information + if ($pathDirName -eq $expectedDirName) { + Write-PSFMessage -Level Verbose -String 'New-AzOpsDeployment.Root.Processing' -StringValues $defaultDeploymentRegion, $scopeObject -Target $scopeObject } - # Invalid directory or file name + # Invalid directory name else { - Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Directory.NotFound' -Target $scopeObject -Tag Error -StringValues $pathDirName, $expectedDirName, $filename, $expectedFileName + Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Directory.NotFound' -Target $scopeObject -Tag Error -StringValues $pathDirName, $expectedDirName throw } } @@ -163,7 +152,7 @@ Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Parent.NotFound' -Target $scopeObject -Tag Error -StringValues $parentDir, $addition throw } - } + } else { Write-PSFMessage -Level Warning -String 'New-AzOpsDeployment.Scope.Unidentified' -Target $scopeObject -StringValues $scopeObject $scopeFound = $false diff --git a/src/localized/en-us/Strings.psd1 b/src/localized/en-us/Strings.psd1 index 93a6cb44..6903409c 100644 --- a/src/localized/en-us/Strings.psd1 +++ b/src/localized/en-us/Strings.psd1 @@ -225,8 +225,7 @@ 'New-AzOpsDeployment.WhatIfFile' = 'Creating WhatIf Results file' 'New-AzOpsDeployment.SkipDueToWhatIf' = 'Skipping deployment due to WhatIf' # 'New-AzOpsDeployment.Parent.NotFound' = 'Failed to find parent {0} for template {1}' # $parentDir, $addition - 'New-AzOpsDeployment.Directory.NotFound' = 'Directory name {0} does not match expected {1} or file name {2} does not match expected {3}' # $pathDirName, $expectedDirName, $filename, $expectedFileName - 'New-AzOpsDeployment.Metadata.Failed' = 'Detected custom template: {0}. Please align formatting based on AzOps generated templates.' #$scopeObject + 'New-AzOpsDeployment.Directory.NotFound' = 'Directory name {0} does not match expected {1} does not match expected {1}' # $pathDirName, $expectedDirName 'New-AzOpsStateDeployment.EnrollmentAccount.First' = 'No enrollment account defined, using the first account found: {0}' # @($enrollmentAccounts)[0].PrincipalName 'New-AzOpsStateDeployment.EnrollmentAccount.Selected' = 'Using the defined enrollment account {0}' # $cfgEnrollmentAccount diff --git a/src/tests/integration/Repository.Tests.ps1 b/src/tests/integration/Repository.Tests.ps1 index 8a1382ff..9290953b 100644 --- a/src/tests/integration/Repository.Tests.ps1 +++ b/src/tests/integration/Repository.Tests.ps1 @@ -305,6 +305,11 @@ Describe "Repository" { $script:bicepDeploymentName = "AzOps-{0}-{1}" -f $($script:bicepTemplatePath[0].Name.Replace(".bicep", '')), $deploymentLocationId $script:bicepResourceGroupName = ((Get-Content -Path ($Script:bicepTemplatePath.FullName[1])) | ConvertFrom-Json).parameters.resourceGroupName.value + $script:pushmgmttest1idManagementGroupTemplatePath = Get-Item "$($global:testroot)/templates/pushmgmttest1displayname (pushmgmttest1id)" | Copy-Item -Destination $script:testManagementGroupDirectory -Recurse -PassThru -Force + $script:pushmgmttest1idManagementGroupDeploymentName = "AzOps-{0}-{1}" -f 'pushmgmttest1id', $deploymentLocationId + $script:pushmgmttest1idName = ((Get-Content -Path ($script:pushmgmttest1idManagementGroupTemplatePath.FullName[1])) | ConvertFrom-Json).resources.name[0] + + $script:pushmgmttest2idManagementGroupTemplatePath = Get-Item "$($global:testroot)/templates/pushmgmttest1displayname (pushmgmttest1id)" | Copy-Item -Destination $script:platformManagementGroupDirectory -Recurse -PassThru -Force #endregion Paths #Test push based on pulled resources @@ -319,7 +324,8 @@ Describe "Repository" { "A`t$script:routeTableFile", "A`t$script:ruleCollectionGroupsFile", "A`t$script:locksFile", - "A`t$($script:bicepTemplatePath.FullName[0])" + "A`t$($script:bicepTemplatePath.FullName[0])", + "A`t$($script:pushmgmttest1idManagementGroupTemplatePath.FullName[0])" ) Invoke-AzOpsPush -ChangeSet $changeSet @@ -930,6 +936,24 @@ Describe "Repository" { } #endregion + #region Deploy Management Group using folder structure and file + It "ManagementGroup deployment using folder structure and file should be successful" { + $script:pushmgmttest1Deployment = Get-AzManagementGroupDeployment -ManagementGroupId $script:pushmgmttest1idName -Name $script:pushmgmttest1idManagementGroupDeploymentName + $pushmgmttest1Deployment.ProvisioningState | Should -Be "Succeeded" + } + + It "ManagementGroup deployed using folder structure and file should exist" { + $script:pushmgmttest1Mg = Get-AzManagementGroup -GroupName $script:pushmgmttest1idName + $pushmgmttest1Mg.Name | Should -Be $script:pushmgmttest1idName + } + It "ManagementGroup deployment using folder structure and file at folder scope not matching content parent should fail" { + $changeSet = @( + "A`t$($script:pushmgmttest12dManagementGroupTemplatePath.FullName[0])" + ) + {Invoke-AzOpsPush -ChangeSet $changeSet -WhatIf:$true} | Should -Throw + } + #endregion + #region Scope - Policy DeletionDependency It "Deletion of policyDefinitionsFile with assignment dependency should fail" { $changeSet = @( diff --git a/src/tests/templates/pushmgmttest1displayname (pushmgmttest1id)/microsoft.management_managementgroups-pushmgmttest1id.json b/src/tests/templates/pushmgmttest1displayname (pushmgmttest1id)/microsoft.management_managementgroups-pushmgmttest1id.json new file mode 100644 index 00000000..0830e76a --- /dev/null +++ b/src/tests/templates/pushmgmttest1displayname (pushmgmttest1id)/microsoft.management_managementgroups-pushmgmttest1id.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "AzOps" + } + }, + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Management/managementGroups", + "name": "pushmgmttest1id", + "apiVersion": "2021-04-01", + "scope": "/", + "properties": { + "displayName": "pushmgmttest1displayname", + "details": { + "parent": { + "id": "/providers/Microsoft.Management/managementGroups/52fd72ab-b56e-5a52-83a1-1f87365f7998" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2020-10-01", + "name": "AzOps-microsoft.management_managementgroups-nested", + "location": "[deployment().location]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": {} + } + }, + "dependsOn": [ + "Microsoft.Management/managementGroups/pushmgmttest1id" + ] + } + ], + "outputs": {} +} From a44f507284d5c42ecae972022dd409747cc51c7f Mon Sep 17 00:00:00 2001 From: Jesper Fajers Date: Mon, 28 Nov 2022 19:08:34 +0000 Subject: [PATCH 3/7] Update --- src/internal/functions/New-AzOpsDeployment.ps1 | 2 ++ src/tests/integration/Repository.Tests.ps1 | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/internal/functions/New-AzOpsDeployment.ps1 b/src/internal/functions/New-AzOpsDeployment.ps1 index 478d4735..076b82c2 100644 --- a/src/internal/functions/New-AzOpsDeployment.ps1 +++ b/src/internal/functions/New-AzOpsDeployment.ps1 @@ -140,6 +140,8 @@ # Validate directory name match resource information if ($pathDirName -eq $expectedDirName) { Write-PSFMessage -Level Verbose -String 'New-AzOpsDeployment.Root.Processing' -StringValues $defaultDeploymentRegion, $scopeObject -Target $scopeObject + $whatIfCommand = 'Get-AzTenantDeploymentWhatIfResult' + $deploymentCommand = 'New-AzTenantDeployment' } # Invalid directory name else { diff --git a/src/tests/integration/Repository.Tests.ps1 b/src/tests/integration/Repository.Tests.ps1 index 9290953b..7bb6b602 100644 --- a/src/tests/integration/Repository.Tests.ps1 +++ b/src/tests/integration/Repository.Tests.ps1 @@ -306,7 +306,7 @@ Describe "Repository" { $script:bicepResourceGroupName = ((Get-Content -Path ($Script:bicepTemplatePath.FullName[1])) | ConvertFrom-Json).parameters.resourceGroupName.value $script:pushmgmttest1idManagementGroupTemplatePath = Get-Item "$($global:testroot)/templates/pushmgmttest1displayname (pushmgmttest1id)" | Copy-Item -Destination $script:testManagementGroupDirectory -Recurse -PassThru -Force - $script:pushmgmttest1idManagementGroupDeploymentName = "AzOps-{0}-{1}" -f 'pushmgmttest1id', $deploymentLocationId + $script:pushmgmttest1idManagementGroupDeploymentName = "AzOps-{0}-{1}" -f "$($script:pushmgmttest1idManagementGroupTemplatePath[1].Name.Replace(".json", ''))", $deploymentLocationId $script:pushmgmttest1idName = ((Get-Content -Path ($script:pushmgmttest1idManagementGroupTemplatePath.FullName[1])) | ConvertFrom-Json).resources.name[0] $script:pushmgmttest2idManagementGroupTemplatePath = Get-Item "$($global:testroot)/templates/pushmgmttest1displayname (pushmgmttest1id)" | Copy-Item -Destination $script:platformManagementGroupDirectory -Recurse -PassThru -Force @@ -325,7 +325,7 @@ Describe "Repository" { "A`t$script:ruleCollectionGroupsFile", "A`t$script:locksFile", "A`t$($script:bicepTemplatePath.FullName[0])", - "A`t$($script:pushmgmttest1idManagementGroupTemplatePath.FullName[0])" + "A`t$($script:pushmgmttest1idManagementGroupTemplatePath.FullName[1])" ) Invoke-AzOpsPush -ChangeSet $changeSet @@ -938,17 +938,16 @@ Describe "Repository" { #region Deploy Management Group using folder structure and file It "ManagementGroup deployment using folder structure and file should be successful" { - $script:pushmgmttest1Deployment = Get-AzManagementGroupDeployment -ManagementGroupId $script:pushmgmttest1idName -Name $script:pushmgmttest1idManagementGroupDeploymentName + $script:pushmgmttest1Deployment = Get-AzTenantDeployment -Name $script:pushmgmttest1idManagementGroupDeploymentName $pushmgmttest1Deployment.ProvisioningState | Should -Be "Succeeded" } - It "ManagementGroup deployed using folder structure and file should exist" { $script:pushmgmttest1Mg = Get-AzManagementGroup -GroupName $script:pushmgmttest1idName $pushmgmttest1Mg.Name | Should -Be $script:pushmgmttest1idName } - It "ManagementGroup deployment using folder structure and file at folder scope not matching content parent should fail" { + It "ManagementGroup deployed using folder structure and file at folder scope not matching content parent should fail" { $changeSet = @( - "A`t$($script:pushmgmttest12dManagementGroupTemplatePath.FullName[0])" + "A`t$($script:pushmgmttest2idManagementGroupTemplatePath.FullName[1])" ) {Invoke-AzOpsPush -ChangeSet $changeSet -WhatIf:$true} | Should -Throw } From 3dd6747e6084da38369fbc21b4c8a8999e61752f Mon Sep 17 00:00:00 2001 From: Jesper Fajers Date: Tue, 29 Nov 2022 11:08:46 +0000 Subject: [PATCH 4/7] Update --- src/tests/integration/Repository.Tests.ps1 | 2 +- ...ment_managementgroups-pushmgmttest2id.json | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/tests/templates/pushmgmttest2displayname (pushmgmttest2id)/microsoft.management_managementgroups-pushmgmttest2id.json diff --git a/src/tests/integration/Repository.Tests.ps1 b/src/tests/integration/Repository.Tests.ps1 index 7bb6b602..af5ced62 100644 --- a/src/tests/integration/Repository.Tests.ps1 +++ b/src/tests/integration/Repository.Tests.ps1 @@ -309,7 +309,7 @@ Describe "Repository" { $script:pushmgmttest1idManagementGroupDeploymentName = "AzOps-{0}-{1}" -f "$($script:pushmgmttest1idManagementGroupTemplatePath[1].Name.Replace(".json", ''))", $deploymentLocationId $script:pushmgmttest1idName = ((Get-Content -Path ($script:pushmgmttest1idManagementGroupTemplatePath.FullName[1])) | ConvertFrom-Json).resources.name[0] - $script:pushmgmttest2idManagementGroupTemplatePath = Get-Item "$($global:testroot)/templates/pushmgmttest1displayname (pushmgmttest1id)" | Copy-Item -Destination $script:platformManagementGroupDirectory -Recurse -PassThru -Force + $script:pushmgmttest2idManagementGroupTemplatePath = Get-Item "$($global:testroot)/templates/pushmgmttest2displayname (pushmgmttest2id)" | Copy-Item -Destination $script:platformManagementGroupDirectory -Recurse -PassThru -Force #endregion Paths #Test push based on pulled resources diff --git a/src/tests/templates/pushmgmttest2displayname (pushmgmttest2id)/microsoft.management_managementgroups-pushmgmttest2id.json b/src/tests/templates/pushmgmttest2displayname (pushmgmttest2id)/microsoft.management_managementgroups-pushmgmttest2id.json new file mode 100644 index 00000000..fdfa16cc --- /dev/null +++ b/src/tests/templates/pushmgmttest2displayname (pushmgmttest2id)/microsoft.management_managementgroups-pushmgmttest2id.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "AzOps" + } + }, + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Management/managementGroups", + "name": "pushmgmttest2id", + "apiVersion": "2021-04-01", + "scope": "/", + "properties": { + "displayName": "pushmgmttest2displayname", + "details": { + "parent": { + "id": "/providers/Microsoft.Management/managementGroups/52fd72ab-b56e-5a52-83a1-1f87365f7998" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2020-10-01", + "name": "AzOps-microsoft.management_managementgroups-nested", + "location": "[deployment().location]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": {} + } + }, + "dependsOn": [ + "Microsoft.Management/managementGroups/pushmgmttest2id" + ] + } + ], + "outputs": {} +} From 309ee5df8e51c7e4e771b7bc8b42ee6aef850af3 Mon Sep 17 00:00:00 2001 From: Jesper Fajers Date: Tue, 29 Nov 2022 14:47:27 +0100 Subject: [PATCH 5/7] Update --- src/internal/classes/AzOpsScope.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal/classes/AzOpsScope.ps1 b/src/internal/classes/AzOpsScope.ps1 index d71492a0..3f94cd7e 100644 --- a/src/internal/classes/AzOpsScope.ps1 +++ b/src/internal/classes/AzOpsScope.ps1 @@ -449,8 +449,8 @@ } else { Write-PSFMessage -Level Warning -Tag error -String 'AzOpsScope.GetAzOpsManagementGroupPath.NotFound' -StringValues $managementgroupName -FunctionName AzOpsScope -ModuleName AzOps - $assumenewresource = "azopsscope-assume-new-resource_$managementgroupName" - return $assumenewresource.ToLower() + $assumeNewResource = "azopsscope-assume-new-resource_$managementgroupName" + return $assumeNewResource.ToLower() } } From 36b9e8da7a591a52bdfdbf734e37e6f5226846d9 Mon Sep 17 00:00:00 2001 From: Jesper Fajers Date: Wed, 30 Nov 2022 17:57:27 +0000 Subject: [PATCH 6/7] Update --- src/internal/functions/New-AzOpsDeployment.ps1 | 16 ++++++---------- src/localized/en-us/Strings.psd1 | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/internal/functions/New-AzOpsDeployment.ps1 b/src/internal/functions/New-AzOpsDeployment.ps1 index 076b82c2..a1438ed0 100644 --- a/src/internal/functions/New-AzOpsDeployment.ps1 +++ b/src/internal/functions/New-AzOpsDeployment.ps1 @@ -129,29 +129,25 @@ if ((Get-PSFConfigValue -FullName 'AzOps.Core.AutoGeneratedTemplateFolderPath') -ne '.') { $pathDir = Split-Path -Path $pathDir -Parent } - $pathDirName = (Get-Item -Path $pathDir).Name - $parentDir = Split-Path -Path $pathDir -Parent - $parentDirScopeObject = New-AzOpsScope -Path $parentDir | Where-Object {(-not ($_.StatePath).StartsWith('azopsscope-assume-new-resource_'))} - $parentId = ($resource).properties.details.parent.id - $parentId = New-AzOpsScope -Scope $parentId | Where-Object {(-not ($_.StatePath).StartsWith('azopsscope-assume-new-resource_'))} - $expectedDirName = "$($resource.properties.displayName) ($($resource.name))" + $parentDirScopeObject = New-AzOpsScope -Path (Split-Path -Path $pathDir -Parent) | Where-Object {(-not ($_.StatePath).StartsWith('azopsscope-assume-new-resource_'))} + $parentIdScope = New-AzOpsScope -Scope (($resource).properties.details.parent.id) | Where-Object {(-not ($_.StatePath).StartsWith('azopsscope-assume-new-resource_'))} # Validate parent existence with content parent scope, statepath and name match, determines file location match deployment scope - if ($parentDirScopeObject -and $parentId -and $parentDirScopeObject.Scope -eq $parentId.Scope -and $parentDirScopeObject.StatePath -eq $parentId.StatePath -and $parentDirScopeObject.Name -eq $parentId.Name) { + if ($parentDirScopeObject -and $parentIdScope -and $parentDirScopeObject.Scope -eq $parentIdScope.Scope -and $parentDirScopeObject.StatePath -eq $parentIdScope.StatePath -and $parentDirScopeObject.Name -eq $parentIdScope.Name) { # Validate directory name match resource information - if ($pathDirName -eq $expectedDirName) { + if ((Get-Item -Path $pathDir).Name -eq "$($resource.properties.displayName) ($($resource.name))") { Write-PSFMessage -Level Verbose -String 'New-AzOpsDeployment.Root.Processing' -StringValues $defaultDeploymentRegion, $scopeObject -Target $scopeObject $whatIfCommand = 'Get-AzTenantDeploymentWhatIfResult' $deploymentCommand = 'New-AzTenantDeployment' } # Invalid directory name else { - Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Directory.NotFound' -Target $scopeObject -Tag Error -StringValues $pathDirName, $expectedDirName + Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Directory.NotFound' -Target $scopeObject -Tag Error -StringValues (Get-Item -Path $pathDir).Name, "$($resource.properties.displayName) ($($resource.name))" throw } } # Parent missing else { - Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Parent.NotFound' -Target $scopeObject -Tag Error -StringValues $parentDir, $addition + Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Parent.NotFound' -Target $scopeObject -Tag Error -StringValues (Split-Path -Path $pathDir), $addition throw } } diff --git a/src/localized/en-us/Strings.psd1 b/src/localized/en-us/Strings.psd1 index 6903409c..c9f9f4c8 100644 --- a/src/localized/en-us/Strings.psd1 +++ b/src/localized/en-us/Strings.psd1 @@ -225,7 +225,7 @@ 'New-AzOpsDeployment.WhatIfFile' = 'Creating WhatIf Results file' 'New-AzOpsDeployment.SkipDueToWhatIf' = 'Skipping deployment due to WhatIf' # 'New-AzOpsDeployment.Parent.NotFound' = 'Failed to find parent {0} for template {1}' # $parentDir, $addition - 'New-AzOpsDeployment.Directory.NotFound' = 'Directory name {0} does not match expected {1} does not match expected {1}' # $pathDirName, $expectedDirName + 'New-AzOpsDeployment.Directory.NotFound' = 'Directory name {0} does not match expected {1}' # (Get-Item -Path $pathDir).Name, "$($resource.properties.displayName) ($($resource.name))" 'New-AzOpsStateDeployment.EnrollmentAccount.First' = 'No enrollment account defined, using the first account found: {0}' # @($enrollmentAccounts)[0].PrincipalName 'New-AzOpsStateDeployment.EnrollmentAccount.Selected' = 'Using the defined enrollment account {0}' # $cfgEnrollmentAccount From 1dcc66691067f2def98a41fe4b78f571081de14b Mon Sep 17 00:00:00 2001 From: Jesper Fajers Date: Wed, 30 Nov 2022 19:41:10 +0000 Subject: [PATCH 7/7] Update --- src/internal/functions/New-AzOpsDeployment.ps1 | 2 +- src/localized/en-us/Strings.psd1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal/functions/New-AzOpsDeployment.ps1 b/src/internal/functions/New-AzOpsDeployment.ps1 index a1438ed0..61ec633b 100644 --- a/src/internal/functions/New-AzOpsDeployment.ps1 +++ b/src/internal/functions/New-AzOpsDeployment.ps1 @@ -147,7 +147,7 @@ } # Parent missing else { - Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Parent.NotFound' -Target $scopeObject -Tag Error -StringValues (Split-Path -Path $pathDir), $addition + Write-PSFMessage -Level Error -String 'New-AzOpsDeployment.Parent.NotFound' -Target $scopeObject -Tag Error -StringValues $addition throw } } diff --git a/src/localized/en-us/Strings.psd1 b/src/localized/en-us/Strings.psd1 index c9f9f4c8..4e5a22c9 100644 --- a/src/localized/en-us/Strings.psd1 +++ b/src/localized/en-us/Strings.psd1 @@ -224,7 +224,7 @@ 'New-AzOpsDeployment.WhatIfResults' = 'WhatIf Results: {0}' # $TemplateFilePath 'New-AzOpsDeployment.WhatIfFile' = 'Creating WhatIf Results file' 'New-AzOpsDeployment.SkipDueToWhatIf' = 'Skipping deployment due to WhatIf' # - 'New-AzOpsDeployment.Parent.NotFound' = 'Failed to find parent {0} for template {1}' # $parentDir, $addition + 'New-AzOpsDeployment.Parent.NotFound' = 'Failed to find parent scope for template {0}' # $addition 'New-AzOpsDeployment.Directory.NotFound' = 'Directory name {0} does not match expected {1}' # (Get-Item -Path $pathDir).Name, "$($resource.properties.displayName) ($($resource.name))" 'New-AzOpsStateDeployment.EnrollmentAccount.First' = 'No enrollment account defined, using the first account found: {0}' # @($enrollmentAccounts)[0].PrincipalName