Wednesday, August 17, 2011

Getting remote PowerShell output back to your local machine

PowerShell remoting has been around for some time now but I have not had a reason to use it.  I finally found one, I needed some information from within a file on a remote system.

This is where WMI let me down.  It could give me information about the file(s) I needed, but I needed to read and parse the content of the file and I further needed to process that at the client machine that was calling the remote machine.

Searching on this really did very little for me, in the end the solution was relatively simple.  Cast my session output to a variable.

So…  PSRemoting.  First of all you need a PSCredential.  I am hitting remote systems, so I need to build a credential object using a username and password.  My password begins as plain text.

$securePass = ConvertTo-SecureString $password -AsPlainText -force
$creds = New-Object System.Management.Automation.PSCredential($userName,$securepass)

I then open a PS session.

$s = new-pssession -ComputerName $computername -Credential $creds

Now, I can simply invoke commands using this session.  Like this.

invoke-command -Session $s -ScriptBlock { 
    $file = get-wmiobject CIM_DataFile -filter 'Extension="config" and FileName="MyFile"'

    $fileContents = get-content -path ([string]$file.DesiredContent)
}

On the screen I have exactly what I want.  I have captured it to $fileContents.  The problem is that cannot use $fileContents, it does not exist within the local scope – it exists within the remote (PSSession) scope. 

My C# classes make me think global and remote variables.  But that isn’t quite right either.  It is closer to user security context and the fact that they are separate.  But I want to pass between them.  And I don’t just want to pass a variable in, that is straightforward.

Come to find out, I needed to change where I capture $fileContents.

$fileContents = invoke-command -Session $s -ScriptBlock {
$file = get-wmiobject CIM_DataFile -filter 'Extension="config" and FileName="MyFile"'

get-content -path ([string]$file.DesiredContent)
}

Now, I have a local object of $fileContents that I can manipulate.

Just remember to close your remote PS session if you are going to make multiple calls.

No comments: