Skip to content

Instantly share code, notes, and snippets.

@wpsmith
Created April 16, 2015 14:16
Show Gist options
  • Save wpsmith/e8a9c54ca1c7c741b5e9 to your computer and use it in GitHub Desktop.
Save wpsmith/e8a9c54ca1c7c741b5e9 to your computer and use it in GitHub Desktop.
PowerShell: Creates an custom ErrorRecord that can be used to report a terminating or non-terminating error.
<#
.Synopsis
Creates an custom ErrorRecord that can be used to report a terminating or non-terminating error.
.Description
Creates an custom ErrorRecord that can be used to report a terminating or non-terminating error.
.Parameter Exception
The Exception that will be associated with the ErrorRecord.
.Parameter ErrorID
A scripter-defined identifier of the error. This identifier must be a non-localized string for a specific error type.
.Parameter ErrorCategory
An ErrorCategory enumeration that defines the category of the error. .Parameter TargetObject The object that was being processed when the error took place.
.Parameter Message
Describes the Exception to the user.
.Parameter InnerException
The Exception instance that caused the Exception association with the ErrorRecord.
.Example
# advanced functions for testing
function Test-1 {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[String]
$Path
)
process {
foreach ($_path in $Path) {
$content = Get-Content -LiteralPath $_path -ErrorAction SilentlyContinue
if (-not $content) {
$errorRecord = New-ErrorRecord InvalidOperationException FileIsEmpty InvalidOperation $_path -Message "File '$_path' is empty."
$PSCmdlet.ThrowTerminatingError($errorRecord)
}
}
}
}
function Test-2 {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[String]
$Path
)
process {
foreach ($_path in $Path) {
$content = Get-Content -LiteralPath $_path -ErrorAction SilentlyContinue
if (-not $content) {
$errorRecord = New-ErrorRecord InvalidOperationException FileIsEmptyAgain InvalidOperation $_path -Message "File '$_path' is empty again." -InnerException $Error[0].Exception
$PSCmdlet.ThrowTerminatingError($errorRecord)
}
}
}
}
# code to test the custom terminating error reports
Clear-Host
$null = New-Item -Path .\MyEmptyFile.bak -ItemType File -Force -Verbose
Get-ChildItem *.bak | Where-Object {-not $_.PSIsContainer} | Test-1 Write-Host System.Management.Automation.ErrorRecord -ForegroundColor Green $Error[0] | Format-List * -Force Write-Host Exception -ForegroundColor Green $Error[0].Exception | Format-List * -Force
Get-ChildItem *.bak | Where-Object {-not $_.PSIsContainer} | Test-2 Write-Host System.Management.Automation.ErrorRecord -ForegroundColor Green $Error[0] | Format-List * -Force Write-Host Exception -ForegroundColor Green $Error[0].Exception | Format-List * -Force
Remove-Item .\MyEmptyFile.bak -Verbose
Description
===========
Both advanced functions throw a custom terminating error when an empty file is being processed.
-Function Test-2's custom ErrorRecord includes an inner exception, which is the ErrorRecord reported by function Test-1.
The test code demonstrates this by creating an empty file in the curent directory -which is deleted at the end- and passing its path to both test functions.
The custom ErrorRecord is reported and execution stops for function Test-1, then the ErrorRecord and its Exception are displayed for quick analysis.
Same process with function Test-2; after analyzing the information, compare both ErrorRecord objects and their corresponding Exception objects.
-In the ErrorRecord note the different Exception, CategoryInfo and FullyQualifiedErrorId data.
-In the Exception note the different Message and InnerException data.
.Example
$errorRecord = New-ErrorRecord System.InvalidOperationException FileIsEmpty InvalidOperation $Path -Message "File '$Path' is empty." $PSCmdlet.ThrowTerminatingError($errorRecord)
Description
===========
A custom terminating ErrorRecord is stored in variable 'errorRecord' and then it is reported through $PSCmdlet's ThrowTerminatingError method.
The $PSCmdlet object is only available within advanced functions.
.Example
$errorRecord = New-ErrorRecord System.InvalidOperationException FileIsEmpty InvalidOperation $Path -Message "File '$Path' is empty." Write-Error -ErrorRecord $errorRecord
Description
===========
A custom non-terminating ErrorRecord is stored in variable 'errorRecord' and then it is reported through the Write-Error Cmdlet's ErrorRecord parameter.
.Inputs System.String
.Outputs System.Management.Automation.ErrorRecord
.Link Write-Error Get-AvailableExceptionsList
.Notes
Name: New-ErrorRecord
Author: Robert Robelo
LastEdit: 08/24/2011 12:35 #>
function New-ErrorRecord {
param(
[Parameter(Mandatory = $true, Position = 0)]
[System.String]
$Exception,
[Parameter(Mandatory = $true, Position = 1)]
[Alias('ID')]
[System.String]
$ErrorId,
[Parameter(Mandatory = $true, Position = 2)]
[Alias('Category')]
[System.Management.Automation.ErrorCategory]
[ValidateSet('NotSpecified', 'OpenError', 'CloseError', 'DeviceError',
'DeadlockDetected', 'InvalidArgument', 'InvalidData', 'InvalidOperation',
'InvalidResult', 'InvalidType', 'MetadataError', 'NotImplemented',
'NotInstalled', 'ObjectNotFound', 'OperationStopped', 'OperationTimeout',
'SyntaxError', 'ParserError', 'PermissionDenied', 'ResourceBusy',
'ResourceExists', 'ResourceUnavailable', 'ReadError', 'WriteError',
'FromStdErr', 'SecurityError')]
$ErrorCategory,
[Parameter(Mandatory = $true, Position = 3)]
[System.Object]
$TargetObject,
[Parameter()]
[System.String]
$Message,
[Parameter()]
[System.Exception]
$InnerException
)
begin {
# check for required function, if not defined...
if (-not (Test-Path function:Get-AvailableExceptionsList)) {
$message1 = "The required function Get-AvailableExceptionsList is not defined. " +
"Please define it in the same scope as this function's and try again."
$exception1 = New-Object System.OperationCanceledException $message1
$errorID1 = 'RequiredFunctionNotDefined'
$errorCategory1 = 'OperationStopped'
$targetObject1 = 'Get-AvailableExceptionsList'
$errorRecord1 = New-Object Management.Automation.ErrorRecord $exception1, $errorID1,
$errorCategory1, $targetObject1
# ...report a terminating error to the user
$PSCmdlet.ThrowTerminatingError($errorRecord1)
}
# required function is defined, get "available" exceptions
$exceptions = Get-AvailableExceptionsList
$exceptionsList = $exceptions -join "`r`n"
}
process {
# trap for any of the "exceptional" Exception objects that made through the filter
trap [Microsoft.PowerShell.Commands.NewObjectCommand] {
$PSCmdlet.ThrowTerminatingError($_)
}
# verify input exception is "available". if so...
if ($exceptions -match "^(System\.)?$Exception$") {
# ...build and save the new Exception depending on present arguments, if it...
$_exception = if ($Message -and $InnerException) {
# ...includes a custom message and an inner exception
New-Object $Exception $Message, $InnerException
} elseif ($Message) {
# ...includes a custom message only
New-Object $Exception $Message
} else {
# ...is just the exception full name
New-Object $Exception
}
# now build and output the new ErrorRecord
New-Object Management.Automation.ErrorRecord $_exception, $ErrorID,
$ErrorCategory, $TargetObject
} else {
# Exception argument is not "available";
# warn the user, provide a list of "available" exceptions and...
Write-Warning "Available exceptions are:`r`n$exceptionsList"
$message2 = "Exception '$Exception' is not available."
$exception2 = New-Object System.InvalidOperationExceptionn $message2
$errorID2 = 'BadException'
$errorCategory2 = 'InvalidOperation'
$targetObject2 = 'Get-AvailableExceptionsList'
$errorRecord2 = New-Object Management.Automation.ErrorRecord $exception2, $errorID2,
$errorCategory2, $targetObject2
# ...report a terminating error to the user
$PSCmdlet.ThrowTerminatingError($errorRecord2)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment