# Резервирование файлового сервера (v.2)
# Создание архивных копий актуальных данных файлового сервера


# Назначение переменной $s для исключения из пути-источника (используется далее)
$s="D:\\fs\\"

# Назначение переменной $spth - каталог скрипта (базовый)
$spth = split-path -parent $MyInvocation.MyCommand.Definition

# Назначение переменной $cA - Каталог с актуальными копиями (далее - 'A')
$cA = "D:\fs\01-Общие\"
 
# Назначение переменной $cB - Каталог постоянного хранения (далее - 'B')
$cB = "\\domain\fs\08-Backup\01-B00\02-FS"

# Назначение переменной $ht и $htD (путь и файл таблицы хешей)
$ht="$spth\hashtable.csv"
$htD="$spth\hashtable_dup.csv"

# Создание комплексной переменной на основе даты (раздельные значения для "год"=$dt.y, "месяц"=$dt.m, "день"=$dt.d)
$dt = New-Object PsObject -Property @{y=Get-date -f "yyyy"; m=Get-Date -f "MM"; d=Get-Date -f "dd"; f=Get-Date -f "yyyyMMdd"; h=Get-date -f "hh"; mm=Get-date -f "mm";}

# ПО для выполнения архивации (7zip)
$7z = "C:\Program Files\7-Zip\7z.exe"

# Проверка существования и загрузка текущей таблицы хешей в массив $hta (создание массива в случае отсутсвия)
if(Test-Path ($ht)) {
	[psobject[]]$hta=import-csv "$ht" -Encoding UTF8
} else {
	$hta=@()
}

# Проверка существования и загрузка текущей таблицы хешей дубликатов в массив $htb (создание массива в случае отсутсвия)
if(Test-Path ($htD)) {
	[psobject[]]$htb=import-csv "$htD" -Encoding UTF8
} else {
	$htb=@()
}

# Создание полного списка файлов для хеширования и проверки
$toCheck = Get-ChildItem $cA -R | where {! $_.PSIsContainer -eq $true}

# Назначение функции Calc-Hash для хеширования
Function Calc-Hash {
		Param (
			[parameter(Position=0, Mandatory=$true, ValueFromPipeline=$false)]
			$file
		)
		Begin {
			$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
		}
		Process {
			$hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($file)))
			Write-Output $hash
		}
}

# Создание массива $toBackup из файлов к резервированию
$toBackup=@()

# Цикл создания хешей в массив $hta (в случае отсутсвия) и формирование списка файлов к резервированию
Foreach ($f in $toCheck) {
	$h=Calc-Hash $f.FullName
	# Пропустить обработку текущего файла, если хэш не создан (например, изза недостатка прав)
	if (!($h)) {
		Write-Output "File '$f' Locked" | Out-File -filepath "$cB\locked.log" -encoding "UTF8" -Append
		Continue
	}
	$uid=($h+$f.FullName)
	if ($hta.hash -notcontains $h) {
		# Пополнение массива хешей (таблицы) новым уникальным значением
		$hta+=New-Object PsObject -Property @{hash=$h;file=$f.FullName;uid=$uid;}
		# Формирование списка файлов для резервирования с дополнительными параметрами (стандартные для файла + хеш)
		$toBackup+=$f | select @{n='Extension';e={$f.Extension}},@{n='FullName';e={$f.FullName}},@{n='BaseName';e={$f.BaseName}},@{n='Name';e={$f.Name}},@{n='Directory';e={$f.DirectoryName}},@{n='Hash';e={$h}}
	} elseif ($hta.uid -notcontains $uid) {
		if ($htb.uid -notcontains $uid) {
			# Назначение переменных для текущего и существующего файла
			$CurrentFile=$f.FullName
			$ExistFile=($hta -match $h).file
			# Переменная для лог-файла (полная дата и время)
			$dtf=$dt.y+"-"+$dt.m+"-"+$dt.d+" "+$dt.h+":"+$dt.mm
			$htb+=New-Object PsObject -Property @{hash=$h;fileA=$CurrentFile;fileB=$ExistFile;uid=$uid;}
			# Формирование лог-файла с сопоставлением дубликат = оригинал
			$duplog="$cB\dublicates.log"
			Write-Output "[$dtf] $CurrentFile = $ExistFile" | Out-File -filepath $duplog -encoding "UTF8" -Append
		}
	}
}

# Цикл резервирования файлов по списку массива $toBackup
Foreach ($b in $toBackup) {
	# Формирование каталога размещения копии из замены $s в пути-источника на $cB (размещение идентично начальному, внутри каталога назначения)
	$bD=($b.Directory -replace $s,$cB)
	$bF=$bD+"\"+($b.Name)
	# Проверка существования каталога (создание, если отсутствует)
	if(!(Test-Path ($bD))) {
		md $bD
	}
	# Копирование файла
	# Проверка существование старой версии файла (архивация, если существует)
	if(Test-Path ($bF)) {
		# Назначение переменной для имени будущего архива
		$bFn=$bD+"\"+$b.BaseName+$b.Extension+"_"+$dt.f+".7z"
		# Архивация старой версии файла
		& $7z @('a','-t7z',$bFn,$bF)
		# Удалить старую версию файла
		Remove-Item $bF
		# Скопировать новую
		Copy-Item $b.FullName $bD
	} else {
		Copy-Item $b.FullName $bD
	}
}

# Выгрузить новые значения для таблиц с хешами архивированных файлов
$hta | export-csv $ht -NoTypeInformation -Encoding UTF8
$htb | export-csv $htD -NoTypeInformation -Encoding UTF8