精确比较目录-包括移动文件 [英] Compare directories exactly - including moved files
问题描述
我的目的是精确比较两个目录-包括目录和子目录的结构.
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屋!