PowerShell Profile and Global Functions
by dwarfsoft on Jul.16, 2012, under Scripting, Work
So I came across an interesting problem today while trying to dynamically load Functions using a Load-Lib function. The issue was that Loading a Script within a function means that the functions defined within that File are only defined within the Scope of the loading function. The two ways around this are to Define every Function like:
Function Global:Load-Lib { ... |
Personally, I wanted my script to be the same whether I was loading it as a Global Module, or locally within a Function. In order to get the behaviour I wanted I had to redefine the functions as Global dynamically. This idea would also resolve the other issue I had: Redefining functions did not seem to always overwrite or replace the existing function code.
So now to some code…
Function Load-Lib { Param( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] [String]$LibraryName ) dir "$__ProfileDir\Libraries" -recurse | ?{$_.name -match $LibraryName} | foreach { #Clean out Functions Unload-Lib $LibraryName $funcbefore = Get-Item Function: Write-Host "Loading Library $($_.Name)" -Foreground Blue; . $_.FullName $funcafter = Get-Item Function: $funcafter | where { !($funcbefore -contains $_) } | %{ Write-Host $_.Name If (Test-Path "Function:Global:$($_.Name)") { Remove-Item "Function:Global:$($_.Name)" -Force | Out-Null } If (Test-Path "Function:$($_.Name)") { Remove-Item "Function:$($_.Name)" -Force | Out-Null } #Get-Item Function: try { New-Item -Path Function: -Name "Global:$($_.Name)" -Value $_.ScriptBlock -Force | Out-Null Write-Host " Reloaded function as Function:Global:$($_.Name)" -Foreground Green } catch { Write-Host " Failed to Reload function as Function:Global:$($_.Name)" -Foreground Red } } } } |
So in the above script I poll the defined functions before loading the script, then for each one I redefine as “Function:Global:$_”. In order for it to work properly I need to make sure that existing functions are unloaded, so I need to do some funky regex to get the functions defined in the script, and remove them each individually (either Function:Global:$_ or Function:$_ because it still shows up in the “Get-Item Function:” list without Global: (even if it is).
Function Unload-Lib { Param( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] [String]$LibraryName ) dir "$__ProfileDir\Libraries" -recurse | ?{$_.name -match $LibraryName} | foreach { $txt = [io.file]::ReadAllText($_.FullName) $funcs = ($txt.Split("`n`r") | % {$_.Trim()} | Select-String -Pattern '^(Function) (?<FName>[^ ({]*)' | %{$_.Matches[0].Groups["FName"].Value}) $funcs | % { if (Test-Path Function:$_) { Write-Host " Removing Function:$_" -Foreground Magenta Remove-Item Function:$_ -Force | Out-Null } if (Test-Path Function:Global:$_) { Write-Host " Removing Function:Global:$_" -Foreground Magenta Remove-Item Function:Global:$_ -Force | Out-Null } } } } |
There are a few more things I’ve found out, I’ll try and get up sometime in the next few days.
Cheers, Chris.
You must be logged in to post a comment.