Skip to content

Instantly share code, notes, and snippets.

@Jaykul
Last active April 15, 2023 23:24
Show Gist options
  • Save Jaykul/34135ce93ed8de0310e486d59a32185e to your computer and use it in GitHub Desktop.
Save Jaykul/34135ce93ed8de0310e486d59a32185e to your computer and use it in GitHub Desktop.
Remote Invoke Concept

At work, we have a frequently recurring pattern involving a pair of scripts like a Controller and work that function as a pair to invoke code onto a bunch of remote servers.

Unlike these sample scripts, the controllers usually look up the set of servers based on a role or something, but never mind that. The point of this paste is to show the motivation for a module. When we run these scripts in a scheduled task, if there's an error on the remote server, we don't generally have enough information:

<# C:\PS: #> .\Controller-Original.ps1 .\Work.ps1 -Args @('NoSuchFile') -Cn Server1
Start Remote Test
Copy File To Remote: \\Server1\C$\Temp\5b5e9981-8fac-4541-a436-f411cec7e162\ChildItem.ps1
Invoke the script C:\Temp\5b5e9981-8fac-4541-a436-f411cec7e162\ChildItem.ps1 remotely on Entertainer
Enter ChildItem
Cannot find path 'C:\Temp\5b5e9981-8fac-4541-a436-f411cec7e162\NoSuchFile' because it does not exist.
    + CategoryInfo          : ObjectNotFound: (C:\Temp\5b5e9981-8fac-4541-a436-f411cec7e162\NoSuchFile:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
    + PSComputerName        : Server1

Exit ChildItem
Clean up remote files
End Remote Test

In a few cases, someone has added an error handler that logs the error message, which might output something like this:

writeErrorStream      : True
OriginInfo            : Entertainer
Exception             : System.Management.Automation.RemoteException: Cannot find path 'C:\Temp\39796a26-624d-46a8-a917-d1c538c4f3b6\NoSuchFile' because it
                        does not exist.
TargetObject          : C:\Temp\39796a26-624d-46a8-a917-d1c538c4f3b6\NoSuchFile
CategoryInfo          : ObjectNotFound: (C:\Temp\39796a2...f3b6\NoSuchFile:String) [Get-ChildItem], ItemNotFoundException
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
ErrorDetails          :
InvocationInfo        :
ScriptStackTrace      : at <ScriptBlock>, C:\Temp\39796a26-624d-46a8-a917-d1c538c4f3b6\TestScript.ps1: line 28
                        at <ScriptBlock>, <No file>: line 4
PipelineIterationInfo : {}
PSMessageDetails      :

However. this does not tell us a whole lot, and there's absolutely nothing more available. In many cases, even the stack trace isn't logged properly, and many of the developers who're writing these tasks aren't comfortable enough with PowerShell error handling to figure out what's going wrong, or to use remote debugging, etc. This has led to our teams adding Write-Host messages (as you saw in this example) as an attempt to keep track of what has been executed so far in a script just from the logs that the build or deploy tools capture.

What we really want is to collect everything there is to know about every error that happens...

The Information module now includes a Trace-Info command which you can wrap around another command to automatically convert Write-Host to Write-Info and also capture all the Error information at the end. In this extreme case where we're making a remote call, we need to make a change at two levels. First, we need to wrap the code that runs remotely, and then we can tweak with the invocation.

We'll add a line to copy the module to the remote server:

    Copy-Item (Get-Module Information).ModuleBase -Destination $RemotePath\Information -Recurse

And then inside the Invoke-Command, we need to import the module, and possibly, pass the InfoTemplate to make sure the remote is logging with the same template as the local server. So we add a InfoTemplate parameter, and then Import-Module and Set-InfoTemplate before wrapping everything that was there before into Trace-Info:

Invoke-Command -ComputerName $Server -Credential $Credential -ArgumentList $FileName, $ArgumentList, (Get-InfoTemplate) {
    param($FileName, $ArgumentList, $InfoTemplate)
    Import-Module (Join-Path (Split-Path $FileName) Information\Information.psd1)
    Set-InfoTemplate $InfoTemplate
    Trace-Info {
        Push-Location (Split-Path $FileName)
        &$FileName @ArgumentList
    }
}

The finished script is below as Controller.ps1 -- with that in place, if we set a simple template, we can call our script as before and get the same output. But if we add -InformationAction Continue, we suddenly get a full dump of the error:

<# C:\PS: #> Set-InfoTemplate '${Message}'
<# C:\PS: #> .\Controller.ps1 .\TestScript.ps1 -Args @('NoSuchFile') -Cn Server1 -InformationAction Continue
Start Remote Test
Copy File To Remote: \\Entertainer\C$\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Work.ps1
Copy Module To Remotes: \\Entertainer\C$\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Information
Invoke the script C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Work.ps1 remotely on Entertainer
Enter TestScript
Enter TestScript
Cannot find path 'C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\NoSuchFile' because it does not exist.
    + CategoryInfo          : ObjectNotFound: (C:\Temp\a065e87...22b8\NoSuchFile:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
    + PSComputerName        : Entertainer

Exit TestScript
Exit TestScript
ERROR LOG: Cannot find path 'C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\NoSuchFile' because it does not exist.


    [System.Management.Automation.ErrorRecord]

    writeErrorStream              : True
    Exception                     : System.Management.Automation.ItemNotFoundException: Cannot find path
                                    'C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\NoSuchFile' because it does not exist.
                                       at System.Management.Automation.SessionStateInternal.GetChildItems(String path,
                                    Boolean recurse, UInt32 depth, CmdletProviderContext context)
                                       at Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()
    TargetObject                  : C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\NoSuchFile
    FullyQualifiedErrorId         : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
    InvocationInfo                : System.Management.Automation.InvocationInfo
    ErrorCategory_Category        : 13
    ErrorCategory_Activity        : Get-ChildItem
    ErrorCategory_Reason          : ItemNotFoundException
    ErrorCategory_TargetName      : C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\NoSuchFile
    ErrorCategory_TargetType      : String
    ErrorCategory_Message         : ObjectNotFound: (C:\Temp\a065e87...22b8\NoSuchFile:String) [Get-ChildItem],
                                    ItemNotFoundException
    SerializeExtendedInfo         : False
    ErrorDetails_ScriptStackTrace : at <ScriptBlock>, C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Work.ps1: line 27
                                    at <ScriptBlock>, <No file>: line 7
                                    at <ScriptBlock>,
                                    C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Information\Information.psm1: line 359
                                    at Trace-Info<End>,
                                    C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Information\Information.psm1: line 357
                                    at <ScriptBlock>, <No file>: line 5
    PSMessageDetails              :
    CategoryInfo                  : ObjectNotFound: (C:\Temp\a065e87...22b8\NoSuchFile:String) [Get-ChildItem],
                                    ItemNotFoundException
    ErrorDetails                  :
    ScriptStackTrace              : at <ScriptBlock>, C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Work.ps1: line 27
                                    at <ScriptBlock>, <No file>: line 7
                                    at <ScriptBlock>,
                                    C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Information\Information.psm1: line 359
                                    at Trace-Info<End>,
                                    C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\Information\Information.psm1: line 357
                                    at <ScriptBlock>, <No file>: line 5
    PipelineIterationInfo         : {0, 1}


        [System.Management.Automation.ItemNotFoundException]

        ErrorRecord                 : Cannot find path 'C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\NoSuchFile' because it
                                      does not exist.
        ItemName                    : C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\NoSuchFile
        SessionStateCategory        : Drive
        WasThrownFromThrowStatement : False
        Message                     : Cannot find path 'C:\Temp\a065e873-bb6a-48d4-b224-a0b70c0b22b8\NoSuchFile' because it
                                      does not exist.
        Data                        : {}
        InnerException              :
        TargetSite                  : Void GetChildItems(System.String, Boolean, UInt32,
                                      System.Management.Automation.CmdletProviderContext)
        StackTrace                  :    at System.Management.Automation.SessionStateInternal.GetChildItems(String path,
                                      Boolean recurse, UInt32 depth, CmdletProviderContext context)
                                         at Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()
        HelpLink                    :
        Source                      : System.Management.Automation
        HResult                     : -2146233087


Clean up remote files
End Remote Test

And if we use a more informative InfoTemplate and wrap the initial call in Trace-Info, we suddenly get much more information:

<# C:\PS: #> Set-InfoTemplate '${Env:UserName}@${Env:ComputerName} $e[38;5;1m$("{0:hh\:mm\:ss\.fff}" -f ${Time}) $("  " * ${CallStackDepth})$e[38;5;6m${Message} $e[38;5;5m<${Command}> ${ScriptName}:${LineNumber}$e[39m'
<# C:\PS: #> Trace-Info { .\Controller.ps1 .\Work.ps1 -Args @('NoSuchFile') -Cn Server1 -InformationAction Continue }
Joel@DUO 01:35:27.224         Start Remote Test <<ScriptBlock>> Remote.ps1:21
Joel@DUO 01:35:27.273         Copy File To Remote: \\Entertainer\C$\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\TestScript.ps1 <<ScriptBlock>> Remote.ps1:30
Joel@DUO 01:35:27.325         Copy Module To Remotes: \\Entertainer\C$\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\Information <<ScriptBlock>> Remote.ps1:33
Joel@DUO 01:35:27.465         Invoke the script C:\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\TestScript.ps1 remotely on Entertainer <<ScriptBlock>> Remote.ps1:38
Joel@ENTERTAINER 01:34:25.417         Enter TestScript <<ScriptBlock>> TestScript.ps1:6
Cannot find path 'C:\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\NoSuchFile' because it does not exist.
    + CategoryInfo          : ObjectNotFound: (C:\Temp\1390b88...851c\NoSuchFile:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
    + PSComputerName        : Entertainer

Joel@ENTERTAINER 01:34:25.586         Exit TestScript <<ScriptBlock>> TestScript.ps1:29
Joel@ENTERTAINER 01:34:25.648         ERROR LOG: Cannot find path 'C:\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\NoSuchFile' because it does not exist.


    [System.Management.Automation.ErrorRecord]

    writeErrorStream              : True
    Exception                     : System.Management.Automation.ItemNotFoundException: Cannot find path
                                    'C:\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\NoSuchFile' because it does not exist.
                                       at System.Management.Automation.SessionStateInternal.GetChildItems(String path,
                                    Boolean recurse, UInt32 depth, CmdletProviderContext context)
                                       at Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()
    TargetObject                  : C:\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\NoSuchFile
    FullyQualifiedErrorId         : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
    InvocationInfo                : System.Management.Automation.InvocationInfo
    ErrorCategory_Category        : 13
    ErrorCategory_Activity        : Get-ChildItem
    ErrorCategory_Reason          : ItemNotFoundException
    ErrorCategory_TargetName      : C:\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\NoSuchFile
    ErrorCategory_TargetType      : String
    ErrorCategory_Message         : ObjectNotFound: (C:\Temp\1390b88...851c\NoSuchFile:String) [Get-ChildItem],
                                    ItemNotFoundException
    SerializeExtendedInfo         : False
    ErrorDetails_ScriptStackTrace : at <ScriptBlock>, C:\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\TestScript.ps1: line 27
                                    at <ScriptBlock>, <No file>: line 7
                                    at <ScriptBlock>,
                                    C:\Temp\1390b885-79c4-4067-9a3d-fcda4236851c\Information\Information.psm1: line 359
Joel@DUO 02:31:55.770         Start Remote Test <<ScriptBlock>> Controller.ps1:21
Joel@DUO 02:31:55.818         Copy File To Remote: \\Entertainer\C$\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Work.ps1 <<ScriptBlock>> Controller.ps1:30
Joel@DUO 02:31:55.879         Copy Module To Remotes: \\Entertainer\C$\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Information <<ScriptBlock>> Controller.ps1:33
Joel@DUO 02:31:56.027         Invoke the script C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Work.ps1 remotely on Entertainer <<ScriptBlock>> Controller.ps1:38
Joel@ENTERTAINER 02:30:54.035         Enter TestScript <<ScriptBlock>> Work.ps1:6
Joel@ENTERTAINER 02:30:54.035         Enter TestScript <<ScriptBlock>> Work.ps1:6
Cannot find path 'C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile' because it does not exist.
    + CategoryInfo          : ObjectNotFound: (C:\Temp\fdfc78f...6d27\NoSuchFile:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
    + PSComputerName        : Entertainer

Joel@ENTERTAINER 02:30:54.202         Exit TestScript <<ScriptBlock>> Work.ps1:29
Joel@ENTERTAINER 02:30:54.202         Exit TestScript <<ScriptBlock>> Work.ps1:29
Joel@ENTERTAINER 02:30:54.264         ERROR LOG: Cannot find path 'C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile' because it does not exist.


    [System.Management.Automation.ErrorRecord]

    writeErrorStream              : True
    Exception                     : System.Management.Automation.ItemNotFoundException: Cannot find path
                                    'C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile' because it does not exist.
                                       at System.Management.Automation.SessionStateInternal.GetChildItems(String path,
                                    Boolean recurse, UInt32 depth, CmdletProviderContext context)
                                       at Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()
    TargetObject                  : C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile
    FullyQualifiedErrorId         : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
    InvocationInfo                : System.Management.Automation.InvocationInfo
    ErrorCategory_Category        : 13
    ErrorCategory_Activity        : Get-ChildItem
    ErrorCategory_Reason          : ItemNotFoundException
    ErrorCategory_TargetName      : C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile
    ErrorCategory_TargetType      : String
    ErrorCategory_Message         : ObjectNotFound: (C:\Temp\fdfc78f...6d27\NoSuchFile:String) [Get-ChildItem],
                                    ItemNotFoundException
    SerializeExtendedInfo         : False
    ErrorDetails_ScriptStackTrace : at <ScriptBlock>, C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Work.ps1: line 27
                                    at <ScriptBlock>, <No file>: line 7
                                    at <ScriptBlock>,
                                    C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Information\Information.psm1: line 359
                                    at Trace-Info<End>,
                                    C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Information\Information.psm1: line 357
                                    at <ScriptBlock>, <No file>: line 5
    PSMessageDetails              :
    CategoryInfo                  : ObjectNotFound: (C:\Temp\fdfc78f...6d27\NoSuchFile:String) [Get-ChildItem],
                                    ItemNotFoundException
    ErrorDetails                  :
    ScriptStackTrace              : at <ScriptBlock>, C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Work.ps1: line 27
                                    at <ScriptBlock>, <No file>: line 7
                                    at <ScriptBlock>,
                                    C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Information\Information.psm1: line 359
                                    at Trace-Info<End>,
                                    C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\Information\Information.psm1: line 357
                                    at <ScriptBlock>, <No file>: line 5
    PipelineIterationInfo         : {0, 1}


        [System.Management.Automation.ItemNotFoundException]

        ErrorRecord                 : Cannot find path 'C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile' because it
                                      does not exist.
        ItemName                    : C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile
        SessionStateCategory        : Drive
        WasThrownFromThrowStatement : False
        Message                     : Cannot find path 'C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile' because it
                                      does not exist.
        Data                        : {}
        InnerException              :
        TargetSite                  : Void GetChildItems(System.String, Boolean, UInt32,
                                      System.Management.Automation.CmdletProviderContext)
        StackTrace                  :    at System.Management.Automation.SessionStateInternal.GetChildItems(String path,
                                      Boolean recurse, UInt32 depth, CmdletProviderContext context)
                                         at Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()
        HelpLink                    :
        Source                      : System.Management.Automation
        HResult                     : -2146233087

             <<ScriptBlock>> Work.ps1:27
Joel@DUO 02:31:57.213         Clean up remote files <<ScriptBlock>> Controller.ps1:48
Joel@DUO 02:31:57.438         End Remote Test <<ScriptBlock>> Controller.ps1:52
Cannot find path 'C:\Temp\fdfc78f2-aba5-4619-aafa-6eb622f06d27\NoSuchFile' because it does not exist.
At C:\Users\Joel\Projects\Modules\Information\0.4.1\Information.psm1:393 char:13
+             throw $ErrorRecord
+             ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Temp\fdfc78f...6d27\NoSuchFile:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
    + PSComputerName        : Entertainer

Of course, in the console, it's colored to make things stand out ...

Screenshot

However, the most important thing is that it logs this easily: just add -LogPath .\Remote.clixml and you get a full serialized copy of everything to disk. Later on, you can come back and Import-CliXml the file and you can even examine exceptions in detail:

<# C:\PS: #> (import-clixml .\Remote.clixml | Where Tags -contains Error).MessageData.MessageData | Format-List -f
writeErrorStream              : True
Exception                     : System.Management.Automation.RemoteException: Cannot find path 'C:\Temp\392b3818-fa63-48a3-ada2-ee735b38f0bd\NoSuchFile' because it
                                does not exist.
TargetObject                  : C:\Temp\392b3818-fa63-48a3-ada2-ee735b38f0bd\NoSuchFile
FullyQualifiedErrorId         : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
InvocationInfo                :
ErrorCategory_Category        : 13
ErrorCategory_Activity        : Get-ChildItem
ErrorCategory_Reason          : ItemNotFoundException
ErrorCategory_TargetName      : C:\Temp\392b3818-fa63-48a3-ada2-ee735b38f0bd\NoSuchFile
ErrorCategory_TargetType      : String
ErrorCategory_Message         : ObjectNotFound: (C:\Temp\392b381...f0bd\NoSuchFile:String) [Get-ChildItem], ItemNotFoundException
SerializeExtendedInfo         : False
ErrorDetails_ScriptStackTrace : at <ScriptBlock>, C:\Temp\392b3818-fa63-48a3-ada2-ee735b38f0bd\TestScript.ps1: line 28
                                at <ScriptBlock>, <No file>: line 6
                                at <ScriptBlock>, C:\Temp\392b3818-fa63-48a3-ada2-ee735b38f0bd\Information\Information.psm1: line 191
                                at Protect-Trace<End>, C:\Temp\392b3818-fa63-48a3-ada2-ee735b38f0bd\Information\Information.psm1: line 188
                                at <ScriptBlock>, <No file>: line 4
PSMessageDetails              :
#.Synopsis
# Copy a script to a remote session and invoke it
[CmdletBinding()]
param(
# Path to script to run remotely
[Alias('PSPath')]
[string]$ScriptPath,
# Hashtable or array for splatting to script
[Alias('Args')]
$ArgumentList,
# Computers to run the script on
[Alias('CN')]
[string[]]$ComputerName,
# Credentials to use, if necessary
[PSCredential]$Credential
)
Write-Host "Start Remote Test"
$Guid = [Guid]::NewGuid().Guid
foreach($Server in $ComputerName) {
$RemotePath = "\\$Server\C`$\Temp\$Guid"
$null = mkdir $RemotePath -Force
$FileName = Join-Path $RemotePath (Split-Path $ScriptPath -Leaf)
Write-Host "Copy File To Remote: $FileName"
Copy-Item $ScriptPath -Destination $FileName
# Turn it into a local path
$FileName = $FileName -replace '\\\\[^\\]*\\(.*)\$\\','$1:\'
Write-Host "Invoke the script $FileName remotely on $Server"
Invoke-Command -ComputerName $Server -Credential $Credential -ArgumentList $FileName, $ArgumentList {
param($FileName, $ArgumentList)
&$FileName @ArgumentList
}
Write-Host "Clean up remote files"
Remove-Item $RemotePath -Recurse
}
Write-Host "End Remote Test"
#.Synopsis
# Copy a script to a remote session and invoke it
[CmdletBinding()]
param(
# Path to script to run remotely
[Alias('PSPath')]
[string]$ScriptPath,
# Hashtable or array for splatting to script
[Alias('Args')]
$ArgumentList,
# Computers to run the script on
[Alias('CN')]
[string[]]$ComputerName,
# Credentials to use, if necessary
[PSCredential]$Credential
)
Write-Host "Start Remote Test"
$Guid = [Guid]::NewGuid().Guid
foreach($Server in $ComputerName) {
$RemotePath = "\\$Server\C`$\Temp\$Guid"
$null = mkdir $RemotePath -Force
$FileName = Join-Path $RemotePath (Split-Path $ScriptPath -Leaf)
Write-Host "Copy File To Remote: $FileName"
Copy-Item $ScriptPath -Destination $FileName
Write-Host "Copy Module To Remotes: $RemotePath\Information"
Copy-Item (Get-Module Information).ModuleBase -Destination $RemotePath\Information -Recurse
# Turn it into a local path
$FileName = $FileName -replace '\\\\[^\\]*\\(.*)\$\\','$1:\'
Write-Host "Invoke the script $FileName remotely on $Server"
Invoke-Command -ComputerName $Server -Credential $Credential -ArgumentList $FileName, $ArgumentList, (Get-InfoTemplate) {
param($FileName, $ArgumentList, $InfoTemplate)
Import-Module (Join-Path (Split-Path $FileName) Information\Information.psd1)
Set-InfoTemplate $InfoTemplate
Trace-Info {
Push-Location (Split-Path $FileName)
&$FileName @ArgumentList
}
}
Write-Host "Clean up remote files"
Remove-Item $RemotePath -Recurse
}
Write-Host "End Remote Test"
[CmdletBinding()]
param(
$InputObject
)
Write-Host "Enter TestScript"
# This function could be anything, the point is for you to see a nested exception
function Test-Function {
[CmdletBinding()]
param(
$InputObject
)
Write-Host "Enter Test-Function"
Get-ChildItem $InputObject -ErrorVariable ChildItemError -ErrorAction Ignore
if($ChildItemError) {
# Turn their error into our terminating error
$PSCmdlet.ThrowTerminatingError($ChildItemError[-1])
}
Write-Host "Exit Test-Function"
}
Get-ChildItem $InputObject
Write-Host "Exit TestScript"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment