Scott Hanselman

Making Junctions/ReparsePoints visible in PowerShell

May 12, 2006 Comment on this post [1] Posted in PowerShell | XML
Sponsored By

CmdjunctionI'm not sure if this the right way to do this, and I'm sure someone more clever will speak up but...I use a lot of junctions/reparsepoints in my development here, and I was used to seeing them called out when I typed "dir" from cmd.exe.

(Notice in the screenshot from cmd.exe that the "foo" directory is actually marked <junction>)

In PowerShell when you type Dir, you're getting an Array of System.IO.FileInfo/System.IO.DirectoryInfo objects that are displayed using some default formatting. That default Formatting is a combination of two things, a Type definition and a View definition.

First, there's no "Mode" property on a DirectoryInfo, so how is one being shown? In PowerShell you can "tack on" new properties with Script. This isn't derivation, as it's type extension. Adding to functionality, type-wide (within the context of PowerShell) for any .NET type. So, in C:\program files\Windows PowerShell\v1.0\ there's a file called types.ps1xml that has this little bit of info:

  <Type>
        <Name>System.IO.DirectoryInfo</Name>
        <Members>
            <ScriptProperty>
                <Name>Mode</Name>
                <GetScriptBlock>
                     here's where the magic happens...
                </GetScriptBlock>
            </ScriptProperty>
        </Members>
    </Type>

So, I created a personal My.Types.Ps1.xml file in my PSConfiguration folder that looked like this, where 1024 is the value of the [int]([System.IO.FileAttributes]::ReparsePoint) enum and "-band" is "bitwise and."

<Types>
   <Type>
        <Name>System.IO.DirectoryInfo</Name>
        <Members>
            <ScriptProperty>
                <Name>ExtMode</Name>
                <GetScriptBlock>
                    $catr = "";
                    if ( $this.Attributes -band 1024 ) { $catr += "j" } else { $catr += "-" };
                    if ( $this.Attributes -band 16 ) { $catr += "d" } else { $catr += "z" };
                    if ( $this.Attributes -band 32 ) { $catr += "a" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 1 )  { $catr += "r" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 2 )  { $catr += "h" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 4 )  { $catr += "s" } else { $catr += "-" } ;
                    $catr
                </GetScriptBlock>
            </ScriptProperty>
        </Members>
    </Type>
    <Type>
        <Name>System.IO.FileInfo</Name>
        <Members>
            <ScriptProperty>
                <Name>ExtMode</Name>
                <GetScriptBlock>
                    # Added the extra "-" to make sure things line up when FileInfos and DirectoryInfos are listed together
                    $catr = "-"; 
                    if ( $this.Attributes -band 16 ) { $catr += "d" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 32 ) { $catr += "a" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 1 )  { $catr += "r" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 2 )  { $catr += "h" } else { $catr += "-" } ;
                    if ( $this.Attributes -band 4 )  { $catr += "s" } else { $catr += "-" } ;
                    $catr
                </GetScriptBlock>
            </ScriptProperty>
          </Members>
     </Type>
</Types>

Then in my Microsoft.PowerShell_profile.ps1 (the file that gets executed every time I start a PowerShell) I added:

$profileTypes = $profile | split-path | join-path -childPath "My.Types.ps1xml"
Update-TypeData $profileTypes

Now, I'm not sure how to get dir (alias get-childitem) to use MY ExtMode rather than its own, but I think I'd need to override the default View Definition. It's a little tricky with these scoped XML files, because I originally named my new property "Mode" and was chastised for my efforts:

Microsoft.PowerShell, C:\Documents and Settings\shanselm\My Documents\PSConfigu
ration\My.Types.ps1xml(39) : Error in type "System.IO.FileInfo": Member "Mode"
is already present.

So, I named it "ExtMode." We shall see if there's a better way, until then, this function worked.

function edir
{
 dir | select ExtMode, LastWriteTime, Length, Name
}

and got me this output. Notice the "j" now in the ExtMode column.

Psedir

If I can't override dir's default view, I probably could also have removed the alias for "dir" and replaced it with my own:

if (test-path alias:\dir) { remove-item -force alias:\dir }
set-alias dir edir

but edir is fine for me now.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
May 13, 2006 6:02
That's smart, Scott. Nice idea. You should also post this as a feature request to the MS Connect site so that we can keep it as a feature idea for the next version.

To answer your specific problem, use the -prependpath option to Update-FormatData. You might find this post (part 3 of a 3-part series) helpful: http://www.leeholmes.com/blog/DESCRIPTIONSupportInMonadPart3.aspx
Lee

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.