Skip to content

Commit dd82c8a

Browse files
Update Copy-and-Sync-Folder-to-ADComputers-viaGPO.ps1
Signed-off-by: LUIZ HAMILTON ROBERTO DA SILVA <[email protected]>
1 parent 2df5d7a commit dd82c8a

1 file changed

Lines changed: 88 additions & 58 deletions

File tree

Lines changed: 88 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,154 @@
1-
<#
1+
<#
22
.SYNOPSIS
3-
PowerShell Script for Synchronizing Folders to AD Computers via GPO.
3+
PowerShell script to synchronize folders from a network share to Active Directory computers via GPO.
44
55
.DESCRIPTION
6-
This script synchronizes folders from a network location to AD computers, ensuring that only new
7-
or updated files are copied while outdated files are removed. It also includes full logging of the operation.
6+
This script synchronizes a folder from a network location (e.g. NETLOGON share)
7+
to the local Administrator's desktop on AD workstations. It copies only new or updated files,
8+
and removes obsolete files and folders that are no longer in the source.
9+
Intended for use as a machine-level GPO startup script.
810
911
.AUTHOR
1012
Luiz Hamilton Silva - @brazilianscriptguy
1113
1214
.VERSION
13-
Last Updated: October 22, 2024
15+
Updated: August 5, 2025 - Refactored for GPO startup context and system execution.
1416
#>
1517

16-
# Determine the script name and set up logging path
18+
param (
19+
[string]$LogDirectory = "C:\Logs-TEMP"
20+
)
21+
22+
# Get the script name and define the full log path
1723
$scriptName = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)
18-
$logDir = 'C:\Logs-TEMP'
1924
$logFileName = "${scriptName}.log"
20-
$logPath = Join-Path $logDir $logFileName
25+
$logPath = Join-Path $LogDirectory $logFileName
2126

2227
# Ensure the log directory exists
23-
if (-not (Test-Path $logDir)) {
28+
if (-not (Test-Path $LogDirectory)) {
2429
try {
25-
New-Item -Path $logDir -ItemType Directory -ErrorAction Stop | Out-Null
26-
} catch {
27-
Write-Error "Failed to create log directory at $logDir. Logging will not be possible."
28-
return
30+
New-Item -Path $LogDirectory -ItemType Directory -ErrorAction Stop | Out-Null
31+
}
32+
catch {
33+
Write-Error "Failed to create log directory at $LogDirectory. Logging will be disabled."
34+
exit 1
2935
}
3036
}
3137

32-
# Enhanced logging function with error handling
33-
function Log-Message {
38+
# Logging function with timestamp and severity
39+
function Write-Log {
3440
param (
35-
[Parameter(Mandatory = $true)]
36-
[string]$Message
41+
[Parameter(Mandatory = $true)][string]$Message,
42+
[string]$Severity = "INFO"
3743
)
3844
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
39-
$logEntry = "[$timestamp] $Message"
45+
$logEntry = "[$timestamp] [$Severity] $Message"
4046
try {
41-
Add-Content -Path $logPath -Value $logEntry -ErrorAction Stop
42-
} catch {
47+
Add-Content -Path $logPath -Value $logEntry -Encoding UTF8 -ErrorAction Stop
48+
}
49+
catch {
4350
Write-Error "Failed to write to log: $_"
4451
}
4552
}
4653

47-
# Define the source folder path
54+
# === CONFIGURATION ===
55+
56+
# Source network folder (change as needed)
4857
$sourceFolderPath = "\\forest-logonserver-name\NETLOGON\Source-Folder-Name"
4958

50-
# Get the specific desktop path
51-
$userDesktopPath = 'C:\Users\Administrator\Desktop' # Destination path
59+
# Determine Administrator profile path
60+
$adminProfilePath = "$env:SystemDrive\Users\Administrator"
61+
$adminDesktopPath = Join-Path $adminProfilePath "Desktop"
5262

53-
# Define the destination folder path on the desktop
54-
$destinationFolderPath = Join-Path -Path $userDesktopPath -ChildPath "Destination-Folder-Name"
63+
# Check if desktop path exists
64+
if (-not (Test-Path -Path $adminDesktopPath)) {
65+
Write-Log "Administrator desktop not found at: $adminDesktopPath" -Severity "ERROR"
66+
exit 1
67+
}
68+
69+
# Define destination folder under Administrator desktop
70+
$destinationFolderPath = Join-Path -Path $adminDesktopPath -ChildPath "Destination-Folder-Name"
71+
72+
# === FOLDER SYNC FUNCTION ===
5573

56-
# Function to copy files if they are newer or missing and remove older files
5774
function Sync-Folders {
5875
param (
5976
[string]$sourceFolder,
6077
[string]$destinationFolder
6178
)
6279

63-
# Ensure the destination directory exists
80+
# Create destination folder if it doesn't exist
6481
if (-not (Test-Path -Path $destinationFolder)) {
6582
try {
66-
New-Item -ItemType Directory -Path $destinationFolder | Out-Null
67-
Log-Message "Created directory: $destinationFolder"
68-
} catch {
69-
Log-Message "Failed to create directory: $destinationFolder. Error: $_"
83+
New-Item -ItemType Directory -Path $destinationFolder -ErrorAction Stop | Out-Null
84+
Write-Log "Created destination folder: $destinationFolder"
85+
}
86+
catch {
87+
Write-Log "Failed to create destination folder: $destinationFolder. Error: $_" -Severity "ERROR"
7088
return
7189
}
7290
}
7391

74-
# Copy new/updated files from source to destination
75-
Get-ChildItem -Path $sourceFolder -Recurse | ForEach-Object {
76-
$destinationPath = $_.FullName.Replace($sourceFolder, $destinationFolder)
92+
# Copy new or updated files from source to destination
93+
$sourceItems = Get-ChildItem -Path $sourceFolder -Recurse -Force
94+
foreach ($item in $sourceItems) {
95+
$relativePath = $item.FullName.Substring($sourceFolder.Length).TrimStart('\')
96+
$destinationPath = Join-Path $destinationFolder $relativePath
7797

78-
if ($_.PSIsContainer) {
98+
if ($item.PSIsContainer) {
7999
if (-not (Test-Path -Path $destinationPath)) {
80100
try {
81-
New-Item -ItemType Directory -Path $destinationPath | Out-Null
82-
Log-Message "Created directory: $destinationPath"
83-
} catch {
84-
Log-Message "Failed to create directory: $destinationPath. Error: $_"
101+
New-Item -ItemType Directory -Path $destinationPath -ErrorAction Stop | Out-Null
102+
Write-Log "Created directory: $destinationPath"
103+
}
104+
catch {
105+
Write-Log "Failed to create directory: $destinationPath. Error: $_" -Severity "ERROR"
85106
}
86107
}
87-
} else {
108+
}
109+
else {
88110
try {
89-
if ((-not (Test-Path -Path $destinationPath)) -or ($_.LastWriteTime -gt (Get-Item -Path $destinationPath).LastWriteTime)) {
90-
Copy-Item -Path $_.FullName -Destination $destinationPath -Force
91-
Log-Message "Updated: $destinationPath"
92-
} else {
93-
Log-Message "Skipped: $destinationPath"
111+
$destItem = Get-Item -Path $destinationPath -ErrorAction SilentlyContinue
112+
if ((-not $destItem) -or ($item.LastWriteTime -gt $destItem.LastWriteTime)) {
113+
Copy-Item -Path $item.FullName -Destination $destinationPath -Force -ErrorAction Stop
114+
Write-Log "Copied/Updated file: $destinationPath"
94115
}
95-
} catch {
96-
Log-Message "Failed to copy: $destinationPath. Error: $_"
116+
else {
117+
Write-Log "Skipped (already up-to-date): $destinationPath"
118+
}
119+
}
120+
catch {
121+
Write-Log "Failed to copy file: $destinationPath. Error: $_" -Severity "ERROR"
97122
}
98123
}
99124
}
100125

101-
# Remove files/folders from destination if they don't exist in the source
102-
Get-ChildItem -Path $destinationFolder -Recurse | ForEach-Object {
103-
$sourcePath = $_.FullName.Replace($destinationFolder, $sourceFolder)
126+
# Remove obsolete files/folders in destination that don't exist in source
127+
$destItems = Get-ChildItem -Path $destinationFolder -Recurse -Force
128+
foreach ($item in $destItems) {
129+
$relativePath = $item.FullName.Substring($destinationFolder.Length).TrimStart('\')
130+
$sourcePath = Join-Path $sourceFolder $relativePath
104131

105132
if (-not (Test-Path -Path $sourcePath)) {
106133
try {
107-
Remove-Item -Path $_.FullName -Recurse -Force
108-
Log-Message "Removed: $($_.FullName)"
109-
} catch {
110-
Log-Message "Failed to remove: $($_.FullName). Error: $_"
134+
Remove-Item -Path $item.FullName -Recurse -Force -ErrorAction Stop
135+
Write-Log "Removed obsolete item: $($item.FullName)"
136+
}
137+
catch {
138+
Write-Log "Failed to remove obsolete item: $($item.FullName). Error: $_" -Severity "ERROR"
111139
}
112140
}
113141
}
114142
}
115143

116-
# Copy the folder to the desktop, only updating files that are newer and removing older files
144+
# === EXECUTION ===
145+
117146
if (Test-Path -Path $sourceFolderPath) {
118147
Sync-Folders -sourceFolder $sourceFolderPath -destinationFolder $destinationFolderPath
119-
Log-Message "Folder successfully synced to $destinationFolderPath with only new/updated files and older files removed."
120-
} else {
121-
Log-Message "Source folder does not exist: $sourceFolderPath."
148+
Write-Log "Synchronization completed successfully to $destinationFolderPath."
149+
}
150+
else {
151+
Write-Log "Source folder not found: $sourceFolderPath" -Severity "ERROR"
122152
}
123153

124154
# End of script

0 commit comments

Comments
 (0)