tl;dr:
There is no documentation for ETS (Extended Type System) members such as .Target
.
c:\windows\System32\atl.dll
is one of two so-called hard links that point to the same file data (the other being C:\Windows\WinSxS\amd64_microsoft-windows-atl_31bf3856ad364e35_10.0.18362.1_none_7d7dafc1d6eadbc7\atl.dll
).
- For hard links,
.Target
reports all the other hard links (paths that point to the same file), which is why the .Target
property values of the two items point to the respective other path.
Your code no longer works in PowerShell [Core], where support for reporting hard links via .Target
was removed - see this GitHub issue.
As Mathias R. Jessen points out, the .Target
property is an ETS (Extended Type System) property - a property added by PowerShell to extend the capabilities of a native .NET type.
There is no documentation for such ETS members (which may also include methods) - your best bet is to study their definition, which isn't guaranteed to give you the full story or only with a nontrivial amount of effort:
In a first step, you can use the Get-TypeData
cmdlet to inspect the definition of the .Target
property (which is added to both System.IO.FileInfo
and System.IO.DirectoryInfo
instances):
# Windows PowerShell
PS> (Get-TypeData System.IO.FileInfo).Members.Target | foreach GetCodeReference
Name : GetTarget
DeclaringType : Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods
[...]
MemberType : Method
ReturnType : System.Collections.Generic.IEnumerable`1[System.String]
[...]
(Get-Item $PROFILE | Get-Member Target
can also be used, but lacks important information in this case: the .Target
property is of type CodeProperty
, i.e. a property whose value is determined by a call to a static method of a .NET type, but the output's .Definition
property shows the method only as Target{get=GetTarget;}
; that is, the full type name is missing).
That is, a call to [Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods]::GetTarget()
with the System.IO.DirectoryInfo
instance at hand is used to return that instance's .Target
property value.
In Windows PowerShell, this is the end of the line, given that its source code isn't publicly available.
In PowerShell [Core] 6+, you can examine the source code in the GitHub repository, notably in file FileSystemProvider.cs
(this link is a permalink, which will become outdated over time; click on the Branch:
dropdown list at the top of the page to switch to the current master
branch).
The partially inferred behavior of .Target
is discussed next.
.Target
's purpose and behavior:
The .Target
property returns a file-system reparse point's (Windows) / symlink's (symbolic link's; Unix) target path(s).[1]
If the input path isn't a reparse point or symlink, .Target
returns "nothing": specifically, [System.Management.Automation.Internal.AutomationNull]::Value
(Windows PowerShell; behaves like $null
in most contexts) / $null
(PowerShell [Core]).
There's an important difference in the behavior of .Target
between Windows PowerShell and PowerShell [Core] 6+ (as of PowerShell 7.0):
In Windows PowerShell, .Target
returns an enumeration of target paths, meaning that multiple paths may be returned, which only applies if the input path is one of several hard links to the same file (data).
Specifically, a hard link's .Target
property reports all other hard links that exist to that file (i.e., not including the input path).
This explains why, given a file with two hard links, their .Target
properties point to the respective other path, as is the case with the file pointed to by hard link C:\Windows\System32\atl.dll
, for instance.
In PowerShell [Core], .Target
only every returns a single path, because support for hard links was removed - see this GitHub issue.
- As an aside: Unlike Windows, Unix-like platforms have no system-level support for enumerating hard links, so finding all hard links to a given file is both cumbersome and slow.
[1] Apart from hard links, Unix-like platforms have only symbolic links, whereas on Windows the category of reparse points comprises not only symbolic links, but also junctions, volume mount points, and, in recent Windows versions, AppX reparse points (app execution aliases for Microsoft Store applications).