GhostyIs1337
GhostyIs1337

Reputation: 33

Saving XML on remote machine using Invoke-Command

Basically, I'm loading the XML from my local machine, and then I'm trying to save it on a remote machine using Invoke-Command.

I know I can use Copy-item via UNC path, but it takes too long on some machines, and Invoke-Command is faster - I tested this already.

However, I think I'm passing the argument wrong?

The error I get is:

Method invocation failed because [System.String] does not contain a method named 'Save'.
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound
    + PSComputerName        : -

This is how I'm passing it:

    foreach ($serverPath in $serverLocations) {

        if ($null -ne $serverPath) {

            $generatedPath = "$(Get-Location)\Generated.ManageSQLJobs.xml" 
            [Xml]$generatedFile = Get-Content $generatedPath


            Write-Log "INFO" "Checking on $serverPath" $ExecutionLogFullPath
            $testPath = Invoke-Command -ComputerName "$serverPath" -ArgumentList [Xml]$generatedFile -ScriptBlock {

                param (
                    $value
                )
                Test-Path -Path "C:\AppData\MonitoringConfig\" 

                if (!$testPath) {
                    $destinationPath = New-Item -Path "C:\AppData\" -Name "MonitoringConfig" -ItemType Directory
                }
                if ($testPath) {
                    $destinationPath = "C:\AppData\MonitoringConfig"
                    #Write-Log "INFO" "Exists on $serverPath." $ExecutionLogFullPath 
                }

                $GetPathToDeleteXML = "C:\AppData\MonitoringConfig\Generated.ManageSQLJobs.xml" 
                if (Test-Path -Path $GetPathToDeleteXML) {
                    Remove-Item -Path * #-Filter Generated.ManageSQLJobs.xml
                }

                $GetPathForXML = "C:\AppData\MonitoringConfig\Generated.ManageSQLJobs.xml" 

                $value.Save($GetPathForXML.fullname)

            }

        }
    }

Upvotes: 1

Views: 179

Answers (1)

mklement0
mklement0

Reputation: 440142

-ArgumentList [Xml]$generatedFile

should be (note the (...)):

-ArgumentList ([Xml]$generatedFile)

[Xml]$generatedFile isn't recognized as an expression, because when PowerShell parses in argument mode (commands with arguments, shell-style), an initial [ isn't special.

In effect, your argument is interpreted as an expandable string, i.e. as if you had passed
"[Xml]$generatedFile".
Therefore, $value in your remotely executed script block received a [string] instance, not an [xml] instance, and strings don't have a .Save() method, which explains the error message.

Enclosing your argument in (...) forces its interpretation as an expression.

See this answer for a comprehensive overview of how PowerShell parses unquoted tokens in argument mode.


A general caveat re passing complex objects as arguments to code executed remotely / in background jobs:

Arguments passed to remote / background script blocks must undergo XML-based serialization and deserialization, because they pass computer / process boundaries.

Only a limited set of known types are deserialized faithfully (deserialized as the original type), others are emulated.

While [xml] instances, [string] instances and .NET primitive types such as [int] are faithfully deserialized, most other types are not.

See this answer for more information.

Upvotes: 1

Related Questions