【问题标题】:Find out whether a file is a symbolic link in PowerShell找出文件是否是 PowerShell 中的符号链接
【发布时间】:2022-04-01 02:36:33
【问题描述】:

我有一个正在遍历目录树的 PowerShell 脚本,有时我在那里有硬链接的辅助文件,这些文件不应该被处理。有没有一种简单的方法可以确定文件(即System.IO.FileInfo)是否为硬链接?

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

【问题讨论】:

  • 在 Windows 上处理符号链接、硬链接、联结等时,必须安装 Link Shell Extension schinagl.priv.at/nt/hardlinkshellext/hardlinkshellext.html
  • @kamikater:这与这个问题有什么关系吗?该外壳扩展是否使脚本更容易确定这一点?
  • LSE 只是让用户更容易查看和理解符号链接等,因为 Windows 资源管理器缺少这些。我的建议更笼统的意思是你想看看你正在处理和调试什么,因此只是一个评论。

标签: powershell symlink hardlink


【解决方案1】:

试试这个:

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

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

【讨论】:

  • 硬链接只是 MFT 中的附加文件条目,因此显示为普通文件,除非有人查看指向该文件的链接数。但到目前为止我还没有尝试过符号链接。实际上,它具有 ReparsePoint 属性集。谢谢。 (即使符号链接处理起来更麻烦,因为我没有默认创建它们的权限:/)
  • 我认为硬链接和符号链接使用相同的机制是不正确的。正如 Johannes 所指出的,硬链接只是 MFT 中的另一个条目。符号链接是重解析点。他们是不同的。 stackoverflow.com/questions/817794/…
  • 是否也可以检查符号链接是否仍然有效? (或者换句话说,如果目标目录没有被删除)
【解决方案2】:

如果您拥有 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:\ 上运行此脚本。

【讨论】:

  • LinkType 对于重解析点似乎并不可靠。例如,在我的使用 PS 5.1 运行 W10 的计算机上,LinkType 对于“C:\ProgramData\Desktop”和“C:\Users\All Users”都为空,而dir /aL(命令提示符,而不是 PowerShell)表示第一个是连接点,第二个是符号链接。
  • Powershell 不是一个精确的工具。这只是尽力而为。如果结合 say symlink 和 hardlink 询问 powershell 来确定什么是什么,你可以获得更有趣的结果。使用 PS 处理相对符号链接也很痛苦。
  • 这是一些令人不安的信息。我读过很多关于 PowerShell 是命令提示符的绝佳替代品,它是类固醇的命令提示符。我从未见过任何关于它不精确的事情。你能参考一下你的意思吗?我正在努力在我的计算机上查找所有 NTFS 链接。对于重解析点,我想我已经使用命令提示符dir /aL 得到了它。对于硬链接,我计划使用LinkTypeFSutil 测试PowerShell 脚本,看看它们是否给了我相同的结果。但你是说我可能无法相信任何一个结果?
  • 撰写本文时,Windows Powershell Core 6.2.3 上的 Target 数组始终为空。也许 PS 7 会恢复它。
【解决方案3】:

利用Where-Object 搜索ReparsePoint 文件属性。

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

【讨论】:

  • 更简单的实现 (+1)
  • @user66001 - 更简单的是,但需要注意的是,对于大型文件夹结构,这会慢很多。
  • 与其他答案(我发表评论时存在)相比?
【解决方案4】:

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

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

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

【讨论】:

    【解决方案5】:

    我在 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 位,而硬链接则没有。

    【讨论】:

      【解决方案6】:

      以下 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
      

      【讨论】:

        【解决方案7】:

        这是一个检查一个文件 $FilePath 并返回它是否是符号链接的单行程序,适用于文件和目录

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

        【讨论】:

        • 对于(大概)应该在命令行中输入的单行代码,您可以通过省略子表达式和 returns 来简化它(哎呀,这甚至是有保证的对于一个写得很漂亮的函数)。
        【解决方案8】:

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

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

        【讨论】:

        • 这和Keith Hill's answer差不多,只是用了正则表达式。
        • 是的!但它更短并且(恕我直言)更容易理解
        猜你喜欢
        • 2023-04-03
        • 2012-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-02
        • 1970-01-01
        相关资源
        最近更新 更多