Search code examples
powershellpowershell-remoting

File operation failed with New-PSSession


I'm loading a json file that contains a list of computer names and each of them contains a list of files I need to operate on. For this example, I'm just displaying the file sizes.

But I'm getting file not found errors. I think it's because new-pssession is not activated or opened. I confirmed the file does exist on the remote computers. Is there something I need to do to "activate/open" the session after new-pssession?

$cred = Get-Credential -UserName admin -Message "Enter Password" 
$computers = Get-Content "sample.json" | ConvertFrom-Json    
foreach($computer in $computers){
    $s = new-pssession -ComputerName $computer.computer -Credential $cred
    foreach($file in $computer.files){        
        write-host $file has (get-item $file).length "bytes"
    }
    remove-pssession $s 
}

json file

[
    {
        "computer": "machine1",
        "files": [
            "c:\\temp\\done.png",
            "c:\\temp\\Permissions.xlsx"
        ]
    },
    {
        "computer": "machine2",
        "files": [
            "c:\\software\\TortoiseSVN.msi",
            "c:\\software\\TortoiseSVN.txt"
        ]
    }
]

Solution

  • As mklement0 points out in his helpful comment, New-PSSession will only establish the persistent connection with the remote hosts, however if you need to execute code on them you would need to use Invoke-Command.

    I have removed New-PSSession for this example as there is no need for it in this case, but note, when using a PSSession, you would be using the -Session parameter instead of -ComputerName.

    $cred = Get-Credential -UserName admin -Message "Enter Password" 
    $computers = Get-Content "sample.json" | ConvertFrom-Json
    foreach($computer in $computers)
    {
        Invoke-Command -ComputerName $computer.computer {
            $computer = $using:computer
            foreach($file in $computer.files)
            {
                Write-Host "$file has $((Get-Item $file).Length) bytes"
            }
        } -Credential $cred 
    }
    

    Since Invoke-Command allows parallel execution of script blocks on remote hosts, the same can be done with your code, however it would be a bit more complex. $computers would be passed to each remote session and each host would need to figure out which object of the object[] has to run:

    $cred = Get-Credential -UserName admin -Message "Enter Password" 
    $computers = Get-Content "sample.json" | ConvertFrom-Json
    Invoke-Command -ComputerName $computers.computer {
        $computers = $using:computers
        $files = $computers.Where({ $_.computer -eq $env:ComputerName }).files
        foreach($file in $files)
        {
            Write-Host "$file has $((Get-Item $file).Length) bytes"
        }
    } -Credential $cred