Точно сравнивайте каталоги - включая перемещенные файлы
Моя цель состоит в том, чтобы сравнить два каталога точно, включая структуру каталогов и подкаталогов.
Мне это нужно, потому что я хочу контролировать, если что-то в папке 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://stackru.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://stackru.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"
}
Я знаю, что вывод не отформатирован, но все в порядке.:-)
Этот скрипт успешно определяет следующие изменения:
- создать новую папку или новый файл
- переименовать папку или файл -> это отображается как ошибка, но вывод пуст. Я могу жить с этим. Но, возможно, кто-то видит причину.:-)
- удалить папку или файл
- изменить содержимое файла
Этот скрипт НЕ обнаруживает следующие изменения:
- переместить папку или файл в другую подпапку. Сценарий все еще говорит "все в порядке"
Я много чего пробовал, но не смог решить.
Кто-нибудь может мне помочь, как скрипт может быть расширен, чтобы определить перемещенную папку или файл?
2 ответа
Я думаю, что вам лучше всего использовать класс.NET FileSystemWatcher. Реализовать продвинутую функцию, которая ее использует, нетривиально, но я думаю, что это упростит вам задачу.
Я использовал статью " Отслеживание изменений в папке с помощью 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. Но у меня всегда есть 15 вкладок, открытых в каждом из пяти окон PowerShell, и закрытие одной из них создает неудобства.
Вместо этого вы можете использовать Get-Job, чтобы получить Id зарегистрированных событий. Тогда используйте Unregister-Event -SubscriptionId n
ну, в общем, отмените регистрацию события, где 'n' представляет число, которое вы найдете в свойстве Id Get-Job.
В общем, вы хотите синхронизировать две папки и отметить все изменения, сделанные в этом:
Я бы предложил вам использовать
Или же