Skip to main content

Windows

Modify Internet Explorer Settings

Problem

You want to modify Internet Explorer’s configuration options.

Solution

To modify the Internet Explorer configuration registry keys, use the SetItemProperty cmdlet. For example, to update the proxy:

SetLocation "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" SetItemProperty . Name ProxyServer Value http://proxy.example.com SetItemProperty . Name ProxyEnable Value 1

Discussion

Internet Explorer stores its main configuration information as properties on the registry key HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings.To change these properties, use the SetItemProperty cmdlet as demonstrated in the solution.

Another common set of properties to tweak are the configuration parameters that define a security zone. An example of this is to prevent scripts from running in the Restricted Sites zone. For each zone, Internet Explorer stores this information as properties of the registry key HKCU:\Software\Microsoft\Windows\CurrentVersion\ Internet Settings\Zones\Zone>, where > represents the zone identifier (0, 1, 2, 3, or 4) to manage.

The Internet Explorer zone identifiers are:

  1. My Computer
  2. Local intranet
  3. Trusted sites
  4. Internet
  5. Restricted sites

The names of the properties in this key are not designed for human consumption, as they carry illuminating titles such as 1A04 and 1809. While not wellnamed, you can still script them.

For more information about using the Internet Explorer registry settings to configure security zones, see the Microsoft KB article “Description of Internet Explorer Security Zones Registry Entries” at http://support.microsoft.com/kb/182569.

Experiment with the Command Shell

Problem

You want to experiment with the features and functionality of the Operations Manager Command Shell without working on a production system.

Solution

To explore the Operations Manager Command Shell, use the Microsoft Forefront and System Center Demonstration Toolkit.

Discussion

Downloadable Virtual PC images and online virtual labs have recently become an incredibly effective means by which you can experiment with new technologies. The Microsoft System Center application suite offers several Virtual PC images for download, one of them tailored to Forefront Security and its interaction with the rest of the System Center family. The Oxford computer in this virtual lab represents a computer running System Center Operations Manager 2007, which provides an excellent avenue for exploration of this new technology.

To download this demonstration toolkit, visit the Microsoft download page at http:// download.microsoft.com . Then, search for “System Center demonstration toolkit.”

After registering, download all the files for the demonstration toolkit and launch the included installer. Once the installation completes, visit the VMImages directory in the installation directory and launch the Oxford demo virtual machine.

Once the machine loads, Click Start ➝ All Programs ➝ System Center Operations Manager 2007 ➝ Command Shell to launch the Operations Manager Command Shell.

Program: Search Help for Text in Windows PowerShell

Both the GetCommand and GetHelp cmdlets let you search for command names that match a given pattern. However, when you don’t know exactly what portions of a command name you are looking for, you will more often have success searching through the help content for an answer. On Unix systems, this command is called Apropos. Similar functionality does not exist as part of the PowerShell’s help facilities, however.

That doesn’t need to stop us, though, as we can write the functionality ourselves.

To run this program, supply a search string to the SearchHelp script The script then displays the name and synopsis of all help topics that match. To see the help content for that topic, use the GetHelp cmdlet.

############################################################################## ## ## SearchHelp.ps1 ## ## Search the PowerShell help documentation for a given keyword or regular ## expression. ## ## Example: ## SearchHelp hashtable ## SearchHelp "(datetime|ticks)" ##############################################################################

param($pattern = $(throw "Please specify content to search for"))

$helpNames = $(GetHelp * | WhereObject { $_.Category ne "Alias" })

foreach($helpTopic in $helpNames)

{ $content = GetHelp Full $helpTopic.Name | OutString if($content match $pattern) {

$helpTopic | SelectObject Name,Synopsis } }

Access Pipeline Input in Windows PowerShell

Problem

You want to interact with input that a user sends to your function, script, or script block via the pipeline.

Solution

To access pipeline input, use the $input variable as shown by Example 107.

Example 107. Accessing pipeline input

function InputCounter {

$count = 0

## Go through each element in the pipeline, and add up

## how many elements there were.

foreach($element in $input)

{

$count++

}

$count }

which produces the following (or similar) output when run against your Windows system directory:

PS >dir $env:WINDIR | InputCounter

295

Discussion

In your scripts, functions, and script blocks, the $input variable represents an enumerator (as opposed to a simple array) for the pipeline input the user provides. An enumerator lets you use a foreach statement to efficiently scan over the elements of the input (as shown in Example 107) but does not let you directly access specific items (such as the fifth element in the input, for example).

An enumerator only lets you to scan forward through its contents. Once you access an element, PowerShell automatically moves on to the next one. If you need to access an item that you’ve already

accessed before, you must call $input.Reset() to scan through the list again from the beginning, or store the input in an array.

If you need to access specific elements in the input (or access items multiple times), the best approach is to store the input in an array. This prevents your script from

taking advantage of the $input enumerator's streaming behavior, but is sometimes the only alternative. To store the input in an array, use PowerShell’s list evaluation syntax ( @() ) to force PowerShell to interpret it as an array.

function ReverseInput

{

$inputArray = @($input)

$inputEnd = $inputArray.Count 1

$inputArray[$inputEnd..0] }

which produces

PS >1,2,3,4 | ReverseInput 4 3 2 1

If dealing with pipeline input plays a major role in your script, function, or script block, PowerShell provides an alternative means of dealing with pipeline input that may make your script easier to write and understand. 

Create a Directory in PowerShell

Problem

You want to create a directory, or file folder.

Solution

To create a directory, use the md or mkdir function: PS >md NewDirectory

Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp

Mode
LastWriteTime
Length Name

d

4/29/2007
7:31 PM
NewDirectory

Discussion
 

The md and mkdir functions are simple wrappers around the more sophisticated NewItem cmdlet. As you might guess, the NewItem cmdlet creates an item at the location you provide. The NewItem cmdlet doesn’t work only against the filesystem, however. Any providers that support the concept of items automatically support this cmdlet as well.

For more information about the NewItem cmdlet, type GetHelp NewItem.

Retrieve Printer Queue Statistics

Problem

You want to get information about print queues for printers on the current system.

Solution

To retrieve information about printers attached to the system, use the Win32_ PerfFormattedData_Spooler_PrintQueue WMI class:

PS >GetWmiObject Win32_PerfFormattedData_Spooler_PrintQueue | >> Select Name,TotalJobsPrinted >>

Name TotalJobsPrinted

Microsoft Office Document Image Wr...

0 Microsoft Office Document Image Wr...

0 CutePDF Writer

0 Brother DCP1000

2 _Total

2

To retrieve information about a specific printer, apply a filter based on its name, as shown in Example 244.

Example 244. Retrieving information about a specific printer

PS >$queueClass = "Win32_PerfFormattedData_Spooler_PrintQueue" PS >$filter = "Name='Brother DCP1000'" PS >$stats = GetWmiObject $queueClass Filter $filter PS >$stats | FormatList *

AddNetworkPrinterCalls : 129 BytesPrintedPersec : 0 Caption : Description : EnumerateNetworkPrinterCalls : 0 Frequency_Object : Frequency_PerfTime : Frequency_Sys100NS : JobErrors : 0 Jobs : 0 JobsSpooling : 0 MaxJobsSpooling : 1 MaxReferences : 3 Name : Brother DCP1000 NotReadyErrors : 0 OutofPaperErrors : 0 References : 2 Timestamp_Object : Timestamp_PerfTime : Timestamp_Sys100NS : TotalJobsPrinted : 2 TotalPagesPrinted : 0

To retrieve specific properties, access as you would access properties on other PowerShell objects:

PS >$stats.TotalJobsPrinted

Discussion

The Win32_PerfFormattedData_Spooler_PrintQueue WMI class provides access to the various Windows performance counters associated with print queues. Because of this, you can also access them through the .NET Framework.

$printer = "Brother DCP1000" $pc = NewObject Diagnostics.PerformanceCounter "Print Queue","Jobs",$printer $pc.NextValue()

Access Information in an XML File

Problem

You want to work with and access information in an XML file.

Solution

Use PowerShell’s XML cast to convert the plaintext XML into a form that you can more easily work with. In this case, the RSS feed downloaded from the Windows PowerShell blog:

PS >$xml = [xml] (GetContent powershell_blog.xml)

Like other rich objects, PowerShell displays the properties of the XML as you explore. These properties are child nodes and attributes in the XML, as shown by Example 81.

Example 81. Accessing properties of an XML document

PS >$xml

xml
xmlstylesheet
rss

rss

PS >$xml.rss

version : 2.0 dc : http://purl.org/dc/elements/1.1/ slash : http://purl.org/rss/1.0/modules/slash/ wfw : http://wellformedweb.org/CommentAPI/ channel : channel

If more than one node shares the same name (as in the item nodes of an RSS feed), then the property name represents a collection of nodes:

PS >($xml.rss.channel.item).Count 15

You can access those items individually, like you would normally work with an array, as shown in Example 82.

Example 82. Accessing individual items in an XML document

PS >($xml.rss.channel.item)[0]

description :

Since a lot of people have been asking about it, yes my

(...) guid : guid title : "Windows PowerShell in Action" has been released comment : http://blogs.msdn.com/powershell/rsscomments.aspx?PostID=171

8281 link : http://blogs.msdn.com/powershell/archive/2007/02/19/windows

powershellinactionhasbeenreleased.aspx pubDate : Mon, 19 Feb 2007 20:05:00 GMT comments : {4, http://blogs.msdn.com/powershell/comments/1718281.aspx} commentRss : http://blogs.msdn.com/powershell/commentrss.aspx?PostID=1718

281 creator : PowerShellTeam

You can access properties of those elements like you would normally work with an object:

PS >($xml.rss.channel.item)[0].title

"Windows PowerShell in Action" has been released

Since these are rich PowerShell objects, Example 83 demonstrates how you can use PowerShell’s advanced objectbased cmdlets for further work, such as sorting and filtering.

Example 83. Sorting and filtering items in an XML document

PS >$xml.rss.channel.item | SortObject title | SelectObject title

title

"Windows PowerShell in Action" has been released Controlling PowerShell Function (Re)Definition Execution Policy and Vista Executive Demo It's All about Economics NetCmdlets Beta 2 is now Available. Payette Podcast Port 25 interview with Bruce Payette PowerShell Benefits Over COM Scripting PowerShell Cheat Sheet Now in XPS PowerShell Tip: How to "shift" arrays Processing text, files and XML Virtual Machine Manager's PowerShell Support Windows PowerShell 1.0 for Windows Vista Working With WMI Events

Discussion

PowerShell’s native XML support provides an excellent way to easily navigate and access XML files. By exposing the XML hierarchy as properties, you can perform most tasks without having to resort to textonly processing, or custom tools.

In fact, PowerShell’s support for interaction with XML goes beyond just presenting your data in an objectfriendly way. The objects created by the [xml] cast in fact represent fully featured System.Xml.XmlDocument objects from the .NET Framework. Each property of the resulting objects represents a System.Xml.XmlElement object from the .NET Framework, as well. The underlying objects provide a great deal of additional functionality that you can use to perform both common and complex tasks on XML files.

The underlying System.Xml.XmlDocument and System.Xml.XmlElement objects that support your XML provide useful properties in their own right, as well: Attributes, Name, OuterXml, and more. Since these properties may interfere with the way you access properties from your XML file, PowerShell hides them by default. To access them, use the PsBase property on any node. The PsBase property works on any object in PowerShell, and represents the object underneath the PowerShell abstraction:

PS >$xml.rss.psbase.Attributes

#text

2.0 http://purl.org/dc/elements/1.1/ http://purl.org/rss/1.0/modules/slash/ http://wellformedweb.org/CommentAPI/

Perform an XPath Query Against an XML File

Problem

You want to perform an advanced query against an XML file, using XML’s standard XPath syntax.

Solution

Use PowerShell’s XML cast to convert the plaintext XML into a form that you can more easily work with. In this case, the RSS feed downloaded from the Windows PowerShell blog:

PS >$xml = [xml] (GetContent powershell_blog.xml)

Then use the SelectNodes() method on that variable to perform the query. For example, to find all post titles shorter than 20 characters:

PS >$query = "/rss/channel/item[stringlength(title) 20]/title" PS >$xml.SelectNodes($query)

#text

Payette Podcast Executive Demo

Discussion

Although a language all its own, the XPath query syntax provides a powerful, XMLcentric way to write advanced queries for XML files.

Modify Data in an XML File

Problem

You want to use PowerShell to modify the data in an XML file.

Solution

To modify data in an XML file, load the file into PowerShell’s XML data type, change the content you want, and then save the file back to disk. Example 84 dem onstrates this approach.

Example 84. Modifying an XML file from PowerShell

PS >## Store the filename PS >$filename = (GetItem phone.xml).FullName PS > PS >## Get the content of the file, and load it PS >## as XML PS >GetContent $filename

Lee 5551212 5551213

Ariel 5551234

PS >$phoneBook = [xml] (GetContent $filename) PS >

Example 84. Modifying an XML file from PowerShell (continued)

PS >## Get the part with data we want to change PS >$person = $phoneBook.AddressBook.Person[0] PS > PS >## Change the text part of the information, PS >## and the type (which was an attribute) PS >$person.Phone[0]."#text" = "5551214" PS >$person.Phone[0].type = "mobile" PS > PS >## Add a new phone entry PS >$newNumber = [xml] '5551215' PS >$newNode = $phoneBook.ImportNode($newNumber.Phone, $true) PS >[void] $person.AppendChild($newNode) PS > PS >## Save the file to disk PS >$phoneBook.Save($filename) PS >GetContent $filename

Lee 5551214 5551213 5551215

Ariel 5551234

Discussion

In the preceding solution, you change Lee’s phone number (which was the “text” portion of the XML’s original first Phone node) from 5551212 to 5551214. You also change the type of the phone number (which was an attribute of the Phone node) from "home" to "mobile".

Adding new information to the XML is nearly as easy. To add information to an XML file, you need to add it as a child node to another of the nodes in the file. The easiest way to get that child node is to write the string that represents the XML and then create a temporary PowerShell XML document from that. From that document, you use the main XML document’s ImportNode() function to import the node you care about—specifically, the Phone node in this example.

Once we have the child node, you need to decide where to put it. Since we want this Phone node to be a child of the Person node for Lee, we will place it there. To add a child node ($newNode , in Example 84) to a destination node ( $person, in the example), use the AppendChild() method from the destination node.

The Save() method on the XML document allows you to save to more than just files. For a quick way to convert XML into a “beautified” form, save it to the console:

$phoneBook.Save([Console]::Out)

Finally, we save the XML back to the file from which it came.

Securely Request Usernames and Passwords in PowerShell

Problem

Your script requires that users provide it with a username and password, but you want to do this as securely as possible.

Solution

To request a credential from the user, use the GetCredential cmdlet: $credential = GetCredential

Discussion

The GetCredential cmdlet reads credentials from the user as securely as possible and ensures that the user’s password remains highly protected the entire time.

Once you have the username and password, you can pass that information around to any other command that accepts a PowerShell credential object without worrying about disclosing sensitive information. If a command doesn’t accept a PowerShell credential object (but does support a SecureString for its sensitive information), the resulting PsCredential object provides a Username property that returns the username in the credential and a Password property that returns a SecureString containing the user’s password.

Unfortunately, not everything that requires credentials can accept either a PowerShell credential or SecureString. If you need to provide a credential to one of these commands or API calls, the PsCredential object provides a GetNetworkCredential() method to convert the PowerShell credential to a less secure NetworkCredential object. Once you've converted the credential to a NetworkCredential, the UserName and Password properties provide unencrypted access to the username and password from the original credential. Many networkrelated classes in the .NET Framework support the NetworkCredential class directly.

The NetworkCredential class is less secure than the PsCredential class because it stores the user’s password in plain text. For more information about the security implications of storing sensitive information in

plain text,

If a frequently run script requires credentials, you might consider caching those credentials in memory to improve the usability of that script. For example, in the region of the script that calls the GetCredential cmdlet, you can instead use the techniques shown by Example 163.

Example 163. Caching credentials in memory to improve usability

$credential = $null if(TestPath Variable:\Lee.Holmes.CommonScript.CachedCredential) {

$credential = ${GLOBAL:Lee.Holmes.CommonScript.CachedCredential} }

${GLOBAL:Lee.Holmes.CommonScript.CachedCredential} = GetCredential $credential

$credential = ${GLOBAL:Lee.Holmes.CommonScript.CachedCredential}

The script prompts the user for their credentials the first time they call it but uses the cached credentials for subsequent calls.

For more information about the GetCredential cmdlet, type GetHelp GetCredential.

Add a PowerShell User to a Security or Distribution Group

Problem

You want to add a user to a security or distribution group.

Solution

To add a user to a security or distribution group, use the [adsi] type shortcut to bind to the group in Active Directory, and then call the Add() method:

$management = [adsi] "LDAP://localhost:389/cn=Management,ou=West,ou=Sales,dc=Fabrikam,dc=COM"

$user = "LDAP://localhost:389/cn=MyerKen,ou=West,ou=Sales,dc=Fabrikam,dc=COM" $management.Add($user)

Discussion

The solution adds the MyerKen user to a group named Management in the Sales West OU.