Skip to Content

PowerShell is a great framework for system administrators. It is fairly easy to learn and use, while allowing you to be extremely efficient. #SAPonMS admins can use PowerShell to administrate their systems and improve their daily work flows, just like the developers in our team use it regularly in all kinds of situations. However, as much as I like PowerShell, I have got one issue with it: The way it handles symbolic links .

It is quite common for admins to use symbolic links, but unfortunately the way they are shown in PowerShell is not what I would consider optimal. Let me show you what I mean before I will explain a possible workaround:

Imagine the following scenario: You have a certain file, let’s call it “MyFile.txt” and it is located in

C:\MyDir\MyFile.txt

Then, you want to have a symbolic fink to that file. For simplicity, let’s put it in the same directory:

You can use the PowerShell Command

New-Item -Name C:\MyDir\MySymLinkFile.txt -ItemType SymbolicLink -Value C:\MyDir\MyFile.txt

to create such a link. You could of course also use the “good old” cmd prompt, which offers mklink.exe command.

Now, try to check the folder’s content by using Get-Childitem:

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d---l         7/30/2018   3:03 PM            MySymLinkFile.txt
-a---         7/30/2018   2:23 PM         12 MyFile.txt

You can immediately see what is bothering me: You don’t recognize that you have a symbolic link. Of course, you can look at the item’s length. However, that is no solution because the same issue holds true for symbolic links to folders. Creating a sub directory “SubDir” and a symlink to it, called “SymLinkSubDir”, results in the following folder view:

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d---l         7/30/2018   3:03 PM            MySymLinkFile.txt
d----         7/30/2018   3:14 PM            SubDir
d---l         7/30/2018   3:14 PM            SymLinkSubDir
-a---         7/30/2018   2:23 PM         12 MyFile.txt

To be completely fair, it has to be stated that starting with PowerShell version 5, you can see that you are dealing with a symlink by looking at the “l” in the Mode property. This means, there is a way to tell the difference between the original folder and the symlink. But still, you cannot see the target that the link is pointing to. Pretty annoying, isn’t it?
Assuming you have a more complicated setup and taking into account that you usually don’t name your symlinks “symlink*”, this has huge potential of confusion for other users and your future self.

So, how do we clean up this mess? First, please note that all of this assumes that we are using PowerShell version 5.
The general idea to fix our issue is to customize the format of the Get-ChildItem output and similar commands. PowerShell allows you to change the format view of almost anything. We want to get a clear visual hint if we have a link and we also want to know where it is linking to. The default format files are located in

C:\Windows\System32\WindowsPowerShell\v1.0

You can choose to place a custom format file there by creating a file called

C:\Windows\System32\WindowsPowerShell\v1.0\MyCustom.format.ps1xml

Open it and paste the following code in it:

<?xml version="1.0" encoding="utf-8" ?> 
<!-- *******************************************************************
Taken from sample files used by the Windows PowerShell engine. 
Modified formatting of directory output to include Symlinks and Hardlinks
******************************************************************** -->
<Configuration>
    <SelectionSets>
        <SelectionSet>
            <Name>FileSystemTypes</Name>
            <Types>
                <TypeName>System.IO.DirectoryInfo</TypeName>
                <TypeName>System.IO.FileInfo</TypeName>
            </Types>
        </SelectionSet>
    </SelectionSets>
    
    <!-- ################ VIEW DEFINITIONS ################ -->

    <ViewDefinitions>
       <View>
            <Name>children</Name>
            <ViewSelectedBy>
                <SelectionSetName>FileSystemTypes</SelectionSetName>
            </ViewSelectedBy>
            <GroupBy>
                <PropertyName>PSParentPath</PropertyName> 
                <CustomControlName>FileSystemTypes-GroupingFormat</CustomControlName>  
            </GroupBy>
            <TableControl>
                <TableHeaders>
                   <TableColumnHeader>
                      <Label>Mode</Label>
                      <Width>7</Width>
                      <Alignment>left</Alignment>
                   </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>LastWriteTime</Label>
                        <Width>25</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Length</Label>
                        <Width>14</Width>
                        <Alignment>right</Alignment>
                    </TableColumnHeader>
                    <TableColumnHeader>
						<Label>Name</Label>
					</TableColumnHeader>
                </TableHeaders>
                <TableRowEntries>
                    <TableRowEntry>
                        <Wrap/>
                        <TableColumnItems>
                            <TableColumnItem>
                                <PropertyName>Mode</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <ScriptBlock>
                                    [String]::Format("{0,10}  {1,8}", $_.LastWriteTime.ToString("d"), $_.LastWriteTime.ToString("t"))
                                </ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                           	<PropertyName>Length</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
								<ScriptBlock>
								    If(-not [string]::IsNullOrEmpty($_.Target))
										 {$_.Name + " --> "+ $_.Target + " (" + $_.LinkType + ")"}
									else {$_.Name}
								</ScriptBlock>
                            </TableColumnItem>
                        </TableColumnItems>
                    </TableRowEntry>
                </TableRowEntries>
            </TableControl>
        </View>         
    </ViewDefinitions>
</Configuration>

Save it and go back to your PowerShell. You can load your customized format by calling

Update-FormatData -prependpath C:\Windows\System32\WindowsPowerShell\v1.0\MyCustom.format.ps1xml

If you don’t want to type this again and again, you can put it in your PowerShell profile so that it loads automatically on startup. You can find your profile under

C:\Users\<user>\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

Afterwards, you can look at your folder again:

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        7/30/2018   3:47 PM                SubDir
d----l        7/30/2018   3:48 PM                SymLinkSubDir --> C:\MyDir\SubDir\ (SymbolicLink)
-a----        7/30/2018   3:47 PM             12 Myfile.txt
-a---l        7/30/2018   3:49 PM              0 MySymLinkFile.txt --> C:\MyDir\Myfile.txt (SymbolicLink)

Tadaaaa! That’s it!

We get a clear view on our files and directories, while also getting the information where a link is pointing to. With these few steps, we can potentially save a lot of time the next time we are working on a system, which heavily uses symbolic links.

 

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply