Framework/Core/AzureMonitoring/OMSMonitoring.ps1
Set-StrictMode -Version Latest class OMSMonitoring: CommandBase { [string] $OMSSampleViewTemplateFilepath; [string] $OMSSearchesTemplateFilepath; [string] $OMSAlertsTemplateFilepath; [string] $OMSGenericTemplateFilepath; [string] $OMSLocation; [string] $OMSResourceGroup; [string] $OMSWorkspaceName; [string] $OMSWorkspaceId; [string] $ApplicationSubscriptionName OMSMonitoring([string] $_omsSubscriptionId,[string] $_omsResourceGroup,[string] $_omsWorkspaceId, [InvocationInfo] $invocationContext): Base([string] $_omsSubscriptionId, $invocationContext) { $this.OMSResourceGroup = $_omsResourceGroup $this.OMSWorkspaceId = $_omsWorkspaceId $omsWorkSpaceInstance = Get-AzureRmOperationalInsightsWorkspace | Where-Object {$_.CustomerId -eq "$_omsWorkspaceId" -and $_.ResourceGroupName -eq "$($this.OMSResourceGroup)"} if($null -eq $omsWorkSpaceInstance) { throw [SuppressedException] "Invalid OMS Workspace." } $this.OMSWorkspaceName = $omsWorkSpaceInstance.Name; $locationInstance = Get-AzureRmLocation | Where-Object { $_.DisplayName -eq $omsWorkSpaceInstance.Location -or $_.Location -eq $omsWorkSpaceInstance.Location } $this.OMSLocation = $locationInstance.Location } [void] ConfigureOMS([string] $_applicationSubscriptionId,[string] $_applicationResourceGroups,[string] $_viewName,[string] $_securityContactEmails,[OMSInstallationOption] $_omsInstallationOption, [bool] $_validateOnly, [bool] $_useOMSModel) { $this.PublishCustomMessage([Constants]::DoubleDashLine + "`r`nStarted setting up AzSDK OMS solution pack`r`n"+[Constants]::DoubleDashLine); $OptionalParameters = New-Object -TypeName Hashtable #the default installation option is All if($null -eq $_omsInstallationOption) { $OMSInstallationOption = [OMSInstallationOption]::All } $OMSLogPath = [Constants]::AzSdkTempFolderPath + "\OMS"; if(-not (Test-Path -Path $OMSLogPath)) { mkdir -Path $OMSLogPath -Force | Out-Null } if($_useOMSModel) { [MessageData] $data = [MessageData]@{ Message = "`nSetting up OMS view using old query language."; MessageType = [MessageType]::Warning; }; $this.PublishCustomMessage($data) $appSub = Get-AzureRmSubscription -SubscriptionId $_applicationSubscriptionId $this.ApplicationSubscriptionName = $appSub.Name if([OMSInstallationOption]::All -eq $_omsInstallationOption -or [OMSInstallationOption]::Queries -eq $_omsInstallationOption) { $searchesTemplateFilepath = [ConfigurationManager]::LoadServerConfigFile("AzSDK.AM.OMS.Searches.omsview"); $this.OMSSearchesTemplateFilepath = $OMSLogPath+"\AzSDK.AM.OMS.Searches.omsview"; $searchesTemplateFilepath | ConvertTo-Json -Depth 100 | Out-File $this.OMSSearchesTemplateFilepath $this.PublishCustomMessage("`r`nSetting up OMS search queries."); $this.ConfigureSearches($_validateOnly); } if([OMSInstallationOption]::All -eq $_omsInstallationOption -or [OMSInstallationOption]::Alerts -eq $_omsInstallationOption) { $alertsTemplateFilepath = [ConfigurationManager]::LoadServerConfigFile("AzSDK.AM.OMS.Alerts.omsview"); $this.OMSAlertsTemplateFilepath = $OMSLogPath+"\AzSDK.AM.OMS.Alerts.omsview"; $alertsTemplateFilepath | ConvertTo-Json -Depth 100 | Out-File $this.OMSAlertsTemplateFilepath $this.PublishCustomMessage("`r`nSetting up OMS alerts."); $this.ConfigureAlerts($_viewName, $_securityContactEmails, $_validateOnly); } if([OMSInstallationOption]::All -eq $_omsInstallationOption -or [OMSInstallationOption]::SampleView -eq $_omsInstallationOption) { $sampleViewTemplateFilepath = [ConfigurationManager]::LoadServerConfigFile("AzSDK.AM.OMS.SampleView.omsview"); $this.OMSSampleViewTemplateFilepath = $OMSLogPath+"\AzSDK.AM.OMS.SampleView.omsview"; $sampleViewTemplateFilepath | ConvertTo-Json -Depth 100 | Out-File $this.OMSSampleViewTemplateFilepath $this.PublishCustomMessage("`r`nSetting up OMS sample view."); $this.ConfigureSampleView($_viewName, $_applicationResourceGroups, $_validateOnly); } if([OMSInstallationOption]::All -eq $_omsInstallationOption -or [OMSInstallationOption]::GenericView -eq $_omsInstallationOption) { $sampleViewTemplateFilepath = [ConfigurationManager]::LoadServerConfigFile("AZSDK.AM.OMS.GenericView.V1.omsview"); $this.OMSGenericTemplateFilepath = $OMSLogPath+"\AZSDK.AM.OMS.GenericView.V1.omsview"; $sampleViewTemplateFilepath | ConvertTo-Json -Depth 100 | Out-File $this.OMSGenericTemplateFilepath $this.PublishCustomMessage("`r`nSetting up OMS AzSDK Generic view."); $this.ConfigureGenericView($_viewName, $_validateOnly); } } else { $genericViewTemplateFilepath = [ConfigurationManager]::LoadServerConfigFile("AZSDK.AM.OMS.GenericView.V2.omsview"); $this.OMSGenericTemplateFilepath = $OMSLogPath+"\AZSDK.AM.OMS.GenericView.V2.omsview"; $genericViewTemplateFilepath | ConvertTo-Json -Depth 100 | Out-File $this.OMSGenericTemplateFilepath $this.PublishCustomMessage("`r`nSetting up OMS AzSDK generic view."); $this.ConfigureGenericView($_viewName, $_validateOnly); } $this.PublishCustomMessage([Constants]::SingleDashLine + "`r`nWe have added new queries for the OMS solution. These will help reflect the aggregate control pass/fail status more accurately. Please go here to get them: https://aka.ms/azsdk/omsqueries `r`n",[MessageType]::Warning); $this.PublishCustomMessage([Constants]::SingleDashLine + "`r`nCompleted setting up AzSDK OMS solution pack.`r`n"+[Constants]::DoubleDashLine); } [void] ConfigureGenericView([string] $_viewName, [bool] $_validateOnly) { $OptionalParameters = New-Object -TypeName Hashtable $OptionalParameters = $this.GetOMSGenericViewParameters($_viewName); $this.PublishCustomMessage([MessageData]::new("Starting template deployment for OMS generic view. Detailed logs are shown below.")); $ErrorMessages = @() if ($_validateOnly) { $ErrorMessages =@() Test-AzureRmResourceGroupDeployment -ResourceGroupName $this.OMSResourceGroup ` -TemplateFile $this.OMSGenericTemplateFilepath ` -TemplateParameterObject $OptionalParameters -Verbose } else { $ErrorMessages =@() $SubErrorMessages = @() New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $this.OMSGenericTemplateFilepath).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $this.OMSResourceGroup ` -TemplateFile $this.OMSGenericTemplateFilepath ` -TemplateParameterObject $OptionalParameters ` -Verbose -Force -ErrorVariable SubErrorMessages $SubErrorMessages = $SubErrorMessages | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") } $ErrorMessages += $SubErrorMessages } if ($ErrorMessages) { "", ("{0} returned the following errors:" -f ("Template deployment", "Validation")[[bool]$_validateOnly]), @($ErrorMessages) | ForEach-Object { $this.PublishCustomMessage([MessageData]::new($_));} } else { $this.PublishCustomMessage([MessageData]::new("Completed template deployment for OMS generic view.")); } } [void] ConfigureSampleView([string] $_applicationName, [string] $_applicationResourceGroups, [bool] $_validateOnly) { $OptionalParameters = New-Object -TypeName Hashtable $_query = $this.GetOMSAppQuery($_applicationResourceGroups); $OptionalParameters = $this.GetOMSSampleViewParameters($_applicationName, $_query); $this.PublishCustomMessage([MessageData]::new("Starting template deployment for OMS sample view. Detailed logs are shown below.")); $ErrorMessages = @() if ($_validateOnly) { $ErrorMessages =@() Test-AzureRmResourceGroupDeployment -ResourceGroupName $this.OMSResourceGroup ` -TemplateFile $this.OMSSampleViewTemplateFilepath ` -TemplateParameterObject $OptionalParameters -Verbose } else { $ErrorMessages =@() $SubErrorMessages = @() New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $this.OMSSampleViewTemplateFilepath).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $this.OMSResourceGroup ` -TemplateFile $this.OMSSampleViewTemplateFilepath ` -TemplateParameterObject $OptionalParameters ` -Verbose -Force -ErrorVariable SubErrorMessages $SubErrorMessages = $SubErrorMessages | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") } $ErrorMessages += $SubErrorMessages } if ($ErrorMessages) { "", ("{0} returned the following errors:" -f ("Template deployment", "Validation")[[bool]$_validateOnly]), @($ErrorMessages) | ForEach-Object { $this.PublishCustomMessage([MessageData]::new($_));} } else { $this.PublishCustomMessage([MessageData]::new("Completed template deployment for OMS sample view.")); } } [void] ConfigureSearches([bool] $_validateOnly) { $OptionalParameters = New-Object -TypeName Hashtable $savedSearches = Get-AzureRmOperationalInsightsSavedSearch -ResourceGroupName $this.OMSResourceGroup -WorkspaceName $this.OMSWorkspaceName $azSdkSearches = @() if($savedSearches -ne $null -and $savedSearches.Value -ne $null) { $savedSearches.Value | %{ Set-Variable -Name savedSearch -Value $_ if($savedSearch.Properties -ne $null -and $savedSearch.Properties.Category -like "AzSDK_Searches*") { $azSdkSearches += $savedSearch } } } if($azSdkSearches.Length -gt 0) { return; } $OptionalParameters = $this.GetOMSBaseParameters(); $this.PublishCustomMessage([MessageData]::new("Starting template deployment for OMS sample search queries. Detailed logs are shown below.")); $ErrorMessages = @() if ($_validateOnly) { $ErrorMessages =@() Test-AzureRmResourceGroupDeployment -ResourceGroupName $this.OMSResourceGroup ` -TemplateFile $this.OMSSearchesTemplateFilepath ` -TemplateParameterObject $OptionalParameters -Verbose } else { $ErrorMessages =@() $SubErrorMessages = @() New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $this.OMSSearchesTemplateFilepath).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $this.OMSResourceGroup ` -TemplateFile $this.OMSSearchesTemplateFilepath ` -TemplateParameterObject $OptionalParameters ` -Verbose -Force -ErrorVariable SubErrorMessages $SubErrorMessages = $SubErrorMessages | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") } $ErrorMessages += $SubErrorMessages } if ($ErrorMessages) { "", ("{0} returned the following errors:" -f ("Template deployment", "Validation")[[bool] $_validateOnly]), @($ErrorMessages) | ForEach-Object { $this.PublishCustomMessage([MessageData]::new($_));} } else { $this.PublishCustomMessage([MessageData]::new("Completed template deployment for OMS sample search queries.")); } } [void] ConfigureAlerts([string] $_applicationName, [string] $_alertemails, [bool] $_validateOnly) { $OptionalParameters = New-Object -TypeName Hashtable $OptionalParameters = $this.GetOMSAlertParameters($_applicationName, $_alertemails); $this.PublishCustomMessage([MessageData]::new("Starting template deployment for OMS sample alerts. Detailed logs are shown below.")); $ErrorMessages = @() if ($_validateOnly) { $ErrorMessages =@() Test-AzureRmResourceGroupDeployment -ResourceGroupName $this.OMSResourceGroup ` -TemplateFile $this.OMSAlertsTemplateFilepath ` -TemplateParameterObject $OptionalParameters -Verbose } else { $ErrorMessages =@() $SubErrorMessages = @() New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $this.OMSAlertsTemplateFilepath).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) ` -ResourceGroupName $this.OMSResourceGroup ` -TemplateFile $this.OMSAlertsTemplateFilepath ` -TemplateParameterObject $OptionalParameters ` -Verbose -Force -ErrorVariable SubErrorMessages $SubErrorMessages = $SubErrorMessages | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") } $ErrorMessages += $SubErrorMessages } if ($ErrorMessages) { "", ("{0} returned the following errors:" -f ("Template deployment", "Validation")[[bool]$_validateOnly]), @($ErrorMessages) | ForEach-Object { $this.PublishCustomMessage([MessageData]::new($_));} } else { $this.PublishCustomMessage([MessageData]::new("Completed template deployment for OMS sample alerts.")); } } [void] UninstallOMSPack() { $this.PublishCustomMessage("Started Clean up of OMS Security Solution pack"); #Get all the searches with the name of AzSDK $savedSearches = Get-AzureRmOperationalInsightsSavedSearch -ResourceGroupName $this.OMSResourceGroup -WorkspaceName $this.OMSWorkspaceName $azSdkSearches = @() if($savedSearches -ne $null -and $savedSearches.Value -ne $null) { $savedSearches.Value | %{ Set-Variable -Name savedSearch -Value $_ if($savedSearch.Properties -ne $null -and $savedSearch.Properties.Category -like "*AzSDK*") { $azSdkSearches += $savedSearch } } } $RequestURI= [Constants]::OMSRequestURI $accessToken = [Helpers]::GetAccessToken([Constants]::ARMManagementUri); $header = "Bearer " + $accessToken $headers = @{"Authorization"=$header;"Content-Type"="application/json"} $schedules = $null $azSdkSearches | %{ Set-Variable -Name azSdkSearch -Value $_ $azSdkSearchId = $azSdkSearch.Id.Replace($azSdkSearch.Properties.DisplayName.ToLower(),$azSdkSearch.Properties.DisplayName) Set-Variable -Name scheduleURI $scheduleURI = ($RequestURI -f ($azSdkSearchId +"/schedules")) #Get all the Schedules configured using this search $result = "" $err = $null; try { $result = Invoke-WebRequest -Method GET -Uri $scheduleURI -Headers $headers } catch{ $err = $_ } if($result.StatusCode -ge 200 -and $result.StatusCode -le 399){ if($result.Content -ne $null){ $json = (ConvertFrom-Json $result.Content) if($json -ne $null){ $schedules = $json if($json.value -ne $null) { $schedules = $json.value } } } } if($err -ne $null) { if($err.ErrorDetails.Message -ne $null){ $json = (ConvertFrom-Json $err.ErrorDetails.Message) if($json -ne $null){ $return = $json if($json.'odata.error'.code -eq "Request_ResourceNotFound") { $return = $json.'odata.error'.message } } } return $null } $actions = $null; #Get AlertActions if($schedules -ne $null) { $schedules | %{ Set-Variable -Name schedule -Value $_ Set-Variable -Name actionsURI if(Get-Member -InputObject $schedule -Name id) { $actionsURI = ($RequestURI -f ($schedule.Id +"/Actions")) #Get all the actions configured using this search $result = "" $err = $null; try { $result = Invoke-WebRequest -Method GET -Uri $actionsURI -Headers $headers } catch{ $err = $_ } if($result.StatusCode -ge 200 -and $result.StatusCode -le 399){ if($result.Content -ne $null){ $json = (ConvertFrom-Json $result.Content) if($json -ne $null){ $actions = $json if($json.value -ne $null) { $actions = $json.value } } } } if($err -ne $null) { if($err.ErrorDetails.Message -ne $null){ $json = (ConvertFrom-Json $err.ErrorDetails.Message) if($json -ne $null){ $return = $json if($json.'odata.error'.code -eq "Request_ResourceNotFound") { $return = $json.'odata.error'.message } } } return $null } if($actions -ne $null) { $actions | %{ Set-Variable -Name action -Value $_ if(Get-Member -InputObject $actions -Name name) { $subValues = $action.name.Split("|",[StringSplitOptions]::RemoveEmptyEntries) if($subValues.Length -gt 0) { $actionid = $subValues[$subValues.Length-1] Set-Variable -Name actionURI $actionURI = ($RequestURI -f ($schedule.Id+"/Actions/"+$actionid)) #Get all the actions configured using this search $result = "" $err = $null; try { $result = Invoke-WebRequest -Method DELETE -Uri $actionURI -Headers $headers $this.PublishCustomMessage($action.Id + " : Deleted") } catch{ $err = $_ } if($result.StatusCode -ge 200 -and $result.StatusCode -le 399){ if($result.Content -ne $null){ $json = (ConvertFrom-Json $result.Content) if($json -ne $null){ $actions = $json if($json.value -ne $null) { $actions = $json.value } } } } if($err -ne $null) { if($err.ErrorDetails.Message -ne $null){ $json = (ConvertFrom-Json $err.ErrorDetails.Message) if($json -ne $null){ $return = $json if($json.'odata.error'.code -eq "Request_ResourceNotFound") { $return = $json.'odata.error'.message } } } return $null } } } #TODO Message } } #clean up schedule Set-Variable -Name scheduleURI $scheduleURI = ($RequestURI -f $schedule.Id) #Get all the actions configured using this search $result = "" try { $result = Invoke-WebRequest -Method DELETE -Uri $scheduleURI -Headers $headers $this.PublishCustomMessage($schedule.Id + " : Deleted") } catch{ $err = $_ } if($result.StatusCode -ge 200 -and $result.StatusCode -le 399){ if($result.Content -ne $null){ $json = (ConvertFrom-Json $result.Content) if($json -ne $null){ $actions = $json if($json.value -ne $null) { $actions = $json.value } } } } if($err -ne $null) { if($err.ErrorDetails.Message -ne $null){ $json = (ConvertFrom-Json $err.ErrorDetails.Message) if($json -ne $null){ $return = $json if($json.'odata.error'.code -eq "Request_ResourceNotFound") { $return = $json.'odata.error'.message } } } return $null } } } } #Done cleaning up all the schedules and actions } #Finally remove the saved search $azSdkSearches | ForEach-Object { $tempAzSDKSearch = $_; Remove-AzureRmOperationalInsightsSavedSearch -ResourceGroupName $this.OMSResourceGroup -WorkspaceName $this.OMSWorkspaceName -SavedSearchId $tempAzSDKSearch.Properties.DisplayName $this.PublishCustomMessage($tempAzSDKSearch.Id + " : Deleted"); } $this.PublishCustomMessage("Completed clean up of OMS Security Solution pack."); } [Hashtable] GetOMSBaseParameters() { [Hashtable] $omsParams = @{}; $omsParams.Add("omsWorkspaceLocation",$this.OMSLocation); $omsParams.Add("omsResourcegroup",$this.OMSResourceGroup); $omsParams.Add("omsSubscriptionId",$this.SubscriptionContext.SubscriptionId); $omsParams.Add("omsWorkspaceName",$this.OMSWorkspaceName); return $omsParams; } [Hashtable] GetOMSAlertParameters([string] $_applicationName, [string] $_alertemails) { $uniqueID = (Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss"); $emailList = $_alertemails.Split(",",[StringSplitOptions]::RemoveEmptyEntries) [Hashtable] $omsParams = $this.GetOMSBaseParameters(); $omsParams.Add("alertEmailsPointOfContact",$emailList); $omsParams.Add("appName",$_applicationName); $omsParams.Add("uniqueId",$uniqueID); $omsParams.Add("applicationSubscriptionName",$this.ApplicationSubscriptionName); return $omsParams; } [Hashtable] GetOMSSampleViewParameters([string] $_applicationName,[string] $_query) { [Hashtable] $omsParams = $this.GetOMSBaseParameters(); $omsParams.Add("appName",$_applicationName); $omsParams.Add("query",$_query); $omsParams.Add("applicationSubscriptionName",$this.ApplicationSubscriptionName); return $omsParams; } [Hashtable] GetOMSGenericViewParameters([string] $_applicationName) { [Hashtable] $omsParams = $this.GetOMSBaseParameters(); $omsParams.Add("viewName",$_applicationName); return $omsParams; } [string] GetOMSAppQuery([string] $_resourceGroups) { $rgQueryFormat = "ResourceGroup=""{0 }""" $queryOutput = "" $resourceGroupList = $_resourceGroups.Split(',',[StringSplitOptions]::RemoveEmptyEntries); if($resourceGroupList.Length -gt 0) { $resourceGroupList | ForEach-Object { if([string]::IsNullOrWhiteSpace($queryOutput)) { $queryOutput = $rgQueryFormat -f $_ } else { $queryOutput += " OR " + [string]::Format($rgQueryFormat, $_); } } } return $queryOutput; } } |