1

I have two servers. Server A needs to contact server B and run a specific function withing a powershell function library (just a .ps1 file) that I've created. The function that is being called also calls other functions during execution, all of which are contained in the same .ps1 file. Finally, when server A calls the function which resides on server B, he also needs to pass 5 parameters to the function.

Using several combinations of New-PSSession, Enter-PSSession, or just Invoke-Command, I am able to successfully call the server B function; however, here's where I'm stuck.

  • I've only been successful in having the server B function prompt me for the parameters it's expecting if I perform an Import-Module on server A before hand and import a copy of the .ps1 file I'm attempting to call the function from. Without that, the remote function on server B cannot be found or recognized.

  • If I don't import the module, when I call the function on server B I can get it to perform simple operations such as echo or Write-Output, but functions cannot be recognized.

  • Finally, building on the situation in which I can import the module and successfully get the function to prompt me for input, following the input the base function on server B begins executing, however it fails when sub functions within it are called, to update logs etc, indicating it can't recognize them. Again, they are all contained in the same .ps1 file.

Here are some code examples outlining what I'm trying to do:

EXAMPLE 1

The following is run on Server A:

Invoke-Command -ScriptBlock { \\SERVERB\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }

Here's the target IvantiSyncEngine_RemotePatchRequest.ps1 file on Server B that we're calling in the above script:

# IvantiSyncEngine_RemotePatchRequest.ps1
Write-Output "Here we go!"

And the output on Server A is as expected:

PS C:\> Invoke-Command -ScriptBlock { \\SERVERB\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }
Here we go!

EXAMPLE 2

Moving forward, I expanded the script on Server B to look as follows:

# IvantiSyncEngine_RemotePatchRequest.ps1
Write-Output "Here we go!"
Request-RemotePatch

The function being called exists on Server B as well, in a separate .ps1 file. That function looks like this:

function Request-RemotePatch {
    Param (
        # Define the parameters this function accepts
        [Parameter(Mandatory=$true, Position=0)]
        [string] $PatchHostname,
        [Parameter(Mandatory=$true, Position=1)]
        [string] $PatchDomain,
        [Parameter(Mandatory=$true, Position=2)]
        [string] $PatchRebootType,
        [Parameter(Mandatory=$true, Position=3)]
        [string] $RequesterHostname,
        [Parameter(Mandatory=$true, Position=4)]
        [string] $RequesterUsername
    )
    Begin{
    }Process{
        Write-Output "Testing"

        # Empty line for spacing
        Update-Log $global:RemotePatchLog "`n"

        # Log to RemoteRequests log file
        $MixedMessage = "Request received from $RequesterHostname\$RequesterUsername to remotely patch $PatchHostname, on domain $PatchDomain, with reboot type $PatchRebootType."
        Update-Log $global:RemotePatchLog $MixedMessage

        # Initialize the scan
        Update-Log $global:RemotePatchLog "Scanning..."
        $scan = Start-PatchScan -Name "RemoteAPI-Scan" -EndpointNames $PatchHostname -TemplateName "Security Patch Scan"

        # Wait for the scan to complete and return details
        $scan | Watch-PatchScan
        Update-Log $global:RemotePatchLog "Scanning complete."

        # Deploy against that scan
        Update-Log $global:RemotePatchLog "Deploying Patches..."
        $DeployTemplateName = "RemoteAPI-" + $PatchRebootType
        $deploy = Start-PatchDeploy -ScanUid ($scan.Uid) -TemplateName $DeployTemplateName

        # Wait for deploy to complete and return details
        $deploy | Watch-PatchDeploy
        Update-Log $global:RemotePatchLog "Deployment complete."

    }
    End{}
}

As you can see, it accepts 5 parameters. It also calls other functions in the same .ps1 file for things like logging mostly.

Finally, when I attempt the same call from Server A, I get this:

PS C:\> Invoke-Command -ScriptBlock { \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }
Here we go!
cmdlet Request-RemotePatch at command pipeline position 1
Supply values for the following parameters:
PatchHostname: 

So up until now, things are working as expected. However, I'm not currently passing parameters to the remote function which I want to fix. But for now to illustrate what's happening I'll simply enter the value in the prompts provided. Here's the final setup before I hit enter to execute:

PS C:\> Invoke-Command -ScriptBlock { \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }
Here we go!
cmdlet Request-RemotePatch at command pipeline position 1
Supply values for the following parameters:
PatchHostname: kam1oqapp161
PatchDomain: connex
PatchRebootType: NoReboot
RequesterHostname: kam1oqweb163
RequesterUsername: Joey

And after hitting execute, here is what we get:

Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+         Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [Out-File], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

Request received from kam1oqweb163\Joey to remotely patch kam1oqapp161, on domain connex, with reboot type NoReboot.
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+         Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [Out-File], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

Scanning...
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+         Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [Out-File], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

Start-PatchScan : The term 'Start-PatchScan' 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.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:675 char:17
+         $scan = Start-PatchScan -Name "RemoteAPI-Scan" -EndpointNames $PatchHost ...
+                 ~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Start-PatchScan:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Watch-PatchScan : The term 'Watch-PatchScan' 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.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:678 char:17
+         $scan | Watch-PatchScan
+                 ~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Watch-PatchScan:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Scanning complete.
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+         Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [Out-File], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

Deploying Patches...
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+         Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [Out-File], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

Start-PatchDeploy : The term 'Start-PatchDeploy' 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.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:684 char:19
+         $deploy = Start-PatchDeploy -ScanUid ($scan.Uid) -TemplateName $DeployTe ...
+                   ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Start-PatchDeploy:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Watch-PatchDeploy : The term 'Watch-PatchDeploy' 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.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:687 char:19
+         $deploy | Watch-PatchDeploy
+                   ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Watch-PatchDeploy:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Deployment complete.
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+         Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [Out-File], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

I'll stop here. Code quoting doesn't preserve coloring but there's a lot of red going on here. The errors center around 2 problems. (1) an inability to find folder references and locations, and (2), an inability to recognize other functions and commands being called.

Question 1: Why is the remote function which has references to remote folder locations, having a hard time finding these locations? I'm only calling the starter function from Server A and it's kicking off everything else from Server B. Shouldn't all of those location references be relevant as they're being called from Server B? I'm assuming if I changed all of the remote references from 'C:...' to '\ServerB\C$...' it would fix it, I'm just uncertain as to why that's necessary?

Question 2 For the functions and commands that aren't being recognized, what's the best practice solution here? A module needing to be imported etc?

I'll continue to add more as we flesh out these pieces because this is the stuff I'm getting hung up on.

Update 5/18/2018

Alright, I've partially solved (1) and (2) above. Here's what I did.

I converted the functions .ps1 file I was using to a .psm1 file, created a proper manifest, setup the proper folder structure when referencing PS modules, and performed a proper module installation/import when I call from the remote server. Doing all of this loads all of the necessary functions into the local space on Server (A), removing any errors regarding unrecognized references or functions. When I perform the import I'm using a UNC path. That new code is as follows:

$s = New-PSSession -ComputerName 'SERVERB.DOMAINX.DOMAINY.com'
Invoke-Command -ScriptBlock {Import-Module STProtect -PassThru} -session $s
Invoke-Command -ScriptBlock {Import-Module \\SERVERB\c$\orchestration\scripts\PSModules\IvantiSyncEngine_Functions -DisableNameChecking -PassThru} -session $s
Invoke-Command -ScriptBlock ${function:Request-RemotePatch} -ArgumentList 'TARGETSERVERTOPATCH','TARGETDOMAIN','REBOOTTYPE','MYPCNAME','MYUSER' -session $s
Remove-PSSession -session $s
Exit-PSSession

If you look at the code above, you'll also notice I've had some success with -ArgumentList to pass through variables to the function we're calling remotely. Now, with all of that when I call the remote function on Server B, from Server A, I'm receiving all of the proper prompts but it's failing now with the following error message:

enter image description here

So...

Question 3

It appears something isn't listening, but I haven't managed to figure out what exactly. Any ideas?

  • Are you entering a PS Session to A, to then run the command on B? – Davidw May 16 '18 at 5:54
  • No, I have direct access on A, am opening powershell window, and attempting to do this through B. It's a test for a user who will ultimately end up calling these scripts on B in the exact same way I am, to have something done for them automatically. Like a crude API basically... – Joey May 16 '18 at 13:28
  • I've added code camples to help illustrate my flow of thought and what's going on. – Joey May 16 '18 at 14:17
  • Have you tried using the -argumentlist parameter for Invoke-command to supply the arguments? – Davidw May 17 '18 at 6:07
  • Thanks @Davidw, I just posted some updates and one of them was exactly that, using -ArgumentList to pass through the variables. We're getting there, but still bumping up against errors. – Joey May 18 '18 at 13:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.