1

I'm ashamedly plagiarising part of an answer given by @mjolinor, here, It works until I replace copy-fileHC with $FunctionName. I need to be able to pass the name of the function to call as a variable.

I think I am getting caught out because the script block can't 'see' the $FunctionName variable, but I am unsure how to get it to work. I have tried passing a separate param($functionName) but still, it doesn't work.

Here is my script thus far (that works):

Function Invoke-FunctionRunAs
{
    [cmdletbinding()]
    Param
    (
        [string]$FunctionName,
        [HashTable]$FunctionParameters,
        [System.Management.Automation.CredentialAttribute()]$Credentials
    )

    $CallingUser = [Security.Principal.WindowsIdentity]::GetCurrent().Name

    $RunAsDomain = $credentials.GetNetworkCredential().Domain
    $RunAsUser = $Credentials.GetNetworkCredential().username

    if(-not($RunAsDomain))
    {
        $RunAsDomain = "."
    }

    #$functionParameters.Add('FunctionName', $FunctionName)    

    Write-Verbose "Calling user: $CallingUser"
    Write-Verbose "Attempting to run scriptblock as $RunAsDomain\$RunAsUser"
    Write-Verbose "Called function: $functionName"
    Write-Verbose ("Passed parameters: $($FunctionParameters | Out-String)") 
    #$FunctionName = "Function:$FunctionName"

    $ScriptBlock = [scriptblock]::Create(".{${Function:Test-Function}} $(&{$args}@FunctionParameters)") #https://stackoverflow.com/questions/28234509/powershell-splatting-the-argumentlist-on-invoke-command

    $ScriptBlock
    Invoke-Command -ComputerName . -Credential $credentials -ScriptBlock $ScriptBlock #-ArgumentList $FunctionName

}

And called thus:

$params = @{
    Contents = "'Some new text. 003'"
    Number = 3.54*10
}

$credential = New-Object System.Management.Automation.PSCredential('COMPUTER\SomeUser',(ConvertTo-SecureString 'SomeUserPassword' -AsPlainText -Force))

Invoke-FunctionRunAs -FunctionName "Test-Function" -FunctionParameters $params -Credentials $credential -Verbose

However, replacing function:Test-Function with function:$FunctionName doesn't work. It doesn't see the function at all. The output of $scriptblock looks like:

.{} -Number: 35.4 -Contents: 'Some new text. 003'

When it works the whole function is printed out inside the {}.

In a previous, similar, question of mine, @Daryl had a problem with a hypen in the functions name, so to test, I renamed Test-Function to TestFunction, but to no avail.

I'd be grateful for any suggestions / ideas.

(PS V 5.1 / Win 10)

woter324
  • 2,608
  • 5
  • 27
  • 47

1 Answers1

1

The parser will recognize $functionName as the literal function name. Use Get-Content against the function: drive instead:

$functionDefinition = Get-Content function:\$functionName
$ScriptBlock = [scriptblock]::Create(".{${functionDefinition}} $(&{$args}@FunctionParameters)")

This also allows for some proper error handling in case the function name does not actually refer to an existing function:

try{
    $functionDefinition = Get-Content function:\$functionName -ErrorAction Stop
    $ScriptBlock = [scriptblock]::Create(".{${functionDefinition}} $(&{$args}@FunctionParameters)")
}
catch{
    throw New-Object Exception "Function $functionName was not found in the current execution context",$_
    return
}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206