-
Notifications
You must be signed in to change notification settings - Fork 50
/
Install.ps1
373 lines (293 loc) · 10.9 KB
/
Install.ps1
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#
# PowerShell displays error messages regardless of whether you redirect it whatever you're executing to null.
# To prevent this from happening, disable all the output(s) by using PowerShell's default variables.
#
$ProgressPreference = 'SilentlyContinue'
$ErrorActionPreference = 'SilentlyContinue'
#
# There is no built-in function to update the (global) Windows env %PATH%. Instead, use this function to update
# the registry directly (https://stackoverflow.com/a/69239861).
#
function Add-Path {
param(
[Parameter(Mandatory, Position=0)]
[string] $LiteralPath,
[ValidateSet('User', 'CurrentUser', 'Machine', 'LocalMachine')]
[string] $Scope
)
Set-StrictMode -Version 1; $ErrorActionPreference = 'Stop'
$isMachineLevel = $Scope -in 'Machine', 'LocalMachine'
if ($isMachineLevel -and -not $($ErrorActionPreference = 'Continue'; net session 2>$null)) { throw "You must run AS ADMIN to update the machine-level Path environment variable." }
$regPath = 'registry::' + ('HKEY_CURRENT_USER\Environment', 'HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment')[$isMachineLevel]
$currDirs = (Get-Item -LiteralPath $regPath).GetValue('Path', '', 'DoNotExpandEnvironmentNames') -split ';' -ne ''
if ($LiteralPath -in $currDirs) {
return
}
$newValue = ($currDirs + $LiteralPath) -join ';'
Set-ItemProperty -Type ExpandString -LiteralPath $regPath Path $newValue
$dummyName = [guid]::NewGuid().ToString()
[Environment]::SetEnvironmentVariable($dummyName, 'foo', 'User')
[Environment]::SetEnvironmentVariable($dummyName, [NullString]::value, 'User')
$env:Path = ($env:Path -replace ';$') + ';' + $LiteralPath
}
#
# Function to remove items from PATH
#
function Remove-Path {
param(
[Parameter(Mandatory, Position=0)]
[string] $LiteralPath,
[ValidateSet('User', 'CurrentUser', 'Machine', 'LocalMachine')]
[string] $Scope
)
Set-StrictMode -Version 1; $ErrorActionPreference = 'Stop'
$isMachineLevel = $Scope -in 'Machine', 'LocalMachine'
if ($isMachineLevel -and -not $($ErrorActionPreference = 'Continue'; net session 2>$null)) { throw "You must run AS ADMIN to update the machine-level Path environment variable." }
# Get PATH
$path = [System.Environment]::GetEnvironmentVariable(
'PATH',
'User'
)
# Remove only unwanted elements
$path = ($path.Split(';') | Where-Object { ($_.TrimEnd('\') -ne $LiteralPath.TrimEnd('\')) } ) -join ';'
# Set it
[System.Environment]::SetEnvironmentVariable(
'PATH',
$path,
'User'
)
# Refresh PATH
$env:Path = [System.Environment]::GetEnvironmentVariable(
'PATH',
'User'
)
}
#
# Helper cleanup function, calls Remove-Path function
#
function Cleanup {
param(
[Parameter(Mandatory, Position=0)]
[string] $LiteralPath
)
if ($LiteralPath.EndsWith("realme-ota.bat")) {
LogToConsole 4 "Removing obsolete realme-bat file...: $LiteralPath"
Remove-Item -Path $LiteralPath
}
$targetPath = $LiteralPath.TrimEnd('realme-ota.bat')
if (($targetPath -match "realme-ota") -or ($targetPath -match "realme_ota")) {
LogToConsole 4 "Removing directory from PATH...: $targetPath"
Remove-Path $targetPath
}
}
#
# Small logger. Includes color-like and symbol-like verbosity.
# @param $verbosity: Logging verbosity (info, fail, success)
# @param $logmessage: Message to print to the console.
#
function LogToConsole {
Param
(
[Parameter(Mandatory = $true)] [int] $verbosity,
[Parameter(Mandatory = $true)] [string] $logmessage
)
Switch ($verbosity) {
1 {
Write-Host "[?] $logmessage" -ForegroundColor White
}
2 {
Write-Host "[-] $logmessage" -ForegroundColor Red
}
3 {
Write-Host "[+] $logmessage" -ForegroundColor Green
}
4 {
Write-Host "[!] $logmessage" -ForegroundColor Yellow
}
default {
Write-Host "[~] $logmessage" -ForegroundColor Gray
}
}
}
#
# We need special privilegies to install the script globally, if we don't have them, bail out.
#
$per = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if (-Not $per.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
LogToConsole 2 "You need privilegies to execute this script!"
} else {
#
# For some reason, Windows 10 (and 11) include different aliases that are used with priority when one
# of the defined keywords is detected. These include python and python3. By default, these aliases cause
# the Windows Store to open regardless of whether Python is installed or not. Since we can't really get
# rid of the aliasses, delete the python(3) Store shortcuts so it uses the real python executables.
#
Remove-Item $env:LOCALAPPDATA\Microsoft\WindowsApps\python.exe
Remove-Item $env:LOCALAPPDATA\Microsoft\WindowsApps\python3.exe
#
# Python installer
#
if ([string]::IsNullOrEmpty((Get-Command python.exe).Path)) {
LogToConsole 4 "Python is not installed!"
LogToConsole 1 "Downloading python..."
Invoke-WebRequest -Uri https://www.python.org/ftp/python/3.11.0/python-3.11.0-amd64.exe -OutFile PythonSetup.exe
if (-Not (Test-Path -Path PythonSetup.exe -PathType Leaf)) {
LogToConsole 2 "Unable to download python!"
exit 1
}
LogToConsole 1 "Installing python..."
Start-Process -Wait -FilePath "PythonSetup.exe" -ArgumentList "InstallAllUsers=1 PrependPath=1 /quiet /log log.txt"
try {
$PythonPath = (Get-Command python.exe).Path.Replace("python.exe", "")
}
catch {
LogToConsole 2 "Unable to install python (check log.txt for more details), please install manually!"
exit 1
}
if (-Not ($env:Path.Contains("Python"))) {
LogToConsole 4 "Adding python to the PATH..."
Add-Path $PythonPath
}
LogToConsole 3 "Successfully installed python!"
} else {
LogToConsole 3 "Found $(python.exe --version) installed"
$PythonPath = (Get-Command python.exe).Path.Replace("python.exe", "")
}
#
# Pip installer
#
if ([string]::IsNullOrEmpty((Get-Command pip.exe).Path)) {
LogToConsole 4 "Pip is not installed!"
LogToConsole 1 "Downloading pip..."
Invoke-WebRequest -Uri https://bootstrap.pypa.io/get-pip.py. -OutFile get-pip.py
if (!Test-Path -Path get-pip.py -PathType Leaf) {
LogToConsole 2 "Unable to download pip!"
exit 1
}
LogToConsole 1 "Installing pip..."
Start-Process -Wait -FilePath "python.exe" -ArgumentList "get-pip.py"
try {
$PipPath = (Get-Command pip.exe).Path.Replace("pip.exe", "")
if (-Not ($env:Path.Contains("Scripts"))) {
LogToConsole 4 "Adding scripts to the PATH..."
Add-Path $PipPath
}
}
catch {
LogToConsole 2 "Unable to install pip, please install manually!"
exit 1
}
LogToConsole 3 "Successfully installed pip!"
} else {
LogToConsole 3 "Found $(pip.exe --version)installed"
$PipPath = (Get-Command pip.exe).Path.Replace("pip.exe", "")
}
#
# Dependencies install
#
LogToConsole 1 "Installing Python modules: Requests and Pycryptodome..."
Start-Process -Wait -FilePath "python.exe" -ArgumentList "-m pip install requests pycryptodome"
Rename-Item -Path $PythonPath + 'Lib\site-packages\crypto' -NewName "Crypto"
#
# Obsolete .bat and PATH cleanup
# First pass removes .bat files found via CMD, second via PowerShell, third cleans PATH
# Only paths that contain "realme-ota" or "realme_ota" will be removed from PATH
#
[bool]$cleanup = 0
LogToConsole 1 "Checking for obsolete or invalid realme-ota files and PATH..."
# First pass
& cmd.exe /c cd %userprofile% "&" where realme-ota | ForEach-Object {
if ($_ -match "realme-ota.bat") {
$cleanup = 1
Cleanup $_
}
}
# Second pass
& (Get-Command realme-ota).Path | ForEach-Object {
if ($_ -match "realme-ota.bat") {
$cleanup = 1
Cleanup $_
}
}
# Third pass - check PATH
$env:Path.Split(';') | ForEach-Object {
if (($_ -match "realme-ota") -or ($_ -match "realme_ota")) {
$cleanup = 1
Cleanup $_
}
}
if ($cleanup -eq 1) {
LogToConsole 4 "Cleanup completed. You may need to remove obsolete directories manually."
}
else {
LogToConsole 3 "No cleanup required."
}
#
# Download Realme-Ota package from Github and extract to \Scripts\
#
if ([string]::IsNullOrEmpty($PipPath)) {
LogToConsole 2 "Pip path Python*\Scripts could not be found. Aborting..."
exit 1
}
else {
cd $PipPath
}
$oldPath = $PipPath + 'realme-ota\'
if (Test-Path $oldPath) {
LogToConsole 1 "Found previous realme-ota install in $oldPath"
do {
$confirmation = Read-Host "Do you want to remove previous realme-ota folder? [y/n]"
$confirmation = $confirmation.ToLower()
}
until (($confirmation -eq 'y') -or ($confirmation -eq 'n'))
if ($confirmation -eq 'y') {
Remove-Item $oldPath -Recurse -Force
LogToConsole 3 "Previous realme-ota was removed."
}
}
LogToConsole 4 "Downloading realme-ota..."
Invoke-WebRequest -Uri https://github.com/R0rt1z2/realme-ota/archive/refs/heads/master.zip -OutFile dist.zip
LogToConsole 4 "Extracting realme-ota..."
Expand-Archive dist.zip -DestinationPath realme-ota -Force; rm -Force dist.zip
LogToConsole 4 "Copying files..."
mv -Force realme-ota\realme-ota-master\* realme-ota\; rm -Force realme-ota\realme-ota-master
#
# Wrapper directory updater
# Replaces 'cd' in .bat file with path to where main.py is located
#
$RealmeOtaPath = $PipPath + 'realme-ota\realme_ota\'
$file = $RealmeOtaPath + 'realme-ota.bat'
$regex = 'cd\s"[^"]*"'
$target = 'cd ' + '"' + $RealmeOtaPath + '"'
try {
(Get-Content $file) -replace $regex, $target | Set-Content $file
LogToConsole 3 "Adjusted working directory in the realme-ota.bat to $target"
}
catch {
LogToConsole 2 "Failed to access realme-ota.bat file. Make sure the file exists and is in correct location of $PipPath\realme_ota\"
exit 1
}
#
# Add realme-ota.bat to PATH
#
if ([string]::IsNullOrEmpty((Get-Command realme-ota).Path)) {
if (-Not ($env:Path.Contains("realme-ota"))) {
LogToConsole 1 "Adding realme-ota to PATH..."
Add-Path $RealmeOtaPath
}
} else {
LogToConsole 3 "Found realme-ota in PATH already"
}
# Test if Windows finds .bat
try {
$BatPath = (Get-Command realme-ota).Path.Replace("realme-ota.bat", "")
LogToConsole 3 "Successfully installed realme-ota!"
LogToConsole 3 "Realme-ota was installed in $BatPath"
}
catch {
LogToConsole 2 "Realme-ota failed to be added to PATH, or Windows can't locate .bat file"
exit 1
}
cd ~
}
pause; exit 0