Public/Invoke-ATMDFileDeployment.ps1
function Invoke-ATMDFileDeployment { <# .SYNOPSIS Запускает копирование папок и файлов. .DESCRIPTION Запускает копирование файлов и папок на основании представленных параметрв в виде объектов / хеш таблиц (см. пример). .PARAMETER FileDeployment Объект с описание файлов (см. пример). .PARAMETER PassThru Используйте параметр -PassThru, чтобы получить список обработаных файлов и код завершения операций. .EXAMPLE $fileDeployment = @{ foldersToDelete =@('E:\tmp\#Daily\qqq') foldersToClear = @( @{ path = 'E:\tmp\#Daily\Tools2\Tools' excludeList = @('#IDF', 'SysInts') } ) filesToDelete =@('E:\tmp\#Daily\new.txt') filesToCopy =@( @{ source = '\\podsrv-rdsfs1.corp.atmd.ru\SysUsrData\CSPRegCerts\AMD\romanova\2019-12-16 14-25-06 ООО АМД' destination = 'E:\tmp\#Daily\new.reg' }, @{ source = '\\podsrv-rdsfs1.corp.atmd.ru\SysUsrData\CSPRegCerts\AMD\romanova\c1d136ec-d665-4db1-b0ca-ed836a270293' destination = 'E:\tmp\#Daily\new2.reg' forceReplace = 'True' } ) filesToUpdate =@( @{ source = '\\srv-fs1.corp.atmd.ru\Deploy\Tools\LAPSx64.msi' destination = 'E:\tmp\#Daily\LAPSx64.msi' }, @{ source = '\\srv-fs1.corp.atmd.ru\Deploy\Tools\PoSh\LogonScript\Atmd-LogonScript.ps1' destination = 'E:\tmp\#Daily\Atmd-LogonScript.ps1' } ) } Invoke-ATMDFileDeployment -FileDeployment $FileDeployment -PassThru -Verbose .INPUTS Inputs (if any) .OUTPUTS Функция возвращает объект, содержащий перечень удалнных, обнавленных и созданных файлов и папок, если указан параметр -PassThru .NOTES Цель написания этой функции - возможность быстро копировать или удалять файлы на основании описания, которое будте храниться в JSON-файле. Фактически, данная функция просто собирает вместе несколько командлетов Powershell, и ряд стандартный проверок, вроде Test-Path и т.п. Отдельно стоит выделить процесс "обновления файлов" - копирование с заменой файлов, основываясь на дате изменения, а для скриптов Powershell - основываясь на версии в PSInfo Возвращаемый результат и коды ошибок описаны следующим образом: $RESULT_REMOVE_FORDER_EXCEPTION = 128 #Ошибка при удалении каталога. $RESULT_REMOVE_FILE_EXCEPTION = 64 #Ошибка при удалении файла. $RESULT_COPY_FILE_EXCEPTION = 32 #Ошибка при копировании файла. $RESULT_COPY_FOLDER_EXCEPTION = 16 #Ошибка при копировании папки целиком. $RESULT_CLEAR_FORDER_EXCEPTION = 8 #Ошибка при очистки каталога. $RESULT_UPDATE_FILE_EXCEPTION = 4 #Ошибка при обновлении файла. $RESULT_NO_ERROR = 0 #Ошибок не. $Result = [PSCustomObject]@{ DeletedFolders = @() DeletedFiles = @() CleanedFolders = @() CopiedFolders = @() CopiedFiles = @() ProblemItems = @() ExitCode = $RESULT_NO_ERROR } В массив $Result.ProblemItems попадают элементы, при работе с которыми возникли исключения. Остальные названия, думаю, понятны. Коды ошибок объединяются бинарными операциями. То есть, значение 160 указывает, что произошли ошибки при удалении папки и при копировании файла: ($RESULT_REMOVE_FORDER_EXCEPTION -bor $RESULT_COPY_FILE_EXCEPTION) рабно 160. #> [CmdletBinding()] [OutputType([System.Object])] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [System.Object] $FileDeployment, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 1)] [switch] $PassThru = $false ) begin { # Для удобства чтения - коды ошибок в виде переменных с мнемоническими названиями. $RESULT_REMOVE_FORDER_EXCEPTION = 128 #Ошибка при удалении каталога. $RESULT_REMOVE_FILE_EXCEPTION = 64 #Ошибка при удалении файла. $RESULT_COPY_FILE_EXCEPTION = 32 #Ошибка при копировании файла. $RESULT_COPY_FOLDER_EXCEPTION = 16 #Ошибка при копировании папки целиком. $RESULT_CLEAR_FORDER_EXCEPTION = 8 #Ошибка при очистки каталога. $RESULT_UPDATE_FILE_EXCEPTION = 4 #Ошибка при обновлении файла. $RESULT_NO_ERROR = 0 #Ошибок не. $Result = [PSCustomObject]@{ DeletedFolders = @() DeletedFiles = @() CleanedFolders = @() CopiedFolders = @() CopiedFiles = @() ProblemItems = @() ExitCode = $RESULT_NO_ERROR } } process { try { #region Удаляем каталоги. foreach ($Folder in $FileDeployment.foldersToDelete) { try { if (Test-Path -Path $Folder) { Write-Verbose -Message "<Invoke-ATMDFileDeployment> Удаляем каталог $Folder" Remove-Item -Path $Folder -Recurse -Force $Result.DeletedFolders += $Folder } } catch { Write-Error -Message "При удалении каталога $Folder произшла ошибка $($PSItem.Exception.Message)" $Result.ProblemItems += $Folder $Result.ExitCode = $Result.ExitCode -bor $RESULT_REMOVE_FORDER_EXCEPTION } } #endregion Удаляем каталоги. #region Очищаем каталоги. foreach ($Folder in $FileDeployment.foldersToClear) { try { if (Test-Path -Path $Folder.path) { Write-Verbose -Message "<Invoke-ATMDFileDeployment> Очищаем каталог $($Folder.path)" Get-ChildItem -Path $Folder.path -Exclude $Folder.excludeList | Remove-Item -Recurse -Force -Confirm:$false -ErrorAction Stop $Result.CleanedFolders += $Folder.path } } catch { Write-Error -Message "При очистки каталога $($Folder.path) произшла ошибка $($PSItem.Exception.Message)" $Result.ProblemItems += $Folder.path $Result.ExitCode = $Result.ExitCode -bor $RESULT_CLEAR_FORDER_EXCEPTION } } #endregion Очищаем каталоги. #region Удаляем файлы. foreach ($File in $FileDeployment.filesToDelete) { try { if (Test-Path -Path $File) { Write-Verbose -Message "<Invoke-ATMDFileDeployment> Удаляем файл $File" Remove-Item -Path $File -Force -ErrorAction Stop $Result.DeletedFiles += $File } } catch { Write-Error -Message "При удалении файла $File произшла ошибка $($PSItem.Exception.Message)" $Result.ProblemItems += $File $Result.ExitCode = $Result.ExitCode -bor $RESULT_REMOVE_FILE_EXCEPTION } } #endregion Копируем папки. #region Копируем папки. foreach ($FolderPair in $FileDeployment.folderToCopy) { try { if (Test-Path -Path $Folder.source) { if (-not(Test-Path -Path $Folder.destination)) { New-Item -Path $Folder.destination -ItemType Directory } Write-Verbose -Message "<Invoke-ATMDFileDeployment> Копируем каталог$($Folder.source). Место назначения - $($Folder.destination)" Copy-Item -Path $Folder.source -Destination $Folder.destination -Recurse -ErrorAction Stop $Result.CopiedFolders += $Folder.source } else { Write-Warning -Message "Каталог $($FolderPair.source) не найден." } } catch { Write-Error -Message "При копировании каталога $($Folder.source) произшла ошибка $($PSItem.Exception.Message)" $Result.ProblemItems += $Folder.source $Result.ExitCode = $Result.ExitCode -bor $RESULT_COPY_FOLDER_EXCEPTION } } #endregion Копируем папки. #region Копируем файлы foreach ($FilePair in $FileDeployment.filesToCopy) { try { # Проверяем, существует ли папка для целевого файла. $DestinationFilePath = Split-Path -Path $FilePair.destination -Parent if (-not(Test-Path -Path $DestinationFilePath)) { New-Item -ItemType Directory -Path $DestinationFilePath } # Копируем файлы из списка Write-Verbose -Message "<Invoke-ATMDFileDeployment> Копируем файл $($FilePair.source)" Copy-Item -Path $FilePair.source -Destination $FilePair.destination -Force:([System.Convert]::ToBoolean($FilePair.forceReplace)) -ErrorAction Stop Write-Verbose -Message "<Invoke-ATMDFileDeployment> Файл назначения - $($FilePair.destination)" $Result.CopiedFiles += $FilePair.source } catch { Write-Error -Message "При копировании файла $($FilePair.source) произшла ошибка $($PSItem.Exception.Message)" $Result.ProblemItems += $FilePair.source $Result.ProblemItems += $FilePair.destination $Result.ExitCode = $Result.ExitCode -bor $RESULT_COPY_FILE_EXCEPTION } } #endregion Копируем файлы #region Обновляем файлы foreach ($FilePair in $FileDeployment.filesToUpdate) { try { # Если исходного файла не будет, значит и делать с ним нечего. if (Test-Path -Path $FilePair.source) { # Тут мы должны определить, копировать файл или нет. # Скрипты Powershell стоит копировать, если у них обновилась версия, а остальные файлы - исходя из даты изменения. # По умолчанию считаем, что копировать не надо. Write-Verbose -Message "<Invoke-ATMDFileDeployment> Обновление файлов - файл $($FilePair.source)" $ShouldCopy = $false # Если файла назначения нет - копируем. if (-not(Test-Path -Path $FilePair.destination)) { $ShouldCopy = $true Write-Verbose -Message '<Invoke-ATMDFileDeployment> Файл назначения отсутствует.' } # Если же существует - смотрим, Powershell-скрипт это или нет else { # Получаем объекты самих файлов. $SourceFile = Get-Item -Path $FilePair.source $DestinationFile = Get-Item -Path $FilePair.destination if ($SourceFile.Extension -eq '.ps1') { try { $SourceScritpInfo = Test-ScriptFileInfo -Path $FilePair.source } catch { $SourceScritpInfo = $null } try { $DestinationScritpInfo = Test-ScriptFileInfo -Path $FilePair.destination } catch { $DestinationScritpInfo = $null } if ($SourceScritpInfo) { if (-not($DestinationScritpInfo)) { Write-Verbose -Message "<Invoke-ATMDFileDeployment> Версия исходного файла: $($SourceScritpInfo.Version) / Версия файла назначения: $($DestinationScritpInfo.Version)" if ($SourceScritpInfo.Version -gt $DestinationScritpInfo.Version) { Write-Verbose -Message '<Invoke-ATMDFileDeployment> Скрипт Powershell устарел...' $ShouldCopy = $true } else { Write-Verbose -Message "<Invoke-ATMDFileDeployment> Пропускаем скрипт $($FilePair.source)" } } else { Write-Verbose -Message '<Invoke-ATMDFileDeployment> Скрипт Powershell не имеет информации о версии - заменим его.' $ShouldCopy = $true } } else { Write-Warning -Message "Исходный скрипт $($FilePair.source) не имеет информации о версии - не будет обработан." } } # Если не скрипт - ориентируемся на дату изменения. else { if (($DestinationFile.LastWriteTime -lt $SourceFile.LastWriteTime)) { Write-Verbose -Message '<Invoke-ATMDFileDeployment> Файл назанчения устарел...' $ShouldCopy = $true } else { Write-Verbose -Message "<Invoke-ATMDFileDeployment> Пропускаем файл $($FilePair.source)" } } } # end of 'if (-not(Test-Path -Path $FilePair.destination)) {...} else {' } # end of 'if (Test-Path -Path $FilePair.source) {' # Если стало ясно, что надо копировать... if ($ShouldCopy) { # Проверяем, существует ли папка для целевого файла. $DestinationFilePath = Split-Path -Path $FilePair.destination -Parent if (-not(Test-Path -Path $DestinationFilePath)) { New-Item -ItemType Directory -Path $DestinationFilePath } # Копируем файлы из списка Write-Verbose -Message "<Invoke-ATMDFileDeployment> Копируем файл $($FilePair.source)" Copy-Item -Path $FilePair.source -Destination $FilePair.destination -Force -ErrorAction Stop Write-Verbose -Message "<Invoke-ATMDFileDeployment> Файл назначения - $($FilePair.destination)" $Result.CopiedFiles += $FilePair.source } } catch { Write-Error -Message "При копировании файла $($FilePair.source) произшла ошибка $($PSItem.Exception.Message)" $Result.ProblemItems += $FilePair.source $Result.ProblemItems += $FilePair.destination $Result.ExitCode = $Result.ExitCode -bor $RESULT_UPDATE_FILE_EXCEPTION } } #endregion Обновляем файлы } catch { # $PSCmdlet.ThrowTerminatingError($PSitem) Write-Error -Exception $PSItem.Exception } } end { if ($PassThru) { return $Result } } } |