PowerShell Probe Examples

PowerShell probes are command-line probes. They launch PowerShell and invoke a command.

The following examples demonstrate two different Intermapper macros:

  • ${PSREMOTE} - for less experienced PowerShell users, this macro handles the connection to the remote machine. It creates a credential object and sets up authentication. It executes the specified command on the remote machine.
  • ${PS} - for experienced PowerShell users, this macro launches PowerShell on the local machine with the specified arguments. It leaves all PowerShell commands up to the developer.

These macros are used in the <command-line> section of the probe.

Scripts must be located in the Intermapper Settings\Tools folder. If you include the script in the <tools> section, it is installed in the Tools folder when you load the probe.

Example 1: Installed Software Probe

This probe lists installed applications, updates, or both on the target device. It launches PowerShell with the arguments supplied in arg, uses ${PSREMOTE} to connect to and authenticate on the remote device, and executes the command specified input.

<!-- 
This probe lists installed Applications, Updates, or Both using PowerShell. Requires PowerShell 2.0 or later and requires that PS remoting be enabled.

File Name: com.helpsystems.powershell.remote.installedSoftware.txt
(c) 2015 Fortra, Inc.
-->

 <header>
	type = "cmd-line"
	package = "com.helpsystems"
	probe_name = "ps.remote.InstalledSoftware"
	human_name = "Installed Software"
	version = "1.0"
	address_type = "IP"
	display_name = "PowerShell/Remote/Installed Software"
	visible_in = "Windows"
	flags = "NTCREDENTIALS"	
</header>

<description>
\GB\List Installed Software\p\

This probe uses PowerShell to provide a listing of installed software, installed updates, or both. This probe requires that \b\PowerShell 2.0\p\ or later be installed, and PowerShell remoting must be enabled and configured to use this probe. This probe uses the registry, not WMI objects

Intermapper invokes the included ApplicationList.ps1 companion script in Intermapper Settings/Tools.

</description>

<parameters>
	"Type[Software,Update,All]"="Software"
	User=""
	"Password*" = ""
    "Authentication[Default,Basic,Negotiate,NegotiateWithImplicitCredential,Credssp,Digest,Kerberos]"="Default"
    "Timeout (sec)"="10"
</parameters>

<command-exit>
	down:${EXIT_CODE}=4
	critical:${EXIT_CODE}=3
	alarm:${EXIT_CODE}=2
	warning:${EXIT_CODE}=1 
	okay:${EXIT_CODE}=0 
</command-exit>

<command-line> 
	path="" 
	cmd="${PSREMOTE}"
	arg="-ExecutionPolicy RemoteSigned -NoProfile"
	input = "Invoke-Command -FilePath .\\ApplicationList.ps1 -ArgumentList '${Type[Software,Update,All]}'"
	timeout = ${Timeout (sec)}
</command-line> 

<command-display>
  ${Type[Software,Update,All]} installed on ${address}
  ${^stdout}
</command-display>

<tool:ApplicationList.ps1>
param([string] $filter)

$exitCode = 0
$reason = ''

if ($filter -eq 'All') 
{
    $software = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, InstallDate, Publisher | Sort-Object DisplayName
}

elseif ($filter -eq 'Update') #show only windows updates
{
    $software = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, InstallDate, Publisher | where {$_.DisplayName -match $filter} | Sort-Object DisplayName
}

elseif  ($filter -eq 'Software')
{
    $software = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, InstallDate, Publisher | where {$_.DisplayName -notmatch 'update'} | Sort-Object DisplayName
}

#get rid of blanks in the input
$cleanedUpList = New-Object System.Collections.ArrayList 

foreach($app in $software)
{
    if ($app.DisplayName ) 
    {
        $cleanedUpList.Add($app) | Out-Null #ArrayList.Add returns the index of the item added, we don't want this goint to standard out, confusing Intermapper.
    }    
}

#set up the object for return

# Intermapper can't take an array or ArrayList of objects yet, so convert to a string.
# Also, Powershell will truncate to a default size, unless the table is formatted using -AutoSize and get around column dropping by setting the width of the resulting string.
$stdoutString = $cleanedUpList |format-table -AutoSize | out-string -width 4096

$result = New-Object PSCustomObject -Property @{
    'stdout'=$stdoutString;
    'ExitCode'=$exitCode;
    'reason'=$reason;
}
write-output $result

</tool:ApplicationList.ps1>
  

Example 2: Windows Disk Space Probe

This probe checks the amount of disk space on the target device. It uses ${PS} to launch PowerShell with the arguments supplied in arg and executes the command specified in input.

Similarly to the first example, this example connects to a remote device, but does not use ${PSREMOTE} to handle the connection. This example also passes thresholds to the script so that it can return the correct exit code.

<!-- 

Windows Disk Space Probe
This probe uses a PowerShell script to look up the amount of disk space on the 
target device.
(c) 2015 Fortra, Inc.
-->

 <header>
	type = "cmd-line"
	package = "com.helpsystems"
	probe_name = "ps.wmi.diskspace"
	human_name = "Non-Remoting (WMI) Disk Space Monitor"
	version = "1.0"
	address_type = "IP"
	display_name = "PowerShell/Disk Space"
	visible_in = "Windows"
    flags = "NTCREDENTIALS" 
</header>

<description>
	\GB\Windows Disk Space Monitor\p\

	This probe uses Powershell to retrieve the disk space available on a drive 
	on the target host. Specifically, it queries the Size and FreeSpace 
	properties of the Win32_LogicalDisk class, computes percentage free space, 
	and compares it against the Warning and Critical parameters you set.  The 
	target host must be running PowerShell with Remoting enabled.

	The Drive parameter may be set to "All" to enumerate all Local hard drives 
	on the host.  It may also be set to a list of comma-separated drive names 
	(including the colon), which will be listed whether or not they are local 
	hard drives.  Zero-sized drives (i.e. an empty cd-rom) will not be listed.  
	The first drive failing the warning or critical criteria will be the one 
	cited in the reason.

	The User parameter may be a local user on the target host, or may take the 
	form of "domain\\user" for a domain login.  Leave it blank if authentication
	is not required, such as when the target is the localhost.

	Intermapper invokes the WindowsFreeDiskSpace.ps1 companion script which was 
	placed in the Tools folder of the Intermapper Settings folder when this 
	probe was loaded.  It uses the exit value to set the condition of the device
	and the performance data returned by the script to create a nice display of 
	chartable data.
</description>

<parameters>
	Drive="C:"
	"Warning (%)"="10"
	"Alarm (%)"="5"
	"Critical (%)"="3"
	"Down (%)"="1"
	User=""
	"Password*" = ""
	"Timeout (sec)"="10"
    "Powershell Version[notSpecified,2.0,3.0,4.0,5.0]"="notSpecified"
</parameters> 

<command-exit>
	down:${EXIT_CODE}=4
	critical:${EXIT_CODE}=3
	alarm:${EXIT_CODE}=2
	warning:${EXIT_CODE}=1 
	okay:${EXIT_CODE}=0 
</command-exit> 

<command-line> 
	path="" 
	cmd="${PS}"
	arg="-ExecutionPolicy RemoteSigned -NoProfile"
	input = "$c = New-Object System.Management.Automation.PSCredential -ArgumentList '${User}', (ConvertTo-SecureString -String '${Password*}' -AsPlainText -Force) ; Invoke-Command -ScriptBlock { & '.\\WindowsFreeDiskSpace.ps1' -compName '${address}' -cred $c -drives '${Drive}' -downThr ${Down (%)} -critThr ${Critical (%)} -alrmThr ${Alarm (%)} -warnThr ${Warning (%)} }"
	timeout = ${Timeout (sec)}
</command-line> 

<command-display>

Disk Space Available 
    ${^stdout}
</command-display>

<tool:WindowsFreeDiskSpace.ps1>
param([string] $compName, [System.Management.Automation.PSCredential] $cred, [string] $drives, [int] $downThr, [int] $critThr, [int] $alrmThr, [int] $warnThr)

Function Update-ExitCode
{
    param([int] $current_status, [int] $new_status)

    if ($new_status -gt $current_status) { return $new_status }
    else { return $current_status }
}

Function Update-Reason
{
    param($disk_name,$disk_threshold)
    return "Disk $disk_name is below $disk_threshold % free."
}

$STATUS = New-Object -TypeName PSObject -Prop(@{'down'=4;'critical'=3;'alarm'=2;'warning'=1;'ok'=0})

#reason and exit code
[int] $exit_code = $STATUS.ok
[string] $reason = "All disks within acceptable limits"
[string] $debugInfo = ''

$disks = New-Object -TypeName System.Collections.ArrayList

if ($drives -eq "All") 
{
    $disks = (Get-WmiObject Win32_LogicalDisk -ComputerName $compName -Credential $cred -Filter "DriveType='3'" | Select-Object Size,FreeSpace,DeviceID)
} 

else 
{
    $diskList = (Get-WmiObject Win32_LogicalDisk -ComputerName $compName -Credential $cred | Select-Object Size, Freespace, DeviceId)

    $driveArray = $drives.replace(' ', '').split(',')
    foreach($drive in $driveArray)
    {
        #$debugInfo += "$drive`r`n"

        $found = $false

        foreach($disk in $diskList)
        {
            #$debugInfo += $disk.GetType().FullName

            if ($disk.DeviceID -eq $drive)
            {
                $found = $true
                if ($disk.Size -ne $null)
                {
                    #$debugInfo += " -- adding " + $disk.DeviceID + "  Size: " + $disk.Size + "  FreeSpace: " + $disk.FreeSpace + "`r`n"
                    $disks.Add($disk)
                }
                else
                {
                    $debugInfo += $disk.DeviceID + "  --- No information ---`r`n"
                }
            }
        }

        if ($found -ne $true)
        {
            $debugInfo += $drive + "  --- Not found ---`r`n"
        }
    } 
}

if ($disks.count -eq 0) 
{
    throw "Disks could not be found or parameter error. Check your probe settings.`r`n" + $debugInfo
}

foreach ($disk in $disks)
{
    #calculate percentage of the disk that is free 
    $disk | Add-Member -type NoteProperty -name "PercentFree" -value ([Math]::round($disk.FreeSpace / $disk.Size * 100))
    $disk.Size          = "{0:N1}" -f [Math]::round(($disk.Size/1GB))
    $disk.FreeSpace     = "{0:N1}" -f [Math]::round(($disk.FreeSpace/1GB))

    # calculate alerts
    if ($disk.PercentFree -le $downThr) 
    { 
        # $disk | Add-Member -type NoteProperty -name "exit_code" -value $STATUS.down
        $old_code = $exit_code
        $exit_code = $STATUS.down
        if ($old_code -ne $exit_code)
        {
            $reason = Update-Reason $disk.DeviceID $downThr
        }
    }

    elseif ($disk.PercentFree -le $critThr -and $disk.PercentFree -gt $downThr ) 
    { 

        # $disk | Add-Member -type NoteProperty -name "exit_code" -value $STATUS.critical
        $old_code = $exit_code
        $exit_code = Update-ExitCode $exit_code $STATUS.critical
        if ($old_code -ne $exit_code)
        {
            $reason = Update-Reason $disk.DeviceID $critThr
        }
    }

    elseif ($disk.PercentFree -le $alrmThr -and $disk.PercentFree -gt $critThr ) 
    { 
        # $disk | Add-Member -type NoteProperty -name "exit_code" -value $STATUS.alarm
        $old_code = $exit_code
        $exit_code = Update-ExitCode $exit_code $STATUS.alarm
        if ($old_code -ne $exit_code)
        {
            $reason = Update-Reason $disk.DeviceID $alrmThr
        }
    }

    elseif ($disk.PercentFree -le $warnThr -and $disk.PercentFree -gt $alrmThr ) 
    { 
        #$disk | Add-Member -type NoteProperty -name "exit_code" -value $STATUS.warning
        $old_code = $exit_code
        $exit_code = Update-ExitCode $exit_code $STATUS.warning
        if ($old_code -ne $exit_code)
        {
            $reason = Update-Reason $disk.DeviceID $warnThr
        }
    }

    else 
    {
        #$disk | Add-Member -type NoteProperty -name "exit_code" -value $STATUS.ok
        $exit_code = Update-ExitCode $exit_code $STATUS.ok
    }
}

#format the output for the probe to display in the status window
$stdoutString = ($disks | Format-Table DeviceID,Size,FreeSpace,PercentFree | out-string)
$stdoutString += $debugInfo


#create the return object that the probe will use for display

$result = New-Object PSCustomObject -Property @{
    'stdout'=$stdoutString;
    'ExitCode'=$exit_code;
    'reason'=$reason;
}
write-output $result 

</tool:WindowsFreeDiskSpace.ps1>