General Advice on Modules, Errors, and Throw

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:

  1. 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?
  2. 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?
  3. 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?