Learn about Windows PowerShell
Summary: In this article, Microsoft Scripting Guy Ed Wilson teaches how to use the Windows PowerShell version of grep to parse the command line.
Hey, Scripting Guy! I have enjoyed reading Sean’s legacy scripting articles, but I am a bit confused. It seems that all these commands return data, and I would love to be able to easily parse the information that the commands return. Can you give me an example of that?
Microsoft Scripting Guy Ed Wilson here. The TechReady conference in Seattle last week was great. We even had a few sun sightings during the week. The day I flew into Seattle was absolutely beautiful, and I was able to see all the mountains stretching up into the sky. The Space Needle was clearly visible. All in all, it was a Seattle Chamber of Commerce type of day.
KG, if you are going to work with legacy commands very often, you will need to become competent at using the Select-String cmdlet. Often, I will look around for an object that will return the same types of information that I might obtain via a legacy command—to avoid the issue of extensive text parsing.
For example, the ipconfig command will return an IP address and a log of other information. But I can use WMI to obtain the IP address as well. The following command returns the IP address on my local computer. Note that gwmi is an alias for the Get-WMIObject cmdlet. I only have one network interface card that is ipenabled, so I can return the ipaddress property directly. Unfortunately, the ipaddress property returns an array with both the IPv4 and IPv6 address in it. I index into the array to return only the IPv4 address:
(gwmi win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress
As you can tell, typing the preceding command is a bit cumbersome when compared to typing ipconfig. However, if I put the above command in a function and I place it in my profile or some module, I can call it as easily as typing Get-IPAddress. Or if I create an alias, I can type gia. The Get-IPAddress function and code to create an alias are shown here:
(Get-WmiObject -class win32_NetworkAdapterConfiguration `
-Filter 'ipenabled = "true"').ipaddress
} #end function Get-Ipaddress
New-Alias -Name GIA -Value Get-IPAddress -Description "HSG alias"
When I run the function to load it into memory, I can then access it by alias if I wish. This is shown in the following figure.
Figuring out how to use the Select-String cmdlet can be a bit confusing. The online help for the cmdlet is rather extensive, and the examples do not seem to cover simple cases. For example, if I want to parse the results of the ipconfig command, I might be tempted to do something like this:
PS C:\> Select-String -Pattern "IPV4" -InputObject ipconfig
Unfortunately, nothing is returned. I try putting parentheses around the command to force evaluation first, and I at least see something returned to the screen. The command is shown here:
Select-String -Pattern "IPV4" -InputObject (ipconfig)
The command and output are shown in the following figure.
As can be seen in the preceding figure, the results are completely jumbled and unreadable. It seems that it might be a lost cause, but if you stick with it and use the pipeline, the output is much more readable. The command that uses the pipeline and the associated output are shown here (in addition, it does not matter if I use the simplematch switched parameter or not):
PS C:\> ipconfig | Select-String -Pattern "IPv4" -SimpleMatch
IPv4 Address. . . . . . . . . . . : 10.0.0.188
PS C:\> ipconfig | Select-String -Pattern "IPv4"
When I try to shorten the command, however, problems arise. I try to use select as an alias for the Select-String cmdlet, and no errors appear, but I am left with a blank screen, as shown in the following figure.
The problem is that select is an alias for the Select-Object cmdlet, and not for the Select-String cmdlet, as shown here:
PS C:\> Get-Alias select
CommandType Name Definition
Alias select Select-Object
Well, what are the aliases for the Select-String cmdlet? According to the output, there isn’t even one:
PS C:\> Get-Alias -Definition select-string
Get-Alias : This command cannot find a matching alias because an alias with definition 'select-string'
does not exist.
At line:1 char:10
+ Get-Alias <<<< -Definition select-string
+ CategoryInfo : ObjectNotFound: (select-string:String) [Get-Alias], ItemNotFoundException
+ FullyQualifiedErrorId : ItemNotFoundException,Microsoft.PowerShell.Commands.GetAliasCommand
Now, I may decide that I would like to create an alias for Select-String. Grep would be a good one to use. The command to accomplish this appears here (you would want to place it in your startup profile; see this collection of Hey, Scripting Guy! posts for information about profiles):
New-Alias -Name grep -Value Select-String -Description "HSG alias"
When I have an alias for Select-String, I can shorten my command quite a bit. The shortened command and associated output are shown here:
PS C:\> ipconfig | grep "IPv4"
KG, this should be enough to get you started playing around with the Select-String cmdlet. Join me again tomorrow, when we will explore some more ways to use this powerful cmdlet.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
Good artcle once again..
(ipconfig) -match 'ipv4'
@JRV Thank you. I am glad you liked the article. Your suggestion is a good one. That is one thing I LOVE about PowerShell is that there are dozens of ways of doing the same thing. I LOVE your alternative solutions ...
Thanks Ed. I am enjoying how far you and Sen have gotten with scavenging all useful thngs from legacy commands and scripts.
Yes. PowerShell has so many ways to do everything.
Do you have any articles on the Script Control?
@jrv I have not written about the Script Control, and I do not believe that Sean has either. It is a great subject for an article, or two. I do have a small article, in the Library that talks about using the Script Control. It is a good suggestion ... Look for something in the next month or so.
(ipconfig | Select-String "IPv4")
@BigTeddy you are right ... on some machines. On my laptop, I get an error about indexing into a match collections ... but the prolbem is that IPV4 only appears ONCE in my output. If I do this: (ipconfig /all | Select-String "dhcp") it works and allows me to index into the collection ...
This seems to work well when you're selecting strings from non-PowerShell commands. But when you are, it's not quite the same.
Consider this. I'm trying to use the Get-WmiObject cmdlet to search Win32_DiskDrive and pluck out only the line that says Caption. I just want to be able to see what drive a machine may have. (Mostly I'm playing around.) What I *want* to do is Get-WmiObject -Class Win32_DiskDrive | grep "Caption". That would give me what I'm looking for. But here I'm trying to do it in PowerShell, so in accordance with your suggestions here, I've tried things like:
Get-WmiObject -Class Win32_DiskDrive | Select-String -Pattern "Caption" -SimpleMatch.
This doesn't work. I get nothing as a response - just another prompt. My guess is that what is being returned is technically not a string at all, but the actual object, so there's really nothing to display. But I don't know how to get what I want.
Is Filter table a solution?
Get-WmiObject -Class Win32_DiskDrive |ft Caption
HITACHI HTS723232A7A364 ATA Device
Ricoh SD Disk Device
Kingston DataTraveler 150 USB Device