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.
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.
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.
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