I am trying to learn how to properly create error objects with non-powershell command output. My first attempt at this involved making a module that wrapped a conda command and tested on $System.Diagnostics.Process.ExitCode. I have set up an example of a command failure by creating a dev_environment.yml with a title too long for conda to successfully create an environment. This thows a conda error called EnvironmentNotWritableError, but as expected when in a try-catch loop and using thow, it is intercepted, and “Conda-Error” is written to the terminal.
Here is the code I use to call the module:
Import-Module -Name C:MyDirectory\EncapsulateComm
andOld.psm1
try {
New-Command -Command "conda" -Arguments "env create --file C:MyDirectory\my_conda_envs\terminating-error\dev_environme
nt.yml"
}
catch {
Write-Host "Conda Error"
}
Here is the code for that module:
function New-Command {
[CmdletBinding(PositionalBinding = $true)]
param(
[Parameter(Mandatory, Position = 0)][string]$Command,
[Parameter(Mandatory, Position = 1)][string]$Arguments
)
# Create an object with the info powershell needs to know
$commandInfo = New-Object System.Diagnostics.ProcessStartInfo
#command program goes here
$commandInfo.FileName = $Command
#command arguments go here (single string)
$commandInfo.Arguments = $Arguments
$commandInfo.RedirectStandardOutput = $true
$commandInfo.RedirectStandardError = $true
$commandInfo.UseShellExecute = $false
$commandInfo.CreateNoWindow = $true
$commandStart = New-Object System.Diagnostics.Process
$commandStart.StartInfo = $commandInfo
$commandStart.Start() | Out-Null
$standardOutput = $commandStart.StandardOutput.ReadToEnd()
$standardError = $commandStart.StandardError.ReadToEnd()
$commandStart.WaitForExit()
# Check if there was an error
if ($commandStart.ExitCode -ne 0) {
throw $standardError
}
# Output the standard output
Write-Host $standardOutput
return $standardOutput, $standardError, $Command
}
Export-ModuleMember -Function New-Command
In a second iteration of creating this module, I attempted to make a custom error from the System.Exception class. However when I attempt to call the class I made, I get this error:
InvalidOperation: MyDirectory/creating-custom-error-records.ps1:9:7
Line |
9 | catch [CondaEnvironmentNotWritableException] {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Unable to find type [CondaEnvironmentNotWritableException].
Here how I call it:
Import-Module -Name ~\MyDirectory\EncapsulateCommand.psm1
try {
New-Command -Command "conda" -Arguments "env create --file C:\MyDirectory\my_conda_envs\terminating-error\dev_environment.yml"
}
catch [CondaEnvironmentNotWritableException] {
Write-Host "Conda Error"
}
Here is the module containing the CondaEnvironmentNotWritableException as well as the encapsulation code.
class CondaEnvironmentNotWritableException : System.Exception {
$erroredCommand
$erroredArguments
#no return type
CondaEnvironmentNotWritableException([string] $message) : base($message) {
}
CondaEnvironmentNotWritableException() {
}
}
function New-Command {
[CmdletBinding(PositionalBinding = $true)]
param(
[Parameter(Mandatory, Position = 0)][string]$Command,
[Parameter(Mandatory, Position = 1)][string]$Arguments
)
# Create an object with the info powershell needs to know
$commandInfo = New-Object System.Diagnostics.ProcessStartInfo
#command program goes here
$commandInfo.FileName = $Command
#command arguments go here (single string)
$commandInfo.Arguments = $Arguments
$commandInfo.RedirectStandardOutput = $true
$commandInfo.RedirectStandardError = $true
$commandInfo.UseShellExecute = $false
$commandInfo.CreateNoWindow = $true
$commandStart = New-Object System.Diagnostics.Process
$commandStart.StartInfo = $commandInfo
$commandStart.Start() | Out-Null
$standardOutput = $commandStart.StandardOutput.ReadToEnd()
$standardError = $commandStart.StandardError.ReadToEnd()
$commandStart.WaitForExit()
# Check if there was an error
if ($commandStart.ExitCode -ne 0) {
if ($standardError -match "EnvironmentNotWritableError") {
$condaError = [CondaEnvironmentNotWritableException]::new("Environment is not writable.")
$condaError.erroredCommand = $Command
$condaError.erroredArguments = $Arguments
throw $condaError
}
else {
throw "Command failed with exit code $($commandStart.ExitCode): $standardError"
}
}
# Output the standard output
Write-Host $standardOutput
return $standardOutput, $standardError, $Command
}
Export-ModuleMember -Function New-Command
My questions are as follows:
- I’ve been getting the impression from reading non-microsoft documentation(reddit/stackoverflow/powershell issues) that using “throw” is bad practice. If I was in a hurry, and did not want to make a class based error, what should I be doing for the first module instead?
- General advice on how to include a module that also includes an error class. I am aware that the export line at the end of the module limits what is exported from the module to file where I import it. However, since the class is created in and thrown by the module itself I was not under the impression I needed to export it as well. Would I need to export the class into the file where I call New-Command in order to catch the error?
- The end goal here is to create a statement-terminating error. I have used throw in the second module to call my error object. I am unsure if this is the best practice way to do this. Is there a better way to call this error class in a way that exhibits that behavior?