-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupdate-all-github-ndemou-scripts.ps1
More file actions
177 lines (152 loc) · 6.09 KB
/
update-all-github-ndemou-scripts.ps1
File metadata and controls
177 lines (152 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
<#
.SYNOPSIS
Ensures all ndemou.github.io/scripts are up-to-date.
.DESCRIPTION
Existing files that differ are replaced and a backup is created.
Identical files are left unchanged.
#>
####################################################################
#
# START OF CONFIG
#
$DESTINATION_DIR = 'C:\it\bin'
$BACKUPS_DIR = 'C:\it\temp'
$DOWNLOAD_URI = 'https://ndemou.github.io/scripts'
#
# END OF CONFIG
#
####################################################################
####################################################################
#
# HELPER FUNCTIONS START
#
function New-EmptyTempDirectory {
<#
.SYNOPSIS
Creates a directory at "$env:TEMP\<Name>" and returns its full path.
.OUTPUTS
System.String, The full path of the created directory under $env:TEMP.
#>
[CmdletBinding()]param([string]$Name)
$tmpRoot = Join-Path $env:TEMP $Name
# If $tmpRoot already exists
if (Test-Path -Path $tmpRoot) {
# If it's a folder: Clear it out
if (Test-Path -Path $tmpRoot -PathType Container) {
Get-ChildItem -Path $tmpRoot -Recurse | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
}
# If it's a file: Find a unique 6-digit alternative name
else {
while (Test-Path -Path $tmpRoot) {
$suffix = Get-Random -Minimum 100000 -Maximum 1000000
$tmpRoot = Join-Path $env:TEMP "$Name-$suffix"
}
}
}
# Create the directory
$null = New-Item -ItemType Directory -Path $tmpRoot -Force
return $tmpRoot
}
function Sync-FileFromWeb {
<#
.SYNOPSIS
Downloads a file and updates the local copy if they differ.
.DESCRIPTION
Downloads file to TempPath and compares it to the file in DestinationPath.
If the destination file does not exist, the downloaded file is placed into
DestinationPath.
If the destination file exists and content is identical, the temp file is
removed, and the destination file remains unchanged.
If the destination file exists and content differs, the destination file is
replaced with the downloaded file and the function returns $true. When
replacing an existing file, the function attempts to create a per-file
backup archive in BackupPath; backup failures do not prevent the update.
Warnings are emitted on download or update failures.
.OUTPUTS
System.Boolean
$true - DestinationPath\FileName was created or replaced.
$false - No change occurred or the operation failed.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)][string]$FileName,
[Parameter(Mandatory=$true)][string]$BaseUri,
[Parameter(Mandatory=$true)][string]$TempPath, # This is the Directory
[Parameter(Mandatory=$true)][string]$DestinationPath,
[Parameter(Mandatory=$true)][string]$BackupPath
)
$srcUrl = "$BaseUri/$FileName"
$DownloadPath = Join-Path $TempPath $FileName
$finalPath = Join-Path $DestinationPath $FileName
$updated = $false
try {
Invoke-WebRequest -Uri $srcUrl -OutFile $DownloadPath -UseBasicParsing -ErrorAction Stop
$newHash = (Get-FileHash -Path $DownloadPath -Algorithm SHA256).Hash
$existingHash = $null
if (Test-Path $finalPath) {
try { $existingHash = (Get-FileHash -Path $finalPath -Algorithm SHA256).Hash } catch { $existingHash = $null }
}
$isDifferent = $true
if ($existingHash -ne $null -and $existingHash -eq $newHash) { $isDifferent = $false }
if ($isDifferent) {
if (Test-Path $finalPath) {
$leaf = Split-Path $finalPath -Leaf
$dateStr = (Get-Date -Format 'yyyyMMdd.hhmmss')
$first8 = if ($existingHash) { $existingHash.Substring(0,8) } else { 'NOHASH' }
$perFileZip = Join-Path $BackupPath ("{0}.{1}_{2}.zip" -f $leaf, $dateStr, $first8)
$stageDir = Join-Path $TempPath ("_bak_{0}_{1}" -f ($leaf -replace '[^\w\.-]','_'), $first8)
if (-not (Test-Path $stageDir)) { $null = New-Item -ItemType Directory -Path $stageDir }
$stageFile = Join-Path $stageDir $leaf
try {
Copy-Item -LiteralPath $finalPath -Destination $stageFile -Force
Compress-Archive -Path $stageFile -DestinationPath $perFileZip -Force
Write-Host -ForegroundColor DarkGray ("Per-file backup created: {0}" -f $perFileZip)
} catch {
Write-Warning ("Failed to create per-file backup for {0}: {1}" -f $leaf, $_.Exception.Message)
}
}
try {
Move-Item -LiteralPath $DownloadPath -Destination $finalPath -Force
Write-Host -ForegroundColor White ("Updated {0}" -f $finalPath)
$updated = $true
} catch {
Write-Warning ("Failed to update {0}: {1}" -f $finalPath, $_.Exception.Message)
try { if (Test-Path $DownloadPath) { Remove-Item -LiteralPath $DownloadPath -Force } } catch {}
}
} else {
Remove-Item -LiteralPath $DownloadPath -Force
Write-Verbose ("No change for {0}" -f $FileName)
$updated = $false
}
} catch {
$statusCode = $null
try { $statusCode = [int]$_.Exception.Response.StatusCode } catch { $statusCode = $null }
if ($statusCode -eq 404) {
Write-Host -ForegroundColor DarkGray ("Script not on the Web, skipping: {0}" -f $FileName)
} else {
Write-Warning ("Failed to download {0}: {1}" -f $srcUrl, $_.Exception.Message)
}
try { if (Test-Path $DownloadPath) { Remove-Item -LiteralPath $DownloadPath -Force } } catch {}
$updated = $false
}
return $updated
}
#
# HELPER FUNCTIONS END
#
####################################################################
####################################################################
#
# MAIN CODE
#
# Download/update scripts
# Write-Host -for DarkGray "Checking for code updates (I will backup & then overwrite local code if updates are found)"
$tmpRoot = New-EmptyTempDirectory -Name "update-all-scripts"
foreach ($file in (ls $DESTINATION_DIR\*.ps1).name) {
# Write-Host -for DarkGray "Checking $file"
$updated = Sync-FileFromWeb -FileName $file `
-BaseUri $DOWNLOAD_URI `
-TempPath $tmpRoot `
-DestinationPath $DESTINATION_DIR `
-BackupPath $BACKUPS_DIR
}