【问题标题】:Compare directories exactly - including moved files准确比较目录 - 包括移动的文件
【发布时间】:2017-07-25 14:55:17
【问题描述】:

我的目标是准确比较两个目录 - 包括目录和子目录的结构。

我需要这个,因为我想监视文件夹 E:\path2 中的某些内容是否已更改。对于这种情况,完整文件夹的副本位于C:\path1。如果有人更改某些内容,则必须在两个目录中完成。

这对我们很重要,因为如果目录中的某些内容发生了变化(无论是否意外),它可能会破坏我们基础架构中的其他功能。

这是我已经写好的脚本:

# Compare files for "copy default folder"
# This Script compares the files and folders which are synced to every client.
# Source: https://mcpmag.com/articles/2016/04/14/contents-of-two-folders-with-powershell.aspx

# 1. Compare content and Name of every file recursively
$SourceDocsHash = Get-ChildItem -recurse –Path C:\path1 | foreach  {Get-FileHash –Path $_.FullName}
$DestDocsHash = Get-ChildItem -recurse –Path E:\path2 | foreach  {Get-FileHash –Path $_.FullName}
$ResultDocsHash = (Compare-Object -ReferenceObject $SourceDocsHash -DifferenceObject $DestDocsHash -Property hash -PassThru).Path

# 2. Compare name of every folder recursively
$SourceFolders = Get-ChildItem -recurse –Path C:\path1 #| where {!$_.PSIsContainer}
$DestFolders = Get-ChildItem -recurse –Path E:\path2 #| where {!$_.PSIsContainer}

$CompareFolders = Compare-Object -ReferenceObject $SourceFolders -DifferenceObject $DestFolders -PassThru -Property Name
$ResultFolders = $CompareFolders |  Select-Object FullName

# 3. Check if UNC-Path is reachable
# Source: https://stackoverflow.com/questions/8095638/how-do-i-negate-a-condition-in-powershell
# Printout, if UNC-Path is not available.
if(-Not (Test-Path \\bb-srv-025.ftscu.be\DIP$\Settings\ftsCube\default-folder-on-client\00_ftsCube)){
  $UNCpathReachable = "UNC-Path not reachable and maybe"
}

# 4. Count files for statistics
# Source: https://stackoverflow.com/questions/14714284/count-items-in-a-folder-with-powershell
$count = (Get-ChildItem -recurse –Path E:\path2 | Measure-Object ).Count;

# FINAL: Print out result for check_mk
if($ResultDocsHash -Or $ResultFolders -Or $UNCpathReachable){
  echo "2 copy-default-folders-C-00_ftsCube files-and-folders-count=$count CRITIAL - $UNCpathReachable the following files or folders has been changed: $ResultDocs $ResultFolders (none if empty after ':')"
}
else{
  echo "0 copy-default-folders-C-00_ftsCube files-and-folders-count=$count OK - no files has changed"
}

我知道输出的格式不完美,但没关系。 :-)

此脚本成功发现以下更改:

  • 创建新文件夹或新文件
  • 重命名文件夹或文件 -> 显示为错误,但输出为空。我可以忍受这一点。但也许有人看到了原因。 :-)
  • 删除文件夹或文件
  • 更改文件内容

此脚本未发现以下更改:

  • 将文件夹或文件移动到其他子文件夹。脚本仍然显示“一切正常”

我已经尝试了很多东西,但无法解决这个问题。

谁能帮助我如何扩展脚本以发现移动的文件夹或文件?

【问题讨论】:

  • 与其在事后追踪更改,您会考虑制作一个必须用于将文件放入目录的脚本吗?文件提交脚本会将文件的副本放入两个目录中。用户可以对目录具有读取权限,但脚本将使用允许其写入目录的凭据。或者,可以有一个单独的提交目录,用户可以在其中放置新的/更改的文件。脚本可以监视目录或定期将提交目录文件复制到其他目录。
  • 使用 .NET FileSystemWatcher 类可能是更好的选择。 From the TechNet gallery.
  • @MikeSherrill'CatRecall':这很有趣。我会尝试并发布反馈。也许我必须澄清一下我的目标:我想查看特定目录中的文件和文件夹是否发生了更改。 (E:\path2) 我的方法是将它与参考目录进行比较。 (C:\path1) 很抱歉让您感到复杂。
  • 嗯,FileSystemWatcher 听起来正是您所需要的。除其他外,它将消除对参考目录的需求,并且可以简化和减少您的代码。

标签: powershell filesystemwatcher


【解决方案1】:

我认为您最好的选择是使用 .NET FileSystemWatcher 类。实现使用它的高级功能并非易事,但我认为它会为您简化事情。

我在学习这门课时使用了文章Tracking Changes to a Folder Using PowerShell。作者的代码如下。我尽量把它清理干净。 (那个发布平台的代码格式看得我眼花。)

我想你想这样运行它。

New-FileSystemWatcher -Path E:\path2 -Recurse

我可能错了。

Function New-FileSystemWatcher  {

    [cmdletbinding()]
    Param (

    [parameter()]
    [string]$Path,

    [parameter()]
    [ValidateSet('Changed', 'Created', 'Deleted', 'Renamed')]
    [string[]]$EventName,

    [parameter()]
    [string]$Filter,

    [parameter()]
    [System.IO.NotifyFilters]$NotifyFilter,

    [parameter()]
    [switch]$Recurse,

    [parameter()]
    [scriptblock]$Action

    )

    $FileSystemWatcher  = New-Object System.IO.FileSystemWatcher

    If (-NOT $PSBoundParameters.ContainsKey('Path')){
        $Path  = $PWD
    }

    $FileSystemWatcher.Path = $Path

    If ($PSBoundParameters.ContainsKey('Filter')) {
        $FileSystemWatcher.Filter = $Filter
    }

    If ($PSBoundParameters.ContainsKey('NotifyFilter')) {
        $FileSystemWatcher.NotifyFilter =  $NotifyFilter
    }

    If ($PSBoundParameters.ContainsKey('Recurse')) {
        $FileSystemWatcher.IncludeSubdirectories =  $True
    }

    If (-NOT $PSBoundParameters.ContainsKey('EventName')){
        $EventName  = 'Changed','Created','Deleted','Renamed'
    }

    If (-NOT $PSBoundParameters.ContainsKey('Action')){
        $Action  = {
            Switch  ($Event.SourceEventArgs.ChangeType) {
                'Renamed'  {
                    $Object  = "{0} was  {1} to {2} at {3}" -f $Event.SourceArgs[-1].OldFullPath,
                    $Event.SourceEventArgs.ChangeType,
                    $Event.SourceArgs[-1].FullPath,
                    $Event.TimeGenerated
                }

                Default  {
                    $Object  = "{0} was  {1} at {2}" -f $Event.SourceEventArgs.FullPath,
                    $Event.SourceEventArgs.ChangeType,
                    $Event.TimeGenerated
                }
            }

            $WriteHostParams  = @{
                ForegroundColor = 'Green'
                BackgroundColor = 'Black'
                Object =  $Object
            }

            Write-Host  @WriteHostParams
        }

    }

    $ObjectEventParams  = @{
        InputObject =  $FileSystemWatcher
        Action =  $Action
    }

    ForEach  ($Item in  $EventName) {
        $ObjectEventParams.EventName = $Item
        $ObjectEventParams.SourceIdentifier =  "File.$($Item)"
        Write-Verbose  "Starting watcher for Event: $($Item)"
        $Null  = Register-ObjectEvent  @ObjectEventParams
    }

} 

我认为我在网上找到的任何示例都没有告诉您如何停止查看文件系统。最简单的方法是关闭 PowerShell 窗口。但我似乎总是在 5 个 PowerShell 窗口中的每个窗口中打开 15 个选项卡,而关闭其中一个很麻烦。

相反,您可以使用 Get-Job 来获取已注册事件的 Id。然后使用Unregister-Event -SubscriptionId n 来取消注册事件,其中“n”代表您在 Get-Job 的 Id 属性中找到的数字。

【讨论】:

  • 你也可以编写一个使用文件系统观察器的Windows服务。
【解决方案2】:

所以基本上你想同步这两个文件夹并注意所有的更改:

我建议你使用

Sync-Folder Script

或者

FreeFile Sync.

【讨论】:

  • 感谢您的回答。我不想同步(写)。只是比较(阅读)。目的是输出到 check_mk 以显示差异并获得警报。是否可以使用同步脚本,但在比较后停止并只是“模拟”并获取输出?
猜你喜欢
  • 1970-01-01
  • 2015-12-24
  • 2015-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-20
  • 2017-12-09
  • 1970-01-01
相关资源
最近更新 更多