none
Powershell: use invoke-command with custom function to execute at remote computer and display output in the host computer RRS feed

  • Question

  • I am struggling with invoke-command to execute custom f
    unction remotely and display the output at the local host. I've read many posts regarding invoke-command online but I haven't find a way to resolve this problem.

    The custom function called get-openfiles is working locally.
    function get-openfiles{                                                                                  
     param(                                                                                                   
     $computername=@($env:computername),                                                                      
     $verbose=$false)                                                                                         
     $collection = @()                                                                                        
     foreach ($computer in $computername){                                                                    
     $netfile = [ADSI]"WinNT://$computer/LanmanServer"                                                        
    
     $netfile.Invoke("Resources") | foreach {                                                                 
     try{                                                                                                     
     $collection += New-Object PsObject -Property @{                                                          
     Id = $_.GetType().InvokeMember("Name", ‘GetProperty’, $null, $_, $null)                                  
     itemPath = $_.GetType().InvokeMember("Path", ‘GetProperty’, $null, $_, $null)                            
     UserName = $_.GetType().InvokeMember("User", ‘GetProperty’, $null, $_, $null)                            
     LockCount = $_.GetType().InvokeMember("LockCount", ‘GetProperty’, $null, $_, $null)                      
     Server = $computer                                                                                       
     }                                                                                                        
     }                                                                                                        
     catch{                                                                                                   
     if ($verbose){write-warning $error[0]}                                                                   
     }                                                                                                        
     }                                                                                                        
     }                                                                                                        
     Return $collection                                                                                       
     }
    There are few ways that I tried but none of them working.
    # NOT WORKING #1
    $s = New-PSSession -ComputerName remote-STL
    $CifServer = "fs-STL-01"
    function get-openfiles{..}
    invoke-command -Session $s -ScriptBlock ${function:get-openfiles} -ArgumentList $CifServer
    
    # NOT WORKING #2
    $s = New-PSSession -ComputerName remote-STL
    $CifServer = "fs-STL-01"
    invoke-command -Session $s -ScriptBlock {Import-Module C:\scripts\grp-functions.psm1}
    invoke-command -Session $s -ScriptBlock {get-openfiles -computername $args[0]} -ArgumentList $CifServer
    
    # Not working #3
    $s = New-PSSession -ComputerName remote-STL
    $CifServer = "fs-STL-01"
    invoke-command -Session $s -ScriptBlock {Import-Module C:\scripts\grp-functions.psm1}
    invoke-command -Session $s -ScriptBlock { param($CifServer) get-openfiles -computername $Cifserver } -ArgumentList $CifServer
    
    
    # Not working #4
    $CifServer = "fs-STL-01"
    function get-openfiles{..}
    invoke-command -ComputerName remote-STL -ScriptBlock ${function:get-openfiles} -ArgumentList $CifServe
    
    # not working #5
    $CifServer = "fs-STL-01"
    invoke-command -ComputerName remote-STL -ScriptBlock {get-openfiles -computername $args[0]} -ArgumentList $CifServer
    

    Saturday, September 10, 2016 2:38 AM

Answers

  • $s = New-PSSession -ComputerName remote-STL
    $CifServer = "fs-STL-01"
    function get-openfiles{..}
    invoke-command -Session $s -ScriptBlock $function:get-openfiles  -ArgumentList $CifServer
    


    \_(ツ)_/

    Saturday, September 10, 2016 8:18 AM

All replies

  • You have failed to say what the problem is.

    What does "not working" mean?


    \_(ツ)_/

    Saturday, September 10, 2016 2:43 AM
  • Have you asked the author of the function for help?


    \_(ツ)_/

    Saturday, September 10, 2016 2:46 AM
  • IIUC, you are trying to use a function on remote computer but this function's defined on local computer only.

    my blog: http://shserg.ru/

    Saturday, September 10, 2016 7:17 AM
  • $s = New-PSSession -ComputerName remote-STL
    $CifServer = "fs-STL-01"
    function get-openfiles{..}
    invoke-command -Session $s -ScriptBlock $function:get-openfiles  -ArgumentList $CifServer
    


    \_(ツ)_/

    Saturday, September 10, 2016 8:18 AM
  • The problem you have is you don't return any output to the host.

    Try this:

    $CifServer = "fs-STL-01"

    $scriptBlock = {

    function get-openfiles{..}

    get-openfiles} $externalOutput = invoke-command -ComputerName remote-STL -ScriptBlock $scriptblock -ArgumentList $CifServe

    Basicly Powershell remoting works like this:

    HOST ----------------------------------------------------------------------------------> TARGET
    Hey I have some  code that I want to run   |

    on you can I do that? OPEN PSSESSION     |

                                                                      | Sure just give me the commands / code

    invoke-command -scriptblock $sBlock        |

                                                                      | Code is being processed by TARGET, so all code that is ran is

                                                                      | on TARGET his pipeline. The code ends and TARGET says

                                                                      | Hey I ran your code. Thanks mate. I'll be going then.

    Hey wait I want to (this would be a second invoke command) .... (since the invoke-command ended you can't ask what happen cause the pipeline is on the TARGET not the HOST. You have to say in the beginning I want you to run this code and give the output to this variable. Otherwise the TARGET will never know it has to return anything.) This is the same for your function. You define your function in the HOST pipeline and ask the TARGET to execute a function. The TARGET looks in his pipeline for the function get-openfiles but can't find it because it's on HOST his pipeline.

    Also don't forget to remove your PSSession with remove-pssession or you will keep opening connections and after a while to many are open. If you know it are all your connections you can use this one liner to remove all pssessions currently active on your system:

    Get-PSSession -ComputerName MyServerName | Remove-PSSession

    If you have any questions just reply to this comment and if this answer has helped you please give a thumbs up and use the answer button in case this has solved your problem.


    Julio Sanchez-Tirado http://scriptomato.com co-founder | CEO | Pitcher










    • Edited by Julio Sanchez-Tirado Monday, September 12, 2016 12:01 PM Added the remove-pssession comment because OP forgot it in his code
    Monday, September 12, 2016 11:32 AM
  • unfortunately it didn't work from your code provided above.

    Error:
    Invoke-command: cannot bind parameter 'ScriptBlock'. Cannot convert the "-openfiles" value of type "system.string" to type

    I then, added parenthesis as

    invoke-command -Session $s -ScriptBlock $function:(get-openfiles) -ArgumentList $CifServer

    error again:

    At line:1 char:41

    invoke-command -session $s -ScriptBlock $function...

    Thanks for contributing however.

    Tuesday, September 13, 2016 12:34 AM
  • Hi Julio, thanks for the modification. It almost worked. It took the custom function and return the values (open files). However, the values are the open files on the remote-STL server, not for the cifs server "fs-stl-01". Here is your code (I swapped out the "remote-STL" with a variable)

    $CifServer = "fs-STL-01"
    $TSserver = "remote-STL"
    $scriptBlock = {
    function get-openfiles{..}
         get-openfiles
    }
    $externalOutput = invoke-command -ComputerName $TSserver -ScriptBlock $scriptblock -ArgumentList $CifServer

    Not quiet working yet, but at least it took the get-openfiles function. Now, the question is how to carry the Argument into the get-openfiles function. So, it will return open files for fs-stl-01 server, not remote-STL server. 

    Thanks for looking into it.

    Tuesday, September 13, 2016 1:11 AM
  • Hi Julio, thanks for the modification. It almost worked. It took the custom function and return the values (open files). However, the values are the open files on the remote-STL server, not for the cifs server "fs-stl-01". Here is your code (I swapped out the "remote-STL" with a variable)

    $CifServer = "fs-STL-01"
    $TSserver = "remote-STL"
    $scriptBlock = {
    function get-openfiles{..}
         get-openfiles
    }
    $externalOutput = invoke-command -ComputerName $TSserver -ScriptBlock $scriptblock -ArgumentList $CifServer

    Not quiet working yet, but at least it took the get-openfiles function. Now, the question is how to carry the Argument into the get-openfiles function. So, it will return open files for fs-stl-01 server, not remote-STL server. 

    Thanks for looking into it.

    This will solve your problem:

    $CifServer = "fs-STL-01"
    $TSserver = "remote-STL"
    $scriptBlock = {
    function get-openfiles{
    Param(
    [Parameter(Mandatory=$True)] 
    [string] $CifServer = $(throw"CifServer paramater is mandatory!")
    .......}
    
         get-openfiles -CifServer $args[0]
    }
    $externalOutput = invoke-command -ComputerName $TSserver -ScriptBlock $scriptblock -ArgumentList $CifServer
    
    $externalOutput

    In your script in the top I think $CifServer inside the function = $computerName

    You just need to give the $args[0] (because it's the first argument in your argumentlist) as a paramater to your function basicly. You have to do that in the "get-openfiles -paramater argument". I just stated an example above :)

    For you change the code in the scriptblock to this:

    $CifServer = "fs-STL-01"
    $TSserver = "remote-STL"
    $scriptBlock = {
       function get-openfiles{..}
         
       get-openfiles -computername $args[0]
    }
    $externalOutput = invoke-command -ComputerName $TSserver -ScriptBlock $scriptblock -ArgumentList $CifServer



    Julio Sanchez-Tirado http://scriptomato.com co-founder | CEO | Pitcher


    • Edited by Julio Sanchez-Tirado Tuesday, September 13, 2016 7:27 AM Added the code OP has to change
    Tuesday, September 13, 2016 7:10 AM
  • I posted the solution two days ago. Please try it.  It is the only what to pass a locally defined function to a remote without having to include the whole function in the scriptblock.


    \_(ツ)_/

    Tuesday, September 13, 2016 7:22 AM
  • I posted the solution two days ago. Please try it.  It is the only what to pass a locally defined function to a remote without having to include the whole function in the scriptblock.


    \_(ツ)_/


    Sorry read past it :) didn't know that was a requirement

    Julio Sanchez-Tirado http://scriptomato.com co-founder | CEO | Pitcher

    Tuesday, September 13, 2016 7:37 AM