Skip to content

Commit 05cdf03

Browse files
Update Copy-and-Sync-Folder-to-ADComputers-viaGPO.ps1
Signed-off-by: LUIZ HAMILTON ROBERTO DA SILVA <luizhamilton.lhr@gmail.com>
1 parent e81d0cc commit 05cdf03

File tree

1 file changed

+71
-84
lines changed

1 file changed

+71
-84
lines changed
Lines changed: 71 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,141 @@
11
<#
22
.SYNOPSIS
3-
PowerShell script to synchronize folders from a network share to Active Directory 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 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.
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 no longer exist in the source.
99
Intended for use as a machine-level GPO startup script.
1010
1111
.AUTHOR
1212
Luiz Hamilton Silva - @brazilianscriptguy
1313
1414
.VERSION
15-
Updated: August 5, 2025 - Refactored for GPO startup context and system execution.
15+
Updated: August 6, 2025 - Enhanced for PSSA compliance and state safety
1616
#>
1717

1818
param (
1919
[string]$LogDirectory = "C:\Logs-TEMP"
2020
)
2121

22-
# Get the script name and define the full log path
22+
# === LOGGING SETUP ===
2323
$scriptName = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)
24-
$logFileName = "${scriptName}.log"
25-
$logPath = Join-Path $LogDirectory $logFileName
24+
$logPath = Join-Path $LogDirectory "$scriptName.log"
2625

27-
# Ensure the log directory exists
2826
if (-not (Test-Path $LogDirectory)) {
2927
try {
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."
28+
New-Item -Path $LogDirectory -ItemType Directory -Force -ErrorAction Stop | Out-Null
29+
} catch {
30+
Write-Error "Failed to create log directory at $LogDirectory. Logging disabled."
3431
exit 1
3532
}
3633
}
3734

38-
# Logging function with timestamp and severity
3935
function Write-Log {
4036
param (
41-
[Parameter(Mandatory = $true)][string]$Message,
42-
[string]$Severity = "INFO"
37+
[Parameter(Mandatory)][string]$Message,
38+
[ValidateSet("INFO", "ERROR", "WARNING")] [string]$Severity = "INFO"
4339
)
4440
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
45-
$logEntry = "[$timestamp] [$Severity] $Message"
41+
$entry = "[$timestamp] [$Severity] $Message"
42+
4643
try {
47-
Add-Content -Path $logPath -Value $logEntry -Encoding UTF8 -ErrorAction Stop
48-
}
49-
catch {
50-
Write-Error "Failed to write to log: $_"
44+
Add-Content -Path $logPath -Value $entry -Encoding UTF8
45+
} catch {
46+
Write-Error "Logging failed: $_"
5147
}
5248
}
5349

54-
# === CONFIGURATION ===
50+
# === PATH SETUP ===
51+
$sourceFolderPath = "\\forest-logonserver-name\NETLOGON\Source-Folder-Name"
52+
$adminProfilePath = "$env:SystemDrive\Users\Administrator"
53+
$adminDesktopPath = Join-Path $adminProfilePath "Desktop"
54+
$destinationFolderPath = Join-Path $adminDesktopPath "Destination-Folder-Name"
5555

56-
# Source network folder (change as needed)
57-
$sourceFolderPath = "\\forest-logonserver-name\NETLOGON\Source-Folder-Name"
58-
59-
# Determine Administrator profile path
60-
$adminProfilePath = "$env:SystemDrive\Users\Administrator"
61-
$adminDesktopPath = Join-Path $adminProfilePath "Desktop"
62-
63-
# Check if desktop path exists
64-
if (-not (Test-Path -Path $adminDesktopPath)) {
65-
Write-Log "Administrator desktop not found at: $adminDesktopPath" -Severity "ERROR"
56+
if (-not (Test-Path $adminDesktopPath)) {
57+
Write-Log "Administrator desktop path not found: $adminDesktopPath" -Severity "ERROR"
6658
exit 1
6759
}
6860

69-
# Define destination folder under Administrator desktop
70-
$destinationFolderPath = Join-Path -Path $adminDesktopPath -ChildPath "Destination-Folder-Name"
71-
72-
# === FOLDER SYNC FUNCTION ===
73-
61+
# === SYNC FUNCTION ===
7462
function Sync-Folders {
63+
[CmdletBinding(SupportsShouldProcess = $true)]
7564
param (
76-
[string]$sourceFolder,
77-
[string]$destinationFolder
65+
[Parameter(Mandatory)][string]$sourceFolder,
66+
[Parameter(Mandatory)][string]$destinationFolder
7867
)
7968

80-
# Create destination folder if it doesn't exist
81-
if (-not (Test-Path -Path $destinationFolder)) {
82-
try {
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"
88-
return
69+
# Create destination folder if needed
70+
if (-not (Test-Path $destinationFolder)) {
71+
if ($PSCmdlet.ShouldProcess($destinationFolder, "Create destination folder")) {
72+
try {
73+
New-Item -ItemType Directory -Path $destinationFolder -Force -ErrorAction Stop | Out-Null
74+
Write-Log "Created destination folder: $destinationFolder"
75+
} catch {
76+
Write-Log "Failed to create destination folder: $destinationFolder. $_" -Severity "ERROR"
77+
return
78+
}
8979
}
9080
}
9181

92-
# Copy new or updated files from source to destination
82+
# Sync files and folders
9383
$sourceItems = Get-ChildItem -Path $sourceFolder -Recurse -Force
9484
foreach ($item in $sourceItems) {
9585
$relativePath = $item.FullName.Substring($sourceFolder.Length).TrimStart('\')
96-
$destinationPath = Join-Path $destinationFolder $relativePath
86+
$destPath = Join-Path $destinationFolder $relativePath
9787

9888
if ($item.PSIsContainer) {
99-
if (-not (Test-Path -Path $destinationPath)) {
100-
try {
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"
89+
if (-not (Test-Path $destPath)) {
90+
if ($PSCmdlet.ShouldProcess($destPath, "Create directory")) {
91+
try {
92+
New-Item -ItemType Directory -Path $destPath -Force -ErrorAction Stop | Out-Null
93+
Write-Log "Created directory: $destPath"
94+
} catch {
95+
Write-Log "Failed to create directory: $destPath. $_" -Severity "ERROR"
96+
}
10697
}
10798
}
108-
}
109-
else {
99+
} else {
110100
try {
111-
$destItem = Get-Item -Path $destinationPath -ErrorAction SilentlyContinue
101+
$destItem = Get-Item -Path $destPath -ErrorAction SilentlyContinue
112102
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"
115-
}
116-
else {
117-
Write-Log "Skipped (already up-to-date): $destinationPath"
103+
if ($PSCmdlet.ShouldProcess($destPath, "Copy file")) {
104+
Copy-Item -Path $item.FullName -Destination $destPath -Force -ErrorAction Stop
105+
Write-Log "Copied/Updated: $destPath"
106+
}
107+
} else {
108+
Write-Log "Skipped (up-to-date): $destPath"
118109
}
119-
}
120-
catch {
121-
Write-Log "Failed to copy file: $destinationPath. Error: $_" -Severity "ERROR"
110+
} catch {
111+
Write-Log "Failed to copy: $destPath. $_" -Severity "ERROR"
122112
}
123113
}
124114
}
125115

126-
# Remove obsolete files/folders in destination that don't exist in source
116+
# Remove orphaned files/folders
127117
$destItems = Get-ChildItem -Path $destinationFolder -Recurse -Force
128118
foreach ($item in $destItems) {
129119
$relativePath = $item.FullName.Substring($destinationFolder.Length).TrimStart('\')
130120
$sourcePath = Join-Path $sourceFolder $relativePath
131121

132-
if (-not (Test-Path -Path $sourcePath)) {
133-
try {
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"
122+
if (-not (Test-Path $sourcePath)) {
123+
if ($PSCmdlet.ShouldProcess($item.FullName, "Remove obsolete item")) {
124+
try {
125+
Remove-Item -Path $item.FullName -Recurse -Force -ErrorAction Stop
126+
Write-Log "Removed obsolete: $($item.FullName)"
127+
} catch {
128+
Write-Log "Failed to remove obsolete: $($item.FullName). $_" -Severity "ERROR"
129+
}
139130
}
140131
}
141132
}
142133
}
143134

144135
# === EXECUTION ===
145-
146-
if (Test-Path -Path $sourceFolderPath) {
136+
if (Test-Path $sourceFolderPath) {
147137
Sync-Folders -sourceFolder $sourceFolderPath -destinationFolder $destinationFolderPath
148-
Write-Log "Synchronization completed successfully to $destinationFolderPath."
138+
Write-Log "Synchronization completed to $destinationFolderPath"
139+
} else {
140+
Write-Log "Source folder missing: $sourceFolderPath" -Severity "ERROR"
149141
}
150-
else {
151-
Write-Log "Source folder not found: $sourceFolderPath" -Severity "ERROR"
152-
}
153-
154-
# End of script

0 commit comments

Comments
 (0)