1

I have written a custom Write-Log Function. If I use the Write-Log function inside the Invoke, I am getting below error message "Error on remote execution: The term 'Write-Log' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again."

I'm using Powershell 5.1. I did try to use ${function:Write-Log} but it didn't work.

Function Write-Log([string]$ComputerList,$message, $level="INFO") {
    $date_stamp = Get-Date -Format s
    $log_entry = "$date_stamp - $level - $message"
    $log_file = "$tmp_dir\upgrade_powershell.log"
    Write-Verbose -Message $log_entry
    Add-Content -Path $log_file -Value $log_entry
}

Function Start-Process ($ComputerList) {    
    Return Invoke-Command -computername $Computer -ScriptBlock {
                Param($file)
                $Application = $args[0]
                $ApplicationName = $Application.Substring($Application.LastIndexOf('\')+1)
                $ApplicationFolderPath = $Application.Substring(0,$Application.LastIndexOf('\'))
                $ApplicationExt = $Application.Substring($Application.LastIndexOf('.')+1)
    Write-Log -message "Installing $file on $($env:COMPUTERNAME)"
    $p = Start-Process $file -Wait -Passthru

    $p.WaitForExit()
                $p.WaitForExit()
                if ($p.ExitCode -ne 0) {
                    Write-Log -message "Failed installing with error code $($p.ExitCode)"  -level "ERROR"
                    $Return = $($env:COMPUTERNAME)
                }
                else{
                    $Return = 0

        if ($p.ExitCode -ne 0 -and $p.ExitCode -ne 3010) {
        $log_msg = "$($error_msg): exit code $p.ExitCode"
        Write-Log  -message $log_msg -level "ERROR"
        #throw $log_msg
        return
      }
    if ($p.ExitCode-eq 3010) {
        Reboot-AndResume
        break
    }}


}
}
3
  • Start-Process is a reserved word that you shouldn't use for the name of your function. That's not the problem, though. Your code is formatted with inconsistent alignment, and it's hard to read your intent from it. I wasn't able to reproduce your issue. Maybe there was a copy-paste error. Commented Mar 22, 2019 at 18:50
  • 1
    besides the horrible misuse of Start-Process [grin], your answer is here ... How do I include a locally defined function when using PowerShell's Invoke-Command for remoting? - Stack Overflow — stackoverflow.com/questions/11367367/… Commented Mar 22, 2019 at 20:05
  • Possible duplicate of How do I include a locally defined function when using PowerShell's Invoke-Command for remoting? Commented Mar 22, 2019 at 20:42

2 Answers 2

0

try including your custom function definition inside the scriptblock, sort of like this

invoke-command -scriptblock {
    param (
        your params
    )

    begin {
        function write-log (etc) {
            the function code
        }
    }

    process {
        your main scriptblock stuff
    }

    end {}
}
Sign up to request clarification or add additional context in comments.

Comments

0

I did try to use ${function:Write-Log} but it didn't work.

${function:Write-Log} uses namespace variable notation to get the Write-Log function's body as a script block.

Since you're using remoting (you're passing a -ComputerName argument to Invoke-Command), you'll either have to pass that script block as an argument to the remotely executing script block, or - more conveniently - utilize the $using: scope (PSv3+) to make a local variable value available remotely.

Unfortunately, $using: cannot be combined with namespace variable notation, as of Windows PowerShell v5.1 / PowerShell Core 6.2.0 - see this GitHub issue.

Therefore, with the bug present, referencing your script block as ${using:function:Write-Log} does not work directly, but you can use an intermediate variable, and then use that to adapt this excellent answer, using a simplified scenario:

Note: To run this code, which simulates remoting by connecting to the same machine, make sure that remoting is enabled on your machine, and invoke the code as admin.

function Write-Log { 
  param([string] $ComputerList, $message, $level="INFO")      
  # For testing simply echo the arguments
  "$ComputerList, $message, $level"
}

# Recreate the function's full source code as a string.
$funcDef = "function Write-Log { ${function:Write-Log} }"

Invoke-Command -Computer . -ScriptBlock {

  # Define the Write-Log function using Invoke-Expression
  # Note: This is a rare case where use of Invoke-Expression is
  #       justified; generally, it is to be AVOIDED - see
  #       https://blogs.msdn.microsoft.com/powershell/2011/06/03/invoke-expression-considered-harmful/
  Invoke-Expression $using:funcDef

  # Now you can call it as you would locally.
  Write-Log 'ws1 ws2' testing DEBUG

}

The above should return ws1 ws2, testing, DEBUG.


Of course, if the Write-Log source code is:

  • readily available to you, and
  • you don't mind duplicating it inside the script block,

you can just make the function definition part of the remotely executing script block:

Invoke-Command -Computer . -ScriptBlock {

  # Embedded copy of Write-Log.
  function Write-Log { 
    param([string] $ComputerList, $message, $level="INFO")      
    # For testing simply echo the arguments
    "$ComputerList, $message, $level"
  }

  # Now you can call it as you would locally.
  Write-Log 'ws1 ws2' testing DEBUG

}

Comments

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.