Framework/Configurations/ContinuousAssurance/RunbookScanAgent.ps1

function ConvertStringToBoolean($strToConvert) {
    switch ($strToConvert) {
        "true" {return $true}
        "false" {return $false}
    }
    return $false #adding this to prevent error all path doesn't return value"
}

function RunAzSDKScan() {
    Set-AzSDKOMSSettings -OMSWorkspaceID $OMSWorkspaceId -OMSSharedKey $OMSWorkspaceSharedKey -Source "CC"

    #set values in azsdksettings.json
    $EnableAADAuthForOnlinePolicyStore = ConvertStringToBoolean($EnableAADAuthForOnlinePolicyStore)
    if ($EnableAADAuthForOnlinePolicyStore) {
        Set-AzSDKPolicySettings -OnlinePolicyStoreUrl $OnlinePolicyStoreUrl -EnableAADAuthForOnlinePolicyStore
    }
    else {
        Set-AzSDKPolicySettings -OnlinePolicyStoreUrl $OnlinePolicyStoreUrl
    }

    $svtResultPath = [string]::Empty
    $subscriptionResultPath = [string]::Empty
    $parentFolderPath = [string]::Empty

    PublishEvent -EventName "CA Scan Started" -Properties @{
        "ResourceGroupNames"       = $ResourceGroupNames; `
            "OnlinePolicyStoreUrl" = $OnlinePolicyStoreUrl; `
            "OMSWorkspaceId"       = $OMSWorkspaceId;
    }

    #------------------------------------Subscription scan----------------------------------------------------------------
    "Running command 'Get-AzSDKSubscriptionSecurityStatus'"
    $subScanTimer = [System.Diagnostics.Stopwatch]::StartNew();
    PublishEvent -EventName "CA Scan Subscription Started"
    $subscriptionResultPath = Get-AzSDKSubscriptionSecurityStatus -SubscriptionId $SubscriptionID -ExcludeTags "OwnerAccess"

    #---------------------------Check subscription scan status--------------------------------------------------------------
    if ([string]::IsNullOrWhiteSpace($subscriptionResultPath)) {
        PublishEvent -EventName "CA Scan Subscription Error" -Metrics @{"TimeTakenInMs" = $subScanTimer.ElapsedMilliseconds; "SuccessCount" = 0}
        "Subscription scan failed."
    }
    else {
        PublishEvent -EventName "CA Scan Subscription Completed" -Metrics @{"TimeTakenInMs" = $subScanTimer.ElapsedMilliseconds; "SuccessCount" = 1}
        "Subscription scan succeeded."
        $parentFolderPath = (Get-Item $subscriptionResultPath).parent.FullName
    }

    #-------------------------------------Resources Scan------------------------------------------------------------------
    "Running command 'Get-AzSDKAzureServicesSecurityStatus'"
    $serviceScanTimer = [System.Diagnostics.Stopwatch]::StartNew();
    PublishEvent -EventName "CA Scan Services Started"
    if ($ResourceGroupNames.Trim() -eq "*") {
        #run command on all resources
        $svtResultPath = Get-AzSDKAzureServicesSecurityStatus -SubscriptionId $SubscriptionID -ExcludeTags "OwnerAccess"
    }
    else {
        $svtResultPath = Get-AzSDKAzureServicesSecurityStatus -SubscriptionId $SubscriptionID -ResourceGroupNames $ResourceGroupNames -ExcludeTags "OwnerAccess"
    }
    #---------------------------Check resources scan status--------------------------------------------------------------
    if ([string]::IsNullOrWhiteSpace($svtResultPath)) {
        "Azure resources scan failed."
        PublishEvent -EventName "CA Scan Services Error" -Metrics @{"TimeTakenInMs" = $serviceScanTimer.ElapsedMilliseconds; "SuccessCount" = 0}
    }
    else {
        "Azure resources scan succeeded."
        $parentFolderPath = (Get-Item $svtResultPath).parent.FullName
        PublishEvent -EventName "CA Scan Services Completed" -Metrics @{"TimeTakenInMs" = $serviceScanTimer.ElapsedMilliseconds; "SuccessCount" = 1}
    }
    #----------------------------------------Export reports to storage---------------------------------------------------
    if (![string]::IsNullOrWhiteSpace($subscriptionResultPath) -or ![string]::IsNullOrWhiteSpace($svtResultPath)) {
        #Check if storage account exists
        try {
            Get-AzureRmStorageAccount -ResourceGroupName $StorageAccountRG -Name $StorageAccountName -ErrorAction stop | Out-Null
        }
        catch {
            Write-Error -Message $_.Exception
            throw $_.Exception
        }

        #Create output files in storage
        $containerName = "azsdkexecutionlogs"
        $archiveFilePath = "$parentFolderPath\AutomationLogs_" + $(Get-Date -format "yyyyMMdd_HHmmss") + ".zip"
        $keys = Get-AzureRmStorageAccountKey -ResourceGroupName $StorageAccountRG -Name $StorageAccountName
        $currentContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $keys[0].Value -Protocol Https
        try {
            Get-AzureStorageContainer -Name $containerName -Context $currentContext -ErrorAction Stop | Out-Null
        }
        catch {
            New-AzureStorageContainer -Name $containerName -Context $currentContext | Out-Null
        }
        try {
            if (![string]::IsNullOrWhiteSpace($svtResultPath)) {
                Compress-Archive -Path $svtResultPath -CompressionLevel Optimal -DestinationPath $archiveFilePath -Update
            }
            if (![string]::IsNullOrWhiteSpace($subscriptionResultPath)) {
                Compress-Archive -Path $subscriptionResultPath -CompressionLevel Optimal -DestinationPath $archiveFilePath -Update
            }
            Set-AzureStorageBlobContent -File $archiveFilePath -Container $containerName -Context $currentContext -ErrorAction Stop | Out-Null
            "Exported reports to storage $StorageAccountName"
            PublishEvent -EventName "CA Scan Reports Persisted" -Properties @{"StorageAccountName" = $StorageAccountName; "ArchiveFilePath" = $archiveFilePath } -Metrics @{"SuccessCount" = 1}
        }
        catch {
            "Could not export reports to storage $StorageAccountName"
            PublishEvent -EventName "CA Scan Reports Persist Error" -Properties @{"ErrorRecord" = ($_ | Out-String); "StorageAccountName" = $StorageAccountName; "ArchiveFilePath" = $archiveFilePath } -Metrics @{"SuccessCount" = 0}
            throw $_.Exception
        }

        #clean-up of logs in automation sandbox
        if (![string]::IsNullOrWhiteSpace($svtResultPath)) {
            Remove-Item -Path $svtResultPath -Recurse -ErrorAction Ignore
        }
        if (![string]::IsNullOrWhiteSpace($subscriptionResultPath)) {
            Remove-Item -Path $subscriptionResultPath -Recurse -ErrorAction Ignore
        }
        if (![string]::IsNullOrWhiteSpace($archiveFilePath)) {
            Remove-Item -Path $archiveFilePath -Recurse -ErrorAction Ignore
        }
    }
}
try {
    #start timer
    $scanAgentTimer = [System.Diagnostics.Stopwatch]::StartNew();

    #config start
    $ResourceGroupNames = Get-AutomationVariable -Name "AppResourceGroupNames"
    $OMSWorkspaceId = Get-AutomationVariable -Name "OMSWorkspaceId"
    $OMSWorkspaceSharedKey = Get-AutomationVariable -Name "OMSSharedKey"
    $StorageAccountName = Get-AutomationVariable -Name "ReportsStorageAccountName"
    $AzSDKModuleName = "AzSDKStaging"
    $StorageAccountRG = "AzSDKRG"
    $RunbookName = "Continuous_Assurance_Runbook"
    $CAHelperScheduleName = "CA_Helper_Schedule"
    #config end

    #Set subscription id
    $SubscriptionID = $RunAsConnection.SubscriptionID

    $isAzSDKAvailable = (Get-AzureRmAutomationModule -ResourceGroupName $AutomationAccountRG `
            -AutomationAccountName $AutomationAccountName `
            -Name $AzSDKModuleName -ErrorAction SilentlyContinue | `
            Where-Object {$_.ProvisioningState -eq "Succeeded" -or $_.ProvisioningState -eq "Created"} | `
            Measure-Object).Count -gt 0

    if ($isAzSDKAvailable) {
        Import-Module $AzSDKModuleName
    }

    #check if AzureRM is available (for scenario where AzSDK is available but AzureRM extraction might have failed)
    $isAzureRMAvailable = (Get-AzureRmAutomationModule -ResourceGroupName $AutomationAccountRG `
            -AutomationAccountName $AutomationAccountName `
            -Name AzureRM -ErrorAction SilentlyContinue | `
            Where-Object {$_.ProvisioningState -eq "Succeeded" -or $_.ProvisioningState -eq "Created"} | `
            Measure-Object).Count -gt 0

    #return if modules are not ready
    if ((Get-Command -Name "Get-AzSDKAzureServicesSecurityStatus" -ErrorAction SilentlyContinue|Measure-Object).Count -eq 0 -or !$isAzureRMAvailable) {
        "AzSDK module not available. Skipping AzSDK scan. Will retry in the next run."
        PublishEvent -EventName "CA Job Skipped" -Properties @{"SubscriptionId" = $RunAsConnection.SubscriptionID} -Metrics @{"TimeTakenInMs" = $timer.ElapsedMilliseconds; "SuccessCount" = 1}
        return;
    }

    #scan and save results to storage
    RunAzSDKScan

    #helper schedule not needed anymore
    Remove-AzureRmAutomationSchedule -Name $CAHelperScheduleName -ResourceGroupName $AutomationAccountRG -AutomationAccountName $AutomationAccountName -Force
    PublishEvent -EventName "CA Scan Completed" -Metrics @{"TimeTakenInMs" = $scanAgentTimer.ElapsedMilliseconds}
}
catch {
    PublishEvent -EventName "CA Scan Error" -Properties @{ "ErrorRecord" = ($_ | Out-String) } -Metrics @{"TimeTakenInMs" = $scanAgentTimer.ElapsedMilliseconds; "SuccessCount" = 0}
}