Skip to main content

Powershell v2 Remoting

In my quest to make my life easier, I have been waiting with bated breath to get my hands on the remoting features of PS v2.  Now that I have access to windows 7 and Windows Server 2008 R2, let the fun begin!

When looking for information about these new features, where better to go than the source.  I found this video on Tech.ED where Jeffery Snover (Powershell Godfather as he is introduced!) co presents using Powershell v2 in large Environments. 

From my findings (mainly from this video) there are primarily 2 new ways of gathering information from remote computers in PS v2, the all singing all dancing big brother that needs all the options installed and configured, and the little brother version which has less pre-requisites for the remote client, but does not do quite as much.

The -computername switch (Little Brother) 

One of the biggest things missing in powershell 1 was the ability to run a cmdlet agains a remote machine.  With PS v2 this has changed. Suddenly, I can get the event logs from my DC from my workstation without too much fuss :  
get-eventlog -ComputerName dc01 -logname "Directory Service" -Newest 5.

This will get information from Server 2003, Server 2008 as well as 2008 R2 so very useful while there is a wait for either all computers that you manage become windows 7 or 2008 R2 or PS v2 becomes available for the earlier OS's.

Sessions and jobs (All Singing All dancing Big Brother)

When you have your server estate (and workstations too) to PS v2, nice things become available. 

The key components to Remoting are as follows :

WinRM service on the Remote Computer.

The service needs to be running and actively listening for connections.  The simplest way of configuring this is running 'winrm qc' at an elevated command prompt.

winrm qc does the following :

set the winrm service to auto start
start the service
create a winrm listener
add firewall exceptions to allow the service to communicate.

Powershell v2 installed

To process the commands, PS v2 need to be installed on the remote machine. (no real suprise there really!)

Permissions!

Even if you are a local admin on the server, you need to be part of the Remote Desktop Users group on the server.  It does seem a bit weird as you are not actually logging in interactivly, but I can only assume it assigns a range of remote access permissions (assuming is a dangerous thing I know - I will try to find out what exact permission is required).


I started with the idea that I would have to manage all my jobs independantly of each other.  By this i mean start all jobs seperatly, check to see if all jobs are still running and once all complete, get the results. 

Here's what I created :

$sb = [scriptblock]{ipconfig;get-service}
$collection = @()
$ComputerArray = "dc01","dc02"
foreach ($Computer in $ComputerArray){
  $store = "" | select "name","job","return"
  $store.name = $Computer
  $store.job = Invoke-command -computername $Computer -scriptblock $sb -asjob
  $collection += $store
}
$count = 0
:main while ($collection.length -gt $count){
  foreach ($col in $collection){
    if ($col.return -eq $null){
      switch ($(get-job $col.job.name).state){
        "Completed" {$col.return = receive-job $col.job -keep;$count++;if ($collection.length -eq $count){break main}}
        "Failed" {$col.return = "job failed";$count++;if ($collection.length -eq $count){break main}}
      }
    }

  }
  "waiting 5 seconds"
  Start-Sleep 5
}


foreach ($col in $collection){
  $col.return
}
I won't go into too much detail about this as there is a much better way script coming up.  But the key lines are as follows:

Define the commands that you want to run on the remote host
$sb = [scriptblock]{ipconfig;get-service}


Run the command using invoke command
$store.job = Invoke-command -computername $Computer -scriptblock $sb -asjob

Grab the results

$col.return = receive-job $col.job -keep

 
After setting up the inital script block - ie the commands that you want to run on the remote machine, I set up individual jobs for each computer in the array and stored them in my $store Array
 
The while loop then checked the job status for all jobs, and when all complete, output all the results.
 
I was infact quite proud of this, until I found out that PowerShell can do all this for you!
 
Remoting script version 2.


$sb = [scriptblock]{ipconfig;get-service}

$ComputerArray = "dc01","dc02"
$Job = invoke-command -computername $ComputerArray -scriptblock $sb -asjob
$Job.childjobs
$Job | wait-job
$results = receive-job $Job -keep
$results

Thats a bit cleaner, Ta very much Mr Snover! Heres the same script with comments :


#Set up the commands you want to run

$sb = [scriptblock]{ipconfig;get-service}


#setup the list of servers you want to target
$ComputerArray = "dc01","dc02"

#run the invoke-command as a job on the whole array. This creates 1 job with multiple child jobs
$Job = invoke-command -computername $ComputerArray -scriptblock $sb -asjob

#view those child jobs
$Job.childjobs

#wait for all the child jobs to complete
$Job | wait-job

#get all the results in one go
$results = receive-job $Job -keep

#display results
$results
Some notes

You can add -throttle to the invoke-command cmdlet to limit the ammount of jobs that are run at once. EG : invoke-command -computername $ComputerArray -scriptblock $sb -asjob -throttle 3

Instead of using a scriptblock, you can use any local ps1 file.  Here is the same code using a file as the source code :

$script = "c:\scripts\example.ps1"

$ComputerArray = "dc01","dc02"
$Job = invoke-command -computername $ComputerArray -filepath $script -asjob
$Job.childjobs
$Job | wait-job
$results = receive-job $Job -keep
$results

If you don't use the -keep option for receive-job, the results are purged (deleted) from the job

To be clean and tidy, add $job | remove-job when finished

That's about as far as i have got with remoting, just got to wait for PowerShell v2 to be available on all my OS's!

Comments

Popular posts from this blog

Enable Powershell Remoting (WinRM) via Group Policy

I have been doing some testing on enabling WinRM via group policy, being that WinRM is the service that Powershell v2 sets up it remoting capabilities. Here are the GPO settings that you need to configure WinRM .... set the winrm service to auto start Computer Configuration \ Policies \ Windows Settings \ Security Settings \ System Services Windows Remote Management (WS-Management)  set Startup Mode to Automatic start the service incorporated in to the above - you may need a restart. create a winrm listener Computer Configuration / Policies / Administrative Templates / Windows Components / Windows Remote Management (WinRM) / WinRM Service / Allow automatic configuration of listeners IPv4 filter: * * is listen on all addresses, or if you only want a particular IP address to respond use an iprange eg 10.1.1.1-10.1.1.254 - don't forget that this IP range has to be valid for all hosts that fall in the scope of the GPO you are creating.  You can use 10.1.1.1 -

Assigning Permissions - AGDLP

AGDLP It seems I have been mildly distracted away from the title of this blog site.   It does say AD Admin, but I seem to have been taken away by file system stuff.   I have to say, it has all been worthwhile, but it’s probably time I got back to the real heart of what I do. There are probably a million permission assigning advice pages, but I thought I would put another one out there after referring to AGDLP in my last post. So, what is this all about – AGDLP.   Well, it is something I learned in my MCSE 2003 studies and has become ingrained into my ideals since.   As a contractor, I get to move job often.   This enables me to forge opinions on how to configure things in a domain, and more importantly how NOT to configure things. AGDLP is definitely on the to do list…for anyone in any size domain or forest, as it follows some very basic principals.   I will explain these whilst I go through what AGDPL stands for. A A is for account.   It is the securit

PowerShell 3 behavioural change

It's taken me way too long to get into PowerShell 3, I guess opportunity hasn't shown it's self until now and so, here, my V3 journey begins. I was asked to debug a script that would run fine in PS v2 and not in v3.  The issue was a that a variable length was being checked and was failing in v3.  This is why... In v2 if a variable is undefined , this test returns false PS C:\windows\system32> $var.length -eq 0 False In v3 the same test returns true.... PS C:\windows\system32> $var.length -eq 0 True Not a biggie, but as in this case, a script has broken so something to consider! cheers Adam