Skip to main content

Windows

Create an Organizational Unit in Windows PowerShell

Problem

You want to create an organizational unit (OU) in Active Directory.

Solution

To create an organizational unit in a container, use the [adsi] type shortcut to bind to a part of the Active Directory, and then call the Create() method.

$domain = [adsi] "LDAP://localhost:389/dc=Fabrikam,dc=COM" $salesOrg = $domain.Create("OrganizationalUnit", "OU=Sales") $salesOrg.Put("Description", "Sales Headquarters, SF") $salesOrg.Put("wwwHomePage", "http://fabrikam.com/sales") $salesOrg.SetInfo()

Discussion

The solution shows an example of creating a Sales organizational unit (OU) at the root of the organization. You can use the same syntax to create OUs under other OUs as well. Example 231 demonstrates how to create an East and West sales division.

Example 231. Creating East and West sales divisions

$sales = [adsi] "LDAP://localhost:389/ou=Sales,dc=Fabrikam,dc=COM"

$east = $sales.Create("OrganizationalUnit", "OU=East") $east.Put("wwwHomePage", "http://fabrikam.com/sales/east") $east.SetInfo()

$west = $sales.Create("OrganizationalUnit", "OU=West") $west.Put("wwwHomePage", "http://fabrikam.com/sales/west") $west.SetInfo()

Get Detailed Documentation About Types and Objects in .NET Framework

Problem

You have a type of object and want to know detailed information about the methods and properties it supports.

Solution

The documentation for the .NET Framework (available on http://msdn.microsoft. com ) is the best way to get detailed documentation about the methods and properties supported by an object. That exploration generally comes in two stages:

1. Find the type of the object.

To determine the type of an object, you can use either the type name shown by the GetMember cmdlet, or call the GetType() method of an object (if you have an instance of it):

PS >$date = GetDate PS >$date.GetType().ToString() System.DateTime

2. Enter that type name into the search box at http://msdn.microsoft.com .

Discussion

When the GetMember cmdlet does not provide the information you need, the MSDN documentation for a type is a great alternative. It provides much more detailed information than the help offered by the GetMember cmdlet—usually including detailed descriptions, related information, and even code samples. MSDN documentation focuses on developers using these types through a language such as C#, though, so you may find interpreting the information for use in PowerShell to be a little difficult at first.

Typically, the documentation for a class first starts with a general overview, and then provides a hyperlink to the members of the class—the list of methods and properties it supports.

To get to the documentation for the members quickly, search for them more explicitly by adding the term “members” to your MSDN search term:

typename members

Documentation for the members of a class lists its methods and properties, as does the output of the GetMember cmdlet. The S icon represents static methods and properties. Click the member name for more information about that method or property.

Public constructors

This section lists the constructors of the type. You use a constructor when you create the type through the NewObject cmdlet. When you click on a constructor, the documentation provides all the different ways that you can create that object, including the parameter list that you will use with the NewObject cmdlet.

Public fields/public properties

This section lists the names of the fields and properties of an object. The S icon represents a static field or property. When you click on a field or property, the documentation also provides the type returned by this field or property.

For example, you might see the following in the definition for System.DateTime.Now:

C#

public static DateTime Now { get; } Public means that the Now property is public—that everybody can access it. Static means that the property is static. DateTime means that the property returns a DateTime object when you call it. Get; means that you can get information from this property but cannot set the information. Many properties support a Set; as well (such as the IsReadOnly property on System.IO.FileInfo), which means that you can change its value.

Public methods

This section lists the names of the methods of an object. The S icon represents a static method. When you click on a method, the documentation provides all the different ways that you can call that method, including the parameter list that you will use to call that method in PowerShell.

For example, you might see the following in the definition for System.DateTime. AddDays():

C# public DateTime AddDays ( double value ) Public means that the AddDays method is public—that everybody can access it. DateTime means that the method returns a DateTime object when you call it. The text, double value, means that this method requires a parameter (of type double). In this case, that parameter determines the number of days to add to the DateTime object on which you call the method.

Access Information About Your Command’s Invocation

Problem

You want to learn about how the user invoked your script, function, or script block.

Solution

To access information about how the user invoked your command, use the $myInvocation variable:

"You invoked this script by typing: " + $myInvocation.Line

Discussion

The $myInvocation variable provides a great deal of information about the current script, function, or script block—and the context in which it was invoked:

MyCommand

Information about the command (script, function, or script block) itself.

ScriptLineNumber

The line number in the script that called this command.

ScriptName

When in a function or script block, the name of the script that called this command.

Line

The verbatim text used in the line of script (or command line) that called this command.

InvocationName

The name that the user supplied to invoke this command. This will be different from the information given by MyCommand if the user has defined an alias for the command.

PipelineLength

The number of commands in the pipeline that invoked this command.

PipelinePosition

The position of this command in the pipeline that invoked this command.

One important point about working with the $myInvocation variable is that it changes depending on the type of command from which you call it. If you access this information from a function, it provides information specific to that function—not the script from which it was called. Since scripts, functions, and script blocks are fairly unique, information in the $myInvocation.MyCommand variable changes slightly between the different command types.

Scripts

Definition and Path

The full path to the currently running script

Name

The name of the currently running script

CommandType Always ExternalScript

Functions

Definition and ScriptBlock

The source code of the currently running function

Options The options (None, ReadOnly, Constant, Private, AllScope) that apply to the currently running function

Name

The name of the currently running function

CommandType Always Function

Script blocks

Definition and ScriptBlock

The source code of the currently running script block

Name

Empty

CommandType Always Script

Find Event Log Entries by Their Frequency

Problem

You want to find the event log entries that occur most frequently.

Solution

To find event log entries by frequency, use the GetEventLog cmdlet to retrieve the entries in the event log, and then pipe them to the GroupObject cmdlet to group them by their message.

PS >GetEventLog System | GroupObject Message

Count Name Group

23 The Background Intelli... {LEEDESK, LEEDESK, LEEDESK, LEEDESK... 23 The Background Intelli... {LEEDESK, LEEDESK, LEEDESK, LEEDESK...

3 The Logical Disk Manag... {LEEDESK, LEEDESK, LEEDESK}

3 The Logical Disk Manag... {LEEDESK, LEEDESK, LEEDESK}

3 The Logical Disk Manag... {LEEDESK, LEEDESK, LEEDESK} 161 Driver Microsoft XPS D... {LEEDESK, LEEDESK, LEEDESK, LEEDESK... (...)

Discussion

The GroupObject cmdlet is a useful way to determine which events occur most frequently on your system. It also provides a useful way to summarize the information in the event log.

If you want to learn more information about the items in a specific group, use the WhereObject cmdlet. Since we used the Message property in the GroupObject cmdlet, we need to filter on Message in the WhereObject cmdlet. For example, to learn more about the entries relating to the Microsoft XPS Driver (from the scenario in the solution):

PS >GetEventLog System | >> WhereObject { $_.Message like "Driver Microsoft XPS*" } >>

Index Time
Type Source
EventID Message

2917 May 06 09:13
Erro TermServDevices
1111 Driver Microsoft...

2883 May 05 10:40
Erro TermServDevices
1111 Driver Microsoft...

2877 May 05 08:10
Erro TermServDevices
1111 Driver Microsoft...

(...)

If grouping by message doesn’t provide useful information, you can group by any other property—such as source:

PS >GetEventLog Application | GroupObject Source

Count Name
Group

4 Application
{LEEDESK, LEEDESK, LEEDESK, LEEDESK}

191 Media Center Scheduler
{LEEDESK, LEEDESK, LEEDESK, LEEDESK...

1082 MSSQL$SQLEXPRESS
{LEEDESK, LEEDESK, LEEDESK, LEEDESK...

(...)

If you’ve listed the items in an event log or searched it for entries that have a message with specific text, you often want to get more details about a specific event log entry.

By default, PowerShell’s default table formatting displays a summary of event log entries. If you are retrieving a specific entry, however, you are probably interested in seeing more details about the entry. In this case, use the FormatList cmdlet to format these entries in a more detailed list view, as shown in Example 205.

Example 205. A detailed list view of an event log entry

PS >GetEventLog System | WhereObject { $_.Index –eq 2917 } | >> FormatList >>

Index : 2917 EntryType : Error EventID : 1111 Message : Driver Microsoft XPS Document Writer required for pri

nter Microsoft XPS Document Writer is unknown. Contac t the administrator to install the driver before you log in again.

Category : (0) CategoryNumber : 0 ReplacementStrings : {Microsoft XPS Document Writer, Microsoft XPS Documen

t Writer} Source : TermServDevices TimeGenerated : 5/6/2007 9:13:31 AM TimeWritten : 5/6/2007 9:13:31 AM UserName :

For more information about the GetEventLog cmdlet, type GetHelp GetEventLog. For more information about the GroupObject cmdlet, type GetHelp GroupObject.

Pipelines in Windows PowerShell

One of the fundamental concepts in a shell is called the pipeline. It also forms the basis of one of the most significant advances that PowerShell brings to the table. A pipeline is a big name for a simple concept—a series of commands where the output of one becomes the input of the next. Apipeline in a shell is much like an assembly line in a factory: it successively refines something as it passes between the stages.

Example 21. A PowerShell pipeline

GetProcess | WhereObject { $_.WorkingSet gt 500kb } | SortObject Descending Name

In PowerShell, you separate each stage in the pipeline with the pipe (|) character.

GetProcess cmdlet generates objects that represent actual processes on the system. These process objects contain information about the process’s name, memory usage, process id, and more. The WhereObject cmdlet, then, gets to work directly with those processes, testing easily for those that use more than 500 kb of memory. It passes those along, allowing the SortObject cmdlet to also work directly with those processes, sorting them by name in descending order. This brief example illustrates a significant advancement in the power of pipelines: PowerShell passes fullfidelity objects along the pipeline, not their text representations.

In contrast, all other shells pass data as plain text between the stages. Extracting meaningful information from plaintext output turns the authoring of pipelines into a black art. Expressing the previous example in a traditional Unixbased shell is exceedingly difficult and nearly impossible in cmd.exe.

Traditional textbased shells make writing pipelines so difficult because they require you to deeply understand the peculiarities of output formatting for each command in the pipeline,

Example 22. A traditional textbased pipeline

lee@trinity:~$ ps F | awk '{ if($5 > 500) print }' | sort r k 64,70

UID
PID
PPID
C
SZ
RSS PSR STIME TTY
TIME CMD

lee
8175
7967
0
965
1036
0 21:51 pts/0
00:00:00 ps F

lee
7967
7966
0
1173
2104
0 21:38 pts/0
00:00:00 bash

In this example, you have to know that, for every line, group number five represents the memory usage. You have to know another language (that of the awk tool) to filter by that column. Finally, you have to know the column range that contains the process name (columns 64 to 70 on this system) and then provide that to the sort command. And that’s just a simple example.

An objectbased pipeline opens up enormous possibilities, making system administration both immensely more simple and more powerful.

Program: Display a Menu to the User

It is often useful to read input from the user but restrict it to a list of choices that you specify. The following script lets you access PowerShell’s prompting functionality in a manner that is friendlier than what PowerShell exposes by default. It returns a number that represents the position of their choice from the list of options you provide.

PowerShell's prompting requires that you include an accelerator key (the & before a letter in the option description) to define the keypress that represents that option. Since you don't always control the list of options (for example, a list of possible directories), Example 121 automatically generates sensible accelerator characters for any descriptions that lack them.

Example 121. ReadHostWithPrompt.ps1

############################################################################## ## ## ReadHostWithPrompt.ps1 ## ## Read user input, with choices restricted to the list of options you ## provide. ## ## ie: ## ## PS >$caption = "Please specify a task" ## PS >$message = "Specify a task to run" ## PS >$option = "&Clean Temporary Files","&Defragment Hard Drive" ## PS >$helptext = "Clean the temporary files from the computer", ## >> "Run the defragment task" ## >> ## PS >$default = 1 ## PS >ReadHostWithPrompt $caption $message $option $helptext $default ##

Example 121. ReadHostWithPrompt.ps1 (continued)

## Please specify a task ## Specify a task to run ## [C] Clean Temporary Files [D] Defragment Hard Drive [?] Help ## (default is "D"):? ## C Clean the temporary files from the computer ## D Run the defragment task ## [C] Clean Temporary Files [D] Defragment Hard Drive [?] Help ## (default is "D"):C ## 0 ## ##############################################################################

param( $caption = $null, $message = $null, $option = $(throw "Please specify some options."), $helpText = $null, $default = 0 )

## Create the list of choices [Management.Automation.Host.ChoiceDescription[]] $choices = @()

## Create a list of possible key accelerators for their options $accelerators = NewObject System.Collections.ArrayList

## First, add a the list of numbers as possible choices $startNumber = [int][char] '0' $endNumber = [int][char] '9' foreach($number in $startNumber..$endNumber) {

[void] $accelerators.Add([char] $number) }

## Then, a list of characters as possible choices $startLetter = [int][char] 'A' $endLetter = [int][char] 'Z' foreach($letter in $startLetter .. $endLetter) {

[void] $accelerators.Add([char] $letter) }

## Go through each of the options, and add them to the choice collection for($counter = 0; $counter lt $option.Length; $counter++) {

$optionText = $option[$counter]

## If they didn't provide an accelerator, generate new option ## text for them if($optionText notmatch '&') {

$optionText = "&{0} {1}" f $accelerators[0],$optionText }

Example 121. ReadHostWithPrompt.ps1 (continued)

## Now, remove their option character from the list of possibilities $acceleratorIndex = $optionText.IndexOf('&') $optionCharacter = $optionText[$acceleratorIndex + 1] $accelerators.Remove($optionCharacter)

## Create the choice $choice = NewObject Management.Automation.Host.ChoiceDescription $optionText if($helpText and $helpText[$counter]) {

$choice.HelpMessage = $helpText[$counter] }

## Add the choice to the list of possible choices $choices += $choice }

## Prompt for the choice, returning the item the user selected $host.UI.PromptForChoice($caption, $message, $choices, $default)

Get the ACL of a Registry Key

Problem

You want to retrieve the ACL of a registry key.

Solution

To retrieve the ACL of a registry key, use the GetAcl cmdlet: PS >GetAcl HKLM:\Software

Path Owner Microsoft.PowerShell.... BUILTIN\Administrators
Access CREATOR OWNER Allow
...

Discussion
 

“Get the ACL of a File or Directory,” the GetAcl cmdlet retrieves the security descriptor of an item. This cmdlet doesn’t only work against the registry, however. Any provider (for example, the filesystem provider) that supports the concept of security descriptors also supports the GetAcl cmdlet.

The GetAcl cmdlet returns an object that represents the security descriptor of the item and is specific to the provider that contains the item. In the registry provider, this returns a .NET System.Security.AccessControl.RegistrySecurity object that you can explore for further information.

Schedule a Maintenance Window

Problem

You want to place a server in maintenance mode to prevent it from generating incorrect alerts.

Solution

To schedule a maintenance window on a computer, use the NewMaintenanceWindow cmdlet:

$computer = GetAgent | WhereObject { $_.Name match "Denver" }

$computer.HostComputer | NewMaintenanceWindow `

StartTime (GetDate) `

EndTime (GetDate).AddMinutes(5) `

Comment "Security updates"

To retrieve information about that maintenance window, use the GetMaintenanceWindow cmdlet:

>$computer.HostComputer | GetMaintenanceWindow

MonitoringObjectId : a542ffe891a284a637b00555b15513bd

StartTime : 5/22/2007 9:27:23 AM

ScheduledEndTime : 5/22/2007 9:32:23 AM

EndTime :

Reason : PlannedOther

Comments : Security updates

User : CONTOSO\Administrator

LastModified : 5/22/2007 9:27:23 AM

ManagementGroup : MMS

ManagementGroupId : 846c09747fd058f28020400f125beb67

To stop maintenance mode, use the SetMaintenanceWindow cmdlet to end the maintenance window immediately:

$computer.HostComputer | SetMaintenanceWindow EndTime (GetDate)

Discussion

For more information about the NewMaintenanceWindow cmdlet, type GetHelp NewMaintenanceWindow. For more information about the GetMaintenanceWindow cmdlet, type GetHelp GetMaintenanceWindow. For more information about the SetMaintenanceWindow cmdlet, type GetHelp SetMaintenanceWindow.

Program: Retain Changes to Environment Variables Set by a Batch File in Windows PowerShell

When a batch file modifies an environment variable, cmd.exe retains this change even after the script exits. This often causes problems, as one batch file can accidentally pollute the environment of another. That said, batch file authors sometimes intentionally change the global environment to customize the path and other aspects of the environment to suit a specific task.

However, environment variables are private details of a process and disappear when that process exits. This makes the environment customization scripts mentioned above stop working when you run them from PowerShell—just as they fail to work when you run them from another cmd.exe (for example, cmd.exe /c MyScript.cmd).

retain their changes even after cmd.exe exits. It accomplishes this by storing the environment variables in a text file once the batch file completes, and then setting all those environment variables again in your PowerShell session.

To run this script, type InvokeCmdScript Scriptname.cmd or InvokeCmdScript Scriptname.bat—whichever extension the batch files uses.

If this is the first time you’ve run a script in PowerShell, you will need to configure your Execution Policy.

Notice that this script uses the full names for cmdlets: GetContent, ForeachObject, SetContent, and RemoveItem. This makes the script readable and is ideal for scripts that somebody else will read. It is by no means required, though. For quick scripts and interactive use, shorter aliases (such as gc, %, sc, and ri) can make you more productive.

Example 16. InvokeCmdScript.ps1

############################################################################## ## ## InvokeCmdScript.ps1 ## ## Invoke the specified batch file (and parameters), but also propagate any ## environment variable changes back to the PowerShell environment that ## called it. ## ## i.e., for an already existing 'foothatsetstheFOOenvvariable.cmd': ## ## PS > type foothatsetstheFOOenvvariable.cmd ## @set FOO=%* ## echo FOO set to %FOO%. ## ## PS > $env:FOO ## ## PS > InvokeCmdScript "foothatsetstheFOOenvvariable.cmd" Test ## ## C:\Temp>echo FOO set to Test. ## FOO set to Test. ## ## PS > $env:FOO ## Test ## ##############################################################################

param([string] $script, [string] $parameters)

Example 16. InvokeCmdScript.ps1 (continued)

$tempFile = [IO.Path]::GetTempFileName( )

## Store the output of cmd.exe. We also ask cmd.exe to output ## the environment table after the batch file completes cmd /c " `"$script`" $parameters && set > `"$tempFile`" "

## Go through the environment variables in the temp file. ## For each of them, set the variable in our local environment. GetContent $tempFile | ForeachObject {

if($_ match "^(.*?)=(.*)$") { SetContent "env:\$($matches[1])" $matches[2] } }

RemoveItem $tempFile

Write a Pipeline-Oriented Function in Windows PowerShell

Problem

Your function primarily takes its input from the pipeline, and you want it to perform the same steps for each element of that input.

Solution

To write a pipelineoriented function, define your function using the filter keyword, rather than the function keyword. PowerShell makes the current pipeline object available as the $_ variable.

filter GetPropertyValue($property)

{

$_.$property

}

Discussion

Afilter is the equivalent of a function that uses the cmdletstyle keywords and has all its code inside the process section.

The solution demonstrates an extremely useful filter: one that returns the value of a property for each item in a pipeline:

PS >GetProcess | GetPropertyValue Name audiodg avgamsvr avgemc avgrssvc avgrssvc avgupsvc (...)

Lists, Arrays, and Hashtables

Most scripts deal with more than one thing—lists of servers, lists of files, lookup codes, and more. To enable this, PowerShell supports many features to help you through both its language features and utility cmdlets.

PowerShell makes working with arrays and lists much like working with other data types: you can easily create an array or list and then add or remove elements from it. You can just as easily sort it, search it, or combine it with another array. When you want to store a mapping between one piece of data and another, a hashtable solves that need perfectly.