Skip to main content

Windows

Get the Properties of a Group in Windows PowerShell

Problem

You want to get and list the properties of a specific security or distribution group.

Solution

To list the properties of a group, use the [adsi] type shortcut to bind to the group in Active Directory, and then pass the group to the FormatList cmdlet: $group = [adsi] "LDAP://localhost:389/cn=Management,ou=West,ou=Sales,dc=Fabrikam,dc=COM"

$group | FormatList *

Discussion

The solution retrieves the Management group from the Sales West OU. By default, the FormatList cmdlet shows only the DN of the group, so we type FormatList * to display all properties.

If you know the property for which you want the value, specify it by name:

PS >$group.Member CN=SmithRobin,OU=West,OU=Sales,DC=Fabrikam,DC=COM CN=MyerKen,OU=West,OU=Sales,DC=Fabrikam,DC=COM

Unlike groups, some types of Active Directory objects don’t allow you to retrieve their properties by name this way. Instead, you must call the Get() method to retrieve specific properties:

PS >$group.Get("name") Management

Search for a Security or Distribution Group in PowerShell

Problem

You want to search for a specific group, but don’t know its DN.

Solution

To search for a security or distribution group, use the [adsi] type shortcut to bind to a container that holds the group in Active Directory, and then use the System. DirectoryServices.DirectorySearcher class from the .NET Framework to search for the group:

$domain = [adsi] "LDAP://localhost:389/dc=Fabrikam,dc=COM" $searcher = NewObject System.DirectoryServices.DirectorySearcher $domain $searcher.Filter = '(&(objectClass=Group)(name=Management))'

$groupResult = $searcher.FindOne() $group = $groupResult.GetDirectoryEntry()

Discussion

When you don’t know the full DN of a group, the System.DirectoryServices. DirectorySearcher class from the .NET Framework lets you search for it.

You provide an LDAP filter (in this case, searching for groups with the name of Management), and then call the FindOne() method. The FindOne() method returns the first search result that matches the filter, so we retrieve its actual Active Directory entry. Although the solution searches on the group’s name, you can search on any field in Active Directory—the mailNickname and sAMAccountName are two other good choices.

When you do this search, always try to restrict it to the lowest level of the domain possible. If we know that the Management group is in the Sales OU, it would be better to bind to that OU instead:

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

For more information about the LDAP search filter syntax, search http://msdn. microsoft.com for “Search Filter Syntax.”

Place Formatted Information in a String in Windows PowerShell

Problem

You want to place formatted information (such as rightaligned text or numbers rounded to a specific number of decimal places) in a string.

Solution

Use PowerShell’s formatting operator to place formatted information inside a string.

PS >$formatString = "{0,8:D4} {1:C}`n" PS >$report = "Quantity Price`n" PS >$report += "`n" PS >$report += $formatString f 50,2.5677 PS >$report += $formatString f 3,9 PS >$report Quantity Price

0050 $2.57 0003 $9.00

Discussion

PowerShell’s string formatting operator (f) uses the same string formatting rules as the String.Format() method in the .NET Framework. It takes a format string on its left side, and the items you want to format on its right side.

In the solution, you format two numbers: a quantity and a price. The first number ({0}) represents the quantity and is rightaligned in a box of 8 characters (,8). It is formatted as a decimal number with 4 digits (:D4). The second number ({1}) represents the price, which you format as currency (:C).

For a detailed explanation of PowerShell’s formatting operator, see “Simple Opera tors”, PowerShell Language and Environment.

Although primarily used to control the layout of information, the stringformatting operator is also a readable replacement for what is normally accomplished with string concatenation:

PS >$number1 = 10 PS >$number2 = 32 PS >"$number2 divided by $number1 is " + $number2 / $number1 32 divided by 10 is 3.2

The string formatting operator makes this much easier to read:

PS >"{0} divided by {1} is {2}" f $number2, $number1, ($number2 / $number1) 32 divided by 10 is 3.2

In addition to the string formatting operator, PowerShell provides three formatting commands (FormatTable, FormatWide, and FormatList) that lets you to easily gen erate formatted reports.

Access Windows Management Instrumentation Data

Problem

You want to work with data and functionality provided by the WMI facilities in Windows.

Solution

To retrieve all instances of a WMI class, use the GetWmiObject cmdlet:

GetWmiObject ComputerName Computer Class Win32_Bios To retrieve specific instances of a WMI class, using a WMI filter, supply an argument to the –Filter parameter of the GetWmiObject cmdlet:

GetWmiObject Win32_Service Filter "StartMode = 'Auto'"

To retrieve instances of a WMI class using WMI’s WQL language, use the [WmiSearcher] type shortcut:

$query = [WmiSearcher] "SELECT * FROM Win32_Service WHERE StartMode = 'Auto'"

$query.Get() To retrieve a specific instance of a WMI class using a WMI filter, use the [Wmi] type shortcut:

[Wmi] 'Win32_Service.Name="winmgmt"'

To retrieve a property of a WMI instance, access that property as you would access a .NET property:

$service = [Wmi] 'Win32_Service.Name="winmgmt"' $service.StartMode

To invoke a method on a WMI instance, invoke that method as you would invoke a .NET method:

$service = [Wmi] 'Win32_Service.Name="winmgmt"' $service.ChangeStartMode("Manual") $service.ChangeStartMode("Automatic")

To invoke a method on a WMI class, use the [WmiClass] type shortcut to access that WMI class. Then, invoke that method as you would invoke a .NET method:

$class = [WmiClass] "Win32_Process" $class.Create("Notepad")

Discussion

Working with WMI has long been a staple of managing Windows systems—especially systems that are part of corporate domains or enterprises. WMI supports a huge amount of Windows management tasks, albeit not in a very userfriendly way.

Traditionally, administrators required either VBScript or the WMIC commandline tool to access and manage these systems through WMI. While powerful and useful, these techniques still provided plenty of opportunities for improvement. VBScript lacks support for an ad hoc investigative approach, and WMIC fails to provide (or take advantage of) knowledge that applies to anything outside WMIC.

In comparison, PowerShell lets you work with WMI just like you work with the rest of the shell. WMI instances provide methods and properties, and you work with them the same way you work with methods and properties of other objects in PowerShell.

Not only does PowerShell make working with WMI instances and classes easy once you have them, but it also provides a clean way to access them in the first place. For most tasks, you need only to use the simple [Wmi], [WmiClass],or [WmiSearcher] syntax as shown in the solution.

Along with WMI’s huge scope, though, comes a related problem: finding the WMI class that accomplishes your task.

Some advanced WMI tasks require that you enable your security privileges or adjust the packet privacy settings used in your request. The syntax given by the solution does not directly support these tasks, but PowerShell still supports these options by providing access to the underlying objects that represent your WMI query.

When you want to access a specific WMI instance with the [Wmi] accelerator, you might at first struggle to determine what properties WMI lets you search on. These properties are called key properties on the class.

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

Work with .NET Objects

Problem

You want to use and interact with one of the features that make PowerShell so powerful—its intrinsic support for .NET objects.

Solution

PowerShell offers ways to access methods (both static and instance) and properties.

To call a static method on a class, place the type name in square brackets, and then separate the class name from the method name with two colons:

[ClassName]::MethodName(parameter list)

To call a method on an object, place a dot between the variable that represents that object and the method name:

$objectReference.MethodName(parameter list)

To access a static property on a class, place the type name in square brackets, and then separate the class name from the property name with two colons:

[ClassName]::PropertyName

To access a property on an object, place a dot between the variable that represents that object and the property name:

$objectReference.PropertyName

Discussion

One feature that gives PowerShell its incredible reach into both system administration and application development is its capability to leverage Microsoft’s enormous and broad .NET Framework. The .NET Framework is a large collection of classes. Each class embodies a specific concept and groups closely related functionality and information. Working with the .NET Framework is one aspect of PowerShell that introduces a revolution to the world of management shells.

An example of a class from the .NET Framework is System.Diagnostics.Process— the grouping of functionality that “provides access to local and remote processes, and enables you to start and stop local system processes.”

The terms type and class are often used interchangeably.

Classes contain methods (which allow you to perform operations) and properties (which allow you to access information).

For example, the GetProcess cmdlet generates System.Diagnostics.Process objects, not a plaintext report like traditional shells. Managing these processes becomes incredibly easy, as they contain a rich mix of information (properties) and operations (methods). You no longer have to parse a stream of text for the ID of a process—you can just ask the object directly!

PS >$process = GetProcess Notepad PS >$process.Id 3872

Static methods

[ClassName]::MethodName(parameter list)

Some methods apply only to the concept the class represents. For example, retrieving all running processes on a system relates to the general concept of processes, instead of a specific process. Methods that apply to the class/type as a whole are called static methods.

For example:

PS >[System.Diagnostics.Process]::GetProcessById(0) This specific task is better handled by the GetProcess cmdlet, but it demonstrates PowerShell’s capability to call methods on .NET classes. It calls the static GetProcessById method on the System.Diagnostics.Process class to get the process with the ID of 0. This generates the following output:

Handles
NPM(K)
PM(K)
WS(K) VM(M)
CPU(s)
Id ProcessName

0
0
0
16
0

0 Idle

Instance methods

$objectReference.MethodName(parameter list)

Some methods relate only to specific, tangible realizations (called instances) of a class. An example of this would be stopping a process actually running on the system, as opposed to the general concept of processes. If $objectReference refers to a specific System.Diagnostics.Process (as output by the GetProcess cmdlet, for example), you may call methods to start it, stop it, or wait for it to exit. Methods that act on instances of a class are called instance methods.

The term object is often used interchangeably with the term instance.

For example:

PS >$process = GetProcess Notepad

PS >$process.WaitForExit() Stores the process with an ID of 0 into the $process variable. It then calls the WaitForExit() instance method on that specific process to pause PowerShell until the process exits.

To learn about the different sets of parameters (overloads) that a given method supports, type that method name without any parameters:

PS >$now = GetDate

PS >$now.AddDays

MemberType : Method OverloadDefinitions : {System.DateTime AddDays(Double value)}

TypeNameOfValue
: System.Management.Automation.PSMethod

Value
: System.DateTime AddDays(Double value)

Name
: AddDays

IsInstance
: True

Static properties

[ClassName]::PropertyName

or

[ClassName]::PropertyName = value

Like static methods, some properties relate only to information about the concept that the class represents. For example, the System.DateTime class “represents an instant in time, typically expressed as a date and time of day.It provides a Now static property that returns the current time:

PS >[System.DateTime]::Now

Saturday, June 2, 2007 4:57:20 PM This specific task is better handled by the GetDate cmdlet, but it demonstrates PowerShell’s capability to access properties on .NET objects.

Although relatively rare, some types allow you to set the value of some static properties as well: for example, the [System.Environment]::CurrentDirectory property. This property represents the process’s current directory—which represents PowerShell’s startup directory, as opposed to the path you see in your prompt.

Instance properties

$objectReference.PropertyName

or

$objectReference.PropertyName = value

Like instance methods, some properties relate only to specific, tangible realizations (called instances) of a class. An example of this would be the day of an actual instant in time, as opposed to the general concept of dates and times. If $objectReference refers to a specific System.DateTime (as output by the GetDate cmdlet or [System. DateTime]::Now, for example), you may want to retrieve its day of week, day, or month. Properties that return information about instances of a class are called instance properties.

For example:

PS >$today = GetDate PS >$today.DayOfWeek Saturday

This example stores the current date in the $today variable. It then calls the DayOfWeek instance property to retrieve the day of the week for that specific date.

With this knowledge, the next questions are: “How do I learn about the functionality available in the .NET Framework?” and “How do I learn what an object does?”

Output Warnings, Errors, and Terminating Errors in PowerShell

Problem

You want your script to notify its caller of a warning, error, or terminating error.

############################################################################## ## ## GetWarningsAndErrors.ps1 ## ## Demonstrates the functionality of the WriteWarning, WriteError, and throw ## statements ## ##############################################################################

WriteWarning "Warning: About to generate an error" WriteError "Error: You are running this script" throw "Could not complete operation."

Solution

To write warnings and errors, use the WriteWarning and WriteError cmdlets, respectively. Use the throw statement to generate a terminating error.

Discussion

When you need to notify the caller of your script about an unusual condition, the WriteWarning, WriteError, and throw statements are the way to do it. If your user should consider the message as more of a warning, use the WriteWarning cmdlet. If your script encounters an error (but can reasonably continue past that error), use the WriteError cmdlet. If the error is fatal and your script simply cannot continue, use a throw statement.

Verify Integrity of File Sets

Problem

You want to determine whether any files have been modified or damaged in a set of files.

Solution

To verify the integrity of file sets, use the GetFileHash script provided “Program: Get the MD5 or SHA1 Hash of a File” to generate the signatures of those files in question. Do the same for the files on a known good system. Finally, use the CompareObject cmdlet to compare those two sets.

Discussion

To generate the information from the files in question, use a command like:

dir C:\Windows\System32\WindowsPowerShell\v1.0 | GetFileHash | ExportCliXml c:\temp\PowerShellHashes.clixml

This command gets the hash values of the files from C:\Windows\System32\ WindowsPowerShell\v1.0, and uses the ExportCliXml cmdlet to store that data in a file.

Transport this file to a system with files in a known good state, and then import the data from that file.

$otherHashes = ImportCliXml c:\temp\PowerShellHashes.clixml

You can also map a network drive to the files in question and skip the export, transport, and import steps altogether:

net use x: \\leedesk\c$\Windows\System32\WindowsPowerShell\

v1.0

$otherHashes = dir x: | GetFileHash

Generate the information from the files you know are in a good state:

$knownHashes = dir C:\Windows\System32\WindowsPowerShell\v1.0 | GetFileHash Finally, use the CompareObject cmdlet to detect any differences: CompareObject $otherHashes $knownHashes Property Path,HashValue

If there are any differences, the CompareObject cmdlet displays them in a list, as shown in Example 191.

Example 191. The CompareObject cmdlet showing differences between two files

PS >CompareObject $otherHashes $knownHashes Property Path,HashValue

Path HashValue SideIndicator

Example 191. The CompareObject cmdlet showing differences between two files (continued)

system.management.aut... 247F291CCDA8E669FF9FA... => system.management.aut... 5A68BC5819E29B8E3648F... =

PS >CompareObject $otherHashes $knownHashes Property Path,HashValue | >> SelectObject Path >>

Path

system.management.automation.dllhelp.xml system.management.automation.dllhelp.xml

For more information about the CompareObject cmdlet, type GetHelp CompareObject. For more information about the ExportCliXml and ImportCliXml cmdlets, type GetHelp ExportCliXml and GetHelp ImportCliXml, respectively.

Display the Properties of an Item As a List in Windows PowerShell

Problem

You have an item (for example, an error record, directory item, or .NET object), and you want to display detailed information about that object in a list format.

Solution

To display detailed information about an item, pass that item to the FormatList cmdlet. For example, to display an error in list format, type the commands:

$currentError = $error[0] $currentError | FormatList Force

Discussion

The FormatList cmdlet is one of the three PowerShell formatting cmdlets. These cmdlets include FormatTable, FormatList, and FormatWide. The FormatList cmdlet takes input and displays information about that input as a list. By default, PowerShell takes the list of properties to display from the *.format.ps1xml files in PowerShell’s installation directory. To display all properties of the item, type FormatList *. Sometimes, you might type FormatList * but still not get a list of the item’s properties. This happens when the item is defined in the *.format.ps1xml files, but does not define anything to be displayed for the list command. In that case, type

FormatList Force.

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

Find Items in an Array Greater or Less Than a Value

Problem

You have an array and want to find all elements greater or less than a given item or value.

Solution

To find all elements greater or less than a given value, use the –gt, ge, lt, and –le comparison operators:

PS >$array = "Item 1","Item 2","Item 3","Item 1","Item 12" PS >$array ge "Item 3" Item 3 PS >$array lt "Item 3" Item 1 Item 2 Item 1 Item 12

Discussion

The gt, ge, lt, and le operators are useful ways to find elements in a collection that are greater or less than a given value. Like all other PowerShell comparison operators, these use the comparison rules of the items in the collection. Since the array in the solution is an array of strings, this result can easily surprise you:

PS >$array lt "Item 2" Item 1 Item 1 Item 12

The reason for this becomes clear when you look at the sorted array—"Item 12" comes before "Item 2" alphabetically, which is the way that PowerShell compares arrays of strings.

PS >$array | SortObject Item 1 Item 1 Item 12 Item 2 Item 3

Use the ArrayList Class for Advanced Array Tasks

Problem

You have an array that you want to frequently add elements to, remove elements from, search, and modify.

Solution

To work with an array frequently after you define it, use the System.Collections. ArrayList class:

PS >$myArray = NewObject System.Collections.ArrayList PS >[void] $myArray.Add("Hello") PS >[void] $myArray.AddRange( ("World","How","Are","You") ) PS >$myArray Hello World How Are You PS >$myArray.RemoveAt(1) PS >$myArray Hello How Are You

Discussion

Like most other languages, arrays in PowerShell stay the same length once you create them. PowerShell allows you to add items, remove items, and search for items in an array, but these operations may be time consuming when you are dealing with large amounts of data. For example, to combine two arrays, PowerShell creates a new array large enough to hold the contents of both arrays and then copies both arrays into the destination array.

In comparison, the ArrayList class is designed to let you easily add, remove, and search for items in a collection.

PowerShell passes along any data that your script generates, unless you capture it or cast it to [void]. Since it is designed primarily to be used from programming languages, the System.Collections.ArrayList

class produces output, even though you may not expect it to. To prevent it from sending data to the output pipeline, either capture the data or cast it to [void]:

PS >$collection = NewObject System.Collections.ArrayList PS >$collection.Add("Hello") 0 PS >[void] $collection.Add("World")

If you plan to add and remove data to and from an array frequently, the System. Collections.ArrayList class provides a more dynamic alternative.