Framework/Core/SVT/SVTStatusReport.ps1
Set-StrictMode -Version Latest class SVTStatusReport : SVTCommandBase { [SVTResourceResolver] $ServicesResolver = $null; SVTStatusReport([string] $subscriptionId, [InvocationInfo] $invocationContext, [SVTResourceResolver] $resolver): Base($subscriptionId, $invocationContext) { if(-not $resolver) { throw [System.ArgumentException] ("The argument 'resolver' is null"); } $this.ServicesResolver = $resolver; $this.ServicesResolver.LoadAzureResources(); } hidden [SVTEventContext[]] RunAllControls() { [SVTEventContext[]] $result = @(); # Run all Subscription security controls try { $this.PublishCustomMessage(" `r`n" + [Constants]::DoubleDashLine + "`r`nStarted Subscription security controls`r`n" + [Constants]::DoubleDashLine); $sscore = [SubscriptionSecurityStatus]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext); if ($sscore) { # Just copy all the tags without validation. Validation will be done internally $sscore.FilterTags = $this.FilterTags; $sscore.ExcludeTags = $this.ExcludeTags; $sscore.ControlIdString = $this.ControlIdString; $sscore.ExcludeControlIdString = $this.ExcludeControlIdString; $sscore.GenerateFixScript = $this.GenerateFixScript; $sscore.AttestationOptions = $this.AttestationOptions; $result += $sscore.RunAllControls(); $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted Subscription security controls`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update); } } catch { $this.CommandError($_); } # Run all Azure services security controls try { $this.PublishCustomMessage(" `r`n" + [Constants]::DoubleDashLine + "`r`nStarted Azure services security controls`r`n" + [Constants]::DoubleDashLine); $secStatus = [ServicesSecurityStatus]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $this.ServicesResolver); if ($secStatus) { # Just copy all the tags without validation. Validation will be done internally $secStatus.FilterTags = $this.FilterTags; $secStatus.ExcludeTags = $this.ExcludeTags; $secStatus.ControlIdString = $this.ControlIdString; $secStatus.ExcludeControlIdString = $this.ExcludeControlIdString; $secStatus.GenerateFixScript = $this.GenerateFixScript; $secStatus.AttestationOptions = $this.AttestationOptions; $result += $secStatus.RunAllControls(); $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted Azure services security controls`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update); } } catch { $this.CommandError($_); } return $result; } hidden [SVTEventContext[]] FetchAttestationInfo() { [SVTEventContext[]] $result = @(); # Fetch state of all Subscription security controls try { $this.PublishCustomMessage(" `r`n" + [Constants]::DoubleDashLine + "`r`nGetting attestation info for Subscription level controls`r`n" + [Constants]::DoubleDashLine); $sscore = [SubscriptionSecurityStatus]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext); if ($sscore) { # Just copy all the tags without validation. Validation will be done internally $sscore.ControlIdString = $this.ControlIdString; $sscore.AttestationOptions = $this.AttestationOptions; $result += $sscore.FetchAttestationInfo(); if(($result|Measure-object).count -gt 0) { $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted Subscription level controls`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update); } elseif([string]::IsNullOrWhiteSpace($sscore.ControlIdString)) { $this.PublishCustomMessage([Constants]::SingleDashLine + "`r`nNo attestation data found for Subscription level controls`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update) } } } catch { $this.CommandError($_); } # Fetch state of all Azure services security controls try { $this.PublishCustomMessage(" `r`n" + [Constants]::DoubleDashLine + "`r`nGetting attestation info for Azure services controls`r`n" + [Constants]::DoubleDashLine); $secStatus = [ServicesSecurityStatus]::new($this.SubscriptionContext.SubscriptionId, $this.InvocationContext, $this.ServicesResolver); if ($secStatus) { # Just copy all the tags without validation. Validation will be done internally $secStatus.ControlIdString = $this.ControlIdString; #$secStatus.GenerateFixScript = $this.GenerateFixScript; $secStatus.AttestationOptions = $this.AttestationOptions; $secStatusResult = $secStatus.FetchAttestationInfo() if(($secStatusResult|Measure-Object).Count -gt 0) { $result += $secStatusResult $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nCompleted Azure services controls`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update); } else { $this.PublishCustomMessage([Constants]::SingleDashLine + "`r`nNo attestation data found for Azure services controls`r`n" + [Constants]::DoubleDashLine, [MessageType]::Update) } } } catch { $this.CommandError($_); } #display summary if(($result|Measure-Object).Count -gt 0) { $this.DisplayAttetstationStatistics($result) } else { } return $result; } hidden [void] DisplayAttetstationStatistics([SVTEventContext[]] $Result) { $this.PublishCustomMessage("`r`n"+[Constants]::DoubleDashLine+"`r`nSummary of attestation details:`r`n`r`n"); $this.DisplayAttestationStatusWiseControlsCount($Result); $this.DisplaySeverityWiseControlsCount($Result); $this.DisplayControlIdWiseCount($Result) $this.DisplayExpiryDateWiseControlsCount($Result); } hidden [void] DisplayAttestationStatusWiseControlsCount([SVTEventContext[]] $Result) { $subCoreResult = $Result|Where-Object{!$_.IsResource()}; $resResult = $Result|Where-Object{$_.IsResource()}; if(($subCoreResult|Measure-Object).Count -gt 0) { $subCoreGroup = $subCoreResult.ControlResults|Group-Object ActualVerificationResult,AttestationStatus | ForEach{ [pscustomobject]@{ 'ActualVerificationResult'=$_.Group[0].ActualVerificationResult 'AttestationStatus'=$_.Group[0].AttestationStatus 'ControlsCount'=$_.count} } $this.PublishCustomMessage([Constants]::SingleDashLine+"`r`nSubscription controls:`r`n"+($subCoreGroup|out-string)) $this.PublishCustomMessage([Constants]::SingleDashLine) } if(($resResult|Measure-Object).Count -gt 0) { $resGroup = $resResult.ControlResults|Group-Object ActualVerificationResult,AttestationStatus | ForEach{ [pscustomobject]@{ 'ActualVerificationResult'=$_.Group[0].ActualVerificationResult 'AttestationStatus'=$_.Group[0].AttestationStatus 'ControlsCount'=$_.count} } $this.PublishCustomMessage("Azure Services controls:`r`n"+($resGroup|out-string)) $this.PublishCustomMessage([Constants]::DoubleDashLine) } } hidden [void] DisplaySeverityWiseControlsCount([SVTEventContext[]] $Result) { $groupResult = $Result.ControlItem| Group ControlSeverity | ForEach{ [pscustomobject]@{ 'ControlSeverity'=$_.name 'ControlsCount'=$_.count} } $this.PublishCustomMessage("Distribution of attested controls by severity:`r`n"+($groupResult|out-string)) $this.PublishCustomMessage([Constants]::DoubleDashLine); } hidden [void] DisplayControlIdWiseCount([SVTEventContext[]] $Result) { $groupResult = $Result.ControlItem| Group ControlId | ForEach{ [pscustomobject]@{ 'ControlId'=$_.name 'ControlsCount'=$_.count} } $this.PublishCustomMessage("Distribution of controls that have been attested:`r`n"+($groupResult|out-string)); $this.PublishCustomMessage([Constants]::DoubleDashLine); } hidden [void] DisplayExpiryDateWiseControlsCount([SVTEventContext[]] $Result) { $subCoreResult = $Result|Where-Object{!$_.IsResource()}; $resResult = $Result|Where-Object{$_.IsResource()}; $expiringSubControls = @() $expiringStateResources = @() if(($subCoreResult|Measure-Object).Count -gt 0) { $subControlsWithExpDate = $subCoreResult | Where-Object{ $_.ControlResults|Where-Object{![string]::IsNullOrWhiteSpace($_.StateManagement.AttestedStateData.ExpiryDate)}} $expiringSubControls= $subControlsWithExpDate | Where-Object{ $_.ControlResults | Where-Object{([datetime]$_.StateManagement.AttestedStateData.ExpiryDate - $(Get-Date).ToUniversalTime()).TotalDays -le 30}} } if(($resResult|Measure-Object).Count -gt 0) { $resourcesWithExpDate = $resResult | Where-Object{ $_.ControlResults|Where-Object{![string]::IsNullOrWhiteSpace($_.StateManagement.AttestedStateData.ExpiryDate)}} $expiringStateResources = $resourcesWithExpDate | Where-Object{ $_.ControlResults | Where-Object{([datetime]$_.StateManagement.AttestedStateData.ExpiryDate - $(Get-Date).ToUniversalTime()).TotalDays -le 30}} } if(($expiringSubControls|Measure-Object).Count -gt 0 -or ($expiringStateResources|Measure-Object).Count -gt 0) { $expiringSubControls15Days= $expiringSubControls | Where-Object{ $_.ControlResults | Where-Object{([datetime]$_.StateManagement.AttestedStateData.ExpiryDate - $(Get-Date).ToUniversalTime()).TotalDays -le 15}} $expiringStateResources15Days = $expiringStateResources | Where-Object{ $_.ControlResults | Where-Object{([datetime]$_.StateManagement.AttestedStateData.ExpiryDate - $(Get-Date).ToUniversalTime()).TotalDays -le 15}} $expiringSubControls7Days= $expiringSubControls | Where-Object{ $_.ControlResults | Where-Object{([datetime]$_.StateManagement.AttestedStateData.ExpiryDate - $(Get-Date).ToUniversalTime()).TotalDays -le 7}} $expiringStateResources7Days = $expiringStateResources | Where-Object{ $_.ControlResults | Where-Object{([datetime]$_.StateManagement.AttestedStateData.ExpiryDate - $(Get-Date).ToUniversalTime()).TotalDays -le 7}} $this.PublishCustomMessage("Summary of controls expiring in near future:`r`n`r`nDays CountOfSubscriptionControls CountOfAzureServicesControls`r`n"+[Constants]::SingleDashLine); if(($expiringSubControls7Days|Measure-Object).Count -gt 0 -or ($expiringStateResources7Days|Measure-Object).Count -gt 0) { $this.PublishCustomMessage("07`t`t$(($expiringSubControls7Days|Measure-Object).Count)`t`t`t`t`t`t`t$(($expiringStateResources7Days|Measure-Object).Count)"); } if(($expiringSubControls15Days|Measure-Object).Count -gt 0 -or ($expiringStateResources15Days|Measure-Object).Count -gt 0) { $this.PublishCustomMessage("15`t`t$(($expiringSubControls15Days|Measure-Object).Count)`t`t`t`t`t`t`t$(($expiringStateResources15Days|Measure-Object).Count)`t`t`t`t"); } $this.PublishCustomMessage("30`t`t$(($expiringSubControls|Measure-Object).Count)`t`t`t`t`t`t`t$(($expiringStateResources|Measure-Object).Count)`t`t`t`t`r`n`r`n"); $this.PublishCustomMessage("Recommendation: Check Attestation report to get details of expiring controls and fix/attest them before expiry.",[MessageType]::Warning); } else { $this.PublishCustomMessage([Constants]::SingleDashLine+"`r`n`r`nCount of Controls expiring in the next 30 days: 0`r`n"); } } } |