3

I am trying to pass local function to remote code but not getting any success. Below is my code.

#variables defined over here
...
function comparehash ($source, $destination)
{
    $sourcefiles = @{}
    ...
}

$securePassword = ConvertTo-SecureString -AsPlainText -Force $Password 
$cred = New-Object System.Management.Automation.PSCredential $Username, $securePassword
$session = New-PSSession -ComputerName $srv -port 22 -Credential $cred  –Authentication CredSSP
Invoke-Command -Session $session -ScriptBlock { 
    param( $source, $destination, $application)
    #Write-Host "This is" $source
    # Take backup of the site first
    Copy-Item $source\$application $destination -Recurse -force
    ${function:comparehash}
}  -ArgumentList $site_path_local, $backup_path, $app
Remove-PSSession -Session $session

This code is copying source files to destination. Function has been created to validate md5 sum of the copied files. When I run the script script runs fine but it doesn't call the function code. Is there anything additional need to be done to call function?


Update

Invoke-Command -Session $session -ScriptBlock { 
    param( $source, $destination, $application, $fundef, $comparefunc )
    Write-Host "This is" $source, $destination
    # Take backup of the site first
    #Copy-Item $source\$application $destination -Recurse -force
    [ScriptBlock]::($comparefunc).Invoke($source,$destination)
    #comparehash $site_path_local $backup_path
}  -ArgumentList $site_path_local, $backup_path, $app, ${function:comparehash}
Remove-PSSession -Session $session

Above code is throwing following error:

PS C:\Windows\system32> C:\Users\vijay.patel\Documents\myscripts\Env_Refresh.ps1
This is F:\inetpub F:\Env_Backup\Refresh_Backup\
You cannot call a method on a null-valued expression.
    + CategoryInfo          : InvalidOperation: (Invoke:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
    + PSComputerName        : 172.16.82.124

2 Answers 2

4

Since the function is defined in your own local scope, you'll have to pass it along to the remote session as well. Through testing, it seems that it gets passed as a string, but you can use [scriptblock]::Create() to "recreate" it in the remote session:

Invoke-Command -Session $session -ScriptBlock { 
    param( $source, $destination, $application, $comparefunc)
    # do stuff
    # Now invoke the function that was provided
    [ScriptBlock]::Create($comparefunc).Invoke($source,$destination)
} -ArgumentList $site_path_local, $backup_path, $app, ${function:comparehash}
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks for your time. Now at least it is doing something. I am getting error now. You cannot call a method on a null-valued expression. + CategoryInfo : InvalidOperation: (Invoke:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull + PSComputerName : 172.16.82.124
@Vijay function comparehash needs to be defined at the calling scope first: gist.github.com/IISResetMe/75a16fe7dc40934d3fb4
Yeah I have made those changes suggested by you and after that I am getting this error. Do you know why it is throwing null valued expression?
@Vijay either the function can't be passed to a remote session, or the function itself contains a method call that depends on a variable/object that exists only in the caller scope
@Vijay when I run it against a remote session, the function gets passed as a string, see update
|
3

I found the $Using command can be your friend here. If you keep the remote PSSession open, you can transfer all the functions you will need one at a time, then invoke the final scriptblock that calls/uses those functions.

function comparehash($source, $destination)
{
    Write-Output "I like hash";
    if( $source -eq $destination) { PackThePipe $source; }
}

function PackThePipe($hash)
{
    Write-Output "Pushing $hash through the pipe";
}


$session = New-PSSession -ComputerName $srv -port 22 -Credential $cred  –Authentication CredSSP

#create the functions we need remotely
Invoke-Command $session { Invoke-Expression $Using:function:comparehash.Ast.Extent.Text; }
Invoke-Command $session { Invoke-Expression $Using:function:PackThePipe.Ast.Extent.Text; }

#call the scriptblock that utilizes those functions
Invoke-Command $session { $s = "12345"; $d="12345"; comparehash $s $d; }

Remove-PSSession $session;

4 Comments

Wow. This is so much better than the way I used to create functions remotely :)
How do you have to do the Invoke-Expression, when the functions have an '-' character, like 'compare-hash' and 'Pack-ThePipe'? I get an error message from Invoke-Expression in these cases.
@PainElemental ${Using:function:compare-hash}
@Brain2000 Thx for pointing me in the right direction! Is has to be ${Using:function:compare-hash}.Ast.Extent.Text

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.