pipEnv.psm1

#!/usr/bin/env pwsh
using namespace System.IO
using namespace System.Collections.Generic
using namespace System.Management.Automation

#Requires -RunAsAdministrator
#Requires -Modules clihelper.env, cliHelper.core
#Requires -Psedition Core

#region Classes
enum EnvState {
  Inactive
  Active
}

enum PackageManager {
  pip
  poetry
}

enum EnvManagerName {
  pipEnv
}

class EnvironmentNotFoundException : Exception {
  EnvironmentNotFoundException([string]$Message) : base($Message) {}
}

class EnvManager {
  static [Dictionary[string, string]]$Environments = @{}
  static [PsRecord]$data = @{
    SharePipcache = $False
    ForceCreate   = $false
    CurrentPath   = { return (Resolve-Path .).Path }
    Session       = $null
    Manager       = [EnvManagerName]::pipEnv
    Home          = [EnvManager]::Get_work_Home()
    Os            = Get-HostOs
  }

  static [string] Get_work_Home() {
    $xdgDataHome = [Environment]::GetEnvironmentVariable("XDG_DATA_HOME", [EnvironmentVariableTarget]::User) # For Unix-like systems
    $whm = $xdgDataHome ? ([IO.Path]::Join($xdgDataHome, "virtualenvs")) : ([IO.Path]::Combine([Environment]::GetFolderPath("UserProfile"), ".local", "share", "virtualenvs"))
    $exp = [IO.Path]::Combine([Environment]::ExpandEnvironmentVariables($whm), "")
    $exp = [IO.Path]::GetFullPath([Environment]::ExpandEnvironmentVariables($exp))
    if (![IO.Directory]::Exists($exp)) {
      try {
        New-Item -Path $exp -ItemType Directory -Force | Out-Null
      } catch {
        throw "Failed to create directory '$exp': $_"
      }
    }
    return $exp
  }
  static [void] LoadEnvironments() {
    # Example: Load environments from a JSON file (you can customize this)
    $envFilePath = Join-Path $env:USERPROFILE ".python_environments.json"
    if (Test-Path $envFilePath) {
      [EnvManager]::Environments = Get-Content $envFilePath | ConvertFrom-Json -AsHashtable
    } else {
      [EnvManager]::Environments = @{}
    }
  }
  static [void] SaveEnvironments() {
    $envFilePath = Join-Path $env:USERPROFILE ".python_environments.json"
    [EnvManager]::Environments | ConvertTo-Json | Set-Content $envFilePath
  }
  static [bool] InstallPackage([string]$Environment, [string]$Package, [string]$Version) {
    try {
      if (![EnvManager]::Environments.ContainsKey($Environment)) {
        throw "Environment '$Environment' does not exist."
      }

      $pipPath = [EnvManager]::GetPipPath($Environment)
      if (!$pipPath) {
        throw "Could not find pip for environment '$Environment'."
      }

      $packageSpec = if ($Version) { "$Package==$Version" } else { $Package }
      & $pipPath install $packageSpec
      return $true
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to install package. $_" -f LightCoral
      return $false
    }
  }
  static [string] FindEnvFile() {
    return [EnvManager]::FindEnvFile((Resolve-Path .).Path)
  }
  static [string] FindEnvFile([string]$folderPath) {
    $envFilePriority = @(".env.local", ".env", ".env.development", ".env.production", ".env.test")
    $files = Get-ChildItem -File -Path $folderPath -Force
    foreach ($envFile in $envFilePriority) {
      $foundFile = $files.Where({ $_.Name -eq $envFile }) | Select-Object -First 1
      if ($foundFile) {
        return $foundFile.FullName
      }
    }
    return [IO.Path]::Combine($folderPath, ".env")
  }
  static [bool] UpdatePackage([string]$Environment, [string]$Package, [string]$Version) {
    try {
      if (![EnvManager]::Environments.ContainsKey($Environment)) {
        throw [InvalidOperationException]::new("Environment '$Environment' does not exist!")
      }

      $pipPath = [EnvManager]::GetPipPath($Environment)
      if (!$pipPath) {
        throw "Could not find pip for environment '$Environment'."
      }

      $packageSpec = if ($Version) { "$Package==$Version" } else { $Package }
      & $pipPath install --upgrade $packageSpec
      return $true
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to update package. $_" -f LightCoral
      return $false
    }
  }
  static [List[Hashtable]] ListPackages([string]$Environment) {
    try {
      if (![EnvManager]::Environments.ContainsKey($Environment)) {
        throw [InvalidOperationException]::new("Environment '$Environment' does not exist!")
      }

      $pipPath = [EnvManager]::GetPipPath($Environment)
      if (!$pipPath) {
        throw "Could not find pip for environment '$Environment'."
      }

      $packages = & $pipPath list --format=json
      return $packages | ConvertFrom-Json | ForEach-Object { @{
          Name    = $_.name
          Version = $_.version
        } }
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to list packages. $_" -f LightCoral
      return [List[Hashtable]]::new()
    }
  }
  static [List[string]] ListEnvironments() {
    return [List[string]][EnvManager]::Environments.Keys
  }
  static [string] GetPipPath([string]$Environment) {
    $envPath = [EnvManager]::Environments[$Environment]
    if (!$envPath) {
      return $null
    }
    if ((xcrypt Get_Host_Os) -eq "Windows") {
      return [IO.Path]::Combine($envPath, "Scripts", "pip.exe")
    } else {
      return [IO.Path]::Combine($envPath, "bin", "pip")
    }
  }
  static [bool] AddEnvironment([string]$Name, [string]$Path) {
    if ([EnvManager]::Environments.ContainsKey($Name)) {
      Write-Console "Environment '$Name' already exists." -f LightCoral
      return $false
    }
    [EnvManager]::Environments[$Name] = $Path
    [EnvManager]::SaveEnvironments()
    return $true
  }
  static [bool] RemoveEnvironment([string]$Name) {
    if (![EnvManager]::Environments.ContainsKey($Name)) {
      Write-Console "Environment '$Name' does not exist." -f LightCoral
      return $false
    }
    [EnvManager]::Environments.Remove($Name)
    [EnvManager]::SaveEnvironments()
    return $true
  }
}

# .SYNOPSIS
# python virtual environment manager
class venv : EnvManager, IDisposable {
  [string]$Path
  static [InstallRequirements]$req = @(
    ("Python", "Programming Language. i.e: https://github.com/python/cpython", { Install-Python } ),
    ("PipEnv", "Python virtualenv management tool", { Install-PipEnv } )
  )
  [PackageManager]$PackageManager
  [version]$PythonVersion
  [string]$CreatedAt
  hidden [string]$ProjectPath
  hidden [bool] $__Isdisposed
  hidden [string]$__name
  venv() {
    [void][venv]::From([IO.DirectoryInfo]::new([venv]::data.CurrentPath), [ref]$this)
  }
  venv([string]$dir) {
    [void][venv]::From([IO.DirectoryInfo]::new([xcrypt]::GetUnResolvedPath($dir)), [ref]$this)
  }
  venv([IO.DirectoryInfo]$dir) {
    [void][venv]::From($dir, [ref]$this)
  }
  static [venv] Create() {
    return [venv]::Create([IO.DirectoryInfo]::new([venv]::data.CurrentPath))
  }
  static [venv] Create([string]$dir) {
    return [venv]::Create([IO.DirectoryInfo]::new($dir))
  }
  static [venv] Create([IO.DirectoryInfo]$dir) {
    # .INPUTS
    # DirectoryInfo: It can be the project path or the exact path for the venv.
    if (!$dir.Exists) { throw [Argumentexception]::new("Please provide a valid path!", [DirectoryNotFoundException]::new("Directory not found: $dir")) }
    $new = $null; if (!$dir.IsNotValidVenv) { $e = $dir -as [venv]; $e.IsValid ? $(return $e) : $null }
    # Create new virtual environment named $dir.BaseName and save in work_home [venv]::data.Home
    $_root_path = (Resolve-Path .).Path
    $usrEnvfile = [IO.FileInfo]::new([venv]::FindEnvFile());
    $wasNotHere = !$usrEnvfile.Exists
    $name = ($dir.BaseName -as [version] -is [version]) ? ("{0}_{1}" -f $dir.Parent.BaseName, $dir.BaseName) : $dir.BaseName
    # https://pipenv.pypa.io/en/latest/virtualenv.html#virtual-environment-name
    if (![string]::IsNullOrWhiteSpace($name)) {
      Edit-EnvCfg -Path $usrEnvfile.FullName -key "PIPENV_CUSTOM_VENV_NAME" -value $name
    }
    try {
      Set-Location $dir.FullName
      Write-Console "[venv] " -f BlueViolet -NoNewLine; Write-Console "Creating virtual env for '$($dir.FullName | Invoke-PathShortener)' ... " -f PaleTurquoise -NoNewLine
      Invoke-PipEnv "install", "check"
      $p = Search-EnvPath
      if ([IO.Directory]::Exists("$p")) {
        $new = [venv]::new($p)
      } else {
        Write-Warning "LOOPING!"
        $new = [venv]::Create()
      }
      Write-Console "Done" -f Green
    } catch {
      throw [InvalidOperationException]::new("Failed to create a venv Object", $_.Exception) | Write-Console -f PaleTurquoise
    } finally {
      Set-Location $_root_path;
      if ($wasNotHere) { $usrEnvfile.FullName | Remove-Item -Force -ea Ignore }
    }
    return $new
  }
  static hidden [venv] From([IO.DirectoryInfo]$dir, [ref]$o) {
    # .SYNOPSIS
    # Loads the venv object from directory info
    # .DESCRIPTION
    # Does not create a new venv, meaning it can create a valid venv object from a directory
    # Only if that directory is a valid env directory.
    $p = $dir.FullName; $v = [ProgressUtil]::data.ShowProgress
    if (![venv]::IsValid($p)) {
      $valid_env_paths = $dir.EnumerateDirectories("*", [SearchOption]::TopDirectoryOnly).Where({ [venv]::IsValid($_.FullName) })
      if ($valid_env_paths.count -ne 1) {
        # possible reason 1: ($valid_env_paths.count -eq 0) => throw [EnvironmentNotFoundException]::new("No environment directory found for in $dir")
        # possible reason 2: ($valid_env_paths.count -gt 1) => throw [EnvironmentNotFoundException]::new("Multiple environment directories found in $dir")
        $v ? $(Write-Debug "[venv] Try using already created env in: $([venv]::data.Home | Invoke-PathShortener) ... ") : $null
        $p = Search-EnvPath $p
      } else {
        $p = $valid_env_paths[0].FullName
      }
    }
    if (![venv]::IsValid($p)) {
      $msg = "Path $p is not a valid venv"
      if ([venv]::data.ForceCreate) {
        $v ? $(Write-Console "[venv] " -f BlueViolet -NoNewLine; Write-Console "$msg, so lets create a new one." -f PaleTurquoise) : $null
        $dir.PsObject.Properties.Add([psnoteproperty]::new("IsNotValidVenv", $true))
        return [venv]::Create($dir)
      } else {
        throw [System.InvalidOperationException]::new("InvalidOperation: $msg")
      }
    }
    [venv]::data.set('Session', $([ref]$o.Value).Value)
    [IO.Directory]::Exists($p) ? (Get-Item $p | Set-ItemProperty -Name Attributes -Value ([IO.FileAttributes]::Hidden)) : $null
    [venv].PsObject.Properties.Add([PsScriptproperty]::new('CONSTANTS', { return [scriptblock]::Create("@{
            # Add your constant primitives here:
            validversionregex = '^(0|[1-9]\d*)(\.(0|[1-9]\d*)){0,3}$'
          }"
).InvokeReturnAsIs()
        }, { throw [SetValueException]::new("CONSTANTS is read-only") }
      )
    )
    $o.Value.PsObject.Properties.Add([Psscriptproperty]::new('Name', {
          $v = [venv]::IsValid($this.Path)
          $has_deact_command = $null -ne (Get-Command deactivate -ea Ignore);
          $this.PsObject.Properties.Add([Psscriptproperty]::new('State', [scriptblock]::Create("return [EnvState][int]$([int]$($has_deact_command -and $v))"), { throw [SetValueException]::new("State is read-only") }));
          $this.PsObject.Properties.Add([Psscriptproperty]::new('IsValid', [scriptblock]::Create("return [IO.Path]::Exists(`$this.Path) -and [bool]$([int]$v)"), { throw [SetValueException]::new("IsValid is read-only") }));
          return "({0}) {1}" -f [venv]::data.Manager, ($v ? $this.__name : '✖');
        }, { Param([string]$n) [string]::IsNullOrWhiteSpace("$($this.__name) ".Trim()) ? ($this.__name = $n) : $null }
      )
    )
    $o.Value.Name = (Get-Item $p).Name;
    $o.Value.Path = $p; #the exact path for the venv
    $o.Value.ProjectPath = $dir.FullName
    $o.Value.PsObject.Properties.Add([Psscriptproperty]::new('BinPath', { return [IO.Path]::Combine($this.Path, "bin") }, { throw [SetValueException]::new("BinPath is read-only") }))
    $o.Value.CreatedAt = [Datetime]::Now.ToString();
    [venv]::data.PsObject.Properties.Add([PsScriptproperty]::new('PythonVersions', { return [venv]::get_python_versions() }, { throw [SetValueException]::new("PythonVersions is read-only") }))
    [venv]::data.PsObject.Properties.Add([PsScriptproperty]::new('SelectedVersion', { return [version]$(python --version).Split(" ").Where({ $_ -match '^(0|[1-9]\d*)(\.(0|[1-9]\d*)){0,3}$' })[0] }, { throw [SetValueException]::new("SelectedVersion is read-only") }))
    # $p = python -c "import pipenv; print(pipenv.__file__)"; ie: (Get-Command pipenv -Type Application -ea Ignore).Source
    [venv]::data.set('RequirementsFile', "requirements.txt"); ![venv]::req.resolved ? [venv]::req.Resolve() : $null
    $o.Value.PythonVersion = [venv]::data.selectedversion;
    if (![string]::IsNullOrWhiteSpace($dir.Name) -and $o.Value.IsValid) {
      $env_config = Read-Env -File ([IO.Path]::Combine($o.Value.Path, 'pyvenv.cfg'));
      $config_map = @{}; $env_config.Name.ForEach({ $n = $_; $config_map[$n] = $env_config.Where({ $_.Name -eq $n }).value });
      [venv]::data.Set($config_map)
    }
    return $o.Value
  }
  static [Object[]] SetLocalVersion() {
    return [venv]::SetLocalVersion([Path]::Combine([venv]::data.CurrentPath, ".python-version"))
  }
  static [Object[]] SetLocalVersion([string]$str = "versionfile_or_version") {
    $res = $null; [ValidateNotNullOrWhiteSpace()][string]$str = $str;
    $ver = switch ($true) {
      ([IO.File]::Exists($str)) {
        $ver_in_file = Get-Content $str; $localver = pyenv local
        ($localver -ne $ver_in_file) ? $ver_in_file : $null
        break
      }
      ($str -as [version] -is [version]) { $str; break }
      Default { $null }
    }
    if ($null -ne $ver) {
      $res = [ThreadRunner]::Run("Install python $ver", { param([string]$v) pyenv install $v }, ($ver))
    }
    return $res
  }
  [string] get_activation_script() {
    return $this.get_activation_script($this.Path)
  }
  [string] get_activation_script([string]$Path) {
    $s = ([venv]::IsValid($Path) ? ([IO.Path]::Combine($Path, 'bin', 'activate.ps1')) : '')
    if (![IO.File]::Exists($s)) { throw [Exception]::new("Failed to get activation script", [FileNotFoundException]::new("file '$s' not found!")) }
    return $s
  }
  static [IO.FileInfo] get_python_executable() {
    $pyenv_root = [IO.Path]::Combine($(Get-Variable HOME -ValueOnly), ".pyenv")
    if (![venv]::has_pyenv()) { Install-PyEnv } # i.e: will create $pyenv_root
    $py = [IO.FileInfo]::new([IO.Path]::Combine($pyenv_root, "shims", "python"))
    if (!$py.Exists) { throw [Exception]::new("Python not found", [FileNotFoundException]::new("file '$py' not found!")) }
    return $py
  }
  static [version[]] get_python_versions() {
    $py = [venv]::get_python_executable(); $versions = @()
    $pe = [IO.Path]::Combine($(Get-Variable HOME -ValueOnly), ".pyenv", "bin", "pyenv")
    $vs = (&$pe versions).Split("`n").Trim()
    if ($vs.count -gt 1) {
      $versions = ($vs | Select-Object @{l = "version"; e = {
            $l = $_;
            if ($l.StartsWith("*")) { $l = $l.Substring(1).TrimStart().Split(' ')[0] };
            ($l -match '^(0|[1-9]\d*)(\.(0|[1-9]\d*)){0,3}$') ? $l : "not-a-version"
          }
        } | Where-Object { $_.version -ne "not-a-version" }).version
    } elseif ($vs -like "*system (*") {
      $versions += (&$py --version).Split(" ")[1] -as [version]
    }
    return $versions
  }
  static [bool] IsValid([string]$dir) {
    $v = $true; $d = [IO.DirectoryInfo]::new([xcrypt]::GetUnResolvedPath($dir)); ("bin", "lib").ForEach{
      $_d = $d.EnumerateDirectories($_); $v = $v -and (($_d.count -eq 1) ? $true : $false)
      if ($_ -eq 'bin') { $v = $v -and (($_d[0].EnumerateFiles("activate*").Count -gt 0) ? $true : $false) }
    }; $v = $v -and (($d.EnumerateFiles("pyvenv.cfg").Count -eq 1) ? $true : $false);
    return $v
  }
  [Object[]] Activate() {
    if ($this.__Isdisposed) { throw [InvalidOperationException]::new("Activation is not possible as Environment is already disposed") }
    return & ([venv]::data.Session.get_activation_script())
  }
  [Object[]] Verify() { return Invoke-PipEnv "verify" }
  [Object[]] Upgrade() { pip install --user --upgrade pipenv; return Invoke-PipEnv "upgrade" }
  [Object[]] Sync() { return Invoke-PipEnv "sync" }
  [Object[]] Lock() { return Invoke-PipEnv "lock" }
  [Object[]] Install() { python -m pipenv install -q; return Invoke-PipEnv "install" }
  [Object[]] Install([string]$package) { python -m pipenv install -q $package; return Invoke-PipEnv "install" }
  [Object[]] Remove() { return python -m pipenv --rm }

  [bool] Clone([string]$Source, [string]$Destination) {
    try {
      if (!$this.Environments.ContainsKey($Source)) {
        throw [InvalidOperationException]::new("Source environment '$Source' does not exist!")
      }
      $sourcePath = $this.Environments[$Source]
      $destinationPath = "$sourcePath\..\$Destination"
      Copy-Item -Path "$sourcePath" -Destination $destinationPath -Recurse
      $this.Environments[$Destination] = $destinationPath
      $this.Save()
      return $true
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to clone environment. $_" -f LightCoral
      return $false
    }
  }
  [bool] Export([string]$Name, [string]$OutputFile) {
    try {
      if (!$this.Environments.ContainsKey($Name)) {
        throw "Environment '$Name' does not exist."
      }
      & "$($this.Environments[$Name])/$Name/Scripts/pip.exe" freeze > $OutputFile
      return $true
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to export environment. $_" -f LightCoral
      return $false
    }
  }
  [bool] Import([string]$InputFile) {
    try {
      $packages = Get-Content $InputFile
      foreach ($package in $packages) {
        $this.InstallPackage($package, $null)
      }
      return $true
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to import environment. $_" -f LightCoral
      return $false
    }
  }
  [bool] CheckCompatibility([string]$Package, [string]$Version) {
    try {
      $result = pip check "$Package==$Version"
      return ($result -eq "No broken dependencies")
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to check compatibility: $_" -f LightCoral
      return $false
    }
  }
  [Hashtable] GetDetails([string]$Name) {
    try {
      if (!$this.Environments.ContainsKey($Name)) {
        throw "Environment '$Name' does not exist."
      }
      $details = @{
        Name     = $Name
        Path     = $this.Environments[$Name]
        Packages = $this.ListPackages($Name)
        Active   = ($this.Name -eq $Name)
      }
      return $details
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to get details. $_" -f LightCoral
      return @{}
    }
  }
  static [bool] has_pyenv() {
    return [bool](Get-Command pyenv -type Application -ea Ignore)
  }
  [bool] SyncWithGlobal([List[string]]$Exclusions) {
    try {
      if ($null -eq $this.Name) {
        throw "No environment is currently active."
      }
      $globalPackages = pip list --format=json | ConvertFrom-Json | ForEach-Object { $_.name }
      foreach ($package in $globalPackages) {
        if (!($Exclusions -contains $package)) {
          $this.InstallPackage($package, $null)
        }
      }
      return $true
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine ; Write-Console "Failed to sync with global. $_" -f LightCoral
      return $false
    }
  }
  [EnvState] CheckStatus([string]$Name) {
    if (!$this.Environments.ContainsKey($Name)) { throw "Environment '$Name' does not exist." }
    $status = ''
    try {
      $status = switch ($true) {
        ($this.Name -eq $Name) { "active"; break }
        default {
          "inactive"
        }
      }
    } catch {
      throw "Failed to check status: $_"
    }
    return $status
  }
  [bool] Deactivate() {
    try {
      if ($null -eq $this.Name) {
        throw [System.InvalidOperationException]::new("No environment is currently active.")
      }
      if (!$this.__Isdisposed) {
        if ([bool](Get-Command deactivate -CommandType Function -ea Ignore)) {
          deactivate
        }
        $this.Name = $null
        return $true
      } else {
        Write-Console "[✖] " -f Red -NoNewLine; Write-Console "Environment is already disposed." -f LightCoral
      }
    } catch {
      Write-Console "[✖] " -f Red -NoNewLine; Write-Console "Failed to deactivate environment. $_" -f LightCoral
    }
    return $false
  }
  [void] Save() {
    # Save environments to a configuration file or registry
    # This is a placeholder for actual implementation
    # For example, writing to a JSON file
    # $config = @{ Environments = $this.Environments }
    # $config | ConvertTo-Json | Set-Content -Path "EnvManagerConfig.json"
  }
  [string] ToString() {
    return $this.Name
  }
  [void] Delete() {
    $this.Path | Remove-Item -Force -Recurse -Verbose:$false -ea Ignore
  }
  [void] Dispose() {
    if (!$this.__Isdisposed) {
      $this.Deactivate()
      $this.Delete()
      $this.__Isdisposed = $true
    }
  }
}

#endregion Classes
# Types that will be available to users when they import the module.
$typestoExport = @(
  [EnvManagerName],
  [EnvState],
  [venv]
)
$TypeAcceleratorsClass = [PsObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')
foreach ($Type in $typestoExport) {
  if ($Type.FullName -in $TypeAcceleratorsClass::Get.Keys) {
    $Message = @(
      "Unable to register type accelerator '$($Type.FullName)'"
      'Accelerator already exists.'
    ) -join ' - '
    "TypeAcceleratorAlreadyExists $Message" | Write-Debug
  }
}
# Add type accelerators for every exportable type.
foreach ($Type in $typestoExport) {
  $TypeAcceleratorsClass::Add($Type.FullName, $Type)
}
# Remove type accelerators when the module is removed.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
  foreach ($Type in $typestoExport) {
    $TypeAcceleratorsClass::Remove($Type.FullName)
  }
}.GetNewClosure();

$scripts = @();
$Public = Get-ChildItem "$PSScriptRoot/Public" -Filter "*.ps1" -Recurse -ErrorAction SilentlyContinue
$scripts += Get-ChildItem "$PSScriptRoot/Private" -Filter "*.ps1" -Recurse -ErrorAction SilentlyContinue
$scripts += $Public

foreach ($file in $scripts) {
  Try {
    if ([string]::IsNullOrWhiteSpace($file.fullname)) { continue }
    . "$($file.fullname)"
  } Catch {
    Write-Warning "Failed to import function $($file.BaseName): $_"
    $host.UI.WriteErrorLine($_)
  }
}

$Param = @{
  Function = $Public.BaseName
  Cmdlet   = '*'
  Alias    = '*'
  Verbose  = $false
}
Export-ModuleMember @Param