准确比较目录 - 包括移动的文件

问题描述 投票:1回答:2

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

我需要这个,因为我想监视文件夹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"
}

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

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

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

此脚本不会发现以下更改:

  • 将文件夹或文件移动到其他子文件夹。剧本仍然说“一切都好”

我一直在尝试很多东西,但无法解决这个问题。

有没有人可以帮助我如何扩展脚本以发现移动的文件夹或文件?

powershell filesystemwatcher
2个回答
0
投票

所以基本上你想要同步这两个文件夹并记下对它做出的所有更改:

我建议你使用

Sync-Folder Script

要么

FreeFile Sync


0
投票

我认为最好的办法是使用.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窗口。但我似乎总是在五个PowerShell窗口中打开15个选项卡,关闭其中一个是令人讨厌的。

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

© www.soinside.com 2019 - 2024. All rights reserved.