DemoMonitor.ps1


<#PSScriptInfo
 
.VERSION 0.9.0
 
.GUID ad5c215d-1c10-42c3-95ac-2acf9ee87113
 
.AUTHOR dairwin
 
.COMPANYNAME Microsoft Corporation
 
.COPYRIGHT
 
.TAGS ServiceMap OMS OperationsManagementSuite
 
.LICENSEURI https://www.gnu.org/licenses/gpl-3.0.txt
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
#>


<#
 
.DESCRIPTION
 A script that uses the Service Map API to monitor a server, process, and connections.
 This script will use armclient for calling the Service Map API. While running, this script will write to a log
 file every 5 minutes (period is configurable) the status of the demo machines. This is designed to work in
 conjunction with Custom Log ingestion by OMS to pull the log data into Log Analytics. There, OMS Alerts are
 used to alert users if the demo machines are not working properly or if the demo monitor itself is not running.
#>
 
param (
)
 
# Change these settings to match your servers, processes, links
$targetMachine = "<Your servername here>"
$targetProcess = "Tomcat"
$targetPort = 3306
$LogFilePath = "DemoMonitor.log"
$period = 300

##################################################
#
# Azure account settings. Don't share these!
#
##################################################

# SubscriptionID of Azure Subscription
$SubscriptionId = "<Your subscription ID>"

# Resource Group containing OMS Workspace in Azure Subscription
$ResourceGroupName = "<Your Azure Resource Group>"

# Name of OMS Workspace
$WorkSpaceName = "<Your OMS Workspace name>" 

# Service Principal values - see http://blog.davidebbo.com/2014/12/azure-service-principal.html for explanation
$TenantId = "<Your SPN's Tenant Id>"
$AppId = "<Your SPN's Application Id>"
$Password = "<Your SPN's password>"



$foundMachine = $false
$foundProcess = $false
$foundProcessOutgoingEdges = $false

$myAPIPath = "/subscriptions/$SubscriptionId/resourcegroups/$ResourceGroupName/providers/microsoft.operationalinsights/workspaces/$WorkSpaceName"

function Write-Log
{
    param (
        [Parameter(Mandatory)]
        [string]$Message,
        
        [Parameter()]
        [ValidateSet('1','2','3')]
        [string]$Severity = 1 ## Default to a low severity. Otherwise, override
    )
    
    $line = [pscustomobject]@{
        'DateTime' = (Get-Date)
        'Severity' = $Severity
        'Message' = $Message
    }
    
    ## Ensure that $LogFilePath is set to a global variable at the top of script
    $line | Export-Csv -Path $LogFilePath -Append -NoTypeInformation
}

Function FindPort($ports, $id) {

    foreach ($port in $ports) {
        if ($port.id -eq $id) {
            return, $port
        }
    }

    return, $null
}

Function FindProcess ($processes, $id) {
    foreach ($process in $processes) {
        if ($process.id -eq $id) {
            return, $process
        }
    }

    return, $null
}



while ($true) {
    # Login to armclient - put this inside the loop, because the token will expire otherwise
    armclient spn $TenantId $AppId $Password

    
    $endTime = ([DateTime]::UtcNow | Get-Date -format s)
    $startTime = ([DateTime]::UtcNow.AddSeconds(0 - $period) | Get-Date -format s)

    $foundMachine = $false
    $foundProcess = $false
    $foundProcessOutgoingEdges = $false

    $apicall = "$myAPIPath/features/serviceMap/machines?api-version=2015-11-01-preview&startTime=$startTime&endTime=$endTime"
    $apicall
    
    $machines = armclient get $apicall | ConvertFrom-Json
    $machines

    "========= Machines - (" + $machines.value.Count  + " Total ) ================"
    foreach($machine in $machines.value) {
        if ($machine.properties.displayName -like $targetMachine) {
            $foundMachine = $true

            # Call to get the processes for this machine
            $apicall = "$myAPIPath/features/serviceMap/machines/" + $machine.name + "/processes?api-version=2015-11-01-preview&startTime=" + $startTime + "&endTime=" + $endTime
            $processes = armclient get $apicall | ConvertFrom-Json

            foreach ($process in $processes.value) {
                if ($process.properties.displayName -like $targetProcess) {
                    $foundProcess = $true
                    break
                }
            }
            if ($foundProcess) {
                # Call to get everything in a map
                $mapRequest = "{ 'startTime':'$startTime', 'endTime':'$endTime', 'kind':'map:single-machine-dependency', 'machineId':'" + $machine.id + "' }"

                $apicall = "$myAPIPath/features/serviceMap/generateMap?api-version=2015-11-01-preview"
                $serverdep = armclient post $apicall $mapRequest | ConvertFrom-Json
                
                foreach ($connection in $serverdep.map.edges.connections) {
                    $clientProcess = FindProcess $serverDep.map.nodes.processes $connection.properties.source.id
                    $serverPort = FindPort $serverDep.map.nodes.ports $connection.properties.serverPort.id
                    if (($clientProcess.properties.displayName -like $targetProcess) -and ($serverPort.properties.portNumber -eq $targetPort)){
                        $foundProcessOutgoingEdges = $true
                        break
                    }
                }
            }
            break
        }
    }

    # Check status
    if (!$foundMachine) {
        Write-Log -Message ("Can't find machine " + $targetMachine) -Severity 3
    }
    elseif (!$foundProcess) {
        Write-Log -Message ("Can't find " + $targetProcess + " on machine " + $targetMachine) -Severity 3
    }
    elseif (!$foundProcessOutgoingEdges) {
        Write-Log -Message ("Can't find connections to port " + $targetPort + " from " + $targetProcess + " on machine " + $targetMachine) -Severity 3
    }
    else {
        Write-Log -Message "Demo application is healthy"
    }
    
    Start-Sleep -s $period
}