Search code examples
powershellpowershell-5.1

Allow function to run in parent scope?


Pardon the title wording if it's a bit confusing. . .

I have a very simple script that just dot sources a .ps1 file but, since it runs inside a function, it doesn't get loaded into the parent scope which is my ultimate objective.

function Reload-ToolBox {
    Param (
        [Parameter(Mandatory=$false)]
        [ValidateSet('TechToolBox',
                     'NetworkToolBox','All')]
        [string[]]$Name = 'TechToolBox'
    )
    Begin 
    {
        $ToolBoxes = @{
            TechToolBox     = "\\path\to\my\ps1.ps1"
            NetworkToolBox  = "\\path\to\my\ps2.ps1"
        }
        if ($($PSBoundParameters.Values) -contains 'All') {
            $null = $ToolBoxes.Add('All',$($ToolBoxes.Values | Out-String -Stream))
        }

        $DotSource = {
            foreach ($PS1Path in $ToolBoxes.$ToolBox)
            {
                . $PS1Path
            }
        }
    }
    Process 
    {
        foreach ($ToolBox in $Name) 
        {
            
            Switch -Regex ($ToolBoxes.Keys) 
            {
                {$_ -match "^$ToolBox$"} { & $DotSource } 
            }

        }

    }
    End { }
}

Question:

  • How would I be able to load the ps1 being called in the function, into the parent scope?

google no helped:(


Solution

    • In order for dot-sourcing performed inside your function to also take effect for the function's caller, you must dot-source the function call itself (. Reload-TooBox ...)

    • Unfortunately, there is no way to make this dot-sourcing automatic, but you can at least check whether the function was called via dot-sourcing, and report an error with instructions otherwise.

    Here's a streamlined version of your function that includes this check:

    function Reload-ToolBox {
      [CmdletBinding()]
      Param (
        [ValidateSet('TechToolBox', 'NetworkToolBox', 'All')]
        [string[]] $Name = 'TechToolBox'
      )
      Begin {
        # Makes sure that *this* function is also being dot-sourced, as only
        # then does dot-sourcing of scripts from inside it also take effect
        # for the caller.
        if ($MyInvocation.CommandOrigin -ne 'Internal') { # Not dot-sourced?
          throw "You must DOT-SOURCE calls to this function: . $((Get-PSCallStack)[1].Position.Text)"
        }
    
        $ToolBoxes = @{
          TechToolBox    = "\\path\to\my\ps1.ps1"
          NetworkToolBox = "\\path\to\my\ps2.ps1"
        }
        $ToolBoxes.All = @($ToolBoxes.Values)
    
        if ($Name -Contains 'All') { $Name = 'All' }
    
      }
    
      Process {
    
        foreach ($n in $Name)  {
          foreach ($script in $ToolBoxes.$n) {
            Write-Verbose "Dot-sourcing $script..."
            . $script
          }
        }
    
      }
    }