Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new command New-ErrorRecord #118

Merged
merged 3 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
}
}