MSH: Get Extended Properties of a File

If you right click on an image file in Windows explorer and then go to the Summary tab you will see some handy properties listed there like the image’s width, height and bit depth.  Wouldn’t it be handy to be able to access these properties from MSH.  Jim Truher posted the basic code snippet for doing this in MSH on the newsgroup microsoft.public.windows.server.scripting.  I modified it to accept pipeline input.  With this script copied into a file named get-metainfo.msh and placed in your path, you can do cool stuff like the following: search for any picture taken on May 14, 2003.
 
MSH:212 # dir *.jpg *.png | get-metainfo | where {$_.DatePictureTaken} |
where {([DateTime]$_.DatePictureTaken).Date -eq [DateTime]"5/14/2003"}
Path             : C:\Documents and Settings\hillr\My Documents\My Pictures\Eds
                   2003KTM450EXC.JPG
DateCreated      : 4/30/2004 9:12 AM
CameraModel      : GC-X1
DateModified     : 5/14/2003 4:24 PM
Attributes       : A
Type             : JPEG Image
DatePictureTaken : 5/14/2003 5:24 PM
<snip>
 
Note that the first "where" filter filters out objects that either don’t have a DatePictureTaken property or the property is null.  BTW, this is good example of a cmdlet written in MSH that accepts both pipeline input and arguments.  Here’s the script (place in an MSH file named something like get-metainfo.msh):
 
begin {
    $props = @{
        Name = 0;
        Size = 1;
        Type = 2;
        DateModified = 3;
        DateCreated = 4;
        DateAccessed = 5;
        Attributes = 6;
        Status = 7;
        Owner = 8;
        Author = 9;
        Title = 10;
        Subject = 11;
        Category = 12;
        Pages = 13;
        Comments = 14;
        Copyright = 15;
        Artist = 16;
        AlbumTitle = 17;
        Year = 18;
        TrackNumber = 19;
        Genre = 20;
        Duration = 21;
        BitRate = 22;
        Protected = 23;
        CameraModel = 24;
        DatePictureTaken = 25;
        Dimensions = 26;
        Company = 30;
        Description = 31;
        FileVersion = 32;
        ProductName = 33;
        ProductVersion = 34
    }
   
    function add-member {
        param($type, $name, $value, $input)
        $note = "system.management.automation.psnoteproperty"
        $member = new-object $note $name,$value
        $metaInfoObj.psobject.members.add($member)
        return $metaInfoObj
    }
   
    function emitMetaInfoObject($path) {
        [string]$path = (resolve-path $path).path
        [string]$dir  = split-path $path
        [string]$file = split-path $path -leaf
        $shellApp = new-object -com shell.application
        $myFolder = $shellApp.Namespace($dir)
        $fileobj = $myFolder.Items().Item($file)
       
        $metaInfoObj = new-object system.management.automation.psobject
        $metaInfoObj.psobject.typenames[0] = "Custom.IO.File.Metadata"
        $metaInfoObj = add-member noteproperty Path $path -input $metaInfoObj
        foreach ($key in $props.keys) {
            $v = $myFolder.GetDetailsOf($fileobj,$props.$key)
            if ($v) {
                $metaInfoObj = add-member noteproperty $key $v -input $metaInfoObj
            }
        }
        write-output $metaInfoObj
    }
}

process {
    if ($_) {
        emitMetaInfoObject $_
    }
}

end {
    if ($args) {
        $paths
        foreach ($path in $args) {
            if (!(test-path $path)) {
                write-error "$path is not a valid path"
            }
            $paths += resolve-path $path
        }
   
        foreach ($path in $paths) {
            emitMetaInfoObject $path
        }
    }
}

About these ads
This entry was posted in Monad. Bookmark the permalink.

4 Responses to MSH: Get Extended Properties of a File

  1. rick says:

    Keith,
     
    I updated this for PowerShell RC1 as a learning exercise. :)
     
    The thing I really love about this example is the extra effort out into making this CMDLET pipeable using custom.io
     
    .\\get-metainfo | get-members
     
    this is cool !!!
     
     
     
    BTW: I have not fixed the bug where the filename contains [xxxx] – like many W3C file seem to have
     
     
    begin {    $props = @{         Name = 0;         Size = 1;         Type = 2;         DateModified = 3;         DateCreated = 4;        DateAccessed = 5;         Attributes = 6;         Status = 7;         Owner = 8;         Author = 9;        Title = 10;         Subject = 11;         Category = 12;         Pages = 13;         Comments = 14;        Copyright = 15;         Artist = 16;         AlbumTitle = 17;         Year = 18;         TrackNumber = 19;        Genre = 20;         Duration = 21;         BitRate = 22;         Protected = 23;         CameraModel = 24;        DatePictureTaken = 25;         Dimensions = 26;        Company = 30;         Description = 31;         FileVersion = 32;        ProductName = 33;         ProductVersion = 34    }        function add-member {        param($type, $name, $value, $input)        $note = "system.management.automation.psnoteproperty"        $member = new-object $note $name,$value        $metaInfoObj.psobject.members.add($member)        return $metaInfoObj    }        function emitMetaInfoObject($path) {        [string]$path = (resolve-path $path).path        [string]$dir  = split-path $path        [string]$file = split-path $path -leaf        $shellApp = new-object -com shell.application        $myFolder = $shellApp.Namespace($dir)        $fileobj = $myFolder.Items().Item($file)                $metaInfoObj = new-object system.management.automation.psobject        $metaInfoObj.psobject.typenames[0] = "Custom.IO.File.Metadata"        $metaInfoObj = add-member noteproperty Path $path -input $metaInfoObj        foreach ($key in $props.keys) {            $v = $myFolder.GetDetailsOf($fileobj,$props.$key)            if ($v) {                 $metaInfoObj = add-member noteproperty $key $v -input $metaInfoObj             }        }        write-output $metaInfoObj    }}process {    if ($_) {        emitMetaInfoObject $_    }}end {    if ($args) {        $paths        foreach ($path in $args) {            if (!(test-path $path)) {                write-error "$path is not a valid path"            }            $paths += resolve-path $path        }            foreach ($path in $paths) {            emitMetaInfoObject $path        }    }}

  2. Keith says:

    Hey Rick, thanks for the update!  I have updated this entry based on your port.

  3. coleman says:

    Is it possible to do something similar with folders as well as files?  I would like to add data to the "Description" field on some folders, but this functionality is not directly built into XP or Server 03….

  4. Keith says:

    Yeah I think the example could be modified to work on $myFolder (don\’t split the path assuming the path is to a folder).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s