workloadAccelerators/lighthouse/scripts/lighthouseAccelerator.ps1 (201 lines of code) (raw):
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
<#
.SYNOPSIS
This PowerShell script serves as the overarching script to deploy the workload template either in its entirety or in a piecemeal manner the below individual modules.
.DESCRIPTION
- Executes the individual modules - lighthouse
#>
using namespace System.Collections
param (
$parAttendedLogin = $true
)
#reference to common scripts
. "..\..\..\common\common.ps1"
#Processing parameters from JSON and creating a hash table
$varParameters = @{}
$varWorkloadParameters = Get-Content -Path '.\parameters\lighthouse.parameters.json' | ConvertFrom-Json
$varWorkloadParameters.parameters.psobject.properties | ForEach-Object {
if ($_.value.Value -eq $null -or $_.value.Value.count -eq 0) {
$varParameters.add($_.Name, (new-Object PsObject -property @{value = $_.value.defaultValue; defaultValue = $_.value.defaultValue }))
}
else {
$varParameters.add($_.Name, (new-Object PsObject -property @{value = $_.value.Value; defaultValue = $_.value.defaultValue }))
}
}
#constants
$varMaxRetryAttemptTransientErrorRetry = 3
$varRetry = $true
$varRetryWaitTimeTransientErrorRetry = 60
#bicep files
$varLighthouse = '.\lighthouse.bicep'
$varPolicyRemediation = '.\policyRemediation.bicep'
#Parameters
$varLighthouseParams = @('parDeploymentPrefix', 'parDeploymentLocation', 'parLighthouseManagementTenantId', 'parLighthouseOfferName', 'parLighthouseOfferDescription', 'parPrincipalId', 'parPrincipalIdDisplayName', 'parRoleDefinitionId')
#variables to support retry for known transient errors
$varMaxRetryAttemptTransientErrorRetry = 3
$varRetryWaitTimeTransientErrorRetry = 60
<#
.Description
Invokes Policy Remediation for existing subscriptions
#>
function Invoke-PolicyRemediation {
param($varPolicyAssignmentId)
#policy remediation
$guid = New-Guid
$parDeploymentLocation = $varParameters.parDeploymentLocation.value
$varDeploymentName = ("$guid" + $varPolicySetDefinitionName)
$deploymentName = $varDeploymentName.Length -ge 64 ? $varDeploymentName.Substring(0, 64) : $varDeploymentName
$parRemediationName = "rem-" + $deploymentName
$parManagementGroupId = $varParameters.parManagementGroupId.value
$varTotalWaitTime = 0
$varLoopCounter = 0
$parameters = @{
parPolicyRemediationName = $parRemediationName
parPolicyAssignmentId = $varPolicyAssignmentId
parPolicyDefinitionReferenceId = ''
}
while ($varTotalWaitTime -lt $varMaxRetryAttemptTransientErrorRetry) {
try {
Write-Information ">>> Policy Remediation Started" -InformationAction Continue
$modLighthousePolicyRemediation = New-AzManagementGroupDeployment `
-Name $varDeploymentName `
-Location $parDeploymentLocation `
-TemplateFile $varPolicyRemediation `
-ManagementGroupId $parManagementGroupId `
-TemplateParameterObject $parameters `
-WarningAction Ignore
if (!$modLighthousePolicyRemediation -or $modLighthousePolicyRemediation.ProvisioningState -eq "Failed") {
Write-Error "Error while executing policy remediation deployment" -ErrorAction Stop
}
else {
Write-Information ">>> Policy Remediation Successful" -InformationAction Continue
}
return
}
catch {
$varLoopCounter++
$varException = $_.Exception
$varErrorDetails = $_.ErrorDetails
$varTrace = $_.ScriptStackTrace
Write-Error "$varException \n $varErrorDetails \n $varTrace" -ErrorAction Continue
if ($varRetry -and $varLoopCounter -lt $varMaxRetryAttemptTransientErrorRetry) {
Write-Information ">>> Retrying deployment after waiting for $varRetryWaitTimeTransientErrorRetry secs" -InformationAction Continue
Start-Sleep -Seconds $varRetryWaitTimeTransientErrorRetry
}
else {
Write-Error ">>> Error occurred in policy remediation deployment. Please try after addressing the error : $varException \n $varErrorDetails \n $varTrace" -ErrorAction Stop
}
}
}
}
<#
.Description
Invokes Policy evaluation for the lighthouse policy
#>
function Invoke-PolicyEvaluation {
param($varSubscriptions)
$varSubscriptionsCount = $varSubscriptions.count
if ($varSubscriptionsCount -eq 0) {
Write-Information ">>> No subscriptions to evaluate policies" -ErrorAction Stop
}
Write-Information ">>> Policy scan will be executed in synchronous mode. The process may take up to an hour." -InformationAction Continue
$varCounter = 1
foreach ($subscription in $varSubscriptions) {
# register for ManagedServices and PolicyInsights RP
$subscriptionId = $subscription.subscriptionId;
$subscriptionAvailable = Get-AzSubscription -SubscriptionId $subscriptionId
if ($subscriptionAvailable -eq "[]") {
Write-Error ">>> Please refresh credentials by running following commands: Disconnect-AzAccount and Connect-AzAccount and retry the deployment" -ErrorAction Stop
}
# This is not logic requirement, but have to register Microsoft.Network early to avoid Subscription XXXXX-XXXXX-XXXXXXX-XXXXXXX is not registered with NRP because of registration delay.
Write-Information ">>> Registering Microsoft.Network resource provider for the existing subscription $subscriptionId ..." -InformationAction Continue
Set-AzContext -Subscription $subscriptionId
Register-ResourceProvider "Microsoft.Network"
Write-Information ">>> Registering Managed.Services resource provider for the existing subscription $subscriptionId ..." -InformationAction Continue
Register-ResourceProvider 'Microsoft.ManagedServices' `
Write-Information ">>> Registering Managed.PolicyInsights resource provider for the existing subscription $subscriptionId ..." -InformationAction Continue
Register-ResourceProvider 'Microsoft.PolicyInsights' `
#run trigger scan for policy evaluation
Write-Information "Executing policy evaluation scan for subscription id: $subscriptionId. Processing $varCounter subscription out of $varSubscriptionsCount " -InformationAction Continue
$varCounter++
Start-AzPolicyComplianceScan
}
return
}
<#
.DESCRIPTION
Deploys lighthouse
#>
function New-Lighthouse {
param()
$parDeploymentPrefix = $varParameters.parDeploymentPrefix.value
$varLighthouseDeploymentName = "$parDeploymentPrefix-deploy-Lighthouse-$vartimeStamp"
$parManagementGroupId = $varParameters.parManagementGroupId.value
$varLogicAppName = "$parManagementGroupId-logicapp-$parDeploymentLocation"
$parameters = @{
parManagementGroupId = $parManagementGroupId
parLocation = $varParameters.parDeploymentLocation.value
parLogicAppName = $varLogicAppName
parDeploymentSubscriptionId = $varDeploymentSubscriptionId
parLighthouseManagementTenantId = $varParameters.parLighthouseManagementTenantId.value
parLighthouseOfferName = $varParameters.parLighthouseOfferName.value
parLighthouseOfferDescription = $varParameters.parLighthouseOfferDescription.value
parPrincipalId = $varParameters.parPrincipalId.value
parPrincipalIdDisplayName = $varParameters.parPrincipalIdDisplayName.value
parRoleDefinitionId = $varParameters.parRoleDefinitionId.value
}
while ($varLoopCounter -lt $varMaxRetryAttemptTransientErrorRetry) {
try {
Write-Information ">>> Lighthouse deployment started" -InformationAction Continue
$modLighthouse = New-AzManagementGroupDeployment `
-Name $varLighthouseDeploymentName `
-Location $parDeploymentLocation `
-ManagementGroupId $parManagementGroupId `
-TemplateFile $varLighthouse `
-TemplateParameterObject $parameters `
-WarningAction Ignore
if (!$modLighthouse -or $modLighthouse.ProvisioningState -eq "Failed") {
Write-Error "Error while executing lighthouse deployment script" -ErrorAction Stop
}
return $modLighthouse
}
catch {
$varLoopCounter++
$varException = $_.Exception
$varErrorDetails = $_.ErrorDetails
$varTrace = $_.ScriptStackTrace
Write-Error "$varException \n $varErrorDetails \n $varTrace" -ErrorAction Continue
if ($varRetry -and $varLoopCounter -lt $varMaxRetryAttemptTransientErrorRetry) {
Write-Information ">>> Retrying deployment after waiting for $varRetryWaitTimeTransientErrorRetry secs" -InformationAction Continue
Start-Sleep -Seconds $varRetryWaitTimeTransientErrorRetry
}
else {
Write-Error ">>> Error occurred in Lighthouse deployment. Please try after addressing the error : $varException \n $varErrorDetails \n $varTrace" -ErrorAction Stop
}
}
}
}
Confirm-Parameters($varLighthouseParams)
if ($parAttendedLogin) {
# Confirm Prerequisites
Confirm-Prerequisites -parConfirmAZResourceGraphVersion 1
}
#Fetch all existing subscriptions
$parDeploymentPrefix = $varParameters.parDeploymentPrefix.value
$parManagementGroupId = $varParameters.parManagementGroupId.value
$parDeploymentLocation = $varParameters.parDeploymentLocation.value
$varDeploymentSubscriptionId = (Get-AzContext).Subscription.id
$varSubscriptions = Search-AzGraph -Query "ResourceContainers | where type =~ 'microsoft.resources/subscriptions'" -ManagementGroup $parManagementGroupId
$varSubscriptions = $varSubscriptions | Where-Object { $_.properties.state -eq "Enabled" }
$varIsMgSubscription = $varSubscriptions | Where-Object { $_.subscriptionId -eq $varDeploymentSubscriptionId }
if ($null -eq $varIsMgSubscription) {
Write-Error "The subscription $varDeploymentSubscriptionId does not under the management group $parManagementGroupId or disabled. Please use the subscription which is created by Sovereign Landing Zone." -ErrorAction Stop
}
$modLighthouseOutputs = New-Lighthouse
$varPolicyAssignmentId = $modLighthouseOutputs.Outputs.outPolicyAssignmentId.value
#invoke policy evaluation
Invoke-PolicyEvaluation $varSubscriptions
#invoke policy remediation
Invoke-PolicyRemediation $varPolicyAssignmentId
Write-Information ">>> Lighthouse deployment Successful" -InformationAction Continue