Skip to main content

Windows

Program: Create Instances of Generic Objects .NET Framework

When you work with the .NET Framework, you’ll often run across classes that have the primary responsibility of managing other objects. For example, the System. Collections.ArrayList class lets you manage a dynamic list of objects. You can add objects to an ArrayList, remove objects from it, sort the objects inside, and more. These objects can be any type of object—String objects, integers, DateTime objects, and many more. However, working with classes that support arbitrary objects can sometimes be a little awkward. One example is type safety: if you accidentally add a String to a list of integers, you might not find out until your program fails.

Although the issue becomes largely moot when working only inside PowerShell, a more common complaint in strongly typed languages (such as C#) is that you have to remind the environment (through explicit casts) about the type of your object when you work with it again:

// This is C# code

System.Collections.ArrayList list =

new System.Collections.ArrayList();

list.Add("Hello World");

string result = (String) list[0];

To address these problems, the .NET Framework introduced a feature called generic types: classes that support arbitrary types of objects, but allow you to specify which type of object. In this case, a collection of strings:

// This is C# code System.Collections.ObjectModel.Collection list = new System.Collections.ObjectModel.Collection(); list.Add("Hello World");

string result = list[0]; Although the NewObject cmdlet is powerful, it doesn’t yet handle creating generic types very elegantly. For a simple generic type, you can use the syntax that the .NET Framework uses under the hood:

$coll = NewObject 'System.Collections.ObjectModel.Collection`1[System.String]'

However, that begins to fall apart if you want to use types defined outside the main mscorlib assembly, or want to create complex generic types (for example, ones that refer to other generic types).

Example 33. NewGenericObject.ps1

############################################################################## ## ## NewGenericObject.ps1 ## ## Creates an object of a generic type: ## ## Usage:

##

##
# Simple generic collection

##
NewGenericObject System.Collections.ObjectModel.Collection System.Int32

##

##
# Generic dictionary with two types

##
NewGenericObject System.Collections.Generic.Dictionary `

##
System.String,System.Int32

##

##
# Generic list as the second type to a generic dictionary

##
$secondType = NewGenericObject System.Collections.Generic.List Int32

##
NewGenericObject System.Collections.Dictionary `

##
System.String,$secondType.GetType()

##

##
# Generic type with a nondefault constructor

##
NewGenericObject System.Collections.Generic.LinkedListNode `

##
System.String "Hi"

##

##############################################################################

Collect Detailed Traces of a Script or Command

Problem

You want to access detailed debugging or diagnostic information for the execution of a script or command.

Solution

To trace a script as it executes, use the Trace parameter of the SetPsDebug cmdlet.

To view detailed trace output for the PowerShell engine and its cmdlets, use the TraceCommand cmdlet.

Discussion

The SetPsDebug cmdlet lets you configure the amount of debugging detail that PowerShell provides during the execution of a script. By setting the Trace parameter, PowerShell lets you see the lines of script as PowerShell executes them.

When you want to investigate issues in the way that your code interacts with PowerShell, or with PowerShell commands, use the TraceCommand cmdlet. The TraceCommand cmdlet provides a huge amount of detail, intended mainly for indepth problem analysis.

For example, to gain some insight into why PowerShell can’t seem to find your script:

TraceCommand CommandDiscovery PsHost { ScriptInTheCurrentDirectory.ps1 }

The TraceCommand cmdlet takes a trace source (for example, CommandDiscovery), a destination (usually –PsHost or –File), and a script block to trace. The output of this command shows that PowerShell never actually searches the current directory for your script, so you need to be explicit: .\ScriptInTheCurrentDirectory.ps1.

For more information about the TraceCommand cmdlet, type GetHelp TraceCommand. To learn what trace sources are available, see the command GetTraceSource.

List All Event Logs

Problem

You want to determine which event logs exist on a system.

Solution

To list event logs on a system, use the –List parameter of the GetEventLog cmdlet: PS >GetEventLog List

Max(K) Retain OverflowAction Entries Name

512 0 OverwriteAsNeeded 2,157 ADAM (Test)

512 7 OverwriteOlder 2,090 Application

512 7 OverwriteOlder 0 Internet Explorer

8,192 45 OverwriteOlder 0 Media Center

512 7 OverwriteOlder 0 ScriptEvents

512 7 OverwriteOlder 2,368 System

15,360 0 OverwriteAsNeeded 0 Windows PowerShell

Discussion

The –List parameter of the GetEventLog cmdlet generates a list of the event logs registered on the system. Like the output of nearly all PowerShell commands, these event logs are fully featured .NET objects—in this case, objects of the .NET System. Diagnostics.EventLog type. For information on how to use these objects to write entries to an event log.

Although the heading of the GetEventLog output shows a table heading called Name, the actual property you need to use in WhereObject (and similar commands) is Log.

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

Manage the Error Output of Windows PowerShell Commands

Problem

You want to display detailed information about errors that come from commands.

Solution

To list all errors (up to $MaximumErrorCount) that have occurred in this session, access the $error array:

$error

To list the last error that occurred in this session, access the first element in the $error array:

$error[0]

To list detailed information about an error, pipe the error into the FormatList cmdlet with the Force parameter:

$currentError = $error[0]

$currentError | FormatList Force

To list detailed information about the command that caused an error, access its InvocationInfo property:

$currentError = $error[0]

$currentError.InvocationInfo To display errors in a more succinct categorybased view, change the $errorView variable to "CategoryView":

$errorView = "CategoryView" To clear the list of errors collected by PowerShell so far, call the Clear( ) method on the $error variable:

$error.Clear( )

Discussion

Errors are a simple fact of life in the administrative world. Not all errors mean disaster, though. Because of this, PowerShell separates errors into two categories: nonterminating and terminating.

Nonterminating errors are the most common type of error. They indicate that the cmdlet, script, function, or pipeline encountered an error that it was able to recover from or was able to continue past. An example of a nonterminating error comes from the CopyItem cmdlet. If it fails to copy a file from one location to another, it can still proceed with the rest of the files specified.

Aterminating error, on the other hand, indicates a deeper, more fundamental error in the operation. An example of this can again come from the CopyItem cmdlet when you specify invalid commandline parameters.

For more information on how to handle both nonterminating and terminating errors, see Chapter 13, Tracing and Error Management.

Sort a Hashtable by Key or Value in Windows PowerShell

Problem

You have a hashtable of keys and values, and want to get the list of values that result from sorting the keys in order.

Solution

To sort a hashtable, use the GetEnumerator() method on the hashtable to gain access to its individual elements. Then use the SortObject cmdlet to sort by Name or Value.

foreach($item in $myHashtable.GetEnumerator() | Sort Name)

{

$item.Value

}

Discussion

Since the primary focus of a hashtable is to simply map keys to values, you should not depend on it to retain any ordering whatsoever—such as the order you added the items, the sorted order of the keys, or the sorted order of the values.

This becomes clear in Example 113.

Example 113. A demonstration of hashtable items not retaining their order

PS >$myHashtable = @{} PS >$myHashtable["Hello"] = 3 PS >$myHashtable["Ali"] = 2 PS >$myHashtable["Alien"] = 4 PS >$myHashtable["Duck"] = 1 PS >$myHashtable["Hectic"] = 11

PS >$myHashtable

Name
Value

Hectic
11

Duck
1

Alien
4

Hello
3

Ali
2

However, the hashtable object supports a GetEnumerator() method that lets you deal with the individual hashtable entries—all of which have a Name and Value property. Once you have those, we can sort by them as easily as we can sort any other PowerShell data. Example 114 demonstrates this technique.

Example 114. Sorting a hashtable by name and value

PS >$myHashtable.GetEnumerator() | Sort Name

Name Value

Ali 2 Alien 4 Duck 1 Hectic 11 Hello 3

PS >$myHashtable.GetEnumerator() | Sort Value

Name Value

Duck 1 Ali 2 Hello 3 Alien 4 Hectic 11

Remove a Registry Key

Problem

You want to remove a registry key and all its properties.

Solution

To remove a registry key, use the RemoveItem cmdlet: PS >dir

Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\ Microsoft\Windows\CurrentVersion\Run

SKC VC Name Property

0 0 Spyware {}

PS >RemoveItem Spyware

Discussion

The registry provider lets you remove items and containers with the RemoveItem cmdlet. The RemoveItem cmdlet has the standard aliases rm, rmdir, del, erase, and rd.

As always, use caution when changing information in the registry. Deleting or changing the wrong item can easily render your system unbootable.

As in the filesystem, the RemoveItem cmdlet lets you specify multiple files through its Path, Include, Exclude, and Filter parameters.

For more information about the RemoveItem cmdlet, type GetHelp RemoveItem. For more information about the registry provider, type GetHelp Registry.

Manage Transport Rules

Problem

You want to manage transport rules applied to incoming or outgoing mail.

Solution

To create transport rules on the server, use the NewTransportRule cmdlet, as shown in Example 251.

Example 251. Creating a new transport rule

$from = GetTransportRulePredicate FromScope $from.Scope = "NotInOrganization"

$attachmentSize = GetTransportRulePredicate AttachmentSizeOver $attachmentSize.Size = 0

$action = GetTransportRuleAction ApplyDisclaimer $action.Text = "Warning: Only open attachments you were already expecting."

NewTransportRule Name "Attachment Warning" ` Conditions $from,$attachmentSize Action $action Enabled:$true

Discussion

The NewTransportRule cmdlet adds transport rules on the server. A transport rule is a collection of predicates and actions—conditions and actions that apply to the rule.

In the example given by the solution, we add a rule that warns internal users about the dangers of unexpected attachments received from the outside world. For more information about the NewTransportRule cmdlet, type GetHelp NewTransportRule.

Find a Windows PowerShell Command to Accomplish a Task

Problem

You want to accomplish a task in PowerShell but don’t know the command or cmdlet to accomplish that task.

Solution

Use the GetCommand cmdlet to search for and investigate commands.

To get the summary information about a specific command, specify the command name as an argument:

GetCommand CommandName To get the detailed information about a specific command, pipe the output of GetCommand to the FormatList cmdlet: GetCommand CommandName | FormatList To search for all commands with a name that contains text, surround the text with asterisk characters:

GetCommand *text* To search for all commands that use the Get verb, supply Get to the Verb parameter: GetCommand Verb Get

To search for all commands that act on a service, supply Service to the Noun parameter:

GetCommand Noun Service

Discussion

One of the benefits that PowerShell provides administrators is the consistency of its command names. All PowerShell commands (called cmdlets) follow a regular VerbNoun pattern. For example: GetProcess, GetEventLog, and SetLocation. The verbs come from a relatively small set of standard verbs and describe what action the cmdlet takes. The nouns are spe cific to the cmdlet and describe what the cmdlet acts on.

Knowing this philosophy, you can easily learn to work with groups of cmdlets. If you want to start a service on the local machine, the standard verb for that is Start.A good guess would be to first try StartService (which in this case would be correct), but typing GetCommand Verb Start would also be an effective way to see what things you can start. Going the other way, you can see what actions are supported on services by typing GetCommand Noun Service.

The GetCommand cmdlet is one of the three commands you will use most commonly as you explore Windows PowerShell. The other two commands are GetHelp and GetMember.

There is one important point when it comes to looking for a PowerShell command to accomplish a task. Many times, that PowerShell command does not exist, because the task is best accomplished the same way it always was—shutdown.exe to reboot a machine, netstat.exe to list protocol statistics and current TCP/IP network connections, and many more.

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

Place Common Functions in a Library in Windows PowerShell

Problem

You’ve developed a useful set of functions and want to share them between multiple scripts.

Solution

First, place these common function definitions by themselves in a script, with a name that starts with Library. While the Library prefix is not required, it is a useful naming convention. Example 104 demonstrates this approach.

Example 104. A library of temperature functions

## LibraryTemperature.ps1 ## Functions that manipulate and convert temperatures

## Convert Fahrenheit to Celsius function ConvertFahrenheitToCelsius([double] $fahrenheit)

Example 104. A library of temperature functions (continued)

{ $celsius = $fahrenheit 32 $celsius = $celsius / 1.8 $celsius

}

Next, dotsource that library from any scripts that need to use those functions, as shown by Example 105.

Example 105. A script that uses a library

param([double] $fahrenheit)

$scriptDirectory = SplitPath $myInvocation.MyCommand.Path . (JoinPath $scriptDirectory LibraryTemperature.ps1)

$celsius = ConvertFahrenheitToCelsius $fahrenheit

## Output the answer "$fahrenheit degrees Fahrenheit is $celsius degrees Celsius."

Discussion

Although mostly used for libraries, you can dotsource any script or function. When you dotsource a script or function, PowerShell acts as though the calling script itself had included the commands from that script or function.

Monitor a File for Changes

Problem

You want to monitor the end of a file for new content.

Solution

To monitor the end of a file for new content, use the –Wait parameter of the GetContent cmdlet.

GetContent log.txt Wait

Discussion

The –Wait parameter on the GetContent cmdlet acts much like the traditional Unix tail command with the –follow parameter. If you provide the –Wait parameter, the GetContent cmdlet reads the content of the file but doesn’t exit. When a program appends new content to the end of the file, the GetContent cmdlet returns that content and continues to wait.

Unlike the Unix tail command, the GetContent cmdlet does not support a feature to let you start reading from the end of a file. If you need to monitor the end of an extremely large file, a specialized file moni

toring utility is a valid option.

For more information about the GetContent cmdlet, type GetHelp GetContent. For more information about the –Wait parameter, type GetHelp FileSystem.