Instantly share code, notes, and snippets.
Created
May 14, 2024 07:43
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save ll4mat/a5c94bb2bca4521b1cba2c550c698481 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Automates the copying (copy-deleting) of new files from a network share to a local directory and logs the actions taken. | |
.DESCRIPTION | |
This script monitors specified folders on a network share for new files using a FileSystemWatcher. When a new file is detected, it is copied to a local destination directory. The script logs all operations and can be stopped by the presence of an exit condition file. It also includes a mode that allows for copying without removing the original files. | |
.PARAMETER CopyOnly | |
When enabled, the script will copy files as usual but will not delete the source files after copying. This mode is useful for verifying the copy process without modifying the source files. | |
.PARAMETER credentialPath | |
The path to the XML file containing the credentials for the network share. | |
.PARAMETER DestDir | |
The destination directory where files should be copied to. | |
.PARAMETER SrcShare | |
The (UNC) path to the source network share. | |
.PARAMETER logFile | |
The path to the log file where actions should be logged. | |
.PARAMETER netDrive | |
The name of the temporary PSDrive that maps to the network share. | |
.PARAMETER exitConditionFile | |
The path to a file that, when deleted, will cause the script to stop running. | |
.PARAMETER maxConcurrentJobs | |
The maximum number of concurrent jobs that can run. | |
.PARAMETER subFoldersToProcess | |
An array of subfolder names to process. | |
.EXAMPLE | |
.\CopyScript.ps1 -CopyOnly -credentialPath "C:\Credentials.xml" -DestDir "D:\Destination" -SrcShare "\\Server\Share" -logFile "D:\CopyScript.log" -netDrive "NetDrive" -exitConditionFile "D:\StopCopy.lock" -maxConcurrentJobs 5 -subFoldersToProcess @('Folder1', 'Folder2') | |
This example runs the script with the specified parameters, copying files without deleting the originals from the source share. | |
#> | |
param( | |
[switch]$CopyOnly, | |
[string]$credentialPath = "C:\Path\To\Credentials.xml", | |
[string]$DestDir = "D:\Data\DestinationFolder", | |
[string]$SrcShare = "\\Server\Share\Subfolder1\Subfolder2", | |
[string]$logFile = "D:\Logs\CopyScript.log", | |
[string]$netDrive = "Temp_NetworkDrive1", | |
[string]$exitConditionFile = "D:\Data\StopCopy.lock", | |
[int]$maxConcurrentJobs = 5, | |
[string[]]$subFoldersToProcess = @('FOO', 'BAR', 'BAZ', 'QUX', 'THUD', 'WALDO', 'CORGE') | |
) | |
# Determine the list separator for the current culture | |
$listSeparator = (Get-Culture).TextInfo.ListSeparator | |
# Write-Log function | |
function Write-Log { | |
[CmdletBinding()] | |
Param ( | |
[Parameter(Mandatory=$true)] | |
[string]$message | |
) | |
Add-Content -Path $logFile -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')$listSeparator$message" | |
} | |
# Initialize-Log function | |
function Initialize-Log { | |
[CmdletBinding()] | |
Param ( | |
[Parameter(Mandatory=$true)] | |
[string]$logFilePath | |
) | |
if (-Not (Test-Path -Path $logFilePath)) { | |
New-Item -Path $logFilePath -ItemType File | |
Write-Log -message "Log file created at $logFilePath on $(Get-Date -Format 'yyyy-MM-dd')." | |
} else { | |
Write-Host "Log file already exists at $logFilePath" | |
} | |
} | |
# Cleanup completed and failed jobs function | |
function Remove-JobCompletedOrFailed { | |
[CmdletBinding()] | |
param() | |
Get-Job | Where-Object { $_.State -eq 'Completed' -or $_.State -eq 'Failed' } | ForEach-Object { | |
$job = $_ | |
if ($job.State -eq 'Failed') { | |
Write-Log -message "Job $($job.Id) failed with error: $($job.ChildJobs[0].Error[0])" | |
$script:exitCode = 1 | |
$script:stopScript = $true | |
} | |
Remove-Job -Job $job | |
} | |
} | |
# Import credentials for mounting the source-share | |
$cred = Import-Clixml -Path $credentialPath | |
# Initialize log file | |
Initialize-Log -logFilePath $logFile | |
# Map network share to a temporary PSDrive | |
New-PSDrive -Name $netDrive -PSProvider FileSystem -Root $SrcShare -Credential $cred | |
# Create the exit condition file | |
New-Item -Path $exitConditionFile -ItemType File | |
# Initialize FileSystemWatcher | |
$watcher = New-Object System.IO.FileSystemWatcher | |
$watcher.Path = "${netDrive}:\" | |
$watcher.Filter = "*.*" | |
$watcher.IncludeSubdirectories = $true | |
$watcher.EnableRaisingEvents = $true | |
# Event handler | |
$handler = { | |
param($source, $e) | |
$subFolderName = [System.IO.Path]::GetDirectoryName($e.Name) | |
if ($subFolderName -in $subFoldersToProcess) { | |
$newFilePath = $e.FullPath | |
$destinationPath = Join-Path -Path $DestDir -ChildPath $e.Name | |
while ((Get-Job -State Running).Count -ge $maxConcurrentJobs) { | |
Start-Sleep -Seconds 1 | |
Remove-JobCompletedOrFailed | |
} | |
Start-Job -ScriptBlock { | |
param($sourcePath, $destPath, $logPath, $CopyOnly) | |
function Write-Log { | |
Param ([string]$message) | |
Add-Content -Path $logPath -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): $message" | |
} | |
try { | |
if (-Not (Test-Path -Path $destPath)) { | |
Copy-Item -Path $sourcePath -Destination $destPath | |
Write-Log "File $sourcePath was copied to $destPath." | |
if (-not $CopyOnly) { | |
Remove-Item -Path $sourcePath | |
Write-Log "File $sourcePath was deleted from Network-Share." | |
} else { | |
Write-Log "CopyOnly Mode is ON: File $sourcePath was not deleted from Network-Share." | |
} | |
} | |
} catch { | |
Write-Log "An error occurred: $_" | |
Write-Log "The script will be terminated as a precaution." | |
$script:exitCode = 1 | |
Throw | |
} | |
} -ArgumentList $newFilePath, $destinationPath, $logFile, $CopyOnly | |
} | |
} | |
# Register event handler with named parameter | |
Register-ObjectEvent -InputObject $watcher -EventName Created -Action $handler | |
# Main loop | |
while (Test-Path -Path $exitConditionFile -and -not $script:stopScript) { | |
Start-Sleep -Seconds 10 | |
Remove-JobCompletedOrFailed | |
} | |
# Cleanup and release resources | |
try { | |
if ($watcher) { | |
$watcher.Dispose() | |
Write-Log "The FileSystemWatcher was disposed successfully." | |
} | |
} catch { | |
Write-Log "An error occurred while disposing the FileSystemWatcher: $_" | |
$exitCode = 1 | |
} | |
try { | |
Remove-PSDrive -Name $netDrive -ErrorAction Stop | |
Write-Log "Network drive $netDrive was removed successfully." | |
} catch { | |
Write-Log "An error occurred while removing the network drive '$netDrive': $_" | |
$exitCode = 1 | |
} | |
# Exit with the determined exit code | |
Exit $exitCode |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment