Skip to main content

Windows

Access Features of the Host’s User Interface

Problem

You want to interact with features in the user interface of the hosting application, but PowerShell doesn’t directly provide cmdlets for them.

Solution

To access features of the host’s user interface, use the $host.UI.RawUI variable: $host.UI.RawUI.WindowTitle = (GetLocation)

Discussion

PowerShell itself consists of two main components. The first is an engine that interprets commands, executes pipelines, and performs other similar actions. The second is the hosting application—the way that users interact with the PowerShell engine.

The default shell, PowerShell.exe, is a user interface based on the traditional Windows console. Other applications exist that host PowerShell in a graphical user interface. In fact, PowerShell makes it relatively simple for developers to build their own hosting applications, or even to embed the PowerShell engine features into their own application.

You (and your scripts) can always depend on the functionality available through the $host.UI variable, as that functionality remains the same for all hosts. Example 127 shows the features available to you in all hosts.

Example 127. Functionality available through the $host.UI property

PS >$host.UI | GetMember | Select Name,MemberType | FormatTable Auto

Name
MemberType

(...)

Prompt
Method

PromptForChoice
Method

PromptForCredential
Method

ReadLine
Method

ReadLineAsSecureString Method Write Method WriteDebugLine Method WriteErrorLine Method WriteLine Method WriteProgress Method WriteVerboseLine Method WriteWarningLine Method RawUI Property

If you (or your scripts) want to interact with portions of the user interface specific to the current host, PowerShell provides that access through the $host.UI.RawUI variable. Example 128 shows the features available to you in the PowerShell console host.

Example 128. Functionality available through the default console host

PS >$host.UI.RawUI | GetMember | >> Select Name,MemberType | FormatTable Auto >>

Name MemberType

(...) FlushInputBuffer Method GetBufferContents Method

Example 128. Functionality available through the default console host (continued)

GetHashCode
Method

GetType
Method

LengthInBufferCells
Method

NewBufferCellArray
Method

ReadKey
Method

ScrollBufferContents
Method

SetBufferContents
Method

BackgroundColor
Property

BufferSize
Property

CursorPosition
Property

CursorSize
Property

ForegroundColor
Property

KeyAvailable
Property

MaxPhysicalWindowSize
Property

MaxWindowSize
Property

WindowPosition
Property

WindowSize
Property

WindowTitle
Property

If you rely on the hostspecific features from $host.UI.RawUI, be aware that your script will require modifications (perhaps major) before it will run properly on other hosts.

Program: Set Properties of Remote Registry Keys

Discussion

Although PowerShell does not directly let you access and manipulate the registry of a remote computer, it still supports this by working with the .NET Framework. The functionality exposed by the .NET Framework is a bit more developeroriented than we want, so we can instead use a script to make it easier to work with.

Example 188 lets you set the value of a property on a given remote registry key. In order for this script to succeed, the target computer must have the remote registry service enabled and running.

Example 188. SetRemoteRegistryKeyProperty.ps1

############################################################################## ## ## SetRemoteRegistryKeyProperty.ps1 ## ## Set the value of a remote registry key property ## ## ie: ## ## PS >$registryPath = ## "HKLM:\software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" ## PS >SetRemoteRegistryKeyProperty LEEDESK $registryPath ` ## "ExecutionPolicy" "RemoteSigned" ## ##############################################################################

param( $computer = $(throw "Please specify a computer name."), $path = $(throw "Please specify a registry path"), $property = $(throw "Please specify a property name"), $propertyValue = $(throw "Please specify a property value") )

## Validate and extract out the registry key if($path match "^HKLM:\\(.*)") {

$baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey

("LocalMachine", $computer) } elseif($path match "^HKCU:\\(.*)") {

$baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey ("CurrentUser", $computer) }

Example 188. SetRemoteRegistryKeyProperty.ps1 (continued)

else { WriteError ("Please specify a fullyqualified registry path " + "(i.e.: HKLM:\Software) of the registry key to open.") return }

## Open the key and set its value $key = $baseKey.OpenSubKey($matches[1], $true) $key.SetValue($property, $propertyValue)

## Close the key and base keys $key.Close() $baseKey.Close()

Program: Learn Aliases for Common Windows Shell Commands

In interactive use, full cmdlet names (such as GetChildItem) are cumbersome and slow to type. Although aliases are much more efficient, it takes awhile to discover them. To learn aliases more easily, you can modify your prompt to remind you of the shorter version of any aliased commands that you use.

This involves two steps:

1. Add the program, GetAliasSuggestion.ps1, to your tools directory or other directory.

Example 19. GetAliasSuggestion.ps1

############################################################################## ## ## GetAliasSuggestion.ps1 ## ## Get an alias suggestion from the full text of the last command ## ## ie: ## ## PS > GetAliasSuggestion RemoveItemProperty ## Suggestion: An alias for RemoveItemProperty is rp ## ##############################################################################

param($lastCommand)

$helpMatches = @( )

## Get the alias suggestions foreach($alias in GetAlias) {

if($lastCommand match ("\b" + [System.Text.RegularExpressions.Regex]::Escape($alias.Definition) + "\b")) { $helpMatches += "Suggestion: An alias for $($alias.Definition) is $($alias.Name)" } }

$helpMatches

2. Prompt function in your profile. If you already have a prompt function, you only need to add the content from inside the prompt function of

A useful prompt to teach you aliases for common commands

function Prompt

{ ## Get the last item from the history $historyItem = GetHistory Count 1

## If there were any history items if($historyItem) {

## Get the training suggestion for that item $suggestions = @(GetAliasSuggestion $historyItem.CommandLine)

Example 110. A useful prompt to teach you aliases for common commands (continued)

## If there were any suggestions if($suggestions) {

## For each suggestion, write it to the screen foreach($aliasSuggestion in $suggestions) {

WriteHost "$aliasSuggestion" } WriteHost ""

} }

## Rest of prompt goes here "PS [$env:COMPUTERNAME] >" }

Sort an Array or List of Items

Problem

You want to sort the elements of an array or list.

Solution

To sort a list of items, use the SortObject cmdlet: PS >GetChildItem | SortObject Descending Length | Select Name,Length

Name
Length

ConvertTextObject.ps1
6868

ConnectWebService.ps1
4178

SelectFilteredObject.ps1
3252

GetPageUrls.ps1
2878

GetCharacteristics.ps1
2515

GetAnswer.ps1
1890

NewGenericObject.ps1
1490

InvokeCmdScript.ps1
1313

Discussion

The SortObject cmdlet provides a convenient way for you to sort items by a property that you specify. If you don’t specify a property, the SortObject cmdlet follows the sorting rules of those items if they define any.

In addition to sorting by a property in ascending or descending order, the SortObject cmdlet’s –Unique switch also allows you to remove duplicates from the sorted collection.

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

Program: Create a Filesystem Hard Link

Discussion

It is sometimes useful to refer to the same file by two different names or locations. You can’t solve this problem by copying the item, because modifications to one file do not automatically affect the other.

The solution to this is called a hard link, an item of a new name that points to the data of another file. The Windows operating system supports hard links, but only Windows Vista includes a utility that lets you create them.

Example 176 lets you create hard links without needing to install additional tools. It uses (and requires) the InvokeWindowsApi.ps1 script.

Example 176. NewFilesystemHardLink.ps1

############################################################################## ## ## NewFileSystemHardLink.ps1 ## ## Create a new hard link, which allows you to create a new name by which you ## can access an existing file. Windows only deletes the actual file once ## you delete all hard links that point to it. ## ## ie: ## ## PS >"Hello" > test.txt ## PS >dir test* | select name ## ## Name ## ## test.txt ## ## PS >NewFilesystemHardLink.ps1 test2.txt test.txt ## PS >type test2.txt ## Hello ## PS >dir test* | select name ## ## Name ## ## test.txt ## test2.txt ## ##############################################################################

param( ## The new filename you want to create [string] $filename,

## The existing file that you want the new name to point to [string] $existingFilename )

## Ensure that the provided names are absolute paths

$filename = $executionContext.SessionState.Path.` GetUnresolvedProviderPathFromPSPath($filename)

$existingFilename = ResolvePath $existingFilename

## Prepare the parameter types and parameters for the CreateHardLink function $parameterTypes = [string], [string], [IntPtr] $parameters = [string] $filename, [string] $existingFilename, [IntPtr]::Zero

## Call the CreateHardLink method in the Kernel32 DLL

$currentDirectory = SplitPath $myInvocation.MyCommand.Path

$invokeWindowsApiCommand = JoinPath $currentDirectory InvokeWindowsApi.ps1

$result = & $invokeWindowsApiCommand "kernel32" ` ([bool]) "CreateHardLink" $parameterTypes $parameters

Example 176. NewFilesystemHardLink.ps1 (continued)

## Provide an error message if the call fails if(not $result) {

$message = "Could not create hard link of $filename to " + "existing file $existingFilename" WriteError $message }

List Network Adapter Properties

Problem

You want to retrieve information about network adapters on a computer.

Solution

To retrieve information about network adapters on a computer, use the Win32_ NetworkAdapterConfiguration WMI class:

GetWmiObject Win32_NetworkAdapterConfiguration –Computer > To list only those with IP addresses assigned to them, use the WhereObject cmdlet to filter on the IpEnabled property:

PS >GetWmiObject Win32_NetworkAdapterConfiguration –Computer LEEDESK |

>> WhereObject { $_.IpEnabled }

>>

DHCPEnabled : True

IPAddress : {192.168.1.100}

DefaultIPGateway : {192.168.1.1}

DNSDomain : hsd1.wa.comcast.net.

ServiceName : USB_RNDIS

Description : Linksys WirelessG USB Network Adapter with SpeedBooste

r v2 Packet Scheduler Miniport

Index : 13

Discussion

The solution uses the Win32_NetworkAdapterConfiguration WMI class to retrieve information about network adapters on a given system. By default, PowerShell displays only the most important information about the network adapter but provides access to much more.

To see all information available, use the FormatList cmdlet, as shown in Example 247.

Example 247. Using the FormatList cmdlet to see detailed information about a network adapter

PS >$adapter = GetWmiObject Win32_NetworkAdapterConfiguration | >> WhereObject { $_.IpEnabled } >> PS >$adapter

Example 247. Using the FormatList cmdlet to see detailed information about a network adapter

DHCPEnabled : True IPAddress : {192.168.1.100} DefaultIPGateway : {192.168.1.1}

DNSDomain
: hsd1.wa.comcast.net.

ServiceName
: USB_RNDIS

Description
: Linksys WirelessG USB Network Adapter with SpeedBooste

r v2 Packet Scheduler Miniport

Index : 13

PS >$adapter | FormatList *

DHCPLeaseExpires Index Description

DHCPEnabled DHCPLeaseObtained DHCPServer DNSDomain DNSDomainSuffixSearchOrder DNSEnabledForWINSResolution DNSHostName DNSServerSearchOrder

: 20070521221927.000000420

: 13

: Linksys WirelessG USB Network Adapter with SpeedBooster v2 Packet Scheduler Minipor t

: True

: 20070520221927.000000420

: 192.168.1.1

: hsd1.wa.comcast.net.

:

: False

: LeeDesk

: {68.87.69.146, 68.87.85.98}

DomainDNSRegistrationEnabled : False

FullDNSRegistrationEnabled
: True

IPAddress
: {192.168.1.100}

IPConnectionMetric
: 25

IPEnabled
: True

IPFilterSecurityEnabled
: False

WINSEnableLMHostsLookup
: True

(...)

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

PS >$adapter.MacAddress 00:12:17:77:B4:EB

Download a Web Page from the Internet

Problem

You want to download a web page from the Internet and work with the content as a plain string.

Solution

Use the DownloadString() method from the .NET Framework’s System.Net.WebClient class to download a web page or plain text file into a string.

PS >$source = "http://blogs.msdn.com/powershell/rss.xml" PS > PS >$wc = NewObject System.Net.WebClient PS >$content = $wc.DownloadString($source)

Discussion

Although web services are becoming increasingly popular, they are still far less common than web pages that display useful data. Because of this, retrieving data from services on the Internet often comes by means of screen scraping: downloading the HTML of the web page and then carefully separating out the content you want from the vast majority of the content that you do not.

The technique of screen scraping has been around much longer than the Internet! As long as computer systems have generated output designed primarily for humans, screen scraping tools have risen to

make this output available to other computer programs.

Unfortunately, screen scraping is an errorprone way to extract content. If the web page authors change the underlying HTML, your code will usually stop working correctly. If the site’s HTML is written as valid XHTML, you may be able to use PowerShell’s built in XML support to more easily parse the content.

Despite its fragility, pure screen scraping is often the only alternative. In Example 91, you use this approach to easily fetch Encarta “Instant Answers” from MSN Search. If the script no longer works when you run it, I apologize—although it does demonstrate the perils of screen scraping.

Example 91. GetAnswer.ps1

############################################################################## ## GetAnswer.ps1 ## ## Use Encarta's Instant Answers to answer your question ## ## Example: ## GetAnswer "What is the population of China?" ############################################################################## param([string] $question = $( throw "Please ask a question."))

function Main

{ ## Load the System.Web.HttpUtility DLL, to let us URLEncode [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Web")

## Get the web page into a single string with newlines between ## the lines. $encoded = [System.Web.HttpUtility]::UrlEncode($question) $url = "http://search.live.com/results.aspx?q=$encoded" $text = (newobject System.Net.WebClient).DownloadString($url)

Example 91. GetAnswer.ps1 (continued)

## Get the answer with annotations $startIndex = $text.IndexOf('') $endIndex = $text.IndexOf('function YNC')

## If we found a result, then filter the result if(($startIndex ge 0) and ($endIndex ge 0)) {

$partialText = $text.Substring($startIndex, $endIndex $startIndex)

## Very fragile screen scraping here $pattern = '

Clear or Remove a File from PowerShell

Problem

You want to clear the content of a file, or remove that file altogether.

Solution

To clear the content from a file, use the ClearContent cmdlet. Use the RemoveItem cmdlet to remove that file altogether, as shown by Example 171.

Example 171. Clearing content from and removing a file

PS >GetContent test.txt Hello World PS >ClearContent test.txt PS >GetContent test.txt PS >GetItem test.txt

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

Mode
LastWriteTime
Length Name

a

4/23/2007
8:05 PM
0 test.txt

PS >RemoveItem test.txt PS >GetItem test.txt GetItem : Cannot find path 'C:\temp\test.txt' because it does not exist. At line:1 char:9

+ GetItem test.txt

Discussion

The (aptly named) ClearContent and RemoveItem cmdlets clear the content from an item and remove an item, respectively. Although the solution demonstrates this only for files in the filesystem, they in fact apply to any PowerShell providers that support the concepts of “content” and “items.” Examples of other drives that support these content and item concepts are the Function:, Alias:, and Variable:. The HKLM:, HKCU:, and Env: drives do not support the concept of content, but do let you remove items with the RemoveItem cmdlet.

The RemoveItem cmdlet has a handful of standard aliases: ri, rm, rmdir, del, erase, and rd.

For more information about the RemoveItem or ClearContent cmdlets, type GetHelp RemoveItem or GetHelp ClearContent.

Windows PowerShell Enterprise Computer Management

When working with Windows systems across an enterprise, the question often arises: “How do I do in PowerShell?In an administrator’s perfect world, anybody who designs a feature with management implications also supports (via PowerShell cmdlets) the tasks that manage that feature. Many management tasks have been around longer than PowerShell, though, so the answer can sometimes be,

“The same way you did it before PowerShell.”

That’s not to say that your life as an administrator doesn’t improve with the introduction of PowerShell, however. PrePowerShell administration tasks generally fall into one of several models: commandline utilities, Windows Management Instrumentation (WMI) interaction, registry manipulation, file manipulation, interaction with COM objects, or interaction with .NET objects.

PowerShell makes it easier to interact with all these task models, and therefore makes it easier to manage functionality that depends on them.

Work with Numbers As Binary in Windows PowerShell

Problem

You want to work with the individual bits of a number, or work with a number built by combining a series of flags.

Solution

To directly enter a hexadecimal number, use the 0x prefix:

PS >$hexNumber = 0x1234

PS >$hexNumber

4660 To convert a number to its binary representation, supply a base of 2 to the [Convert]::ToString() method:

PS >[Convert]::ToString(1234, 2)

10011010010 To convert a binary number into its decimal representation, supply a base of 2 to the [Convert]::ToInt32() method:

PS >[Convert]::ToInt32("10011010010", 2)

1234

To manage the individual bits of a number, use PowerShell’s binary operators. In this case, the Archive flag is just one of the many possible attributes that may be true of a given file:

PS >$archive = [System.IO.FileAttributes] "Archive" PS >attrib +a test.txt PS >GetChildItem | Where { $_.Attributes band $archive } | Select Name

Name

test.txt

PS >attrib a test.txt PS >GetChildItem | Where { $_.Attributes band $archive } | Select Name PS >

Discussion

In some system administration tasks, it is common to come across numbers that seem to mean nothing by themselves. The attributes of a file are a perfect example:

PS >(GetItem test.txt).Encrypt() PS >(GetItem test.txt).IsReadOnly = $true PS >[int] (GetItem test.txt force).Attributes 16417 PS >(GetItem test.txt force).IsReadOnly = $false PS >(GetItem test.txt).Decrypt() PS >[int] (GetItem test.txt).Attributes 32

What can the numbers 16417 and 32 possibly tell us about the file?

The answer to this comes from looking at the attributes in another light—as a set of features that can be either True or False. Take, for example, the possible attributes for an item in a directory shown by Example 63.

Example 63. Possible attributes of a file

PS >[Enum]::GetNames([System.IO.FileAttributes]) ReadOnly Hidden System Directory Archive Device Normal Temporary SparseFile ReparsePoint Compressed Offline NotContentIndexed Encrypted

If a file is ReadOnly, Archive, and Encrypted, then you might consider this as a succinct description of the attributes on that file:

ReadOnly = True Archive = True Encrypted = True

It just so happens that computers have an extremely concise way of representing sets of true and false values—a representation known as binary. To represent the attributes of a directory item as binary, you simply put them in a table. We give the item a “1” if the attribute applies to the item and a “0” otherwise (see Table 61).

Table 61. Attributes of a directory item

Attribute
True (1) or False (0)

Encrypted
1

NotContentIndexed
0

Offline
0

Compressed
0

ReparsePoint
0

SparseFile
0

Temporary
0

Normal
0

Device
0

Archive
1

Directory
0


0

System
0

Hidden
0

ReadOnly
1

If we treat those features as the individual binary digits in a number, that gives us the number 100000000100001. If we convert that number to its decimal form, it becomes clear where the number 16417 came from:

PS >[Convert]::ToInt32("100000000100001", 2) 16417

This technique sits at the core of many properties that you can express as a combination of features or flags. Rather than list the features in a table, though, documentation usually describes the number that would result from that feature being the only one active—such as FILE_ATTRIBUTE_REPARSEPOINT = 0x400 . Example 64 shows the various representations of these file attributes.

Example 64. Integer, hexadecimal, and binary representations of possible file attributes

PS >$attributes = [Enum]::GetValues([System.IO.FileAttributes]) PS >$attributes | SelectObject ` >> @{"Name"="Property"; >> "Expression"= { $_ } }, >> @{"Name"="Integer"; >> "Expression"= { [int] $_ } }, >> @{"Name"="Hexadecimal"; >> "Expression"= { [Convert]::ToString([int] $_, 16) } }, >> @{"Name"="Binary"; >> "Expression"= { [Convert]::ToString([int] $_, 2) } } | >> FormatTable auto >>

Example 64. Integer, hexadecimal, and binary representations of possible file attributes (continued)

Property Integer Hexadecimal Binary

ReadOnly
1 1
1

Hidden
2 2
10

System
4 4
100

Directory
16 10
10000

Archive
32 20
100000

Device
64 40
1000000

Normal
128 80
10000000

Temporary
256 100
100000000

SparseFile
512 200
1000000000

ReparsePoint
1024 400
10000000000

Compressed
2048 800
100000000000

Offline
4096 1000
1000000000000

NotContentIndexed
8192 2000
10000000000000

Encrypted
16384 4000
100000000000000

Knowing how that 16417 number was formed, you can now use the properties in meaningful ways. For example, PowerShell’s –band operator allows you to check if a certain bit has been set:

PS >$encrypted = 16384 PS >$attributes = (GetItem test.txt force).Attributes PS >($attributes band $encrypted) –eq $encrypted True PS >$compressed = 2048 PS >($attributes band $compressed) –eq $compressed False PS >

Although the example above uses the numeric values explicitly, it would be more common to enter the number by its name:

PS >$archive = [System.IO.FileAttributes] "Archive" PS >($attributes band $archive) –eq $archive True

Simplify Math with Administrative Constants in Windows PowerShell

Problem

You want to work with common administrative numbers (that is, kilobytes, megabytes, and gigabytes) without having to remember or calculate those numbers.

Solution

Use PowerShell’s administrative constants (KB, MB, and GB) to help work with these common numbers.

Calculate the download time (in seconds) of a 10.18 megabyte file over a connection that gets 215 kilobytes per second:

PS >10.18mb / 215kb 48.4852093023256

Discussion

PowerShell’s administrative constants are based on powers of two, since those are the kind most commonly used when working with computers. Each is 1,024 times bigger than the one before it:

1kb = 1024 1mb = 1024 * 1 kb 1gb = 1024 * 1 mb

Some (such as hard drive manufacturers) prefer to call numbers based on powers of two “kibibytes,” “mebibytes,” and “gibibytes.” They use the terms “kilobytes,” “megabytes,” and “gigabytes” to mean numbers that are 1,000 times bigger than the one before it—numbers based on powers of 10.

Although not represented by administrative constants, PowerShell still makes it easy to work with these numbers in powers of 10—for example, to figure out how big a “300 GB” hard drive is when reported by Windows:

PS >$kilobyte = [Math]::Pow(10,3) PS >$kilobyte 1000 PS >$megabyte = [Math]::Pow(10,6) PS >$megabyte 1000000 PS >$gigabyte = [Math]::Pow(10,9) PS >$gigabyte 1000000000 PS >(300 * $gigabyte) / 1GB 279.396772384644