在 PowerShell 中查找文件是否为符号链接

问题描述 投票:0回答:10

我有一个正在遍历目录树的 PowerShell 脚本,有时我有硬链接到那里的辅助文件,这些文件不应被处理。有没有一种简单的方法可以找出文件(即

System.IO.FileInfo
)是否是硬链接?

如果没有,使用符号链接(symlinks)会更容易吗?

powershell symlink hardlink
10个回答
50
投票

试试这个:

function Test-ReparsePoint([string]$path) {
  $file = Get-Item $path -Force -ea SilentlyContinue
  return [bool]($file.Attributes -band [IO.FileAttributes]::ReparsePoint)
}

这是一个非常小的实现,但它应该可以解决问题。 请注意,这不区分硬链接和符号链接。 在下面,它们都只是利用NTFS重解析点IIRC


49
投票

如果您有 Powershell 5+,以下一行递归地列出所有文件硬链接、目录连接和符号链接及其从

d:\Temp\
开始的目标:

dir 'd:\Temp' -recurse -force | ?{$_.LinkType} | select FullName,LinkType,Target

输出:

FullName                                LinkType     Target
--------                                --------     ------
D:\Temp\MyJunctionDir                   Junction     {D:\exp\junction_target_dir}
D:\Temp\MySymLinkDir                    SymbolicLink {D:\exp\symlink_target_dir}
D:\Temp\MyHardLinkFile.txt              HardLink     {D:\temp\MyHardLinkFile2.txt, D:\exp\hlink_target.xml}
D:\Temp\MyHardLinkFile2.txt             HardLink     {D:\temp\MyHardLinkFile.txt, D:\exp\hlink_target.xml}
D:\Temp\MySymLinkFile.txt               SymbolicLink {D:\exp\symlink_target.xml}
D:\Temp\MySymLinkDir\MySymLinkFile2.txt SymbolicLink {D:\temp\normal file.txt}

如果您关心硬链接的多个目标,请使用此变体,其中列出了以制表符分隔的目标:

dir 'd:\Temp' -recurse -force | ?{$_.LinkType} | select FullName,LinkType,@{ Name = "Targets"; Expression={$_.Target -join "`t"} }

您可能需要管理员权限才能在

C:\
上运行此脚本。


21
投票

利用

Where-Object
搜索 ReparsePoint 文件属性。

Get-ChildItem | Where-Object { $_.Attributes -match "ReparsePoint" }

17
投票

对于那些想要检查资源是否是硬链接或符号链接的人:

(Get-Item ".\some_resource").LinkType -eq "HardLink"

(Get-Item ".\some_resource").LinkType -eq "SymbolicLink"

3
投票

只想添加我自己的两分钱,这是一个单行函数,对我来说效果非常好:

Function Test-Symlink($Path){
    ((Get-Item $Path).Attributes.ToString() -match "ReparsePoint")
}

2
投票

我在 Vista 上的结果,使用 Keith Hill 的 powershell 脚本测试符号链接和硬链接:

c:\markus\other>mklink symlink.doc \temp\2006rsltns.doc
symbolic link created for symlink.doc <<===>> \temp\2006rsltns.doc

c:\markus\other>fsutil hardlink create HARDLINK.doc  \temp\2006rsltns.doc
Hardlink created for c:\markus\other\HARDLINK.doc <<===>> c:\temp\2006rsltns.doc

c:\markus\other>dir
 Volume in drive C has no label.
 Volume Serial Number is C8BC-2EBD

 Directory of c:\markus\other

02/12/2010  05:21 PM    <DIR>          .
02/12/2010  05:21 PM    <DIR>          ..
01/10/2006  06:12 PM            25,088 HARDLINK.doc
02/12/2010  05:21 PM    <SYMLINK>      symlink.doc [\temp\2006rsltns.doc]
               2 File(s)         25,088 bytes
               2 Dir(s)   6,805,803,008 bytes free

c:\markus\other>powershell \script\IsSymLink.ps1 HARDLINK.doc
False

c:\\markus\other>powershell \script\IsSymLink.ps1 symlink.doc
True

它表明符号链接是重分析点,并且设置了 ReparsePoint FileAttribute 位,而硬链接则没有。


2
投票

这是一个检查一个文件的单行代码

$FilePath
并返回它是否是符号链接,适用于文件和目录

if((Get-ItemProperty $FilePath).LinkType){"symboliclink"}else{"normal path"}

1
投票

以下 PowerShell 脚本将使用 -recurse 开关列出一个或多个目录中的所有文件。它将列出文件的名称(无论是常规文件还是硬链接文件)以及大小,以冒号分隔。

它必须从 PowerShell 命令行运行。从脚本中设置的哪个目录运行它并不重要。

它使用 Windows 附带的 fslink 实用程序,并使用硬链接和列表开关对每个文件运行该实用程序,并计算输出行数。如果两个或更多,则为硬链接文件。

您当然可以通过更改命令中的

c:\windows\system
来更改搜索开始的目录。此外,该脚本只是将结果写入文件,
c:\hardlinks.txt
。您可以更改名称或简单地删除从 > 字符开始的所有内容,它将输出到屏幕上。

Get-ChildItem -path C:\Windows\system -file -recurse -force | 
    foreach-object {
        if ((fsutil hardlink list $_.fullname).count -ge 2) {
            $_.PSChildname + ":Hardlinked:" + $_.Length
        } else {
            $_.PSChildname + ":RegularFile:" + $_.Length
        }
    } > c:\hardlinks.txt

0
投票

我遇到了 .Target 为空(在 OneDrive 文件上)的问题,我想区分 SYMLINKD 和 SYMLINK,所以我想出了这个变体(不处理 HardLink)。我的目标是捕捉那里的东西,以便我可以在其他地方重新创建它们。注意 ? = Where-Object 和 % = Foreach-Object。

### ReparsePoint + Directory + Junction = mklink /j 
### ReparsePoint + Directory + SymbolicLink = mklink /d 
### ReparsePoint + SymbolicLink = mklink 

"cd $( $pwd.Path )"; Get-ChildItem | ? { $_.Attributes -match 'ReparsePoint' -and $_.Target -ne $null } | % {
    $linktype = $_.LinkType
    $target = Resolve-Path -Path $_.Target
    if ($_.Attributes -match 'Directory') {
        if ($linktype -eq "Junction") {
            "mklink /j `"$($_.Name)`" `"$target`""
        } else {
            "mklink /d `"$($_.Name)`" `"$target`""
        }
    } else {
        "mklink `"$($_.Name)`" `"$target`""
    }
}

0
投票

我的两点建议是:对

Get-ChildItem
的语义进行建模。

function Get-BrokenLinks {
     Get-ChildItem -Force -Recurse |
         Where-Object {
             $_.Attributes -match "ReparsePoint"
         } |
         Where-Object {
             if ($_.LinkTarget.Length -eq 0) {
                 $false
             }
             elseif ([System.IO.Path]::IsPathRooted($_.LinkTarget)) {
                 !(Test-Path $_.LinkTarget)
             }
             else {
                 !(Test-Path (Join-Path $_.PSParentPath $_.LinkTarget))
             }
         }
 }
© www.soinside.com 2019 - 2024. All rights reserved.