Skip to content

Commit

Permalink
Add new command New-ErrorRecord (#118)
Browse files Browse the repository at this point in the history
  • Loading branch information
johlju authored Jan 23, 2024
1 parent df361a2 commit fea4a5d
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 58 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
was set.
- `New-Exception`
- New command that creates and returns an `[System.Exception]`.
- `New-ErrorRecord`
- New command that creates and returns an `[System.Management.Automation.ErrorRecord]`
([issue #99](https://github.com/dsccommunity/DscResource.Common/issues/99)).
- `New-ArgumentException`
- Now takes a parameter `PassThru` that returns the error record that was
created (and does not throw).
Expand Down Expand Up @@ -55,10 +58,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `New-ArgumentException`
- Now has a command alias `New-InvalidArgumentException` and the command
was renamed to match the exception name.
- Now uses the new command `New-ErrorRecord`.
- `New-InvalidDataException`
- The parameter `Message` has a parameter alias `ErrorMessage` to make
the command have the same parameter names as the other `New-*Exception`
commands.
- Now uses the new command `New-ErrorRecord`.
- `New-InvalidOperationException`
- Now uses the new command `New-ErrorRecord`.
- `New-InvalidResultException`
- Now uses the new command `New-ErrorRecord`.
- `New-NotImplementedException`
- Now uses the new command `New-ErrorRecord`.
- `New-ObjectNotFoundException`
- Now uses the new command `New-ErrorRecord`.

### Fixed

Expand Down
12 changes: 4 additions & 8 deletions source/Public/New-ArgumentException.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
.OUTPUTS
None
System.Management.Automation.ErrorRecord
System.ArgumentException
.EXAMPLE
New-ArgumentException -ArgumentName 'Action' -Message 'My error message'
Expand All @@ -36,6 +36,7 @@ function New-ArgumentException
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
[CmdletBinding()]
[Alias('New-InvalidArgumentException')]
[OutputType([System.ArgumentException])]
param
(
[Parameter(Mandatory = $true)]
Expand All @@ -53,15 +54,10 @@ function New-ArgumentException
$PassThru
)

$argumentException = New-Object -TypeName 'ArgumentException' `
$argumentException = New-Object -TypeName 'System.ArgumentException' `
-ArgumentList @($Message, $ArgumentName)

$newObjectParameters = @{
TypeName = 'System.Management.Automation.ErrorRecord'
ArgumentList = @($argumentException, $ArgumentName, 'InvalidArgument', $null)
}

$errorRecord = New-Object @newObjectParameters
$errorRecord = New-ErrorRecord -Exception $argumentException -ErrorId $ArgumentName -ErrorCategory 'InvalidArgument'

if ($PassThru.IsPresent)
{
Expand Down
129 changes: 129 additions & 0 deletions source/Public/New-ErrorRecord.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<#
.SYNOPSIS
Creates a new ErrorRecord.
.DESCRIPTION
The New-ErrorRecord function creates a new ErrorRecord with the specified parameters.
.PARAMETER ErrorRecord
Specifies an existing ErrorRecord.
.PARAMETER Exception
Specifies the exception that caused the error.
If an error record is passed to parameter ErrorRecord and if the wrapped exception
in the error record contains a `[System.Management.Automation.ParentContainsErrorRecordException]`,
the new ErrorRecord should have this exception as its Exception instead.
.PARAMETER ErrorCategory
Specifies the category of the error.
.PARAMETER TargetObject
Specifies the object that was being manipulated when the error occurred.
.PARAMETER ErrorId
Specifies a string that uniquely identifies the error.
.EXAMPLE
$ex = New-Exception -Message 'An error occurred.'
$errorRecord = New-ErrorRecord -Exception $ex -ErrorCategory 'InvalidOperation'
This example creates a new ErrorRecord with the specified parameters. Passing
'InvalidOperation' which is one available value of the enum `[System.Management.Automation.ErrorCategory]`.
.EXAMPLE
$ex = New-Exception -Message 'An error occurred.'
$errorRecord = New-ErrorRecord -Exception $ex -ErrorCategory 'InvalidOperation' -TargetObject $myObject
This example creates a new ErrorRecord with the specified parameters. TargetObject
is set to the object that was being manipulated when the error occurred.
.EXAMPLE
$ex = New-Exception -Message 'An error occurred.'
$errorRecord = New-ErrorRecord -Exception $ex -ErrorCategory 'InvalidOperation' -ErrorId 'MyErrorId'
This example creates a new ErrorRecord with the specified parameters. Passing
ErrorId that will be set as the FullyQualifiedErrorId in the error record.
.EXAMPLE
$existingErrorRecord = [System.Management.Automation.ErrorRecord]::new(
[System.Management.Automation.ParentContainsErrorRecordException]::new('Existing error'),
'ExistingErrorId',
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$null
)
$newException = [System.Exception]::new('New error')
$newErrorRecord = New-ErrorRecord -ErrorRecord $existingErrorRecord -Exception $newException
$newErrorRecord.Exception.Message
This example first creates an emulated ErrorRecord that contain a `ParentContainsErrorRecordException`
which will be replaced by the new exception passed to New-ErrorRecord. The
result of `$newErrorRecord.Exception.Message` will be 'New error'.
.INPUTS
System.Management.Automation.ErrorRecord, System.Exception, System.Management.Automation.ErrorCategory, System.Object, System.String
.OUTPUTS
System.Management.Automation.ErrorRecord
.NOTES
The function supports two parameter sets: 'ErrorRecord' and 'Exception'.
If the 'ErrorRecord' parameter set is used, the function creates a new ErrorRecord based on an existing one and an exception.
If the 'Exception' parameter set is used, the function creates a new ErrorRecord based on an exception, an error category, a target object, and an error ID.
#>
function New-ErrorRecord
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'The command does not change state.')]
[CmdletBinding(DefaultParameterSetName = 'Exception')]
[OutputType([System.Management.Automation.ErrorRecord])]
param
(
[Parameter(Mandatory = $true, ParameterSetName = 'ErrorRecord')]
[System.Management.Automation.ErrorRecord]
$ErrorRecord,

[Parameter(Mandatory = $true, ParameterSetName = 'ErrorRecord')]
[Parameter(Mandatory = $true, ParameterSetName = 'Exception')]
[System.Exception]
$Exception,

[Parameter(Mandatory = $true, ParameterSetName = 'Exception')]
[System.Management.Automation.ErrorCategory]
$ErrorCategory,

[Parameter(ParameterSetName = 'Exception')]
[System.Object]
$TargetObject = $null,

[Parameter(ParameterSetName = 'Exception')]
[System.String]
$ErrorId = $null
)

switch ($PSCmdlet.ParameterSetName)
{
'ErrorRecord'
{
$errorRecord = New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList @(
$ErrorRecord,
$Exception
)

break
}

'Exception'
{
$errorRecord = New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList @(
$Exception,
$ErrorId,
$ErrorCategory,
$TargetObject
)

break
}
}

return $errorRecord
}
4 changes: 1 addition & 3 deletions source/Public/New-InvalidDataException.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ function New-InvalidDataException
-TypeName 'System.InvalidOperationException' `
-ArgumentList $Message

$errorRecord = New-Object `
-TypeName 'System.Management.Automation.ErrorRecord' `
-ArgumentList $exception, $ErrorId, $errorCategory, $null
$errorRecord = New-ErrorRecord -Exception $exception -ErrorId $ErrorId -ErrorCategory $errorCategory

throw $errorRecord
}
14 changes: 2 additions & 12 deletions source/Public/New-InvalidOperationException.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,14 @@ function New-InvalidOperationException
-ArgumentList @($Message, $ErrorRecord.Exception)
}

$newObjectParameters = @{
TypeName = 'System.Management.Automation.ErrorRecord'
ArgumentList = @(
$invalidOperationException.ToString(),
'MachineStateIncorrect',
'InvalidOperation',
$null
)
}

$errorRecordToReturn = New-Object @newObjectParameters
$errorRecord = New-ErrorRecord -Exception $invalidOperationException.ToString() -ErrorId 'MachineStateIncorrect' -ErrorCategory 'InvalidOperation'

if ($PassThru.IsPresent)
{
return $invalidOperationException
}
else
{
throw $errorRecordToReturn
throw $errorRecord
}
}
14 changes: 2 additions & 12 deletions source/Public/New-InvalidResultException.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,7 @@ function New-InvalidResultException

$exception = New-Exception @PSBoundParameters

$newObjectParameters = @{
TypeName = 'System.Management.Automation.ErrorRecord'
ArgumentList = @(
$exception.ToString(),
'MachineStateIncorrect',
'InvalidResult',
$null
)
}
$errorRecord = New-ErrorRecord -Exception $exception.ToString() -ErrorId 'MachineStateIncorrect' -ErrorCategory 'InvalidResult'

$errorRecordToThrow = New-Object @newObjectParameters

throw $errorRecordToThrow
throw $errorRecord
}
12 changes: 1 addition & 11 deletions source/Public/New-NotImplementedException.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,7 @@ function New-NotImplementedException
-ArgumentList @($Message, $ErrorRecord.Exception)
}

$newObjectParameters = @{
TypeName = 'System.Management.Automation.ErrorRecord'
ArgumentList = @(
$notImplementedException.ToString(),
'MachineStateIncorrect',
'NotImplemented',
$null
)
}

$errorRecord = New-Object @newObjectParameters
$errorRecord = New-ErrorRecord -Exception $notImplementedException.ToString() -ErrorId 'MachineStateIncorrect' -ErrorCategory 'NotImplemented'

if ($PassThru.IsPresent)
{
Expand Down
14 changes: 2 additions & 12 deletions source/Public/New-ObjectNotFoundException.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,7 @@ function New-ObjectNotFoundException

$exception = New-Exception @PSBoundParameters

$newObjectParameters = @{
TypeName = 'System.Management.Automation.ErrorRecord'
ArgumentList = @(
$exception.ToString(),
'MachineStateIncorrect',
'ObjectNotFound',
$null
)
}
$errorRecord = New-ErrorRecord -Exception $exception.ToString() -ErrorId 'MachineStateIncorrect' -ErrorCategory 'ObjectNotFound'

$errorRecordToThrow = New-Object @newObjectParameters

throw $errorRecordToThrow
throw $errorRecord
}
78 changes: 78 additions & 0 deletions tests/Unit/Public/New-ErrorRecord.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
param ()

BeforeDiscovery {
try
{
if (-not (Get-Module -Name 'DscResource.Test'))
{
# Assumes dependencies has been resolved, so if this module is not available, run 'noop' task.
if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
{
# Redirect all streams to $null, except the error stream (stream 2)
& "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null
}

# If the dependencies has not been resolved, this will throw an error.
Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
}
}
catch [System.IO.FileNotFoundException]
{
throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.'
}
}

BeforeAll {
$script:moduleName = 'DscResource.Common'

# Make sure there are not other modules imported that will conflict with mocks.
Get-Module -Name $script:moduleName -All | Remove-Module -Force

# Re-import the module using force to get any code changes between runs.
Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop'

$PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName
$PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName
$PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName
}

AfterAll {
$PSDefaultParameterValues.Remove('Mock:ModuleName')
$PSDefaultParameterValues.Remove('InModuleScope:ModuleName')
$PSDefaultParameterValues.Remove('Should:ModuleName')

Remove-Module -Name $script:moduleName
}

Describe 'New-ErrorRecord' {
Context 'ErrorRecord parameter set' {
It 'creates a new ErrorRecord based on an existing one and an exception' {
$existingErrorRecord = [System.Management.Automation.ErrorRecord]::new(
[System.Management.Automation.ParentContainsErrorRecordException]::new('Existing error'),
'ExistingErrorId',
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$null
)
$newException = [System.Exception]::new('New error')
$newErrorRecord = New-ErrorRecord -ErrorRecord $existingErrorRecord -Exception $newException

$newErrorRecord.Exception.Message | Should -Be 'New error'
$newErrorRecord.FullyQualifiedErrorId | Should -Be 'ExistingErrorId'
$newErrorRecord.CategoryInfo.Category | Should -Be 'InvalidOperation'
}
}

Context 'Exception parameter set' {
It 'creates a new ErrorRecord based on an exception, an error category, a target object, and an error ID' {
$exception = [System.Exception]::new('An error occurred.')
$targetObject = New-Object -TypeName PSObject
$errorRecord = New-ErrorRecord -Exception $exception -ErrorCategory 'InvalidOperation' -TargetObject $targetObject -ErrorId 'MyErrorId'

$errorRecord.Exception.Message | Should -Be 'An error occurred.'
$errorRecord.FullyQualifiedErrorId | Should -Be 'MyErrorId'
$errorRecord.CategoryInfo.Category | Should -Be 'InvalidOperation'
$errorRecord.TargetObject | Should -Be $targetObject
}
}
}

0 comments on commit fea4a5d

Please sign in to comment.