Framework/Configurations/ContinuousAssurance/Continuous_Assurance_Runbook.ps1
$AzSKRunbookVersion = "[#runbookVersion#]" #Telemetry functions -- start here function SetCommonProperties([psobject] $EventObj) { $notAvailable = "NA" $eventObj.data.baseData.properties.Add("JobId",$PsPrivateMetaData.JobId.Guid) $eventObj.data.baseData.properties.Add("SubscriptionId",$RunAsConnection.SubscriptionID) $eventObj.data.baseData.properties.Add("AzSKRunbookVersion", $AzSKRunbookVersion) } function GetEventBaseObject([string] $EventName) { $eventObj = "" | Select-Object data, iKey, name, tags, time $eventObj.iKey = $telemetryKey $eventObj.name = "Microsoft.ApplicationInsights." + $telemetryKey.Replace("-", "") + ".Event" $eventObj.time = [datetime]::UtcNow.ToString("o") $eventObj.tags = "" | Select-Object ai.internal.sdkVersion $eventObj.tags.'ai.internal.sdkVersion' = "dotnet: 2.1.0.26048" $eventObj.data = "" | Select-Object baseData, baseType $eventObj.data.baseType = "EventData" $eventObj.data.baseData = "" | Select-Object ver, name, measurements, properties $eventObj.data.baseData.ver = 2 $eventObj.data.baseData.name = $EventName $eventObj.data.baseData.measurements = New-Object 'system.collections.generic.dictionary[string,double]' $eventObj.data.baseData.properties = New-Object 'system.collections.generic.dictionary[string,string]' return $eventObj; } function PublishEvent([string] $EventName, [hashtable] $Properties, [hashtable] $Metrics) { try { #return if telemetry key is empty if ([string]::IsNullOrWhiteSpace($telemetryKey)) { return; }; $eventObj = GetEventBaseObject -EventName $EventName SetCommonProperties -EventObj $eventObj if ($null -ne $Properties) { $Properties.Keys | ForEach-Object { try { if (!$eventObj.data.baseData.properties.ContainsKey($_)) { $eventObj.data.baseData.properties.Add($_ , $Properties[$_].ToString()) } } catch { # Left blank intentionally # Error while sending CA events to telemetry. No need to break the execution. } } } if ($null -ne $Metrics) { $Metrics.Keys | ForEach-Object { try { $metric = $Metrics[$_] -as [double] if (!$eventObj.data.baseData.measurements.ContainsKey($_) -and $null -ne $metric) { $eventObj.data.baseData.measurements.Add($_ , $Metrics[$_]) } } catch { # Left blank intentionally # Error while sending CA events to telemetry. No need to break the execution. } } } $eventJson = ConvertTo-Json $eventObj -Depth 100 -Compress Invoke-WebRequest -Uri "https://dc.services.visualstudio.com/v2/track" ` -Method Post ` -ContentType "application/x-json-stream" ` -Body $eventJson ` -UseBasicParsing | Out-Null } catch { # Left blank intentionally # Error while sending CA events to telemetry. No need to break the execution. } } #Telemetry functions -- end here #function to create one time temporary helper schedule function CreateHelperSchedule($nextRetryIntervalInMinutes) { #create next run schedule Get-AzureRmAutomationSchedule -AutomationAccountName $AutomationAccountName ` -ResourceGroupName $AutomationAccountRG -Name $CAHelperScheduleName -ErrorAction SilentlyContinue | Remove-AzureRmAutomationSchedule -Force New-AzureRmAutomationSchedule -AutomationAccountName $AutomationAccountName -Name $CAHelperScheduleName ` -ResourceGroupName $AutomationAccountRG -StartTime $(get-date).AddMinutes($nextRetryIntervalInMinutes) ` -OneTime -ErrorAction Stop | Out-Null Register-AzureRmAutomationScheduledRunbook -RunbookName $RunbookName -ScheduleName $CAHelperScheduleName ` -ResourceGroupName $AutomationAccountRG ` -AutomationAccountName $AutomationAccountName -ErrorAction Stop | Out-Null PublishEvent -EventName "CA Job Rescheduled" -Properties @{"IntervalInMinutes" = $nextRetryIntervalInMinutes} } #function to invoke script from server function InvokeScript($accessToken, $policyStoreURL,$fileName, $version) { [System.Uri] $validatedURI = $null; $URI = $global:ExecutionContext.InvokeCommand.ExpandString($policyStoreURL) $result = "Write-Host 'Error connecting to AzSK policy store server.'" if([System.Uri]::TryCreate($URI, [System.UriKind]::Absolute, [ref] $validatedURI)) { if($accessToken) { $retry = 3 while($retry -gt 0) { $retry = $retry - 1 $result = Invoke-WebRequest $validatedUri -Headers @{"Authorization" = "Bearer $accessToken"} -UseBasicParsing if ($null -ne $result -and $result.StatusCode -ge 200 -and $result.StatusCode -le 399) { $retry = -1; } } } else { $retry = 3 while($retry -gt 0) { $retry = $retry - 1 $result = Invoke-WebRequest $validatedUri -UseBasicParsing if ($null -ne $result -and $result.StatusCode -ge 200 -and $result.StatusCode -le 399) { $retry = -1; } } } Invoke-Expression $result; } } function ConvertStringToBoolean($strToConvert) { switch($strToConvert) { "true" {return $true} "false" {return $false} } return $false #adding this to prevent error all path doesn't return value" } try { #start job timer $jobTimer = [System.Diagnostics.Stopwatch]::StartNew(); #----------------------------------Config start------------------------------------------------------------------ $automationAccountRG = "[#automationAccountRG#]" $automationAccountName="[#automationAccountName#]" $telemetryKey ="[#telemetryKey#]" $onlinePolicyStoreUrl = "[#onlinePolicyStoreUrl#]" $OSSPolicyStoreUrl = "[#OSSPolicyStoreUrl#]" $enableAADAuthForOnlinePolicyStore = "[#enableAADAuthForOnlinePolicyStore#]" $runbookCoreSetupScript = "RunbookCoreSetup.ps1" $runbookScanAgentScript = "RunbookScanAgent.ps1" $RunbookName = "Continuous_Assurance_Runbook" $CAHelperScheduleName = "CA_Helper_Schedule" $UpdateToLatestVersion = "[#UpdateToLatestVersion#]" $azureRmResourceURI = "https://management.core.windows.net/" $RunAsConnection = Get-AutomationConnection -Name "AzureRunAsConnection" #-----------------------------------Config end------------------------------------------------------------------------- #-----------------------------------Telemetry script------------------------------------------------------------------- PublishEvent -EventName "CA Job Started" -Properties @{ "OnlinePolicyStoreUrl"=$OnlinePolicyStoreUrl; ` "AzureADAppId"=$RunAsConnection.ApplicationId } #------------------------------------Execute RunbookCoreSetup.ps1 to download required modules------------------------- #Login if(!$RunAsConnection) { throw "Cannot login to Azure from AzSK CA runbook. Connection info for AzureRunAsConnection not found." } try { "Logging in to Azure..." Add-AzureRmAccount ` -ServicePrincipal ` -TenantId $RunAsConnection.TenantId ` -ApplicationId $RunAsConnection.ApplicationId ` -CertificateThumbprint $RunAsConnection.CertificateThumbprint | Out-Null Set-AzureRmContext -SubscriptionId $RunAsConnection.SubscriptionID | Out-Null } catch { Write-Output ("Failed to login to Azure with AzSK CA Runtime account.") throw $_.Exception } #create helper schedule to run job again after 30 minutes in case online policy URL is down "Validating installed AzSK version..." #Step 1: Get module version from installed AzSK module $module = Get-AzureRmAutomationModule -ResourceGroupName $AutomationAccountRG ` -AutomationAccountName $AutomationAccountName | ` Where-Object { $_.Name -like "azsk*"} $moduleVersion = "1.0.0" $UpdateToLatestVersion = ConvertStringToBoolean($UpdateToLatestVersion) PublishEvent -EventName "CA Job Invoke Setup Started" Write-Output ("Starting invocation: policyStoreURL=$OSSPolicyStoreUrl") InvokeScript -policyStoreURL $OSSPolicyStoreUrl -fileName $runbookCoreSetupScript -version $moduleVersion Write-Output ("Completed runbook setup script.") PublishEvent -EventName "CA Job Invoke Setup Completed" #------------------------------------Execute RunbookScanAgent.ps1 to scan subscription and resources------------------- if((Get-Command -Name "Get-AzSKAccessToken" -ErrorAction SilentlyContinue|Measure-Object).Count -gt 0) { if($enableAADAuthForOnlinePolicyStore -eq "true") { $accessToken = Get-AzSKAccessToken -ResourceAppIdURI $azureRmResourceURI } PublishEvent -EventName "CA Job Invoke Scan Started" Write-Output ("Starting invocation: policyStoreURL=$onlinePolicyStoreUrl") Write-Output ("Starting CA scan...") InvokeScript -accessToken $accessToken -policyStoreURL $onlinePolicyStoreUrl -fileName $runbookScanAgentScript -version $moduleVersion Write-Output ("CA scan completed.") PublishEvent -EventName "CA Job Invoke Scan Completed" } else { Write-Output("Not triggering a scan. AzSK module not yet ready in the account.") } Write-Output ("CA job completed.") PublishEvent -EventName "CA Job Completed" -Metrics @{ "TimeTakenInMs" = $jobTimer.ElapsedMilliseconds; ` "SuccessCount" = 1 } } catch { Write-Output ("Exception happened in runbook...") $_ PublishEvent -EventName "CA Job Error" -Properties @{ "ErrorRecord" = ($_ | Out-String) } -Metrics @{"TimeTakenInMs" =$jobTimer.ElapsedMilliseconds; "SuccessCount" = 0} throw; } #----------------------------------Runbook end------------------------------------------------------------------------- |