Logging to elmah.io from PowerShell

There are a couple of options for logging to elmah.io from PowerShell. If you need to log a few messages, using the API is the easiest.

Log through the API

Logging to elmah.io from PowerShell is easy using built-in cmdlets:

$apiKey = "API_KEY"
$logId = "LOG_ID"
$url = "https://api.elmah.io/v3/messages/$logId/?api_key=$apiKey"

$body = @{
    title = "Error from PowerShell"
    severity = "Error"
    detail = "This is an error message logged from PowerShell"
    hostname = hostname
}
Invoke-RestMethod -Method Post -Uri $url -Body ($body|ConvertTo-Json) -ContentType "application/json-patch+json"

Replace API_KEY with your API key (Where is my API key?) and LOG_ID with the ID of the log you want messages sent to (Where is my log ID?).

Log through PoShLog.Sinks.ElmahIo

PoShLog is a PowerShell logging module built on top of Serilog. To log to elmah.io using PoShLog, install the following packages:

Install-Module -Name PoShLog
Install-Module -Name PoShLog.Sinks.ElmahIo

Logging messages can now be done using Write-*Log:

Import-Module PoShLog
Import-Module PoShLog.Sinks.ElmahIo

New-Logger |
    Add-SinkElmahIo -ApiKey 'API_KEY' -LogId 'LOG_ID' |
    Start-Logger

Write-ErrorLog 'Say My Name'

# Don't forget to close the logger
Close-Logger

Log through Elmah.Io.Client

If you prefer to use the Elmah.Io.Client NuGet package, you can do this in PowerShell too. First of all, you will need to include elmah.io.client.dll. How you do this is entirely up to you. You can include this assembly in your script location or you can download it through NuGet on every execution. To download the package through NuGet, you will need nuget.exe:

$source = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$target = ".\nuget.exe"
Invoke-WebRequest $source -OutFile $target
Set-Alias nuget $target -Scope Global

This script will download the latest version of the NuGet command-line tool and make it available through the command nuget.

To install Elmah.Io.Client run nuget.exe:

nuget install Elmah.Io.Client

This will create an Elmah.Io.Client-version folder containing the latest stable version of the Elmah.Io.Client package.

You now have Elmah.Io.Client.dll loaded into your shell and everything is set up to log to elmah.io. To do so, add try-catch around critical code:

$logger = [Elmah.Io.Client.ElmahioAPI]::Create("API_KEY")
Try {
    # some code that may throw exceptions
}
Catch {
    $logger.Messages.Error([guid]::new("LOG_ID"), $_.Exception, "Oh no")
}

In the first line, we create a new logger object. Then, in the Catch block, the catched exception is shipped off to the elmah.io log specified in LOG_ID together with a custom message.

Examples

For inspiration, here's a list of examples of common scenarios where you'd want to log to elmah.io from PowerShell.

Log error on low remaining disk

You can monitor when a server is running low on disk space like this:

$cdrive = Get-Volume -DriveLetter C
$sizeremainingingb = $cdrive.SizeRemaining/1024/1024/1024
if ($sizeremainingingb -lt 10) {
    $apiKey = "API_KEY"
    $logId = "LOG_ID"
    $url = "https://api.elmah.io/v3/messages/$logId/?api_key=$apiKey"

    $body = @{
        title = "Disk storage less than 10 gb"
        severity = "Error"
        detail = "Remaining storage in gb: $sizeremainingingb"
        hostname = hostname
    }
    Invoke-RestMethod -Method Post -Uri $url -Body ($body|ConvertTo-Json) -ContentType "application/json-patch+json"
}

Troubleshooting

Elmah.Io.Client.ElmahioAPI cannot be loaded

If PowerShell complains about Elmah.Io.Client.ElmahioAPI not being found, try adding the following lines to the script after installing the Elmah.Io.Client NuGet package:

$elmahIoClientPath = Get-ChildItem -Path . -Filter Elmah.Io.Client.dll -Recurse `
  | Where-Object {$_.FullName -match "net45"}
[Reflection.Assembly]::LoadFile($elmahIoClientPath.FullName)

$jsonNetPath = Get-ChildItem -Path . -Filter Newtonsoft.Json.dll -Recurse `
  | Where-Object {$_.FullName -match "net45" -and $_.FullName -notmatch "portable"}
[Reflection.Assembly]::LoadFile($jsonNetPath.FullName)

You may need to include additional assemblies if PowerShell keeps complaining.

The catch block is not invoked even though a cmdlet failed

Most errors in PowerShell are non-terminating meaning that they are handled internally in the cmdlet. To force a cmdlet to use terminating errors use the -ErrorAction parameter:

Try {
    My-Cmdlet -ErrorAction Stop
}
Catch {
    // Log to elmah.io
}


This article was brought to you by the elmah.io team. elmah.io is the best error management system for .NET web applications. We monitor your website, alert you when errors start happening, and help you fix errors fast.

See how we can help you monitor your website for crashes Monitor your website