Framework/Core/AzSKInfo/ControlsInfo.ps1
using namespace System.Management.Automation Set-StrictMode -Version Latest class ControlsInfo: AzCommandBase { hidden [string] $ResourceTypeName hidden [string] $ResourceType hidden [bool] $BaslineControls hidden [bool] $PreviewBaslineControls hidden [bool] $ControlsExcludedByOrgPolicy hidden [PSObject] $ControlSettings hidden [string[]] $Tags = @(); hidden [string[]] $ControlIds = @(); hidden [bool] $Full hidden [string] $SummaryMarkerText = "------" hidden [string] $ControlSeverity hidden [string] $ControlIdContains hidden [string] $ControlExclusionWarningMessage = "" hidden [string] $ControlExclusionHelpLink = "" ControlsInfo([string] $subscriptionId, [InvocationInfo] $invocationContext, [string] $resourceTypeName, [string] $resourceType, [string] $controlIds, [bool] $baslineControls,[bool] $previewBaslineControls, [string] $tags, [bool] $full, [string] $controlSeverity, [string] $controlIdContains) : Base($subscriptionId, $invocationContext) { $this.ResourceTypeName = $resourceTypeName; $this.ResourceType = $resourceType; $this.BaslineControls = $baslineControls; $this.PreviewBaslineControls = $previewBaslineControls $this.Full = $full; $this.ControlSeverity = $controlSeverity; $this.ControlIdContains = $controlIdContains if(-not [string]::IsNullOrEmpty($tags)) { $this.Tags += $this.ConvertToStringArray($tags); } if(-not [string]::IsNullOrEmpty($controlIds)) { $this.ControlIds += $this.ConvertToStringArray($controlIds); } if($this.Full) { $this.DoNotOpenOutputFolder = $true; } if([FeatureFlightingManager]::GetFeatureStatus("EnableControlExclusionByOrgPolicy",$($this.SubscriptionContext.SubscriptionId))){ $this.ControlsExcludedByOrgPolicy = $true; }else{ $this.ControlsExcludedByOrgPolicy = $false; } } GetControlDetails() { $resourcetypes = @() $SVTConfig = @{} $allControls = @() $controlSummary = @() # Fetch control Setting data $this.ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json"); # Filter Control for Resource Type / Resource Type Name if([string]::IsNullOrWhiteSpace($this.ResourceType) -and [string]::IsNullOrWhiteSpace($this.ResourceTypeName)) { $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default); $this.PublishCustomMessage([Constants]::DefaultControlInfoCmdMsg, [MessageType]::Default); $this.DoNotOpenOutputFolder = $true; return; } #Check if this org wants IPAddress to be treated as its own resource. if([Helpers]::CheckMember($this.ControlSettings,"PublicIpAddress",$false) -and [Helpers]::CheckMember($this.ControlSettings.PublicIpAddress,"EnablePublicIpResource",$false)) { #If not, let us remove the resource type entry from the mapping $treatPublicIPasResource = $this.ControlSettings.PublicIpAddress.EnablePublicIpResource if( -not $treatPublicIPasResource) { [SVTMapping]::Mapping = ([SVTMapping]::Mapping | Where-Object { $_.ResourceType -ne 'Microsoft.Network/publicIPAddresses'}); } } #throw if user has set params for ResourceTypeName and ResourceType #Default value of ResourceTypeName is All. if($this.ResourceTypeName -ne [ResourceTypeName]::All -and -not [string]::IsNullOrWhiteSpace($this.ResourceType)){ throw [SuppressedException] "Both the parameters 'ResourceTypeName' and 'ResourceType' contains values. You should use only one of these parameters." } if (-not [string]::IsNullOrEmpty($this.ResourceType)) { $resourcetypes += ([SVTMapping]::Mapping | Where-Object { $_.ResourceType -eq $this.ResourceType } | Select-Object JsonFileName) } elseif($this.ResourceTypeName -ne [ResourceTypeName]::All) { $resourcetypes += ([SVTMapping]::Mapping | Where-Object { $_.ResourceTypeName -eq $this.ResourceTypeName } | Select-Object JsonFileName) } else { $resourcetypes += ([SVTMapping]::SubscriptionMapping | Select-Object JsonFileName) $resourcetypes += ([SVTMapping]::Mapping | Sort-Object ResourceTypeName | Select-Object JsonFileName ) } # Filter control for baseline controls $baselineControls = @(); $baselineControls += $this.ControlSettings.BaselineControls.ResourceTypeControlIdMappingList | Select-Object ControlIds | ForEach-Object { $_.ControlIds } $baselineControls += $this.ControlSettings.BaselineControls.SubscriptionControlIdList | ForEach-Object { $_ } if($this.BaslineControls) { $this.ControlIds = $baselineControls } $previewBaselineControls = @(); $excludedControls = @(); if([Helpers]::CheckMember($this.ControlSettings,"PreviewBaselineControls.ResourceTypeControlIdMappingList") ) { $previewBaselineControls += $this.ControlSettings.PreviewBaselineControls.ResourceTypeControlIdMappingList | Select-Object ControlIds | ForEach-Object { $_.ControlIds } } if([Helpers]::CheckMember($this.ControlSettings,"PreviewBaselineControls.SubscriptionControlIdList") ) { $previewBaselineControls += $this.ControlSettings.PreviewBaselineControls.SubscriptionControlIdList | ForEach-Object { $_ } } $TenantId = ([ContextHelper]::GetCurrentRMContext()).Tenant.Id if($this.ControlsExcludedByOrgPolicy ` -and [Helpers]::CheckMember($this.ControlSettings, "ControlsToExcludeFromScan.TenantIds") ` -and ($this.ControlSettings.ControlsToExcludeFromScan.TenantIds -contains $TenantId) ` -and [Helpers]::CheckMember($this.ControlSettings, "ControlsToExcludeFromScan.ControlIds") ) { $excludedControls += $this.ControlSettings.ControlsToExcludeFromScan.ControlIds $this.ControlExclusionWarningMessage = $this.ControlSettings.ControlsToExcludeFromScan.ExclusionWarningMessage $this.ControlExclusionHelpLink = $this.ControlSettings.ControlsToExcludeFromScan.ExclusionHelpLink } if($this.PreviewBaslineControls) { #If preview baseline switch is passed and there is no preview baseline control list present then throw exception if (($previewBaselineControls | Measure-Object).Count -eq 0 -and -not $this.BaslineControls) { throw ([SuppressedException]::new(("There are no preview baseline controls defined for this policy."), [SuppressedExceptionType]::Generic)) } $this.ControlIds += $previewBaselineControls } $resourcetypes | ForEach-Object{ $controls = [ConfigurationManager]::GetSVTConfig($_.JsonFileName); [bool] $PolicyExpandedFlag = $false #Flag to represent whether control attributes have been updated or not if([ConfigurationHelper]::PolicyCacheContent[$_.JsonFileName].State -eq [PolicyCacheStatus]::Final) { $PolicyExpandedFlag = $true } # Filter control for enable only $controls.Controls = ($controls.Controls | Where-Object { $_.Enabled -eq $true }) # Filter control for ControlIds if ($controls.Controls -and $this.ControlIds.Count -gt 0) { $controls.Controls = ($controls.Controls | Where-Object { $this.ControlIds -contains $_.ControlId }) } # Filter control for ControlId Contains if ($controls.Controls -and -not [string]::IsNullOrEmpty($this.ControlIdContains)) { $controls.Controls = ($controls.Controls | Where-Object { $_.ControlId -Match $this.ControlIdContains }) } # Filter control for Tags if ($controls.Controls -and $this.Tags.Count -gt 0) { $controls.Controls = ($controls.Controls | Where-Object { ((Compare-Object $_.Tags $this.Tags -PassThru -IncludeEqual -ExcludeDifferent) | Measure-Object).Count -gt 0 }) } # Filter control for ControlSeverity if ($controls.Controls -and -not [string]::IsNullOrEmpty($this.ControlSeverity)) { $controls.Controls = ($controls.Controls | Where-Object { $this.ControlSeverity -eq $_.ControlSeverity }) } if ($controls.Controls -and $controls.Controls.Count -gt 0) { if($PolicyExpandedFlag) { $controls.Controls | Foreach-Object { if($_.FixControl) { $fixControl = "Yes" } else { $fixControl = "No" } if($_.IsBaselineControl) { $isBaselineControls = "Yes" } else { $isBaselineControls = "No" } if($_.IsPreviewBaselineControl) { $isPreviewBaselineControls = "Yes" } else { $isPreviewBaselineControls = "No" } if($this.ControlsExcludedByOrgPolicy -and $_.IsControlExcluded) { $isControlExcluded = "Yes" } else { $isControlExcluded = "No" } $ctrlObj = New-Object -TypeName PSObject $ctrlObj | Add-Member -NotePropertyName FeatureName -NotePropertyValue $controls.FeatureName $ctrlObj | Add-Member -NotePropertyName ControlID -NotePropertyValue $_.ControlID $ctrlObj | Add-Member -NotePropertyName Description -NotePropertyValue $_.Description $ctrlObj | Add-Member -NotePropertyName ControlSeverity -NotePropertyValue $_.ControlSeverity $ctrlObj | Add-Member -NotePropertyName IsBaselineControl -NotePropertyValue $isBaselineControls $ctrlObj | Add-Member -NotePropertyName IsPreviewBaselineControl -NotePropertyValue $isPreviewBaselineControls $ctrlObj | Add-Member -NotePropertyName IsControlExcluded -NotePropertyValue $isControlExcluded $ctrlObj | Add-Member -NotePropertyName Rationale -NotePropertyValue $_.Rationale $ctrlObj | Add-Member -NotePropertyName Recommendation -NotePropertyValue $_.Recommendation $ctrlObj | Add-Member -NotePropertyName Automated -NotePropertyValue $_.Automated $ctrlObj | Add-Member -NotePropertyName SupportsAutoFix -NotePropertyValue $fixControl $tags = [system.String]::Join(", ", $_.Tags) $ctrlObj | Add-Member -NotePropertyName Tags -NotePropertyValue $tags $allControls += $ctrlObj if($this.Full) { $this.PublishCustomMessage([Helpers]::ConvertObjectToString($ctrlObj, $true), [MessageType]::Info); $this.PublishCustomMessage([Constants]::SingleDashLine, [MessageType]::Info); } } } else { $controls.Controls | Foreach-Object { $_.Description = $global:ExecutionContext.InvokeCommand.ExpandString($_.Description) $_.Recommendation = $global:ExecutionContext.InvokeCommand.ExpandString($_.Recommendation) if($_.FixControl) { $fixControl = "Yes" } else { $fixControl = "No" } if($baselineControls -contains $_.ControlID) { $isBaselineControls = "Yes" } else { $isBaselineControls = "No" } if($previewBaselineControls -contains $_.ControlID) { $isPreviewBaselineControls = "Yes" } else { $isPreviewBaselineControls = "No" } if($this.ControlsExcludedByOrgPolicy -and $excludedControls -contains $_.ControlID) { $isControlExcluded = "Yes" } else { $isControlExcluded = "No" } $ControlSeverity = $_.ControlSeverity if([Helpers]::CheckMember($this.ControlSettings,"ControlSeverity.$ControlSeverity")) { $_.ControlSeverity = $this.ControlSettings.ControlSeverity.$ControlSeverity } else { $_.ControlSeverity = $ControlSeverity } $ctrlObj = New-Object -TypeName PSObject $ctrlObj | Add-Member -NotePropertyName FeatureName -NotePropertyValue $controls.FeatureName $ctrlObj | Add-Member -NotePropertyName ControlID -NotePropertyValue $_.ControlID $ctrlObj | Add-Member -NotePropertyName Description -NotePropertyValue $_.Description $ctrlObj | Add-Member -NotePropertyName ControlSeverity -NotePropertyValue $_.ControlSeverity $ctrlObj | Add-Member -NotePropertyName IsBaselineControl -NotePropertyValue $isBaselineControls $ctrlObj | Add-Member -NotePropertyName IsPreviewBaselineControl -NotePropertyValue $isPreviewBaselineControls $ctrlObj | Add-Member -NotePropertyName IsControlExcluded -NotePropertyValue $isControlExcluded $ctrlObj | Add-Member -NotePropertyName Rationale -NotePropertyValue $_.Rationale $ctrlObj | Add-Member -NotePropertyName Recommendation -NotePropertyValue $_.Recommendation $ctrlObj | Add-Member -NotePropertyName Automated -NotePropertyValue $_.Automated $ctrlObj | Add-Member -NotePropertyName SupportsAutoFix -NotePropertyValue $fixControl $tags = [system.String]::Join(", ", $_.Tags) $ctrlObj | Add-Member -NotePropertyName Tags -NotePropertyValue $tags $allControls += $ctrlObj if($this.Full) { $this.PublishCustomMessage([Helpers]::ConvertObjectToString($ctrlObj, $true), [MessageType]::Info); $this.PublishCustomMessage([Constants]::SingleDashLine, [MessageType]::Info); } } } $ctrlSummary = New-Object -TypeName PSObject $ctrlSummary | Add-Member -NotePropertyName FeatureName -NotePropertyValue $controls.FeatureName $ctrlSummary | Add-Member -NotePropertyName Total -NotePropertyValue ($controls.Controls).Count $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Critical') -NotePropertyValue (($controls.Controls | Where-Object { $_.ControlSeverity -eq $this.GetControlSeverity("Critical") })|Measure-Object).Count $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('High') -NotePropertyValue (($controls.Controls | Where-Object { $_.ControlSeverity -eq $this.GetControlSeverity("High") })|Measure-Object).Count $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Medium') -NotePropertyValue (($controls.Controls | Where-Object { $_.ControlSeverity -eq $this.GetControlSeverity("Medium") })|Measure-Object).Count $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Low') -NotePropertyValue (($controls.Controls | Where-Object { $_.ControlSeverity -eq $this.GetControlSeverity("Low") })|Measure-Object).Count $controlSummary += $ctrlSummary } } if($controlSummary.Count -gt 0) { $controlCSV = New-Object -TypeName WriteCSVData $controlCSV.FileName = 'Control_Details_' + [String] $this.InvocationContext.Mycommand.ModuleName + "_" + [String] $this.GetCurrentModuleVersion() $controlCSV.FileExtension = 'csv' $controlCSV.FolderPath = '' $controlCSV.MessageData = $allControls| Sort-Object FeatureName, ControlSeverity $this.PublishAzSKRootEvent([AzSKRootEvent]::WriteCSV, $controlCSV); } else { $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default); $this.PublishCustomMessage("No controls have been found."); $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default); } if($controlSummary.Count -gt 0) { $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default); $this.PublishCustomMessage("Summary of controls available in " + $this.InvocationContext.Mycommand.ModuleName +" "+ $this.GetCurrentModuleVersion(), [MessageType]::Default) $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default); $ctrlSummary = New-Object -TypeName PSObject $ctrlSummary | Add-Member -NotePropertyName FeatureName -NotePropertyValue "Total" $ctrlSummary | Add-Member -NotePropertyName Total -NotePropertyValue ($controlSummary | Measure-Object 'Total' -Sum).Sum $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Critical') -NotePropertyValue ($controlSummary | Measure-Object "$($this.GetControlSeverity('Critical'))" -Sum).Sum $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('High') -NotePropertyValue ($controlSummary | Measure-Object "$($this.GetControlSeverity('High'))" -Sum).Sum $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Medium') -NotePropertyValue ($controlSummary | Measure-Object "$($this.GetControlSeverity('Medium'))" -Sum).Sum $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Low') -NotePropertyValue ($controlSummary | Measure-Object "$($this.GetControlSeverity('Low'))" -Sum).Sum $totalSummaryMarker = New-Object -TypeName PSObject $totalSummaryMarker | Add-Member -NotePropertyName FeatureName -NotePropertyValue $this.SummaryMarkerText $totalSummaryMarker | Add-Member -NotePropertyName Total -NotePropertyValue $this.SummaryMarkerText $totalSummaryMarker | Add-Member -NotePropertyName $this.GetControlSeverity('Critical') -NotePropertyValue $this.SummaryMarkerText $totalSummaryMarker | Add-Member -NotePropertyName $this.GetControlSeverity('High') -NotePropertyValue $this.SummaryMarkerText $totalSummaryMarker | Add-Member -NotePropertyName $this.GetControlSeverity('Medium') -NotePropertyValue $this.SummaryMarkerText $totalSummaryMarker | Add-Member -NotePropertyName $this.GetControlSeverity('Low') -NotePropertyValue $this.SummaryMarkerText $controlSummary += $totalSummaryMarker $controlSummary += $ctrlSummary $this.PublishCustomMessage(($controlSummary | Format-Table | Out-String), [MessageType]::Default) $excludedControls = @($allControls | Where-Object {$_.IsControlExcluded -eq 'Yes'}) if($this.ControlsExcludedByOrgPolicy -and $excludedControls.Count -gt 0){ $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default); $this.PublishCustomMessage("Total no. of excluded controls: " + $excludedControls.Count , [MessageType]::Default) $this.PublishCustomMessage($this.ControlExclusionWarningMessage, [MessageType]::Warning); $this.PublishCustomMessage($this.ControlExclusionHelpLink, [MessageType]::Warning); $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default); } } # Clear the cached state [ConfigOverride]::ClearConfigInstance() } [string] GetControlSeverity($ControlSeverityFromServer) { if([Helpers]::CheckMember($this.ControlSettings,"ControlSeverity.$ControlSeverityFromServer")) { $ControlSeverityFromServer = $this.ControlSettings.ControlSeverity.$ControlSeverityFromServer } return $ControlSeverityFromServer } } class WriteCSVData { [string] $FileName = "" [string] $FileExtension = "" [string] $FolderPath = "" [PSObject] $MessageData } |