Currently, the behavior with respect to following symlinks to directories with Get-ChildItem -Recurse:
differs between editions
is _invariable_ in either case.
_Windows_ PowerShell _always_ follows directory symlinks, whereas PowerShell _Core_ _never_ does - due to #3780.
Note that the Core behavior also applies on Windows.
Given that Get-ChildItem is not just the analog of ls, but also of find, there should at least be a way to _opt in_ with respect to symlink following, as with find -L.
Note that reintroducing symlink recursion would reintroduce the need to detect symlink _loops_, as reported in #1875.
Unless infeasible due to backward compatibility concerns, it's also worth considering changing the Windows edition's default behavior to match the Core edition's.
Note: On _Windows_, you must run the code from an _elevated_ console.
# Create 2 temp. dirs.
$tmpDirRoot = [IO.Path]::GetTempPath()
$tmpDir1 = join-path $tmpDirRoot "$PID-a"
$tmpDir2 = join-path $tmpDirRoot "$PID-b"
$null = New-Item -Type Directory -Path $tmpDir1, $tmpDir2
Push-Location $tmpDir1
# Create 1 file each.
'' > "$tmpDir1/f1"
'' > "$tmpDir2/f2"
# In tmpDir1, create a symlink to tmpDir2
$null = New-Item -Type SymbolicLink dirlink -Value $tmpDir2
# Recurse and count the items.
# If the directory symlink is followed, 3 items are reported, otherwise 2.
$count = (Get-ChildItem -Recurse).Count
[pscustomobject] @{ 'Actual count' = $count; 'Count w/ following' = 3; 'Count w/o following' = 2 }
# Comment out the following 2 lines to prevent cleanup.
Pop-Location
Remove-Item -Force -Recurse $tmpDir1, $tmpDir2
Windows PowerShell:
Actual count Count w/ following Count w/o following
------------ ------------------ -------------------
3 3 2
PowerShell Core:
Actual count Count w/ following Count w/o following
------------ ------------------ -------------------
2 3 2
PowerShell Core v6.0.0-beta (v6.0.0-beta.2) on macOS 10.12.5
PowerShell Core v6.0.0-beta (v6.0.0-beta.2) on Ubuntu 16.04.1 LTS
PowerShell Core v6.0.0-beta (v6.0.0-beta.2) on Microsoft Windows 10 Pro (64-bit; v10.0.14393)
Windows PowerShell v5.1.14393.1198 on Microsoft Windows 10 Pro (64-bit; v10.0.14393)
symlinks aren't used heavily on Windows, but I know they are on Linux
@SteveL-MSFT: Certainly now, but with the ability to create symlinks even without elevation - see #2845 - this will hopefully change over time.
(For existing cross-platform software, the difficulties of creating symlinks on Windows are a pain point.)
Therefore, given the _current_ rarity of symlinks on Windows, it sounds like changing the current Windows behavior to align with Unix (don't follow by default, need to opt in) may be an option.
@SteveL-MSFT Can I assume that opting in will require a new parameter? A switch parameter, or a boolean, or something else?
Also, what is the expected behavior when following symlinks recursively? Does the cmdlet need to be able to detect a recursive symlink loop?
Yes, a new parameter is needed. Pending feedback from @joeyaiello and @HemantMahawar, I would suggest -FollowSymLinks switch (maybe alias to -L to keep it similar to unix tools: ls and find). We should detect loops (perhaps cache directories already visited?) and output a warning similar to what ls -L -R does on Linux
@SteveL-MSFT OK, I'll start with that.
For loop detection I was planning on caching volume IDs and inodes, and their Windows counterparts.
/cc @HemantMahawar I think that -FollowSymlink follows all the rules (no plural, "Symlink" is one word)
Most helpful comment
@SteveL-MSFT OK, I'll start with that.
For loop detection I was planning on caching volume IDs and inodes, and their Windows counterparts.