using powershell select-string creatively…

this came up yesterday.  i thought it was cool enough to blog.  i’m sure this is pretty elementary for most of you.



background

i was trying to find a way to search a list of files for content and pull back some attributes along with the search.  the problem is once you pass objects from get-childitems through select-string, the type changes.

 

looking at the object type

let’s look at the type before we send it through select-string:

PS C:\data\temp> ls | gm -MemberType property

   TypeName: System.IO.FileInfo

Name              MemberType Definition
----              ---------- ----------
Attributes        Property   System.IO.FileAttributes Attributes {get;set;}
CreationTime      Property   System.DateTime CreationTime {get;set;}
CreationTimeUtc   Property   System.DateTime CreationTimeUtc {get;set;}
Directory         Property   System.IO.DirectoryInfo Directory {get;}
DirectoryName     Property   System.String DirectoryName {get;}
Exists            Property   System.Boolean Exists {get;}
Extension         Property   System.String Extension {get;}
FullName          Property   System.String FullName {get;}
IsReadOnly        Property   System.Boolean IsReadOnly {get;set;}
LastAccessTime    Property   System.DateTime LastAccessTime {get;set;}
LastAccessTimeUtc Property   System.DateTime LastAccessTimeUtc {get;set;}
LastWriteTime     Property   System.DateTime LastWriteTime {get;set;}
LastWriteTimeUtc  Property   System.DateTime LastWriteTimeUtc {get;set;}
Length            Property   System.Int64 Length {get;}
Name              Property   System.String Name {get;}

 

now after select-string:

PS C:\data\temp> ls | Select-String marcus | gm -MemberType property

   TypeName: Microsoft.PowerShell.Commands.MatchInfo

Name       MemberType Definition
----       ---------- ----------
Context    Property   Microsoft.PowerShell.Commands.MatchInfoContext Context {get;set;}
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;set;}
Path       Property   System.String Path {get;set;}
Pattern    Property   System.String Pattern {get;set;}

 

retrieving the original attributes

as you can see, after sending it through select-string, it converts the type from FileInfo to MatchInfo.  as long as i only care about the properties i can use from matchinfo, that’s not really a problem.  as noted here:

PS C:\data\temp> ls | Select-String marcus | ft filename, line -auto

Filename        Line
--------        ----
machinelist.txt MARCUS

 

that becomes a problem since the original attributes aren’t maintained.  for example, let’s say i want to pull back the creation time of the file.  this illustrates the problem:

PS C:\data\temp> ls | Select-String marcus | ft filename, line, {$_.creationtime} -auto

Filename        Line   $_.creationtime
--------        ----   ---------------
machinelist.txt MARCUS

 

if we embed a command, we can retrieve the item again and then pull back the property of it.

PS C:\data\temp> ls | Select-String marcus | ft filename, line, {(ls $_.filename).creationtime} -auto

Filename        Line   (ls $_.filename).creationtime
--------        ----   -----------------------------
machinelist.txt MARCUS 4/16/2009 1:45:10 PM

 

shout out

lots of thanks to shay levy and hal rottenberg for their incredibly rich powershell knowledge.


Comments