精确比较目录-包括移动文件 [英] Compare directories exactly - including moved files

查看:54
本文介绍了精确比较目录-包括移动文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目的是精确比较两个目录-包括目录和子目录的结构.

My aim is to compare two directories exactly - including the structure of the directories and sub-directories.

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

I need this, because I want to monitor if something in the folder E:\path2 was changed. For this case a copy of the full folder is in C:\path1. If someone changes something it has to be done in two directories.

这对我们很重要,因为如果目录中的某些内容(偶然或不正确)发生了更改,则可能会破坏基础结构中的其他功能.

It is important for us, because if something is changed in the directory (accidentally or not) it could break down other functions in our infrastructure.

这是我已经编写的脚本:

This is the script I've already written:

# 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"
}

我知道输出的格式不完美,但是可以. :-)

I know the output is not perfect formatted, but it's OK. :-)

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

This script spots the following changes successfully:

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

此脚本无法发现以下更改:

  • 将文件夹或文件移动到其他子文件夹.脚本仍然显示一切正常"
  • move folder or file to other sub-folder. The script still says "everything OK"

我一直在尝试很多事情,但是无法解决这个问题.

I've been trying a lot of things, but could not solve this.

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

Does anyone can help me how the script can be extended to spot a moved folder or file?

推荐答案

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

I think your best bet is to use the .NET FileSystemWatcher class. It's not trivial to implement an advanced function that uses it, but I think it will simplify things for you.

我使用了文章跟踪在学习本课程时,使用PowerShell更改了文件夹.作者的代码如下.我尽力清理了一下. (那个发布平台的代码格式伤害了我的眼睛.)

I used the article Tracking Changes to a Folder Using PowerShell when I was learning this class. The author's code is below. I cleaned it up as little as I could stand. (That publishing platform's code formatting hurts my eyes.)

我认为您想像这样运行它.

I think you want to run it like this.

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个选项卡,而关闭其中一个很麻烦.

I don't think any example I've found online tells you how to stop watching the filesystem. The simplest way is to just close your PowerShell window. But I always seem to have 15 tabs open in each of five PowerShell windows, and closing one of them is a nuisance.

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

Instead, you can use Get-Job to get the Id of registered events. Then use Unregister-Event -SubscriptionId n to, well, unregister the event, where 'n' represents the number(s) you find in the Id property of Get-Job..

这篇关于精确比较目录-包括移动文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆