TechNet Magazine > Home > Issues > 2009 > August >  Stay Seated!
Windows PowerShell Stay Seated!
Don Jones


I've always been frustrated by the dual message that sometimes comes out of Microsoft regarding server management: On the one hand, we're rightly told to install management tools on our own client computers and to use those tools to manage our servers. We're not supposed to go into the data center, and even using Remote Desktop is technically cheating because it's basically just going into the data center without taking the walk. On the other hand, however, there are many server-management tasks that can't be performed easily using existing remote tools—changing IP addresses or anything else with network configuration, for instance.
Windows PowerShell Q&A
Q Can a Windows PowerShell script be used as a logon script?
A Yes, but there might not be any point in doing so. You can't just drag the script into a Group Policy object (GPO) in the way that you can a VBScript file. Instead, you have to basically create a batch file the runs Powershell.exe, passing the command-line parameter that tells it what script to execute. It's awkward. You also have to install Windows PowerShell on every computer where that logon script will run. In the end, keep in mind that Windows PowerShell is a bit more self-contained than VBScript or the Cmd.exe shell. For example, mapping a drive using the New-PSDrive cmdlet won't affect Windows Explorer—you'd have to fall back on the Net Use command to actually map a drive in Windows, and if you're going to do that why not just use a traditional batch file, which is easier to include in a GPO?
Q Can Windows PowerShell scripts be scheduled?

A Absolutely. You'll actually schedule PowerShell.exe (which is located in your %systemroot% folder, under /WindowsPowerShell), and give it a command-line parameter specifying the script you want it to execute. Be sure that the scheduled task is set up to utilize a user account that has the necessary permissions to do whatever the script does, and make sure the shell execution policy is configured to allow script execution (I prefer the AllSigned policy myself, which means your script will need to be digitally signed; run "Help about_signing" in the shell for details on this).
Q Is there an easy way to work with file and folder permissions in Windows PowerShell?
A Sure. You've got the Get-ACL and Set-ACL commands, to start with—Get-ACL is great if all you need to do is report on permissions. Frankly, using these commands to actually change permissions is impractical—Windows' permissions are pretty complicated beasts, and the programming you have to do to set access control lists (ACLs) is equally complicated. But who says you have to use cmdlets? The shell is great at running more traditional command-line tools, and the various iterations of Cacls.exe (including ones like Dsacls for Active Directory) work great from within Windows PowerShell. I always use them when I need to modify or set file and folder permissions.
Setting up a new Server Core installation is another excellent example. Adding roles, configuring the network, even activating Windows must all be done from a local console window or via Remote Desktop, using command-line tools. What tools currently exist are either custom-written point solutions that handle a single task or solutions that require expertise with Windows Management Instrumentation (WMI). I like WMI, but frankly, it's too complex for most administrators to spend a lot of time learning, and so it often goes unused.
Windows PowerShell has promised to make all of this easier—by making WMI a bit easier to handle, but more importantly, by wrapping up administrative tasks into easier-to-use cmdlets that correspond roughly with the command-line utilities we've used for years. The shell's problem is that, aside from WMI, it's essentially a local shell. Many of its core operating system-configuration cmdlets don't provide any support for contacting a remote computer. The shell also doesn't solve one of WMI's more egregious problems: its use of Remote Procedure Calls (RPCs) for remote connectivity. RPCs are a hassle in environments that use local firewalls (and who doesn't these days?), often making WMI unusable for any kind of remote management.

The Solution
Microsoft has been aware of these shortcomings for quite a while, but it's taken some time for all the necessary fixes to line up in a single product. That product is Windows PowerShell v2, which includes a new version of Windows Remote Management (WRM). Both will ship for the first time in Windows 7 and Windows Server 2008 R2, and both will be pre-installed on those operating systems by default.
The technologies will also be made available for older versions of Windows, possibly as far back as Windows XP. But as of this writing, no official announcement has been made about exactly which older operating systems will be supported (the older the OS, the more difficult Microsoft's task, because older versions may lack some of the necessary core supporting technologies).
WinRM is really the key technology that makes all this possible. It's a Microsoft implementation of WS-MAN, or Web Services for Management, and as the name implies, it uses HTTP and HTTPS to communicate, which means that it's easy to get the traffic through a firewall. Unlike RPCs, which start on a single well-known point and then move their conversation to a randomly chosen port, HTTP and HTTPS utilize a single port—80 and 443 by default, but configurable if you don't like those. WinRM allows many different applications to "listen" for incoming management connections, and Windows PowerShell v2 is one application capable of doing so. (Personally, I think WMI might eventually migrate to use WinRM.)
Essentially, you sit on your client computer and ask it to make a shell connection to a remote computer. That activates WinRM on the remote computer, which in turn spins up an instance of Windows PowerShell v2 on the remote computer. That instance of the shell is capable of running your commands and delivering the results back to your computer.

See It in Action
The public beta releases of Windows 7 were the first time the world at large could try this out: Open a Windows PowerShell session on the server—or on multiple servers—and run Enable-PSRemoting to configure WinRM and start the WinRM service. Then, go to your client computer—also running Windows PowerShell v2—and run $session = New-PSSession computername, providing the name of the server you just configured for remoting. The New-PSSession cmdlet can also accept alternate credentials, if needed, and can be told to use non-standard ports if that's what you've configured.
If you see a lengthy error message like the one shown in Figure 1, it's because of the way WinRM authenticates. It uses Kerberos by default, but in a non-domain environment (like the one on the lab computer pictured), Kerberos isn't an option. When Kerberos isn't available, WinRM demands the use of the HTTPS transport, which requires that an SSL certificate be installed on the server computer. This is done to provide mutual authentication between you and the server so that you know you're connected to the machine you wanted. Even specifying Basic or Digest authentication in the –auth parameter won't help, because WinRM wants to use HTTPS to encrypt that traffic. The easiest solution? Be in an Active Directory domain!
Figure 1 A lengthy error message like this one may occur because of the way WinRM authenticates.
With your session activated, you're ready to begin using it. Enter-PSSession $session will connect you, live, to the remote server. Magically, you're typing in its instance of Windows PowerShell. Commands run interactively and you see the results immediately—not unlike SSH or similar technologies often used on UNIX computers.
Windows PowerShell even does some default encryption, so if you're not using HTTPS, you're still pretty safe from eavesdroppers. Run Exit-PSSession to detach from the remote console and return to your local console. The shell prompt even changes when you're connected to a remote computer, to remind you where you are.

One-to-Many Remoting
Being able to run commands on one computer is great, but how often do you need to do one thing on one server? More commonly, I find I need to run a command, or a set of commands, on a whole bunch of computers. What we've used so far in Windows PowerShell v1 is called one-to-one (1:1) remoting, meaning a single administrator managing a single remote computer. But the shell also offers one-to-many (1:n) remoting, where a single administrator can manage multiple computers. The trick is in the –computerName parameter of New-PSSession.
Let me repeat my earlier command, but this time I'll actually spell out the parameter rather than letting the shell assume it: New-PSSession –computerName computer. Because –computerName is a positional parameter, I didn't need to specify the actual parameter name earlier, but doing so now will make this trick easier to understand: $sessions = New-PSSession –computerName (Get-Content c:\names.txt). Assuming that the C:\names.txt file contains a list of computer names, one computer name per line, then the shell will create a remote session to each of them, storing the whole list of sessions in the $sessions variable.
By default, the sessions are created using whatever credentials Windows PowerShell itself is running under—so, either my logon account or an account I used with RunAs when starting the shell. A word of caution: If you have User Account Control (UAC) enabled, be sure to explicitly start the shell "as Administrator" by right-clicking its icon. Alternately, you can specify a different username for the sessions by using the command's –credential parameter.
Once you have this collection of commands, you can continue to work with them in the 1:1 fashion: Enter-PSSession $sessions[0] will connect you to the first computer's shell instance, for example. But the real power is in running a command against all of them at once: Invoke-Command –scriptblock { ipconfig } 0 –session $sessions. That runs the Ipconfig command on every computer to which you've connected a session, and brings the results back to your computer. It will actually connect to the computers in parallel, up to 32 at a time; you can change that parallel execution throttle by using the –throttlelimit parameter.

Put It Out of Your Mind
Of course, sometimes you'll fire off commands that take a while to run, and you might not want to sit around waiting for everything to complete. In such cases, why not let the shell keep working in the background? Just add the –AsJob parameter to Invoke-Command, and the shell will create a background job.
Remember that your copy of the shell isn't really doing that much work; the commands you've specified are being executed on remote instances of Windows PowerShell. Your shell is just waiting for them all to finish, and collecting the results they send back. Those results are stored as part of the job. Run Get-Job to see all current jobs and their status (whether they're still running, for example). Use Receive-Job to grab the results out of a completed job. So it all might look like this:
$sessions = New-PSSession –computerName (Get-Content c:\names.txt)
$job = Invoke-Command –scriptblock { your command(s) } –AsJob
Get-Job (to check the status)
$results = Receive-Job $job
You can then display $results, filter it, sort it, and so forth. Each result will have information attached to help you see which computer it came from. I'll discuss background jobs (which can even have sub-jobs that you have to deal with) in a future article.

It's Remote Management, New-School Style
Forget the old-school way of "remote" management that involved hiking to the data center or using a Remote Desktop "cheat." Windows PowerShell v2's remoting features are a powerful and simple way to run commands—any commands—on remote computers. Although my personal focus is on server management, these same techniques are great for desktop management tasks, as well, which is one reason why Windows PowerShell v2 is pre-installed on Windows 7 as well as Windows Server 2008 R2.

Don Jones is a co-founder of Concentrated Technology, where he blogs weekly about Windows PowerShell, SQL Server, App-V and other topics. Contact him through his Web site.

Page view tracker