Public/ErrorMan/New-ErrorRecord.ps1
function New-ErrorRecord { # .SYNOPSIS # A function to make it easy to create custom ErrorsRecords for "PowerShell noobs" like me. # .DESCRIPTION # Helps when writing complex errors with little knowledge on /dotnet/api/{ErrorID}(s) or ErrorCategories. # All you gotta do is think what the errorId NAME might be and use tab completion. # .EXAMPLE # PS C:\> $ErrRec = New-Error -ErrorId System.DllNotFoundException -RecommendedAction "Take a deep breath; .... TaBleFLIP. (⌐■_■) Quit!" -Category ObjectNotFound # PS C:\> Write-Error $ErrRec -Category $ErrRec.CategoryInfo.Category # .EXAMPLE # PS C:\> New-ErrorRecord -msg "CustomMessage" -ErrorId file<tab><tab> -Category Obj<tab><tab> # CustomMessage. This Exception Is Thrown When A Requested Object Is Not Found In The Underlying Directory Store. # + CategoryInfo : ObjectNotFound: (New-ErrorRecord... ObjectNotFound:String) [], FileLoadException # + FullyQualifiedErrorId : System.IO.FileLoadException # # This example shows the use of <tab> expansion help with New-ErrorRecord. # # All I had to do was write : # # -ErrorId <Keyword_I_think_Might_Be_in_Exception's_TpeName> and keep PRESSING <TAB> until I GET the perfect ErrorId. # .EXAMPLE # PS C:\> $ERRrecord = New-ErrorRecord -ErrorId System.StackOverflowException -Category InvalidOperation # # Then you can # $PSCmdlet.ThrowTerminatingError($ERRrecord) # #or # Write-Error -ErrorRecord $ERRrecord # .INPUTS # [string] # .OUTPUTS # [System.Management.Automation.ErrorRecord] # .NOTES # ErrorIds and Exceptions are from: https://powershellexplained.com/2017-04-07-all-dotnet-exception-list # I' am truly thankful to 'Kevin Marquette' for compiling that list. # .LINK # ErrorManager [Alias('New-Error')] [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'default')] [OutputType([System.Management.Automation.ErrorRecord])] param ( # A short Message that sums up all the error [Parameter(Mandatory = $false, Position = 0, ParameterSetName = 'default')] [Parameter(Mandatory = $false, Position = 1, ParameterSetName = 'ByException')] [Alias('msg')] [ValidateNotNullorEmpty()] [String]$Message, # For example An exception you already got from the pipeline. [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'ByException')] [System.Exception]$Exception, # Qualified Error Id, or Exception typename. [Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'default')] [Alias('Id', 'QualifiedErrorId')] [ArgumentCompleter({ [OutputType([System.Management.Automation.CompletionResult])] param([string]$CommandName, [string]$ParameterName, [string]$WordToComplete, [System.Management.Automation.Language.CommandAst]$CommandAst, [System.Collections.IDictionary]$FakeBoundParameters) $CompletionResults = [System.Collections.Generic.List[System.Management.Automation.CompletionResult]]::new() Get-Variable -Name AllExptnTypes -Scope Global | Select-Object -ExpandProperty value | Select-Object -ExpandProperty Typename | Where-Object { $_ -like "*$wordToComplete*" } | ForEach-Object { $CompletionResults.Add([System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)) } return $CompletionResults })] [System.String]$ErrorId, # Error Category [Parameter(Mandatory = $false, Position = 2, ParameterSetName = 'default')] [Alias('c', 'Category')] [ArgumentCompleter({ [OutputType([System.Management.Automation.CompletionResult])] param([string]$CommandName, [string]$ParameterName, [string]$WordToComplete, [System.Management.Automation.Language.CommandAst]$CommandAst, [System.Collections.IDictionary]$FakeBoundParameters) $CompletionResults = [System.Collections.Generic.List[System.Management.Automation.CompletionResult]]::new() [System.Management.Automation.ErrorCategory].GetMembers() | Where-Object { $_.MemberType -eq 'Field' -and $_.Name -notlike "*__*" } | Select-Object -ExpandProperty Name | Where-Object { $_ -like "*$wordToComplete*" } | ForEach-Object { $CompletionResults.Add([System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)) } return $CompletionResults })] [System.String]$ErrorCategory = 'NotSpecified', [Parameter(Mandatory = $false, Position = 3, ParameterSetName = 'default')] [string]$CategoryReason, # Description [Parameter(Mandatory = $false, Position = 4, ParameterSetName = 'default')] [Alias('d', 'desc')] [System.String]$Description, # Recommended Action to avoid the exception [Parameter(Mandatory = $false, Position = 5, ParameterSetName = 'default')] [Parameter(Mandatory = $false, Position = 2, ParameterSetName = 'ByException')] [Alias('rca', 'Recommendation')] [System.String]$RecommendedAction, [Parameter(Mandatory = $false, Position = 6, ParameterSetName = 'default')] [System.Exception]$InnerException, [Parameter(Mandatory = $false, Position = 7, ParameterSetName = 'default')] [Alias('Target', 'OffendingObject')] [System.Object]$TargetObject ) DynamicParam { $DynamicParams = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() $attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() $attributes = [System.Management.Automation.ParameterAttribute]::new(); $attHash = @{ Position = 8 ParameterSetName = '__AllParameterSets' Mandatory = $False ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true ValueFromRemainingArguments = $true HelpMessage = 'Allows splatting with arguments that do not apply. Do not use directly.' DontShow = $False }; $attHash.Keys | ForEach-Object { $attributes.$_ = $attHash.$_ } $attributeCollection.Add($attributes) # $attributeCollection.Add([System.Management.Automation.ValidateSetAttribute]::new([System.Object[]]$ValidateSetOption)) # $attributeCollection.Add([System.Management.Automation.ValidateRangeAttribute]::new([System.Int32[]]$ValidateRange)) # $attributeCollection.Add([System.Management.Automation.ValidateNotNullOrEmptyAttribute]::new()) # $attributeCollection.Add([System.Management.Automation.AliasAttribute]::new([System.String[]]$Aliases)) $RuntimeParam = [System.Management.Automation.RuntimeDefinedParameter]::new("IgnoredArguments", [Object[]], $attributeCollection) $DynamicParams.Add("IgnoredArguments", $RuntimeParam) return $DynamicParams } process { $fxn = ('[' + $MyInvocation.MyCommand.Name + ']') $oeap = $ErrorActionPreference; $ErrorActionPreference = 'SilentlyContinue' $PsCmdlet.MyInvocation.BoundParameters.GetEnumerator() | ForEach-Object { New-Variable -Name $_.Key -Value $_.Value -ea 'SilentlyContinue' } # $PsBoundParameters["Cmdlet"] = $(Get-Variable -Scope $($NestedPromptLevel + 1) PSCmdlet).Value try { $ExcepnTypeName = if (!$PSCmdlet.MyInvocation.BoundParameters.ContainsKey('InnerException') -and $PSCmdlet.ParameterSetName -eq 'default') { $ErrorId } elseif ($PSCmdlet.ParameterSetName -eq 'ByException') { $Exception.pstypenames[0] } $InnerException = New-Object -TypeName $ExcepnTypeName $ExcepnDescr = [string]$($AllExptnTypes | Where-Object { $_.TypeName -eq "$ExcepnTypeName" }).Description $RecommendedAction = if (![string]::IsNullOrEmpty($RecommendedAction)) { "`n + RecommendedAction : $RecommendedAction" }else { [string]::Empty } $MsgString = if ([string]::IsNullOrEmpty($Message)) { [string]$($InnerException.Message) }else { $Message } $ErrorMessage = "{0} {1}{2}" -f $MsgString, $ExcepnDescr, $RecommendedAction # Not sure how this is used for, but ... # TODO: Add a way to create full exception, with members like { Data, HelpLink, Source, StackTrace, WasThrownFromThrowStatement ...} $HelpLink = if ([string]::IsNullOrEmpty($HelpLink)) { "https://docs.microsoft.com/en-us/dotnet/api/$ExcepnTypeName" } $TargetObject = if ($PsCmdlet.MyInvocation.BoundParameters.ContainsKey('TargetObject') -and $null -eq $TargetObject) { [string]::Empty } $Exception = New-Object -TypeName $ExcepnTypeName -ArgumentList ("$ErrorMessage", "$InnerException") $ErrorRecord = [System.Management.Automation.ErrorRecord]::new($Exception, $ExcepnTypeName.Split('.')[-1], $ErrorCategory, $TargetObject) $IsSuccess = $? } catch { $IsSuccess = $false $Errxceptn = $_ } finally { $Execution = [PSCustomObject]@{ Output = $ErrorRecord IsSuccess = $IsSuccess Error = $Errxceptn } $EndMsg = $(if ($Execution.IsSuccess) { "Created Successfully." } else { "Completed With Errors. Check the log file : $LogPath" }) } } end { Out-Verbose $fxn "$EndMsg" $ErrorActionPreference = $oeap return $Execution.Output } } |