SendEffectiveConfiguration.psm1

<#
 .Synopsis
  Collects monitor and rule data from SCOM and sends it to OMS HTTP Data Collector API.
 
 .Description
  The collected data will be presented in OMS via custom solution. This module is for collecting and sending the monitor and rule overrides to OMS.
 
 .Parameter GroupDisplayName
  Display name of a SCOM group where objects are contained.
 
 .Parameter ManagementServer
  SCOM management server to connect to.
 
 .Parameter CustomerID
  OMS Workspace GUID
 
 .Parameter SharedKey
  Primary key of the workspace provided in OMS.
 
 .Example
   # Send-EffectiveConfiguration -GroupDisplayName "All Windows Computers" -ManagementServer SCOM -CustomerId '[Workspace GUID]' -SharedKey '[Workspace primary key]' -Verbose
 
#>

Function Send-EffectiveConfiguration
{
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true,HelpMessage = 'Please specify a SCOM group display name.')]
        [ValidateNotNullOrEmpty()]
        [String]$GroupDisplayName, 

        [Parameter(Mandatory = $true,HelpMessage = 'Please specify a SCOM management server display name.')]
        [ValidateNotNullOrEmpty()]
        [String]$ManagementServer, 

        [Parameter(Mandatory = $true,HelpMessage = 'Please specify a workspace id (OMS).')]
        [ValidateNotNullOrEmpty()]
        [String]$CustomerID, 
    
        [Parameter(Mandatory = $true,HelpMessage = 'Please specify a primary key (OMS).')]
        [ValidateNotNullOrEmpty()]
        [String]$SharedKey
    )
    Try
    {
        Write-Verbose -Message 'Importing OperationsManager module [Send-EffectiveConfiguration]'
        Import-Module -Name OperationsManager
        Write-Verbose -Message ('Creating connection to {0} [Send-EffectiveConfiguration]' -f $ManagementServer)
        New-SCOMManagementGroupConnection -ComputerName $ManagementServer
    }
    Catch
    {
        Throw ('Could not Import OperationsManager module or connection failed. Exception: {0}' -f $_.Exception.InnerException)
    }

    Try
    {
        Write-Verbose -Message ('Getting SCOM class {0} [Send-EffectiveConfiguration]' -f $GroupDisplayName)
        $GroupClass = Get-SCOMClass -DisplayName $GroupDisplayName
        Write-Verbose -Message 'Getting SCOM objects [Send-EffectiveConfiguration]'
        $GroupObject = Get-SCOMMonitoringObject -Class $GroupClass
        Write-Verbose -Message 'Getting related monitoring objects [Send-EffectiveConfiguration]'
        $GroupMembers = $GroupObject.GetRelatedMonitoringObjects()
    }
    Catch
    {
        Throw ('Could not get SCOM class {0}. Exception: {1}' -f $GroupDisplayName, $_.Exception.InnerException)
    }

    If ($GroupMembers)
    {
        Try
        {
            Write-Verbose -Message ('Group {0} members found [Send-EffectiveConfiguration]' -f $GroupMembers.count)
            ForEach($Member in $GroupMembers)
            {
                Write-Verbose -Message ('Getting workflows for {0} [Send-EffectiveConfiguration]' -f $Member.Name)
                $Workflows = (Get-SCOMManagementGroup).EffectiveMonitoring.GetAllEffectiveMonitoringWorkflows($Member.id,$true)
                $Rules = @()
                $Monitors = @()
                Foreach ($Workflow in $Workflows)
                {
                    Write-Verbose -Message ('Determing rule or monitor for {0}' -f $Workflow.WorkflowName)
                    If ($Workflow.Type -eq 'Rule')
                    {
                        $Object = (Get-SCOMRule -id $Workflow.WorkflowId)
                        $Properties = @{}
                        $Properties.Add('Type', 'Rule')
                        $Properties.Add('Overridden', $Workflow.Overridden)
                        $Properties.Add('ManagementPack', $Object.ManagementPackName)
                        $Properties.Add('DisplayName', $Object.DisplayName)
                        $Properties.Add('Enabled', $Object.Enabled)
                        $Properties.Add('TargetObject', $Workflow.EntityName)
                        $Properties.Add('TargetClass', $Workflow.EntityTypeName)
                        $Properties.Add('LastModified', $Object.LastModified)

                        ForEach ($Param in $Workflow.OverrideableParameters)
                        {
                            $Properties.Add("$($Param.ParameterName)_D", $Param.DefaultValue)
                            $Properties.Add("$($Param.ParameterName)_E", $Param.EffectiveValue)
                        }


                        $Rules += New-Object -TypeName PSObject -Property $Properties  
                    }
                    ElseIf ($Workflow.Type -eq 'Monitor')
                    {
                        $Object = (Get-SCOMMonitor -id $Workflow.WorkflowId)
                        $Properties = @{}
                        $Properties.Add('Type', 'Monitor')
                        $Properties.Add('Overridden', $Workflow.Overridden)
                        $Properties.Add('ManagementPack', $Object.GetManagementPack().Name)
                        $Properties.Add('DisplayName', $Object.DisplayName)
                        $Properties.Add('Enabled', $Object.Enabled)
                        $Properties.Add('TargetObject', $Workflow.EntityName)
                        $Properties.Add('TargetClass', $Workflow.EntityTypeName)
                        $Properties.Add('LastModified', $Object.LastModified)

                        If ($Workflow.OverrideableParameters)
                        {
                            ForEach ($Param in $Workflow.OverrideableParameters)
                            {
                                $Properties.Add("$($Param.ParameterName)_D", $Param.DefaultValue)
                                $Properties.Add("$($Param.ParameterName)_E", $Param.EffectiveValue)
                            }
                        }

                        $Monitors += New-Object -TypeName PSObject -Property $Properties
                    }
                }
                Write-Verbose -Message 'Calling Post-OMSData function for monitors'
                Post-OMSData -CustomerId $CustomerID -SharedKey $SharedKey -Body ($Monitors  | ConvertTo-Json) -LogType 'EffMonitor'
                Write-Verbose -Message 'Calling Post-OMSData function for rules'
                Post-OMSData -CustomerId $CustomerID -SharedKey $SharedKey -Body ($Rules  | ConvertTo-Json) -LogType 'EffRule'
            }
        }
        catch
        {
            Write-Verbose -Message ('{0} generated an error. Error {1}' -f $Workflow.Name, $_.Error.Message)
        }
    }
    Else
    {
        Throw ('Provided group {0} does not contain any members' -f $GroupDisplayName)
    }
}

Function Build-Signature 
{
    Param (
        [String]$CustomerID,
        [string]$SharedKey,
        [string]$Date,
        [int]$ContentLength,
        [string]$Method,
        [string]$ContentType,
        [string]$Resource
    )

    Write-Verbose -Message 'Preparing header data [Build-Signature]'
    $xHeaders = "x-ms-date:" + $Date
    $StringToHash = $Method + "`n" + $ContentLength + "`n" + $ContentType + "`n" + $xHeaders + "`n" + $Resource
    Write-Verbose -Message 'Encoding header data [Build-Signature]'
    $BytesToHash = [Text.Encoding]::UTF8.GetBytes($StringToHash)
    $KeyBytes = [Convert]::FromBase64String($SharedKey)
    Write-Verbose -Message 'Encrypting data [Build-Signature]'
    $SHA256 = New-Object System.Security.Cryptography.HMACSHA256
    $SHA256.Key = $KeyBytes
    $CalculatedHash = $SHA256.ComputeHash($BytesToHash)
    $EncodedHash = [Convert]::ToBase64String($CalculatedHash)
    $Authorization = 'SharedKey {0}:{1}' -f $CustomerID,$EncodedHash
    Write-Verbose -Message 'Returning authorization [Build-Signature]'
    return $Authorization
}

#Function to create and post the request
Function Post-OMSData
{
    Param(
        [String]$CustomerID,
        [string]$SharedKey,
        [string]$Body,
        [string]$LogType
    )
    Write-Verbose -Message 'Preparing URI [Post-OMSData]'
    $TimeStampField=""
    $Method = "POST"
    $ContentType = "application/json"
    $Resource = "/api/logs"
    $rfc1123date = [DateTime]::UtcNow.ToString("r")
    $ContentLength = $Body.Length
    $Signature = Build-Signature `
    -customerId $CustomerID `
    -sharedKey $SharedKey `
    -date $rfc1123date `
    -contentLength $ContentLength `
    -fileName $fileName `
    -method $Method `
    -contentType $ContentType `
    -resource $Resource
    $URI = "https://" + $CustomerID + ".ods.opinsights.azure.com" + $Resource + "?api-version=2016-04-01"
    Write-Verbose -Message 'Preparing Header [Post-OMSData]'
    $Headers = @{
        "Authorization" = $Signature;
        "Log-Type" = $LogType;
        "x-ms-date" = $rfc1123date;
        "time-generated-field" = $TimeStampField;
    }

    #$Response = Invoke-WebRequest -Uri $URI -Method $Method -ContentType $ContentType -Headers $Headers -Body $Body -UseBasicParsing
     Try
    {
        Write-Verbose -Message 'Trying to send data [Post-OMSData]'
        $Response = Invoke-WebRequest -Uri $Uri -Method $Method -ContentType $ContentType -Headers $Headers -Body $Body -UseBasicParsing
    }
    Catch
    {
        $Error = $_.Exception.Message
    }
  
    if ($Response.StatusCode -eq 202)
    {
        Write-Verbose -Message 'Data successfully sent!'
    } 
    else 
    {
        Write-Error -Exception $Error
    }
    Write-Verbose -Message 'Returning response code URI [Post-OMSData]'
    Write-Verbose ('Response code: {0}' -f $Response.StatusCode)
    return $Response.StatusCode
}