Ok, I found something that works for simple functions, at least. We can use Get-Item to get an object describing the function, and then pull out the original script. Like this:
function x-caller-generator() { $xFunc = [ScriptBlock]::Create((Get-Item function:x).Definition) return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() }
If a function is never overridden (for example, in my example, when my function is not available), we can avoid removing the definition and simply use the function object directly:
function closure-maker () { function x() { Write-Host 'x!' } $xFunc = Get-Item function:x return { Write-host 'Calling x'; & $xFunc }.GetNewClosure() }
This second method will not work if the function is overridden (at least in the same area as the original function) before closing. The object is apparently dynamic; It keeps track of the current definition.
I seriously doubt that this will work with a function that refers to other user-defined functions that may also not be available, but my use case did not require this.
Output Example:
Creating a script block
PS C:\> function x() { Write-Host 'original x' } PS C:\> function x-caller-generator() { $xFunc = [ScriptBlock]::Create((Get-Item function:x).Definition); return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() } PS C:\> $y = x-caller-generator PS C:\> & $y Calling x! original x PS C:\> function x() { Write-Host 'new x' } PS C:\> & $y Calling x! original x
Functional Object Use
PS C:\> function closure-maker () { >> function x() { Write-Host 'x!' } >> >> $xFunc = Get-Item function:x >> return { Write-host 'Calling x'; & $xFunc }.GetNewClosure() >> } >> PS C:\> $y = closure-maker PS C:\> & $y Calling x x!
Trying to use an object with the first example does not work :
PS C:\> function x() { Write-Host 'original x' } PS C:\> function x-caller-generator() { $xFunc = Get-Item function:x; return { Write-host 'Calling x!'; & $xFunc }.GetNewClosure() } PS C:\> $y = x-caller-generator PS C:\> & $y Calling x! original x PS C:\> function x() { Write-Host 'new x' } PS C:\> & $y Calling x! new x
source share