powershellclasspowershell-module

PowerShell dot source within a dot sourced file - import classes


My project is structured like this:

MyScript.ps1
classes\
    Car.ps1
    Tesla.ps1

Car.ps1 is the base class of Tesla.ps1. I attempt to define Tesla like this in Tesla.ps1:

. "$PSScriptRoot\Car.ps1"

class Tesla : Car
{
}

MyScript.ps1 needs to use the Tesla class, but shouldn't need to know that it inherits from Car.

. "$PSScriptRoot\classes\Tesla.ps1"

$tesla = [Tesla]::new()

Dot sourcing to classes\Tesla.ps1 works fine, but this error is thrown from the Tesla file:

Unable to find type [Car]

If I import all the files in the correct order in MyScript.ps1, it works fine. Example:

. "$PSScriptRoot\classes\Car.ps1"
. "$PSScriptRoot\classes\Tesla.ps1"

$tesla = [Tesla]::new()

This is cumbersome, especially as the complexity grows. Am I dot sourcing incorrectly? Is there a better way to import a custom PowerShell class using a relative path that isn't in the PSModulePath?


Solution

  • PetSerAl, as countless times before, has provided the crucial pointers in a terse comment on the question:

    Due to your use of classes, you must use modules and import them with using module statements in order to use them.

    Specifically, in order to reference a type (class) in a class definition, that type must be known to PowerShell at parse time.

    In your example, in order to derive Tesla from class Car, type Car must be known to PowerShell when the script is parsed, before execution begins - that's why it is too late to try to import Car by dot-sourcing its containing script (. "$PSScriptRoot\Car.ps1")

    PowerShell knows about referenced types at parse time in one of two ways:

    Therefore, as PetSerAl suggests:

    MyScript.ps1
    classes\
        Car.psm1    # Note the .psm1 extension
        Tesla.psm1  # Ditto
    

    Car.psm1:

    class Car {}
    

    Tesla.psm1:

    using module .\Car.psm1
    
    class Tesla : Car {}
    

    MyScript.ps1:

    using module .\classes\Tesla.psm1
    
    $tesla = [Tesla]::new()