functions/Invoke-AzOpsPull.ps1
function Invoke-AzOpsPull { <# .SYNOPSIS Setup a repository for the AzOps workflow, based off templates and an existing Azure deployment. .DESCRIPTION Setup a repository for the AzOps workflow, based off templates and an existing Azure deployment. .PARAMETER IncludeResourcesInResourceGroup Discover only resources in these resource groups. .PARAMETER IncludeResourceType Discover only specific resource types. .PARAMETER SkipChildResource Skip childResource discovery. .PARAMETER SkipPim Skip discovery of Privileged Identity Management resources. .PARAMETER SkipPolicy Skip discovery of policies. .PARAMETER SkipRole Skip discovery of role. .PARAMETER SkipResourceGroup Skip discovery of resource groups .PARAMETER SkipResource Skip discovery of resources inside resource groups. .PARAMETER InvalidateCache Invalidate cached subscriptions and Management Groups and do a full discovery. .PARAMETER ExportRawTemplate Export generic templates without embedding them in the parameter block. .PARAMETER Rebuild Delete all AutoGeneratedTemplateFolderPath folders inside AzOpsState directory. .PARAMETER Force Delete $script:AzOpsState directory. .PARAMETER PartialMgDiscoveryRoot The subset of management groups in the entire hierarchy with which to work. Needed when lacking root access. .PARAMETER StatePath The root folder under which to write the resource json. .EXAMPLE > Invoke-AzOpsPull Setup a repository for the AzOps workflow, based off templates and an existing Azure deployment. #> [CmdletBinding()] [Alias("Initialize-AzOpsRepository")] param ( [string[]] $IncludeResourcesInResourceGroup = (Get-PSFConfigValue -FullName 'AzOps.Core.IncludeResourcesInResourceGroup'), [string[]] $IncludeResourceType = (Get-PSFConfigValue -FullName 'AzOps.Core.IncludeResourceType'), [switch] $SkipChildResource = (Get-PSFConfigValue -FullName 'AzOps.Core.SkipChildResource'), [switch] $SkipPim = (Get-PSFConfigValue -FullName 'AzOps.Core.SkipPim'), [switch] $SkipPolicy = (Get-PSFConfigValue -FullName 'AzOps.Core.SkipPolicy'), [switch] $SkipResource = (Get-PSFConfigValue -FullName 'AzOps.Core.SkipResource'), [switch] $SkipResourceGroup = (Get-PSFConfigValue -FullName 'AzOps.Core.SkipResourceGroup'), [string[]] $SkipResourceType = (Get-PSFConfigValue -FullName 'AzOps.Core.SkipResourceType'), [switch] $SkipRole = (Get-PSFConfigValue -FullName 'AzOps.Core.SkipRole'), [switch] $InvalidateCache = (Get-PSFConfigValue -FullName 'AzOps.Core.InvalidateCache'), [switch] $ExportRawTemplate = (Get-PSFConfigValue -FullName 'AzOps.Core.ExportRawTemplate'), [switch] $Rebuild, [switch] $Force, [string[]] $PartialMgDiscoveryRoot = (Get-PSFConfigValue -FullName 'AzOps.Core.PartialMgDiscoveryRoot'), [string] $StatePath = (Get-PSFConfigValue -FullName 'AzOps.Core.State'), [string] $TemplateParameterFileSuffix = (Get-PSFConfigValue -FullName 'AzOps.Core.TemplateParameterFileSuffix') ) begin { #region Initialize & Prepare Write-PSFMessage -Level Important -String 'Invoke-AzOpsPull.Initialization.Starting' if ((-not $SkipRole) -or (-not $SkipPim)) { try { Write-PSFMessage -Level Verbose -String 'Invoke-AzOpsPull.Validating.UserRole' $null = Get-AzADUser -First 1 -ErrorAction Stop Write-PSFMessage -Level Important -String 'Invoke-AzOpsPull.Validating.UserRole.Success' if (-not $SkipPim) { Write-PSFMessage -Level Verbose -String 'Invoke-AzOpsPull.Validating.AADP2' $servicePlanName = "AAD_PREMIUM_P2" $subscribedSkus = Invoke-AzRestMethod -Uri https://graph.microsoft.com/v1.0/subscribedSkus -ErrorAction Stop $subscribedSkusValue = $subscribedSkus.Content | ConvertFrom-Json -Depth 100 | Select-Object value if ($servicePlanName -in $subscribedSkusValue.value.servicePlans.servicePlanName) { Write-PSFMessage -Level Important -String 'Invoke-AzOpsPull.Validating.AADP2.Success' } else { Write-PSFMessage -Level Warning -String 'Invoke-AzOpsPull.Validating.AADP2.Failed' $SkipPim = $true } } } catch { Write-PSFMessage -Level Warning -String 'Invoke-AzOpsPull.Validating.UserRole.Failed' $SkipRole = $true $SkipPim = $true } } if ($false -eq $SkipChildResource -or $false -eq $SkipResource -and $true -eq $SkipResourceGroup) { Write-PSFMessage -Level Warning -String 'Invoke-AzOpsPull.Validating.ResourceGroupDiscovery.Failed' -StringValues "`n" } $resourceTypeDiff = Compare-Object -ReferenceObject $SkipResourceType -DifferenceObject $IncludeResourceType -ExcludeDifferent if ($resourceTypeDiff) { Write-PSFMessage -Level Warning -Message "SkipResourceType setting conflict found in IncludeResourceType, ignoring $($resourceTypeDiff.InputObject) from IncludeResourceType. To avoid this remove $($resourceTypeDiff.InputObject) from IncludeResourceType or SkipResourceType" $IncludeResourceType = $IncludeResourceType | Where-Object {$_ -notin $resourceTypeDiff.InputObject} } $parameters = $PSBoundParameters | ConvertTo-PSFHashtable -Inherit -Include InvalidateCache, PartialMgDiscovery, PartialMgDiscoveryRoot Initialize-AzOpsEnvironment @parameters Assert-AzOpsInitialization -Cmdlet $PSCmdlet -StatePath $StatePath $tenantId = (Get-AzContext).Tenant.Id Write-PSFMessage -Level Important -String 'Invoke-AzOpsPull.Tenant' -StringValues $tenantId Write-PSFMessage -Level Verbose -String 'Invoke-AzOpsPull.TemplateParameterFileSuffix' -StringValues (Get-PSFConfigValue -FullName 'AzOps.Core.TemplateParameterFileSuffix') Write-PSFMessage -Level Important -String 'Invoke-AzOpsPull.Initialization.Completed' $stopWatch = [System.Diagnostics.Stopwatch]::StartNew() #endregion Initialize & Prepare } process { #region Existing Content if (Test-Path $StatePath) { $migrationRequired = (Get-ChildItem -Recurse -Force -Path $StatePath -File | Where-Object { $_.Name -like $("Microsoft.Management_managementGroups-" + $tenantId + $TemplateParameterFileSuffix) } | Select-Object -ExpandProperty FullName -First 1) -notmatch '\((.*)\)' if ($migrationRequired) { Write-PSFMessage -Level Important -String 'Invoke-AzOpsPull.Migration.Required' } if ($Force -or $migrationRequired) { Invoke-PSFProtectedCommand -ActionString 'Invoke-AzOpsPull.Deleting.State' -ActionStringValues $StatePath -Target $StatePath -ScriptBlock { Remove-Item -Path $StatePath -Recurse -Force -Confirm:$false -ErrorAction Stop } -EnableException $true -PSCmdlet $PSCmdlet } if ($Rebuild) { Invoke-PSFProtectedCommand -ActionString 'Invoke-AzOpsPull.Rebuilding.State' -ActionStringValues $StatePath -Target $StatePath -ScriptBlock { Get-ChildItem -Path $StatePath -File -Recurse -Force -Filter 'Microsoft.*_*.json' | Remove-Item -Force -Recurse -Confirm:$false -ErrorAction Stop } -EnableException $true -PSCmdlet $PSCmdlet } } #endregion Existing Content #region Root Scopes $rootScope = '/providers/Microsoft.Management/managementGroups/{0}' -f $tenantId if ($script:AzOpsPartialRoot.id) { $rootScope = $script:AzOpsPartialRoot.id | Sort-Object -Unique } if ($rootScope -and $script:AzOpsAzManagementGroup) { foreach ($root in $rootScope) { # Create AzOpsState Structure recursively Save-AzOpsManagementGroupChildren -Scope $root -StatePath $StatePath # Discover Resource at scope recursively $parameters = $PSBoundParameters | ConvertTo-PSFHashtable -Inherit -Include IncludeResourcesInResourceGroup, IncludeResourceType, SkipPim, SkipPolicy, SkipRole, SkipResourceGroup, SkipChildResource, SkipResource, SkipResourceType, ExportRawTemplate, StatePath Get-AzOpsResourceDefinition -Scope $root @parameters } } else { # If no management groups are found, iterate through each subscription foreach ($subscription in $script:AzOpsSubscriptions) { $parameters = $PSBoundParameters | ConvertTo-PSFHashtable -Inherit -Include IncludeResourcesInResourceGroup, IncludeResourceType, SkipPim, SkipPolicy, SkipRole, SkipResourceGroup, SkipChildResource, SkipResource, SkipResourceType, ExportRawTemplate, StatePath Get-AzOpsResourceDefinition -Scope $subscription.id @parameters } } #endregion Root Scopes } end { $stopWatch.Stop() Write-PSFMessage -Level Important -String 'Invoke-AzOpsPull.Duration' -StringValues $stopWatch.Elapsed -Data @{ Elapsed = $stopWatch.Elapsed } } } |