Framework/Core/ARMChecker/ARMCheckerStatus.ps1
using namespace System.Management.Automation Set-StrictMode -Version Latest class ARMCheckerStatus: EventBase { hidden [string] $ARMControls; hidden [string []] $BaselineControls; hidden [string] $PSLogPath; hidden [string] $SFLogPath; [bool] $DoNotOpenOutputFolder = $false; ARMCheckerStatus([InvocationInfo] $invocationContext) { if (-not $invocationContext) { throw [System.ArgumentException] ("The argument 'invocationContext' is null. Pass the `$PSCmdlet.MyInvocation from PowerShell command."); } $this.InvocationContext = $invocationContext; #load config file here. $this.ARMControls=$this.LoadARMControlsFile(); if([string]::IsNullOrWhiteSpace($this.ARMControls)) { throw ([SuppressedException]::new(("There are no controls to evaluate in ARM checker. Please contact support team."), [SuppressedExceptionType]::InvalidOperation)) } if($null -ne $this.InvocationContext.BoundParameters["DoNotOpenOutputFolder"]) { $this.DoNotOpenOutputFolder = $this.InvocationContext.BoundParameters["DoNotOpenOutputFolder"]; } } hidden [void] CommandStartedAction() { $currentVersion = $this.GetCurrentModuleVersion(); $moduleName = $this.GetModuleName(); $methodName = $this.InvocationContext.InvocationName; $this.WriteMessage([Constants]::DoubleDashLine + "`r`n$moduleName Version: $currentVersion `r`n" + [Constants]::DoubleDashLine , [MessageType]::Info); $this.WriteMessage("Method Name: $methodName `r`nInput Parameters: $(($this.InvocationContext.BoundParameters | Out-String).TrimEnd()) `r`n" + [Constants]::DoubleDashLine , [MessageType]::Info); } hidden [void] CommandCompletedAction($resultsFolder) { $this.WriteMessage([Constants]::SingleDashLine, [MessageType]::Info); $this.WriteMessage([Constants]::RemediationMsgForARMChekcer, [MessageType]::Info); $this.WriteMessage("For further details, refer: "+[Constants]::CICDShortLink,[MessageType]::Info) $this.WriteMessage([Constants]::SingleDashLine, [MessageType]::Info); $this.WriteMessage("Status and detailed logs have been exported to: $($resultsFolder)", [MessageType]::Info); $this.WriteMessage([Constants]::DoubleDashLine, [MessageType]::Info); } [string] EvaluateStatus([string] $armTemplatePath, [string] $parameterFilePath ,[Boolean] $isRecurse,[string] $exemptControlListPath,[string] $ExcludeFiles, [string] $ExcludeControlIds, [string] $ControlIds,[Boolean] $UseBaselineControls,[Boolean] $UsePreviewBaselineControls, [string[]]$Severity) { if(-not (Test-Path -path $armTemplatePath)) { $this.WriteMessage("ARMTemplate file path or folder path is empty, verify that the path is correct and try again", [MessageType]::Error); return $null; } #load baseline control list $ErrorLoadingControlSettings = $this.LoadControlSettingsFile($UseBaselineControls, $UsePreviewBaselineControls); if($ErrorLoadingControlSettings){ return $null; } # Check if parameter file path is provided by user if([string]::IsNullOrEmpty($parameterFilePath)) { $parameterFileProvided = $false; }else{ $parameterFileProvided = $true; } # Check if provided parameter file path is valid if($parameterFileProvided -and -not (Test-Path -path $parameterFilePath)) { $parameterFileProvided = $false; $this.WriteMessage("Template parameter file path or folder path is empty, verify that the path is correct and try again", [MessageType]::Warning); } # Check if provided parameter file path is a single file or folder $ParameterFiles = $null; $paramterFileContent = $null; if($parameterFileProvided -and (Test-Path -path $parameterFilePath -PathType Leaf)) { $paramterFileContent = Get-Content $parameterFilePath -Raw }elseif ($parameterFileProvided) { if($isRecurse -eq $true) { $ParameterFiles = Get-ChildItem -Path $parameterFilePath -Recurse -Filter '*.parameters.json' } else { $ParameterFiles = Get-ChildItem -Path $parameterFilePath -Filter '*.parameters.json' } } $this.PSLogPath = ""; $baseDirectory = [System.IO.Path]::GetDirectoryName($armTemplatePath); if($isRecurse -eq $true) { $ARMTemplates = Get-ChildItem -Path $armTemplatePath -Recurse -Filter '*.json' } else { $ARMTemplates = Get-ChildItem -Path $armTemplatePath -Filter '*.json' } $armEvaluator = [AzSK.ARMChecker.Lib.ArmTemplateEvaluator]::new([string] $this.ARMControls); $skippedFiles = @(); $timeMarker = [datetime]::Now.ToString("yyyyMMdd_HHmmss") $resultsFolder = Join-Path $([Constants]::AzSKLogFolderPath) $([Constants]::AzSKModuleName + "Logs") | Join-Path -ChildPath "ARMChecker" | Join-Path -ChildPath $timeMarker ; $csvFilePath = Join-Path $resultsFolder ("ARMCheckerResults_" + $timeMarker + ".csv"); [System.IO.Directory]::CreateDirectory($resultsFolder) | Out-Null $this.PSLogPath = Join-Path $resultsFolder "PowerShellOutput.LOG"; $this.SFLogPath = Join-Path $resultsFolder "SkippedFiles.LOG"; $this.CommandStartedAction(); $csvResults = @(); $armcheckerscantelemetryEvents = [System.Collections.ArrayList]::new() $scannedFileCount = 0 $exemptControlList=@() $filesToExclude=@() $filesToExcludeCount=0 $excludedFiles=@() $filteredFiles = @(); $ControlsToScanBySeverity =@(); try{ if(-not([string]::IsNullOrEmpty($exemptControlListPath)) -and (Test-Path -path $exemptControlListPath -PathType Leaf)) { $exemptControlListFile=Get-Content $exemptControlListPath | ConvertFrom-Csv $exemptControlList=$exemptControlListFile| where {$_.Status -eq "Failed" -or $_.Status -eq "Verify"} } }catch{ $this.WriteMessage("Unable to read file containing list of controls to skip, Please verify file path.", [MessageType]::Warning); } if(-not([string]::IsNullOrEmpty($ExcludeFiles))) { $ExcludeFileFilters = @(); $ExcludeFileFilters = $this.ConvertToStringArray($ExcludeFiles); $ExcludeFileFilters | ForEach-Object { if($isRecurse -eq $true) { $filesToExclude = Get-ChildItem -Path $armTemplatePath -Recurse -Filter $_ } else{ $filesToExclude = Get-ChildItem -Path $armTemplatePath -Filter $_ } if($null -ne $filesToExclude -and ($filesToExclude | Measure-Object).Count -gt 0) { $filesToExclude | Select-Object Name | ForEach-Object { $filteredFiles += $_.Name} } } $filesToExclude = $filteredFiles -join "," $filesToExcludeCount = ($filesToExclude| Measure-Object).Count } # Check if both -ControlIds and ExcludeControlIds switch are provided , return with error message if(-not([string]::IsNullOrEmpty($ControlIds)) -and -not([string]::IsNullOrEmpty($ExcludeControlIds))){ $this.WriteMessage("InvalidArgument: Both the parameters 'ControlIds' and 'ExcludeControlIds' contain values. You should use only one of these parameters.", [MessageType]::Error); return $null; } # Check if both -ControlIds and UseBaselineControls switch are provided , return with error message if(-not([string]::IsNullOrEmpty($ControlIds)) -and $UseBaselineControls){ $this.WriteMessage("InvalidArgument: Both the parameters 'ControlIds' and 'UseBaselineControls' contain values. You should use only one of these parameters.", [MessageType]::Error); return $null; } # Check if both -ControlIds and UsePreviewBaselineControls switch are provided , return with error message if(-not([string]::IsNullOrEmpty($ControlIds)) -and $UsePreviewBaselineControls){ $this.WriteMessage("InvalidArgument: Both the parameters 'ControlIds' and 'UsePreviewBaselineControls' contain values. You should use only one of these parameters.", [MessageType]::Error); return $null; } # Check if specific control ids to scan are provided by user $ControlsToScan = @(); if(-not([string]::IsNullOrEmpty($ControlIds))) { $ControlsToScan = $this.ConvertToStringArray($ControlIds); } if(-not([string]::IsNullOrEmpty($Severity))) { $Severity = $this.ConvertToStringArray($Severity); #Discard the severity inputs that are not in enum $Severity = $Severity | Where-Object {$_ -in [Enum]::GetNames('ControlSeverity')} $ControlsToScanBySeverity = $Severity } # Check if exclude control ids are provided by user $ControlsToExclude = @(); if(-not([string]::IsNullOrEmpty($ExcludeControlIds))) { $ControlsToExclude = $this.ConvertToStringArray($ExcludeControlIds); } foreach($armTemplate in $ARMTemplates) { $armFileName = $armTemplate.FullName.Replace($baseDirectory, "."); if(($filesToExcludeCount -eq 0) -or (-not $filteredFiles.Contains($armTemplate.Name))) { try { $results = @(); $csvResultsForCurFile=@(); $relatedParameterFile = $null $relatedParameterFileName = $null $armTemplateContent = Get-Content $armTemplate.FullName -Raw if($null -ne $ParameterFiles -and ($ParameterFiles | Measure-Object).Count -gt 0) { $relatedParameterFileName = $armTemplate.Name.Replace(".json",".parameters.json"); $relatedParameterFile = $ParameterFiles | Where-Object { $_.Name -eq $relatedParameterFileName } if($null -ne $relatedParameterFile) { $relatedParameterFile = $relatedParameterFile | Select-Object -First 1 $paramterFileContent = Get-Content $relatedParameterFile.FullName -Raw } $libResults = $armEvaluator.Evaluate($armTemplateContent, $paramterFileContent); }else { $libResults = $armEvaluator.Evaluate($armTemplateContent, $paramterFileContent); #$libResults = $armEvaluator.Evaluate($armTemplateContent, $null); } $results += $libResults | Where-Object {$_.VerificationResult -ne "NotSupported"} | Select-Object -ExcludeProperty "IsEnabled" if($null -ne $results -and ( $results| Measure-Object).Count -gt 0 -and $this.BaselineControls.Count -gt 0){ $results = $results | Where-Object {$this.BaselineControls -contains $_.ControlId} } if($null -ne $results -and ( $results | Measure-Object).Count -gt 0 -and ( $ControlsToScan | Measure-Object).Count -gt 0 ){ $results = $results | Where-Object {$ControlsToScan -contains $_.ControlId} } if($null -ne $results -and ( $results | Measure-Object).Count -gt 0 -and ( $ControlsToExclude | Measure-Object).Count -gt 0){ $results = $results | Where-Object {$ControlsToExclude -notcontains $_.ControlId} } if($null -ne $results -and ( $results | Measure-Object).Count -gt 0 -and ( $ControlsToScanBySeverity | Measure-Object).Count -gt 0){ $results = $results | Where-Object {$_.Severity -in $ControlsToScanBySeverity} } $this.WriteMessage(([Constants]::DoubleDashLine + "`r`nStarting analysis: [FileName: $armFileName] `r`n" + [Constants]::SingleDashLine), [MessageType]::Info); if($null -ne $relatedParameterFile){ $this.WriteMessage(("`r`n[ParameterFileName: $relatedParameterFileName] `r`n" + [Constants]::SingleDashLine), [MessageType]::Info); } if($null -ne $results -and ($results | Measure-Object).Count -gt 0) { $scannedFileCount += 1; foreach($result in $results) { $csvResultItem = "" | Select-Object "ControlId", "FeatureName","Status", "SupportedResources", "Severity", ` "PropertyPath", "LineNumber", "CurrentValue", "ExpectedProperty", "ExpectedValue", ` "ResourcePath", "ResourceLineNumber", "Description","FilePath" $csvResultItem.SupportedResources = $result.SupportedResources $csvResultItem.ControlId = $result.ControlId $csvResultItem.FeatureName = $result.FeatureName $csvResultItem.Description = $result.Description $csvResultItem.ExpectedProperty = $result.ExpectedProperty $csvResultItem.ExpectedValue = $result.ExpectedValue $csvResultItem.Severity = $result.Severity.ToString() $csvResultItem.Status = $result.VerificationResult $csvResultItem.FilePath = $armFileName if($result.ResultDataMarkers.Count -gt 0) { $csvResultItem.LineNumber = $result.ResultDataMarkers[0].LineNumber $csvResultItem.PropertyPath = $result.ResultDataMarkers[0].JsonPath $data = $result.ResultDataMarkers[0].DataMarker if($data -ieq "true" -or $data -ieq "false") { $csvResultItem.CurrentValue = $data.ToLower() } else { $csvResultItem.CurrentValue = $data } } else { $csvResultItem.LineNumber = -1 $csvResultItem.PropertyPath = "Not found" $csvResultItem.CurrentValue = "" } $csvResultItem.ResourceLineNumber = $result.ResourceDataMarker.LineNumber $csvResultItem.ResourcePath = $result.ResourceDataMarker.JsonPath if(($exemptControlList|Measure-Object).Count -gt 0) { $csvResultItem = Compare-Object -ReferenceObject $csvResultItem -DifferenceObject $exemptControlList -PassThru -IncludeEqual -Property ControlId,PropertyPath $csvResultItem| ForEach-Object { if($_.SideIndicator -eq "==") { $_.Status = "Skipped" } } $csvResultItem =$csvResultItem | where {$_.SideIndicator -eq "==" -or $_.SideIndicator -eq "<="} $csvResultItem =$csvResultItem | Select-Object "ControlId", "FeatureName","Status", "SupportedResources", "Severity", ` "PropertyPath", "LineNumber", "CurrentValue", "ExpectedProperty", "ExpectedValue", ` "ResourcePath", "ResourceLineNumber", "Description","FilePath" } $properties = @{}; $properties.Add("ResourceType", $csvResultItem.FeatureName) $properties.Add("ControlId", $csvResultItem.ControlId) $properties.Add("VerificationResult", $csvResultItem.Status); $telemetryEvent = "" | Select-Object Name, Properties, Metrics $telemetryEvent.Name = "ARMChecker Control Scanned" $telemetryEvent.Properties = $properties [bool] $flag = $true; foreach($cr in $csvResults) { if($cr.ExpectedProperty -eq $csvResultItem.ExpectedProperty -and $cr.ControlId -eq $csvResultItem.ControlId -and $cr.LineNumber -eq $csvResultItem.LineNumber -and $cr.ResourceLineNumber -eq $csvResultItem.ResourceLineNumber -and $cr.FilePath -eq $csvResultItem.FilePath) { $flag = $false; break; } } if($flag) { $csvResults += $csvResultItem; $this.WriteResult($csvResultItem); $csvResultsForCurFile+=$csvResultItem; $armcheckerscantelemetryEvents.Add($telemetryEvent) } } $this.WriteMessage([Constants]::SingleDashLine, [MessageType]::Info); $this.WriteSummary($csvResultsForCurFile, "Severity", "Status"); } else { $skippedFiles += $armFileName; $this.WriteMessage("No controls have been evaluated for file: $armFileName", [MessageType]::Info); } } catch { $skippedFiles += $armFileName; } } else { $excludedFiles += $armFileName; } } $csvResults| Export-Csv $csvFilePath -NoTypeInformation -Force if($excludedFiles.Count -ne 0) { $this.WriteMessage([Constants]::DoubleDashLine, [MessageType]::Warning); $this.WriteMessage("Excluded file(s): $($excludedFiles.Count)", [MessageType]::Warning); $excludedFiles | ForEach-Object { $this.WriteMessage($_, [MessageType]::Warning); }; $this.WriteMessage([Constants]::SingleDashLine, [MessageType]::Warning); } if($skippedFiles.Count -ne 0) { $this.WriteMessage([Constants]::DoubleDashLine, [MessageType]::Warning); $this.WriteMessage("Skipped file(s): $($skippedFiles.Count)", [MessageType]::Warning); $skippedFiles | ForEach-Object { $this.WriteMessage($_, [MessageType]::Warning); $this.AddSkippedFilesLog([Helpers]::ConvertObjectToString($_, $false)); }; $this.WriteMessage([Constants]::SingleDashLine, [MessageType]::Warning); $this.WriteMessage("One or more files were skipped during the scan. `nEither the files are invalid as ARM templates or those resource types are currently not supported by this command.`nPlease verify the files and re-run the command. `nFor files that should not be included in the scan, you can use the '-ExcludeFiles' parameter.",[MessageType]::Error); $this.WriteMessage([Constants]::SingleDashLine, [MessageType]::Warning); } $teleEvent = "" | Select-Object Name, Properties, Metrics $teleEvent.Name = "ARMChecker Command Completed" $teleEvent.Properties = @{}; $teleEvent.Properties.Add("Total", $csvResults.Count); if($csvResults.Count -ne 0) { $this.WriteMessage([Constants]::DoubleDashLine, [MessageType]::Info); $this.WriteSummary($csvResults, "Severity", "Status"); $this.WriteMessage("Total scanned file(s): $scannedFileCount", [MessageType]::Info); $resultsGroup = $csvResults | Group-Object Status | ForEach-Object { $teleEvent.Properties.Add($_.Name, $_.Count); }; } else { $this.WriteMessage("No controls have been evaluated for ARM Template(s).", [MessageType]::Error); } $this.CommandCompletedAction($resultsFolder); $armcheckerscantelemetryEvents.Add($teleEvent) [AIOrgTelemetryHelper]::PublishARMCheckerEvent($armcheckerscantelemetryEvents) if((-not $this.DoNotOpenOutputFolder) -and (-not [string]::IsNullOrEmpty($resultsFolder))) { try { Invoke-Item -Path $resultsFolder; } catch { #ignore if any exception occurs } } return $resultsFolder } hidden [void] WriteResult($result) { $messageType = [MessageType]::Info; switch ($result.Status) { Passed { $messageType = [MessageType]::Update; } Verify { $messageType = [MessageType]::Warning; } Failed { $messageType = [MessageType]::Error; } Exempted { $messageType = [MessageType]::Update; } } $this.WriteMessage("$($result.Status): [$($result.ControlId)]", $messageType); } hidden [void] WriteSummary($summary, $severityPropertyName, $resultPropertyName) { if($summary.Count -ne 0) { $summaryResult = @(); $severities = @(); $severities += $summary | Select-Object -Property $severityPropertyName | Select-Object -ExpandProperty $severityPropertyName -Unique; $verificationResults = @(); $verificationResults += $summary | Select-Object -Property $resultPropertyName | Select-Object -ExpandProperty $resultPropertyName -Unique; if($severities.Count -ne 0) { # Create summary matrix $totalText = "Total"; $MarkerText = "MarkerText"; $rows = @(); $rows += $severities; $rows += $MarkerText; $rows += $totalText; $rows += $MarkerText; $rows | ForEach-Object { $result = [PSObject]::new(); Add-Member -InputObject $result -Name "Summary" -MemberType NoteProperty -Value $_.ToString() Add-Member -InputObject $result -Name $totalText -MemberType NoteProperty -Value 0 [Enum]::GetNames([VerificationResult]) | Where-Object { $verificationResults -contains $_ } | ForEach-Object { Add-Member -InputObject $result -Name $_.ToString() -MemberType NoteProperty -Value 0 }; $summaryResult += $result; }; $totalRow = $summaryResult | Where-Object { $_.Summary -eq $totalText } | Select-Object -First 1; $summary | Group-Object -Property $severityPropertyName | ForEach-Object { $item = $_; $summaryItem = $summaryResult | Where-Object { $_.Summary -eq $item.Name } | Select-Object -First 1; if($summaryItem) { $summaryItem.Total = $_.Count; if($totalRow) { $totalRow.Total += $_.Count } $item.Group | Group-Object -Property $resultPropertyName | ForEach-Object { $propName = $_.Name; $summaryItem.$propName += $_.Count; if($totalRow) { $totalRow.$propName += $_.Count } }; } }; $markerRows = $summaryResult | Where-Object { $_.Summary -eq $MarkerText } $markerRows | ForEach-Object { $markerRow = $_ Get-Member -InputObject $markerRow -MemberType NoteProperty | ForEach-Object { $propName = $_.Name; $markerRow.$propName = "------"; } }; if($summaryResult.Count -ne 0) { $this.WriteMessage(($summaryResult | Format-Table | Out-String), [MessageType]::Info) } } } } hidden [void] WriteMessage([PSObject] $message, [MessageType] $messageType) { if(-not $message) { return; } $colorCode = [System.ConsoleColor]::White switch($messageType) { ([MessageType]::Critical) { $colorCode = [System.ConsoleColor]::Red } ([MessageType]::Error) { $colorCode = [System.ConsoleColor]::Red } ([MessageType]::Warning) { $colorCode = [System.ConsoleColor]::Yellow } ([MessageType]::Info) { $colorCode = [System.ConsoleColor]::Cyan } ([MessageType]::Update) { $colorCode = [System.ConsoleColor]::Green } ([MessageType]::Deprecated) { $colorCode = [System.ConsoleColor]::DarkYellow } ([MessageType]::Default) { $colorCode = [System.ConsoleColor]::White } } $formattedMessage = [Helpers]::ConvertObjectToString($message, (-not [string]::IsNullOrEmpty($this.PSLogPath))); Write-Host $formattedMessage -ForegroundColor $colorCode $this.AddOutputLog([Helpers]::ConvertObjectToString($message, $false)); } hidden [void] AddOutputLog([string] $message) { if([string]::IsNullOrEmpty($message) -or [string]::IsNullOrEmpty($this.PSLogPath)) { return; } Add-Content -Value $message -Path $this.PSLogPath } hidden [void] AddSkippedFilesLog([string] $message) { if([string]::IsNullOrEmpty($message) -or [string]::IsNullOrEmpty($this.PSLogPath)) { return; } Add-Content -Value $message -Path $this.SFLogPath } hidden [Object] MergeExtensionFile([Object] $source,[Object] $extend) { if([Helpers]::CheckMember($extend,"resourceControlSets")){ $extend.resourceControlSets | ForEach-Object { try{ $currentFeature = $_ $existingFeature = $source.resourceControlSets | Where-Object {$_.featureName -eq $currentFeature.featureName } if($existingFeature -ne $null) { $existingFeature.controls += $currentFeature.controls }else{ $source.resourceControlSets += $currentFeature } }catch{ # No need to break execution, source file will be returned } } } return $source; } hidden [string] LoadARMControlsFile() { $serverFileContent=$null; $ARMControlsFileURI = [Constants]::ARMControlsFileURI $checkExtensionFile = $false try { if(-not [ConfigurationManager]::GetLocalAzSKSettings().EnableAADAuthForOnlinePolicyStore) { $serverFileContent = [ConfigurationManager]::LoadServerConfigFile("ARMControls.json"); $checkExtensionFile = $true } else { $AzureContext = Get-AzContext if(-not [string]::IsNullOrWhiteSpace($AzureContext)) { $serverFileContent = [ConfigurationManager]::LoadServerConfigFile("ARMControls.json"); $checkExtensionFile = $true } else { $serverFileContent = [ConfigurationHelper]::InvokeControlsAPI($ARMControlsFileURI, '', '', ''); } } } catch { try { $serverFileContent = [ConfigurationHelper]::InvokeControlsAPI($ARMControlsFileURI, '', '', ''); } catch { # No Need to break Execution # Load Offline File } } if($null -eq $serverFileContent) { $serverFileContent = [ConfigurationHelper]::LoadOfflineConfigFile("ARMControls.json", $false); } #Check if extension file is present on server $extFileContent = $null if($checkExtensionFile -eq $true){ $extFileContent = [ConfigurationManager]::LoadServerFileRaw("ARMControls.ext.json"); } if($null -ne $extFileContent ){ $serverFileContent = $this.MergeExtensionFile($serverFileContent, $extFileContent ) } $serverFileContent= $serverFileContent | ConvertTo-Json -Depth 10 return $serverFileContent; } hidden [boolean] LoadControlSettingsFile([Boolean] $UseBaselineControls, [Boolean] $UsePreviewBaselineControls) { if($UseBaselineControls -eq $true -or $UsePreviewBaselineControls -eq $true){ # Fetch control Settings data $ControlSettings = $null if(-not [ConfigurationManager]::GetLocalAzSKSettings().EnableAADAuthForOnlinePolicyStore) { $ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json"); } else { $AzureContext = Get-AzContext if(-not [string]::IsNullOrWhiteSpace($AzureContext)) { $ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json"); } else { Write-Host "No Azure login found. Azure login context is required to fetch baseline controls defined for this policy." -ForegroundColor Red # return true if EnableAADAuthForOnlinePolicyStore is true but Az login context is null return $true } } # Filter control list for baseline controls $baselineControlList = @(); if($UseBaselineControls) { if([Helpers]::CheckMember($ControlSettings ,"BaselineControls.ResourceTypeControlIdMappingList")) { $baselineControlList += $ControlSettings.BaselineControls.ResourceTypeControlIdMappingList | Select-Object ControlIds | ForEach-Object { $_.ControlIds } } } # Filter control list for preview baseline controls $previewBaselineControls = @(); if($UsePreviewBaselineControls) { if([Helpers]::CheckMember($ControlSettings,"PreviewBaselineControls.ResourceTypeControlIdMappingList") ) { $previewBaselineControls += $ControlSettings.PreviewBaselineControls.ResourceTypeControlIdMappingList | Select-Object ControlIds | ForEach-Object { $_.ControlIds } } $baselineControlList += $previewBaselineControls } if($baselineControlList -and $baselineControlList.Count -gt 0) { $this.BaselineControls += $baselineControlList } else { Write-Host "There are no baseline/preview-baseline controls defined for your org." -ForegroundColor Yellow $this.BaselineControls = @() } } else { $this.BaselineControls = @() } return $false } } |