Remoting Using PowerShell V1

Remoting Using PowerShell V1

  • Comments 18

As you probably know by now, "remoting" is one of the cornerstone features of the next version of PowerShell.  I am absolutely thrilled with the stuff we are doing here and the benefits that come from that approach.  That said, there are lots of things that need to be buttoned up before this is ready: the right user experience, proper serialization, where and how much throttling to do, how to maximize bandwidth utilization and of course our primary concern: how to make remoting safe and secure.  We are working closing with some of the companies top security people reviewing what we are doing to ensure that we do it right.  (Last week we were in a conference room with about 20 people walking through our scenarios.  It became very clear to me that Microsoft's investments and prioritization in security had really paid off as these folks were just awesome.)

So the bottom line is that while I'm optimistic about the remoting, the reality is that is going to take a while before it is cooked.  If I was an IT Pro, I can imagine saying something to the effect of, "That is fine but my hair is on fire - what can I do NOW?"

The answer to that is:  Cheat.

 

Yup - you can do PowerShell remoting with V1.  It's not going to be pretty but it can be done and hey - when your hair is on fire, you'll stick your head in a bucket of #$@! to put it out right?  (this approach isn't a bucket of @#%!, I just wanted to use that phrase :-))

Let's walk through the basics and then compose them into a solution.

Type "Powershell -?" and you'll see the command line parameters you can use to start PowerShell.  There are a couple that are interesting here.  Notice that there is a -Command parameter.  Give it a try by typing

Powershell -Command Get-Process *ss

 

 

You might notice a bunch of cruft before the output, this is  because we are running your profile and that might generate output.  We say -NoProfile to stop that.  We'll also add -NonInteractive so that we don't get prompted for any input.  So now try

PowerShell -NoProfile -NonInteractive -Command Get-Process *ss

 

 

If you plan with this for more than a little bit, you are going to find that you want to run a command that requires a ton of escaping and quoting to work properly (think through a pipeline - it could happen in either process). 

PowerShell -NoProfile -NonInteractive -Command "Get-Process *ss |sort handles"

 

 

What you will find is that at some point, the escaping can become incomprehensible.  That's where the hidden parameter comes in.  I don't know why we decided not to document this or who made that decision but we have a -EncodedCommand parameter that does not show up in our help (I suspect it's because we would have to explain how to encode it and people felt that most people would be too confused by this [you'll see what I mean] and therefore documenting it would do more harm than good.)  I blogged this parameter a while ago HERE.

Here is how you take a scriptblock, turn it into string and then encode it and invoke it:

$script = {gps |where {$_.handles -ge 900}|sort handles}.ToString() 
$encodedScript = [System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes($script))
PowerShell -NoProfile -NonInteractive -EncodedCommand $encodedScript

 

 

Now it is time to remote it!

WINRS is a commandline interface to invoke a command on a remote machine via WS-MGMT.  You can now run this remotely by doing the following:

Winrs "-r:localhost" PowerShell -NoProfile -NonInteractive -EncodedCommand $encodedScript

And there you have it REMOTING using PowerShell V1.   (Notice that WINRS allows you to specify UserName and Password as well)

 

 

Not it is time to put a bow on it and go to hit the gym.

function Invoke-RemoteCommand
{
param(
$ComputerName,
[SCRIPTBLOCK]$script
)
    $encodedScript = [System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes($script))
    Winrs "-r:$ComputerName" PowerShell -NoProfile -NonInteractive -EncodedCommand $encodedScript
}

Invoke-RemoteCommand localhost {gps |where {$_.handles -ge 500} |sort handles}

 

 

It's a beautiful thing!  Oh wait a minute.  That almost works but not really.  Try this and look what happens when you try to do the filtering and sorting locally:

Invoke-RemoteCommand localhost {gps} |where {$_.handles -ge 500} |sort handles

Complete crap.

 

 

If only there was a way I could get objects back instead of text.  That's sorta the point of PowerShell right?  Hmmm, if you go back to the beginning and look at the parameters you can provide PowerShell, you'll see -OutputFormat and that can take the value "XML".  This will produce CLIXML and PowerShell native command processor (the thing that invokes processes) looks at the output of a command for something we call a STRUCTURED DataStream and autoconverts that datastream into objects.  Thus the final script looks like this:

function Invoke-RemoteCommand
{
param(
$ComputerName,
[SCRIPTBLOCK]$script
)
    $encodedScript = [System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes($script))
    $objects = Winrs "-r:$ComputerName" PowerShell -OutputFormat XML -NoProfile -NonInteractive -EncodedCommand $encodedScript
    Write-Output $objects
}

Invoke-RemoteCommand localhost {gps} |where {$_.handles -ge 500} |sort handles

Now it's time to hit the gym. 

Enjoy!

 

Jeffrey Snover [MSFT]
Windows Management Partner Architect
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Leave a Comment
  • Please add 5 and 2 and type the answer here:
  • Post
  • This is awesome!! I just pulled all the processes from my win2k8 box running V1 down to my vista machine. Schweet !!!

  • We have a constant stream of AD environments coming into our IT dept.  We cannot assimilate them (long story).  I would like to [from ONE powershell box] access each domain in a manner not unlike an array of systems.

    Yes, I have ten domains with 10 different user/pw credentials with NO trust (again, long story).

    A sort of stand alone powershell mgmt system that can bridge the scenario of n untrusted ADs.

    I know calling things 'within' an AD is easily done in PS, but my dilemma adds a step, as I am outside the AD.

    (yes, I could put PS on one system per domain, but that defeats my desire to pull this off with zero footprint)

    I have posted this elsewhere with no apparent luck;  Jeffery, will you assist?

  • Hi lrbell,

    Thanks for describing your sceanrio. I have passed it along to the AD team. I will post back here once I hear from them.

    Thanks,

    Abhishek Agrawal[MSFT]

  • I have a similar problem as Irbell, I have to read informations from exchange management console outside the AD.

    Scenario:

    Machine A: Exchange 2007 in AD

    Machine B: My Tool to overview Exchange performance

    I'm not sure if it's possible. I would be happy if you can give me any hints ;)

  • Dude85,

    WMI support has been stripped out of Exchange 2007.  That being said, you could possibly:

    1. Use Exchange Web Services.

    2. Use another local system to get the performance data, save it to a file, etc., and you can then fetch that file.

  • Marco,

    thanks for your answer. The big goal for this problem is, only to have code on the workstation. You install the application and write the name of your exchange server and the tool should monitor the informations without any special configuration on the exchange server.

    The part with web service could be a good solution, but I have to implement my own webservices on the exchange server, because you can't read performance informations with the implemented services.

    Well, if there's no other way, I will implement the web service solution :P

    thanks

  • While I think Powershell is a step in the right direction, this sort of camel through the eye of a needle approach makes me wish that ssh/sshd got added as a role in Win2008...

  • PS C:\> Winrs "-r:localhost" PowerShell -NoProfile -NonInteractive start-psjob -command 'l

    s -rec c:\'

    Winrs error:Access denied. PS C:\> Winrs "-r:localhost" PowerShell -NoProfile -NonInt

    eractive new-runspace

    What's wrong?

    All i need(winrm,firewall,policy) - install, config., and start.

  • Please, help to solve this problem (PSJob, WinRM):

    http://groups.google.ch/group/microsoft.public.windows.powershell/browse_thread/thread/c50f2ed5c1f108b1

  • Abhishek, any word, update, or status?

    Hearing crickets is great for fishing, but not so much on blogs..

    :-)

  • another option is to use SSH

    http://gotmvc.net/?p=3

  • That ssh server Mario mentions in his article won't due for an enterprise.  Running the command with any flags/derivitives that I can think of):

    ssh2 user@host "powershell -command script.ps1"

    ...doesn't work in Tectia SSH Server.  It just hangs.  It's disappointing that we have to battle/justify why admins will need WinRM/WinRS/WinMGMT in addition to SSH, just so we can use powershell on our DMZ systems.  It'll take years for us to actually use WinRM because of the need to duplicate what we already have using ssh.

    I appreciate the efforts of the powershell team, but without being able to exec powershell from ssh, powershell is a novelty for my org (fortune 500 - near the bottom of the stack).  We'll still have to use vbs and bat files.

  • HI ALL

    i want more information for remote connection in power shell v2

  • Just a reminder of how you can remote a script in PowerShell using the V1 capabilities and WinRS/WinRM

  • If you are running your WinRM connection through HTTPS you'll need a cert.  When calling WinRM on a staging server, we use the -skipCNcheck because the server name in the cert doesn't match the staging server.

    Unfortunately, WinRS doesn't support skipCNcheck.  While more complicated, "WinRM Invoke Create Win32_Process" will do the trick.

Page 1 of 2 (18 items) 12