Saturday, June 18, 2011

Blog Post: Top Ten Favorite PowerShell Tricks: Part 1

Create a Record of PowerShell Commands and Output, Find Hidden Objects, and Expand Properties

Summary: Microsoft Scripting Guy, Ed Wilson, shares four of his top ten favorite Windows PowerShell tricks in this first of three blogs.

Weekend Scripter

Microsoft Scripting Guy, Ed Wilson, is here. Without a doubt, I have the perfect job—at least for me. I get to play around with Windows PowerShell all day, and I get to do it every day. In addition, I get to talk to people from all over the world who are as excited about using Windows PowerShell as I am. Whenever two or more Windows PowerShell devotees get together, it is not very long before one of them drags out a laptop and begins to share something they have figured out using Windows PowerShell. It never fails. On Friday evening, following the last session of SQL Rally in Orlando, I sent a text message to the Scripting Wife to join me in the lobby of our hotel so we could go do dinner. The conversation went something like this:

“Hello, Scripting Wife. Would you like to meet me in the lobby so we can go get dinner?” I asked.

“Where have you been?” she asked.

“I went to Mark’s session on data mining,” I replied.

“Then what?” she queried.

“Well, I was talking to Mark after the session,” I said.

“Then what?”

“Then nothing. I was talking to Mark.”

“Oh. OK. Just wondering.”

“I was answering a couple of questions he had about Windows PowerShell.”

“I see. OK. I will see you in a few minutes.”

When I looked at my watch, I saw what had made her curious—it was 7:30 at night, and the session had been over for two hours. Woops! Mark had a question about environmental variables, and that led to me showing him one of my favorite Windows PowerShell tricks.

Trick #1: Use the transcript

When I am exploring Windows PowerShell, the first thing I do is create a transcript. The Start-Transcript cmdlet will create a transcript file that contains every command you type and the output associated with that command. The transcript is a text file that is stored in your user profile location. The file name is based on the current date and time that the transcript was created. To stop the transcript, use the Stop-Transcript cmdlet, or simply close the Windows PowerShell console.

Why do I like the transcript? Well, if I am exploring, I am simply trying out different commands to see if I can find something useful. I do not know what I might find. By having a transcript, I have a complete record of everything I did. If I did find something useful, I have built in documentation for the commands. This facilitates training and learning. In addition, it is useful as a record of changes that I may have made to a system. The transcript shows the commands that are run and the results of those commands. A sample of transcript output is shown in the following image. Notice the header portion that gives user, computer, OS version, and time created information.

Image of transcript

It might be interesting to compare the output from the transcript log file with the commands typed in the Windows PowerShell console. As shown in the following image, the command and output correspond directly.

Image of command output

Trick #2: Look for “hidden” objects

What do I mean by “hidden” objects? Well, perhaps I could have called them “embedded” objects. Let me explain, many Windows PowerShell cmdlets return objects that contain other objects. Some of these objects are rather obvious; others are not. For example, on my laptop I use Get-Process to look for processes that begin with the letters wu and are followed by zero or more letters. The command and output are shown here.

PS C:\> Get-Process -Name wu*

 

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

-------  ------    -----      ----- -----   ------     -- -----------

    213      11     1852       6236    60            1268 WUDFHost

    211       9     1824       5640    37            1360 WUDFHost

 

PS C:\>

To hone in on one of those processes, I use the process ID and pipe the results to the Format-List cmdlet. This command and output are shown here.

PS C:\> Get-Process -id 1360 | fl * -Force

 

__NounName                 : Process

Name                       : WUDFHost

Handles                    : 211

VM                         : 39145472

WS                         : 5775360

PM                         : 1867776

NPM                        : 9496

Path                       :

Company                    :

CPU                        :

FileVersion                :

ProductVersion             :

Description                :

Product                    :

Id                         : 1360

PriorityClass              :

HandleCount                : 211

WorkingSet                 : 5775360

PagedMemorySize            : 1867776

PrivateMemorySize          : 1867776

VirtualMemorySize          : 39145472

TotalProcessorTime         :

BasePriority               : 8

ExitCode                   :

HasExited                  :

ExitTime                   :

Handle                     :

MachineName                : .

MainWindowHandle           : 0

MainWindowTitle            :

MainModule                 :

MaxWorkingSet              :

MinWorkingSet              :

Modules                    :

NonpagedSystemMemorySize   : 9496

NonpagedSystemMemorySize64 : 9496

PagedMemorySize64          : 1867776

PagedSystemMemorySize      : 70936

PagedSystemMemorySize64    : 70936

PeakPagedMemorySize        : 1961984

PeakPagedMemorySize64      : 1961984

PeakWorkingSet             : 5812224

PeakWorkingSet64           : 5812224

PeakVirtualMemorySize      : 40194048

PeakVirtualMemorySize64    : 40194048

PriorityBoostEnabled       :

PrivateMemorySize64        : 1867776

PrivilegedProcessorTime    :

ProcessName                : WUDFHost

ProcessorAffinity          :

Responding                 : True

SessionId                  : 0

StartInfo                  : System.Diagnostics.ProcessStartInfo

StartTime                  :

SynchronizingObject        :

Threads                    : {1364, 1368, 1372, 1376...}

UserProcessorTime          :

VirtualMemorySize64        : 39145472

EnableRaisingEvents        : False

StandardInput              :

StandardOutput             :

StandardError              :

WorkingSet64               : 5775360

Site                       :

Container                  :

 

PS C:\>

In the previous output, the StartInfo property returns an object. The object is an instance of the ProcessStartInfo object. The applicable line from the output is shown here.

StartInfo                  : System.Diagnostics.ProcessStartInfo

To access this object, all one needs to do is to use “dotted notation,” which means I put parentheses around the command, and directly access the property. When I do this, the ProcessStartInfo object will be revealed. I illustrate this technique here.

PS C:\> (Get-Process -id 1360).StartInfo

PS C:\> (Get-Process -id 1360).StartInfo

 

Verb                    :

Arguments               :

CreateNoWindow          : False

EnvironmentVariables    : {temp, processor_revision, processor_level, logonserver...}

RedirectStandardInput   : False

RedirectStandardOutput  : False

RedirectStandardError   : False

StandardErrorEncoding   :

StandardOutputEncoding  :

UseShellExecute         : True

Verbs                   : {}

UserName                :

Password                :

Domain                  :

LoadUserProfile         : False

FileName                :

WorkingDirectory        :

ErrorDialog             : False

ErrorDialogParentHandle : 0

WindowStyle             : Normal

Trick #3: Use Select ExpandProperty

When examining objects in Windows PowerShell, some embedded objects are obvious—like the one in Trick #2 that I just discussed. Other objects are not so obvious. In the previous example, the StartInfo property returns a ProcessStartInfo object. In the output that follows, the EnvironmentVariables property appears truncated.

EnvironmentVariables    : {temp, processor_revision, processor_level, logonserver...}

This information appears to be impossible to retrieve. A few common attempts for seeing all of the EnvironmentVariables information are shown here.

PS C:\> (Get-Process -id 1360).StartInfo | fl environmentVariables

 

EnvironmentVariables : {temp, processor_revision, processor_level, logonserver...}

 

PS C:\> (Get-Process -id 1360).StartInfo | ft environmentVariables

 

EnvironmentVariables

--------------------

{temp, processor_revision, processor_level, logonserver...}

 

PS C:\> (Get-Process -id 1360).StartInfo | ft environmentVariables -Force

 

EnvironmentVariables

--------------------

{temp, processor_revision, processor_level, logonserver...}

 

PS C:\>

Unfortunately, it seems that nothing can return all of this information—that is until I use the Select-Object cmdlet with the ExpandProperty parameter. In the example that follows, I use the Select alias for the Select-Object cmdlet. This results in the command that is shown here.

(Get-Process -id 1360).StartInfo | select -ExpandProperty environmentvariables

As shown in the figure that follows, this command opens an entire page of additional information.

Image of command output

Trick #4 Group and dot

Earlier, I needed to hone in on the StartInfo property of my process. I could have stored the process object in a variable, and then used a dotted notation to reference the StartInfo property. This technique is shown here.

$a = Get-Process -id 1360

$a.StartInfo

But often that technique is not required. If a property returns a single item, I can use a pair of parentheses to group my command, and then use the dotted notation to return my desired property directly. The parentheses tell Windows PowerShell to process the command inside the parentheses first, then return the object, and then return the information from my property. This is illustrated here.

(Get-Process -id 1360).Startinfo

If I want to, I can continue to add additional dots. Because the StartInfo property returns an object, there are additional members exposed via the returned object. If the property is a single item, I can add additional dots to return the additional properties. In general, I do not use this technique because I think it begins to get confusing. However, when exploring in an interactive fashion inside the Windows PowerShell console, I will play around with double-dotted notation, and at times even with triple-dotted notation. The following is an example of using this technique to explore a specific property from the StartInfo object of a process object.

PS C:\> (Get-Process -id 1360).Startinfo.loaduserprofile

False

Join me tomorrow for part 2 of my Top Ten Favorite PowerShell Tricks.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

YAHOO YAHOO XILINX WESTERN DIGITAL VOLT INFORMATION SCIENCES

No comments:

Post a Comment