IN THIS CHAPTER
In previous chapters of this book, aspects of PowerShell 2.0 were explored along with topics about PowerShell 1.0. A number of new features were not touched upon in the earlier chapters, nor was a chapter solely dedicated to just a PowerShell 2.0 feature. Additionally, an attempt was made to keep PowerShell 2.0 clearly labeled and identified.
The reason behind this separation is because at the time of writing this book, PowerShell 2.0 was still a Community Technology Preview (CTP). A CTP version of software is considered pre-beta, which means that features and functionality are still not fully defined, fully functional, and in some cases, they are fully documented. The purpose of this chapter is to discuss the PowerShell 2.0 features that where either not discussed or briefly touched on earlier chapters. As part of the discussion, effort has been made to provide as much information as possible. However, in some cases, because of the possible volatility of a feature, missing documentation, or limited usage scenarios, the details about a feature may have been shortened or not discussed.
Why was this done? As mentioned, PowerShell 2.0 is still a CTP version. It can’t be stressed enough that there will be changes from the CTP version to the RTM version of PowerShell 2.0. However, regardless of its current state, PowerShell 2.0 is a giant step forward for PowerShell. A number of the new features are powerful and should be discussed because of the benefits they might provide current PowerShell users. The most important of these new features is called remoting, which is discussed in the next section.
In PowerShell 1.0, a major disadvantage is the lack of an interface to execute commands on a remote machine. You can use Windows Management Instrumentation (WMI) to accomplish this, but the allure of a native-based “remoting” interface was sorely missing when PowerShell was first released. In fact, the lack of remote command execution was a glaring lack of functionality that needed to be addressed. Naturally, the PowerShell product team took this functionality limitation to heart and addressed it by introducing a new feature in PowerShell 2.0: “remoting.”
For the sake of conformity, a command in this chapter is a summary, a cmdlet, expression, script, and so on. In other words, a command is something that can be executed.
Remoting, as its name suggests, is a new feature that is designed to facilitate command (or script) execution on remote machines. This could mean execution of a command or commands on one remote machine or thousands of remote machines (provided you have the infrastructure to support this). Additionally, commands can be issued synchronously or asynchronously, one at time or through a persistent connection called a runspace, and even scheduled or throttled.
To use remoting, you must have the appropriate permissions to connect to a remote machine, execute PowerShell, and execute the desired command(s). In addition, the remote machine must have PowerShell 2.0 and Windows Remote Management (WSMAN) installed, and PowerShell must be configured for remoting.
At the time this chapter was written, PowerShell remoting was supported only with WSMAN 2.0 CTP2 and on Windows Vista SP1 to Windows Server 2008 machines.
Additionally, when using remoting, the remote PowerShell session that is used to execute commands determines the execution environment. Therefore, the commands you attempt to execute are subject to a remote machine’s execution policies, profiles, and preferences.
Commands that are executed against a remote machine do not have access to information defined in your local profile. Commands that use a function or alias defined on your local machine will fail unless they are defined on the remote machine as well.
In its most basic form, PowerShell remoting works using the following conversation flow between “a client” (most likely the machine with your PowerShell session) and “a server” (remote host) that you want to execute command(s) against:
1. A command is executed on the client.
2. That command is transmitted to the server.
3. The server executes the command and then returns the output to the client.
4. The client displays or uses the returned output.
At a deeper level, PowerShell remoting is dependent on WSMAN for facilitating the command and output exchange between a “client” and “server.” WSMAN, which is a component of Windows Hardware Management, is a Web-based service that enables Administrators to enumerate information on and manipulate remote machines. To handle remote sessions, WSMAN is built around a SOAP-based standards protocol called WS-Management. This protocol is firewall-friendly and primarily developed for the exchange of management information between systems that may be based on a variety of operating systems on various hardware platforms.
When PowerShell uses WSMAN to ship commands and output between a client and server, that exchange is done using a series of XML messages. The first XML message that is exchanged is a request to the server, which contains the desired command to be executed. This message is submitted to the server using the SOAP protocol. The server, in return, executes the command using a new instance of PowerShell called a runspace. After execution of the command is complete, the output from the command is returned to the requesting client as the second XML message. This second message, like the first, is also communicated using the SOAP protocol.
By default, Configure-WSMan.ps1
script configures WSMAN to operate over port 80. However, that doesn’t mean traffic is unencrypted. In this mode, WSMAN will accept only a connection encrypted using Negotiate or Kerberos SSP.
This translation into an XML message is performed because you cannot ship “live” .NET objects (how PowerShell relates to programs or system components) across the network. So, to perform the transmission, objects are serialized into a series of XML (CliXML) data elements. When the server or client receives the transmission, it converts the received XML message into a deserialized object type. The resulting object is no longer “live.” Instead, it is a record of properties based on a point in time, and it no longer possesses any methods.
The Universal Code Execution Model is a theme (or set of features) that was introduced in PowerShell 2.0. This model is defined so that any command, expression, and ScriptBlock is executable:
• In the foreground or background.
• On one or more machines.
• Over any network connection (LAN or a WAN).
• Within unrestricted or restricted environments.
• Over short or long connections.
• Using impersonation or supplied credentials.
• Initiated by user input or by events.
Needless to say, remoting is an aspect of this model in that it meets many, if not all, of these definitions. However, at its core, remoting is a feature that enables commands to be executed on a single machine or many machines.
When using remoting, there are three different modes that can be used to execute commands. These modes are as follows:
• 1 to 1—Referred to as the “Interactive” mode, this mode enables you to remotely manage a machine in much the same way you would an SSH session.
• Many to 1—Referred to as the “Fan-In” mode, this mode enables multiple administrators to manage a single host using an interactive session.
• 1 to Many—Referred to as the “Fan-Out” mode, this mode enables a command to execute across a large number of machines.
More information about each mode is provided in the following sections.
With interactive remoting, the PowerShell session you execute commands in looks and feels much like an SSH session, as shown in Figure 17.1. The key to achieving this mode of remoting is a PowerShell feature called a runspace. Runspaces, by definition, are instances of the System.Management.Automation
class, which defines the PowerShell session and its host program (Windows PowerShell host, cmd.exe, and so on). In other words, a runspace is an execution environment in which PowerShell runs.
Not widely discussed in Powershell 1.0, runspaces in PowerShell 2.0 are the method by which commands are executed on local and remote machines. When a runspace is created, it resides in the global scope and it is an environment to itself that includes its own properties, execution polices, and profiles. This environment persists for the lifetime of the runspace, regardless of the volatility of the host machine’s environment.
Being tied to the host program that created it, a runspace ceases to exist when the host program is closed. When this happens, all aspects of the runspace are gone, and you can no longer retrieve or use the runspace. However, when created on a remote machine, a runspace can remain until it is stopped.
To create a runspace on a machine, there are two cmdlets that can be used. The Push-Runspace
cmdlet is used to create an interactive PowerShell session. This is the cmdlet that was shown in Figure 17.1. When this cmdlet is used against a remote machine, a new runspace (PowerShell process) is created and a connection is established from the local machine to the runspace on the remote computer. If executed against the local machine, a new runspace (PowerShell process) is created and connection is established back to a local machine. To close the interactive session, you use the Pop-Runspace
cmdlet or the quit
alias.
Fan-In remoting is named in reference to the abilities of multiple administrators to open their own runspaces at the same time. In other words, many administrators can “fan in” from many machines into a single machine. When connected, each administrator is then limited to the scope of his own runspace. This partitioning of access can be achieved thanks to the new PowerShell 2.0 security model that enables the creation of restricted shells and cmdlets.
The steps needed to fully utilize the new security model require some software development using the .NET Framework. The ability to provide secure partitioned remote management access on a single host to a number of different administrators is a powerful feature. Usage can range from a Web-hosting company that wants to partition remote management access to each customer for each of its Web sites to internal IT departments that want to consolidate their management consoles on a single server.
Fan-Out remoting is named in reference to the ability to issue commands to a number of remote machines at one time. When using this method or remoting, command(s) are issued on your machine. These commands then “fan out” and are executed on each of the remote machines that have been specified. The results from each remote machine are then returned to your machine in the form an object, which you can then work with or review.
Ironically enough, PowerShell has always supported the concept of Fan-Out remoting. In PowerShell 1.0, Fan-Out remoting was achieved using WMI. For example, you could always import a list of machine names and then use WMI to remotely manage those machines:
Although the ability to perform Fan-Out remoting in PowerShell 1.0 using WMI is a powerful feature, this form of remoting suffers in usability because it is synchronous in nature. In other words, after a command has been issued, it is executed on each remote machine one at a time. Although this happens, further command execution has to wait until the command issued has finished being executed on all of the specified remote machines.
Attempting to synchronously manage a large number of remote machines can prove to be a challenging task. To address this challenge in PowerShell 2.0, the product team tweaked the remoting experience so that Fan-Out remoting could be done asynchronously. With these changes, you can still perform remote WMI management as shown in the previous example; however, you can also asynchronously execute remote commands using the following methods:
• Executing the command as a background job
• Using the Invoke-Command
cmdlet
• Using the Invoke-Command
cmdlet with a reusable runspace
The first method, a background job, as its name might suggest, enables commands to be executed in the background. This is not truly asynchronously, but a command that is executed as a background job allows you to continue executing additional commands while the job is being completed. For example, to run the previously shown WMI example as a background job, you simply add the AsJob
parameter for the Get-WmiObject
cmdlet, as shown in the following:
With the AsJob
parameter (new in PowerShell 2.0) being used, each time the Get-WmiObject
cmdet is called in the foreach
loop, a new background job is created to complete execution of the cmdlet. More details about background jobs are provided later in this chapter; this example shows how background jobs can be used to achieve asynchronous remote command execution when using WMI.
The second method to asynchronously execute remote commands is to use the new cmdlet called Invoke-Command
. This cmdlet is new in PowerShell 2.0 and it enables you to execute commands both locally and remotely on machines. Unlike WMI, which uses remote procedure call (RPC) connections to remotely manage machines, the Invoke-Command
cmdlet utilizes WSMAN to push the commands out to each of the specified “targets” in an asynchronous manner.
To use the cmdlet, there are two primary parameters that need to be defined. The first parameter, ScriptBlock
, is used to specify a scriptblock that contains the command to be executed. The second parameter, ComputerName
(NetBIOS name or IP address), is used to specify the machine or machines to execute the command that is defined in the scriptblock. For example:
You can specify a script file to be executed using the ScriptBlock
parameter. However, the script must be present in the specified location on all of the machines specified using the ComputerName
parameter.
Additionally, the Invoke-Command
cmdlet also supports a set of parameters that make it an even more powerful vehicle to conduct remote automation tasks. These parameters are described in Table 17.1.
As discussed previously, the AsJob
parameter is used to execute the specified command as a background job. However, unlike the Get-WmiObject
cmdlet, when the AsJob
parameter is used with the Invoke-Command
cmdlet, a background job is created on the client machine that then spawns a number of child background job(s) on each of the specified remote machine(s). After execution of a child background is finished, the result(s) are returned to parent background job on the “client” machine.
Needless to say, if a large number of remote machines are defined using the ComputerName
parameter, the client machine might become overwhelmed. To help prevent the client machine or your network from drowning in an asynchronous connection storm, the Invoke-Command
cmdlet will by default limit the number of concurrent remote connections for an issued “command” to 32. If you want to “tweak” the number of concurrent connections allowed, you can use the ThrottleLimit
parameter.
An important concept to understand when using the Invoke-Command
cmdlet is how it actually executes commands on a remote machine. By default, this cmdlet sets up a temporary runspace for each of the targeted remote machine(s). After execution of the specified command has finished, both the runspace and the connection resulting from that runspace are closed. This means that no matter how the ThrottleLimit
parameter is used, if you execute a number of different commands using the Invoke-Command
cmdlet at the same time, the actual number of concurrent connections to a remote machine is the total number of times you invoked the Invoke-Command
cmdlet.
Needless to say, if you want to reuse the same existing connection and runspace, you need to use the Invoke-Command
cmdlet’s Runspace
parameter. However, to make use of the parameter requires an already existing runspace on the targeted remote machine(s). To create a persistent runspace on a remote machine, use the New-Runspace
cmdlet shown in the following example:
After executing the previous command, two persistent runspaces on each the specified targets are created. These runspaces can then be used to complete multiple commands and even share data between those commands. To use these runspaces, you need to retrieve the resulting runspace object(s) using the Get-Runspace
cmdlet, and then pass it into the Invoke-Command
cmdlet. For example:
First, the $Runner
variable is used to store the two resulting runspace objects that are created using the New-Runspace
cmdlet. Next, the $Runner
variable is defined as the argument for the Runspace
parameter of the Invoke-Command
cmdlet. By doing this, the command that is defined as the argument for the ScriptBlock
parameter is executed in each of the runspaces represented by the $Runner
variable. Finally, the results from the command executed in each of the runspaces is returned and piped into Select-Object
cmdlet to format the output. In this case, the output shows the current status of the W32Time service on each of the specified remote machines.
After you have finished executing commands, it’s important to understand that the runspaces that where created will remain open until you close the current PowerShell Console. To free up the resources being consumed by a runspace, you need to delete it using the Remove-Runspace
cmdlet. For example, to remove the runspaces contained in the $Runner
variable, pass that variable into the Remove-Runspace
cmdlet, as shown here:
You can manage machines in a workgroup using remoting. However, some Windows security settings need to be modified or verified before attempting to remotely manage these machines. These settings are discussed in the following sections.
Windows XP SP2 or Greater and Windows Server 2003 For Windows XP SP2 or greater and Windows Server 2003 machines, you need to ensure that the “Network Access: Sharing and security model for local accounts” policy in Security SettingsLocal PoliciesSecurity Options is set to Classic.
Windows Vista and Windows Server 2008 On Windows Vista and Windows Server 2008 machines, you need to execute the following PowerShell command:
For machines that are in another domain, if that domain trusts your domain, then you should be able to almost always remotely execute commands against these machines without issue. However, as a general “best-practice,” you should use the Credential
parameter for the Invoke-Command
, New-Runspace
, or Start-PsJob
cmdlets to authenticate as a member of the Administrators group on the remote machine.
In instances in which the remote machine’s domain doesn’t trust your domain, you need to add your machine as a trusted WSMAN trusted host. To complete this task, use the following command:
By default, the PowerShell Console completes commands only in a synchronous manner. This means that when a command is executed, the command prompt is suppressed until execution of the issued command has completed. To address the impact of a command that takes a long time to complete execution might have on the usability of a console session, background jobs were introduced in PowerShell 2.0. When used, a background job (PsJob
) executes a command “in the background” within its own runspace, so that additional commands can then be issued using the PowerShell Console. In other words, by using a background job, you can complete automation tasks that take an extended period of time to run without impacting the usability of your PowerShell Console session.
The Start-PsJob
cmdlet is used to start a background job on the local machine. For example, to execute a script file as a background job you would use the following command:
After it is executed, the command starts a background that executes the VM_Backup.ps1
script file. To see the current or resulting status of a job or jobs, you need to use the Get-PsJob
cmdlet shown in the next example:
When executed, the Get-PsJob
cmdlet returns an object or objects that represent all of the jobs that have been executed or are being executed in the current PowerShell Console. However, while the resulting objects may contain all of the related information about jobs, they don’t contain the results from any of the jobs. To get the results from a background job, you must use the Receive-PsJob
cmdlet, as shown in the following example:
To delete jobs, you can either close your PowerShell Console or use the Remove-PsJob
cmdlet, as shown in the following example:
Introduced in PowerShell 2.0 is an interactive GUI-based shell called Graphical PowerShell. To run Graphical PowerShell, you can either click Start > All Programs > Windows PowerShell V2 > Graphical Windows PowerShell or, from the command line, you can also execute gpowershell.exe.
Some of Graphical PowerShell’s features are as follows:
• The shell provides syntax coloring and supports Unicode.
• There is an interactive Input pane that enables the execution of commands from within the shell. Results from executed commands are shown in an Output pane.
• There is also a multitabbed scripting pane used for editing or loading different ps1 files.
• Loaded script files can be dot-sourced by either pressing <F5> or by clicking the “Run” option on the toolbar.
• In addition, you can open up to eight runspaces from within the shell.
Graphical PowerShell is installed when you install PowerShell 2.0. However, to use it, you must also have the NET Framework 3.0 installed.
In the Graphical PowerShell GUI, you will find an interactive prompt at the bottom of the shell that can be used to execute commands. This prompt is similar to the prompt found in the PowerShell Console. To complete a task, compose the command you want to execute and press Enter or click the green Run bottom. As the command is executed, the output is streamed into a separate Output pane above the interactive prompt. Also, to open up an additional runspace to execute commands, you can use the Runspace > New Runspace menu option. Both the Input and Output panes are shown in Figure 17.2.
To compose, edit, and execute scripts, you can either open the desired script or activate the Script pane by clicking the Script pane toggle button or using the File > New Script menu option. After the Script pane has been opened, you can compose a new script or edit the script that you opened. This pane is multitabbed, which means you can create or edit additional scripts in additional tabs in the Script pane. Additionally, the script you compose or edit can be executed by clicking the green Run button, pressing F5, or selecting the File > Run menu option. To execute only part of the script, select the portion of the script to be executed and use any of the execution methods mentioned previously.
Graphical PowerShell is an interesting new edition to PowerShell functionality. However, at the time this book was written, Graphical PowerShell was considered an early alpha to beta version. As such, there are a couple known issues on top of being a limited integrated development environment (IDE). These include:
• No support for commands that require user input. For example, netsh
, telnet
, ftp
, and nslookup
are not supported.
• No support for PSHost
functionality.
• Output formatting still has ellipses (...).
• The script editor is not fully optimized and may seem slow for scripts over a 1,000 lines.
As defined earlier in this book, cmdlets are instances of reusable code that are based on the .NET Framework. All cmdlets are compiled into a DLL and must be loaded into a PowerShell session either during startup or by executing a series of commands. Although developing a series of cmdlets can be a great way to extend PowerShell functionality, the aspect of writing a bunch of code and then compiling that code and loading it into PowerShell may seem like daunting work to individuals who are not application developers (scripters and IT professionals).
To empower these individuals with the many of the same benefits that cmdlets provide to application developers, the PowerShell product team introduced a new PowerShell 2.0 feature called script cmdlets. In contrast to cmdlets, script cmdlets are written using the PowerShell script language, just like any other script, but in a specialized script block. For example:
Script cmdlets come in two flavors: unnamed script cmdlets and named script cmdlets, which use the same Verb-Noun
naming format as compiled cmdlets. In either case, both types of script cmdlets make use of the cmdlet
keyword, which is used to identify them as cmdlets. With unnamed script cmdlets, the cmdlet
keyword is declared in the script block using the following structure:
As shown in the previous example, like compiled cmdlets, script cmdlets can declare their own mandatory and optional parameters while also having access to common parameters (such as -verbose
and -debug
). Furthermore, script cmdlets also support the usage of the same input processing methods (Begin
, Process
, and End
) used in compiled cmdlets. Script cmdlets can also accept values from the pipeline while their output can also be piped to other compiled and script cmdlets.
With named script cmdlets, the structure is similar and supported methods, attributes, and parameters are the same as unnamed script cmdlets. The primary difference is that the script block is declared using the cmdlet
keyword as shown in the following example:
Besides the minor differences in structure, the only real difference between named and unnamed script cmdlets is in how they are invoked. Unnamed script cmdlets are invoked either as they are composed in the PowerShell Console or when the script file that contains them is executed. Conversely, named script cmdlets are invoked only when they are called. For example, if you were to execute a script file that contained a named script cmdlet called Get-MyMessage
. The Get-MyMessage
script cmdlet is only declared and must be explicitly called in order to be executed.
The Out-GridView
cmdlet is a new feature in PowerShell 2.0. This cmdlet allows output from any PowerShell command to be sent to a fully rendered and interactive grid window. When executed, the resulting Grid View window can then be used to search, sort, group, filter, and export the output data. For example, the following command creates an instance of the Grid View window:
The resulting Grid View window, shown in Figure 17.3, contains the output from the Get-Process
cmdelt. By using the interactive interface created by the Out-GridView
cmdlet, you can manipulate the output as needed.
The primary goal of the script internationalization features in PowerShell 2.0 is to make it easier to display messages in a script user’s native language. To accomplish this goal, when a script is executed (and provided the internationalization features are being used), PowerShell queries the user interface (UI) culture of the operating system and imports the appropriate predefiend text strings that are stored separately from script code in a DATA section.
Script internationalization is not supported in PowerShell 1.0. If these features are defined in a script that is executed using PowerShell 1.0, the script will not run.
A breakdown of the script international features follows:
• Support for the new .psd1
file type. These types of files store translated text strings and are located in language-specific subdirectories.
• The capability to use the DATA section feature, which allows text strings to be separated from script logic.
• A new variable called $Culture
, which stores the name of the UI language used for elements such as date, time, and currency.
• A new variable called $UICulture
, which stores the name of the UI language used for user interface elements such as menus and text strings.
• A new cmdlet named ConvertFrom-StringData
, which is used to convert text strings into dictionary-like hash tables.
• A new cmdlet named Import-LocalizedData
, which is used to import translated text strings for a specified language into a script at runtime.
Taken from the page of modularity found with Dynamic-Link Libraries (DLL), another new feature introduced in PowerShell 2.0 is called DATA sections. The primary goal with this feature is to make the task of separating data from execution code easier to manage by providing a means to isolate data (text strings and other read-only elements) from script logic.
DATA sections is not supported in PowerShell 1.0. If this feature is used in a script that is executed using PowerShell 1.0, the script will not run.
When data is separated from script logic, you are able to start modularizing a script’s components. For example, using DATA sections, you can create a separate resource file (as explained in the “Script Internationalization” section) for text, error messages, help strings, and so on. Thus, dumping “data” into separate resource files makes not only isolating and locating strings that need to be translated easier, but it also makes performing validation testing on script logic easier.
To create a DATA section, you need to use the following syntax:
Based on the syntax from the previous code box, a valid DATA section might look as follows:
Notice the usage of the DATA
keyword (not case sensitive) to designate that this is a DATA section. In addition, the variable name is required, but the $
prefix is omitted. As for content in a DATA section, you are limited to the elements shown in Table 17.3.
Additionally, you many only use the following cmdlets in a DATA section:
• ConvertFrom-StringData
• Cmdlets you “permitted” using the supportedCommand
parameter
For example, the following code box shows the ConvertFrom-StringData
being used:
Modulization is a concept that was touched upon during the explanation of the DATA sections feature. Interestingly enough, a module is also new PowerShell 2.0 feature that is focused purely on supporting the modularizing of a script’s components. In other words, modules enable scripts to be divided and organized into self-contained, independent, reusable units of code or resources.
A primary characteristic of a module is that it is self contained. When a module is used, code is executed in its own context, which prevents conflicts with any existing variables, functions, aliases, and other resources. In other words, a key aspect of a module is the capability to be portable. Thanks to this portability, modules can be easily used to build complex automation tools by bringing together and/or sharing existing resources.
These reusable components can either be DLLs or script files. To create a script-based module, you just need to take PowerShell code (like a function) and save it as a .psm1
file. Then, to load a module into PowerShell, use the Add-Module
cmdlet. When referring to the module, you can either use an absolute path, or place the module in either of the following directories and refer to it using the file name:
• pshomepackages
• ~DocumentsWindowsPowerShellpackages
Debugging code is often an import task that any programmer or scripter has to do both during the development and support cycle of any type of software. To debug code, you often use a debugging tool or features in a programming language. Depending on the tools or features available for a programming language, the debugging process can either be easy a difficult task, as is the case with lower-level programming languages.
In PowerShell 1.0, debugging is accomplished by using either an IDE tool, such as Powershell Analyzer, by making use of internal PowerShell debug settings, by writing code to insert pseudo breakpoints, or by making use of PowerShell’s exception-handling methods. Needless to say, there is much to be desired from the PowerShell engine in terms of language-based debugging features.
The PowerShell product creators were aware of the pain associated with attempting to perform debugging in PowerShell 1.0. That’s why in PowerShell 2.0, a series of debugging cmdlets were introduced to enable you to actively debug a script, script cmdlet, function, command, or expression. Using these cmdlets, you can set breakpoints, step through script logic, examine the values of variables, run diagnostics and log commands, and even display the call stack. Details about the new debugging cmdlets are shown in Table 17.4:
When released, PowerShell 1.0 was a major step forward in the manageability of Microsoft technologies. PowerShell 2.0 looks to continue with that trend by introducing many new features that further improve the ability for people to manage Microsoft products and environments. In other words, PowerShell has a bright future and some of that future—in the form of new features—was reviewed in this chapter.
Although these features range from remoting to script internationalization, and in appearance seem disconnected, they are, in fact, part of a series of themes that the PowerShell product group has decided to focus on for PowerShell 2.0. These themes are as follows:
• Universal Code Execution Model
• Production scripting
• GUI over PowerShell
• Community Feedback
As mentioned before in this chapter, the Universal Code Execution Model is a theme in PowerShell 2.0 aimed at ensuring that commands can traverse environments located in the foreground, background, or even on remote machines. With features like remoting and background jobs, Universal Code Execution Model is a primary theme in the 2.0 release of PowerShell.
Production scripting is also another important theme; it is aimed at making PowerShell scripting easier and more portable. Central to this theme is the script cmdlets feature, but also the concept of making PowerShell scripts modular in nature. This modularization can either be in the form of actual modules that can be shared among scripts or other scripters. Or, it can simply be the capability to support multiple different languages, much like a compiled application does.
GUI over PowerShell is another theme. It is more developer focused, but two obvious features that are part of this theme are the Graphical PowerShell and the Out-GridView
cmdlet. Graphical PowerShell should provide the most benefit to an IT professional who needs not only a good PowerShell console, but also an IDE to write scripts with.
The final theme is Community Feedback. With PowerShell 2.0, the product team has gone out of its way to listen to the user community. As such, the community drives and dictates the product roadmap and the continued PowerShell improvements.