Summary: Learn how to use Windows PowerShell to search a folder for matching strings and to open them automatically in Notepad.
Hey, Scripting Guy! I have been enjoying using the Select-String cmdlet, but I have a question. When I use Select-String, it lists the file that it finds the match in, but I have to copy and paste from there in order to open it in Notepad. I know that opening a file in Notepad is not very “PowerShell-like” but I still need the ability to quickly find and modify things in Notepad. Can you help me automate this process a bit?
—BL
Hello BL,
Microsoft Scripting Guy Ed Wilson here. One of the things I love about Windows PowerShell is the discoverability aspect of the language. For example, it is seemingly impossible to have a comprehensive document on Windows PowerShell. There is just so much that can be accomplished and are so many different ways of using Windows PowerShell that by the time a complete reference guide was produced, several new versions of Windows PowerShell would have been released. Besides, if a complete reference guide were ever written, no one would have time to read it anyway.
To counterbalance this seeming deficit, Windows PowerShell has very good discoverability. One of the primary tools for anyone who wants to get beyond simply running cmdlets with documented switches and parameters is the Get-Member cmdlet.
Note This is the fifth article in a series of five articles that talk about using the Select-String cmdlet. On Monday, I talked about using the Select-String cmdlet to parse the data returned from an ipconfig command to return only the IP address. On Tuesday, I discussed using the Select-String cmdlet to parse data returned from WMI. Wednesday found me talking about parsing the firewall log, and yesterday I talked about parsing a collection of files in a folder to look for pattern matches in files.
For example, if I pipe the results from a Select-String command, I can see that the command returns a MatchInfo object. This command and output are shown here:
PS C:\fso> dir c:\fso -I *.txt, *.log -R | Select-String fail | gm
TypeName: Microsoft.PowerShell.Commands.MatchInfo
Name MemberType Definition
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
RelativePath Method string RelativePath(string directory)
ToString Method string ToString(), string ToString(string directory)
Context Property Microsoft.PowerShell.Commands.MatchInfoContext Conte...
Filename Property System.String Filename {get;}
IgnoreCase Property System.Boolean IgnoreCase {get;set;}
Line Property System.String Line {get;set;}
LineNumber Property System.Int32 LineNumber {get;set;}
Matches Property System.Text.RegularExpressions.Match[] Matches {get;...
Path Property System.String Path {get;set;}
Pattern Property System.String Pattern {get;set;}
BL, from the preceding output, there are two properties that are of use to help solve your exact scenario. The first property that seems promising is the filename property, and the second property worth investigating is the path property. I will look at both of them by displaying them via the Format-Table cmdlet. Both the command and the associated output are shown here:
PS C:\fso> dir c:\fso -I *.txt, *.log -R | Select-String fail | ft path, filename
Path Filename
C:\fso\BackupLog.txt BackupLog.txt
C:\fso\BackupLog.txt BackupLog.txt
C:\fso\Install.log Install.log
C:\fso\Install.log Install.log
C:\fso\Install.log Install.log
C:\fso\Install.log Install.log
C:\fso\Install.log Install.log
C:\fso\Install.log Install.log
BL, it seems I may be on the right track; however, one problem is that from the preceding output, I see multiple matches for each file. If I were to simply choose the path property (and I must choose the path property because it includes both the file and the folder that contains the file) and open the file in Notepad, I would have multiple instances of Notepad displaying multiple copies of the same file.
To work around the problem of multiple matches, I use the list switch from the Select-String cmdlet. The revised command and associated output are shown here:
PS C:\fso> dir c:\fso -I *.txt, *.log -R | Select-String fail -list | ft path, filename
Path Filename
C:\fso\BackupLog.txt BackupLog.txt
C:\fso\Install.log Install.log
Cool! Now, all I need to do is to walk through the collection of files that appear and open them in Notepad. I can do this by using the ForEach-Object cmdlet as shown here (the % character is an alias for the ForEach-Object cmdlet and dir is an alias for the Get-ChildItem cmdlet):
dir c:\fso -I *.txt, *.log -R | Select-String fail -list | % { notepad $_.path }
The command and associated output are shown in the following figure.
BL, that is all there is to using the Select-String cmdlet to parse text files in a folder, and open the files that contain matches. This also ends Select-String Week. Join me tomorrow as I talk to various community members about starting and running a Windows PowerShell user group. I have two articles this weekend about working with Windows PowerShell user groups—both are important.
I invite you to follow me on Twitter and to join the Scripting Guys group on 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