This commit is contained in:
Vasyl Palamarchuk
2026-09-09 11:19:27 -07:00
parent 4d54318001
commit 8b6a618b5d
3 changed files with 151 additions and 20 deletions
+109 -18
View File
@@ -104,6 +104,7 @@ function Import-SetupConfiguration {
}
$Configuration = @{
AppCatalog = if (Test-Path -LiteralPath (Join-Path $PSScriptRoot 'Config\app-catalog.json') -PathType Leaf) { Import-SetupConfiguration -Name 'app-catalog.json' } else { $null }
CorePackages = Import-SetupConfiguration -Name 'apps-core.json'
OptionalApps = Import-SetupConfiguration -Name 'apps-optional.json'
PortableApps = Import-SetupConfiguration -Name 'portable-apps.json'
@@ -112,6 +113,19 @@ $Configuration = @{
Profiles = Import-SetupConfiguration -Name 'workstation-profiles.json'
Automotive = Import-SetupConfiguration -Name 'automotive-resources.json'
}
function Get-ProfileCatalogItems {
param(
[Parameter(Mandatory)][object[]]$Items,
[Parameter(Mandatory)][string]$Channel
)
$profileFolder = $Profile.Folder
return @($Items | Where-Object {
$_.Channel -eq $Channel -and
((-not $_.PSObject.Properties['Profiles']) -or @($_.Profiles) -contains $profileFolder)
})
}
$Profile = @($Configuration.Profiles.Profiles | Where-Object { $_.Name -eq $WorkstationProfile } | Select-Object -First 1)
if ($Profile.Count -ne 1) {
throw "Workstation profile '$WorkstationProfile' is not defined in Config\workstation-profiles.json."
@@ -313,8 +327,10 @@ function Invoke-ReliableDownload {
[Parameter(Mandatory)][string]$Uri,
[Parameter(Mandatory)][string]$Destination,
[hashtable]$Headers = @{},
[switch]$UseCurl
[switch]$UseCurl,
[switch]$AllowInsecureHttp
)
Test-DownloadUri -Uri $Uri -AllowInsecureHttp:$AllowInsecureHttp
$partial = "$Destination.partial"
$lastError = $null
for ($attempt = 1; $attempt -le $DownloadRetryCount; $attempt++) {
@@ -519,6 +535,48 @@ function Get-HWiNFOPortableUri {
return $portableUri
}
function Test-DownloadUri {
param(
[Parameter(Mandatory)][string]$Uri,
[switch]$AllowInsecureHttp
)
$parsedUri = [Uri]$Uri
if ($parsedUri.Scheme -eq 'https') { return }
if ($parsedUri.Scheme -eq 'http' -and $AllowInsecureHttp) {
Write-Log "Using explicitly approved HTTP download: $Uri" 'WARN'
return
}
throw "Insecure download blocked: $Uri. Use HTTPS or explicitly approve this documented vendor exception."
}
function Test-DownloadedFile {
param(
[Parameter(Mandatory)][string]$Path,
[Parameter(Mandatory)][string]$Name,
[int64]$MinimumBytes = 65536,
[string]$ExpectedSHA256,
[switch]$RequireAuthenticode
)
$file = Get-Item -LiteralPath $Path -ErrorAction Stop
if ($file.Length -lt $MinimumBytes) {
throw "$Name download is unexpectedly small: $($file.Length) bytes; minimum is $MinimumBytes."
}
if (-not [string]::IsNullOrWhiteSpace($ExpectedSHA256) -and $ExpectedSHA256 -notmatch '(?i)^TO_BE_FILLED') {
$actualHash = (Get-FileHash -LiteralPath $Path -Algorithm SHA256 -ErrorAction Stop).Hash
if ($actualHash -ne $ExpectedSHA256.ToUpperInvariant()) {
throw "$Name SHA256 mismatch. Expected $ExpectedSHA256, received $actualHash."
}
Write-Log "$Name SHA256 verified: $actualHash" 'OK'
}
if ($file.Extension -in @('.exe', '.dll')) {
$signature = Get-AuthenticodeSignature -LiteralPath $Path
if ($signature.Status -ne 'Valid') {
if ($RequireAuthenticode) { throw "$Name Authenticode signature is not valid: $($signature.Status)." }
Write-Log "$Name has no valid Authenticode signature: $($signature.Status)." 'WARN'
}
}
}
function Install-PortableArchive {
param(
[Parameter(Mandatory)][string]$Name,
@@ -528,7 +586,10 @@ function Install-PortableArchive {
[string]$ArchiveName = '',
[switch]$FlattenSingleDirectory,
[hashtable]$Headers = @{},
[switch]$DownloadWithCurl
[switch]$DownloadWithCurl,
[string]$ExpectedSHA256,
[switch]$AllowInsecureHttp,
[switch]$RequireAuthenticode
)
$downloadName = if ($ArchiveName) { $ArchiveName } else { [IO.Path]::GetFileName(([Uri]$Uri).AbsolutePath) }
if (-not $downloadName) { $downloadName = ($Name -replace '[^A-Za-z0-9._-]','_') + '.zip' }
@@ -538,6 +599,7 @@ function Install-PortableArchive {
Remove-Item -LiteralPath $staging -Recurse -Force -ErrorAction SilentlyContinue
$null = New-Item -ItemType Directory -Path $staging -Force
try {
Test-DownloadUri -Uri $Uri -AllowInsecureHttp:$AllowInsecureHttp
Invoke-ReliableDownload -Name $Name -Uri $Uri -Destination $archive -Headers $Headers -UseCurl:$DownloadWithCurl
}
catch {
@@ -547,7 +609,7 @@ function Install-PortableArchive {
}
$archiveSize = (Get-Item -LiteralPath $archive).Length
Write-Log "$Name portable archive downloaded: $archiveSize bytes"
if ($archiveSize -lt 64KB) { throw "$Name download is unexpectedly small." }
Test-DownloadedFile -Path $archive -Name $Name -MinimumBytes 65536 -ExpectedSHA256 $ExpectedSHA256
if ([IO.Path]::GetExtension($archive) -ne '.zip') { throw "$Name archive must be ZIP for safe native extraction." }
Expand-Archive -LiteralPath $archive -DestinationPath $staging -Force
@@ -579,7 +641,10 @@ function Install-PortableExecutable {
[Parameter(Mandatory)][string]$Name,
[Parameter(Mandatory)][string]$Uri,
[Parameter(Mandatory)][string]$Destination,
[Parameter(Mandatory)][string]$FileName
[Parameter(Mandatory)][string]$FileName,
[string]$ExpectedSHA256,
[switch]$AllowInsecureHttp,
[switch]$RequireAuthenticode
)
$null = New-Item -ItemType Directory -Path $Destination -Force
$target = Join-Path $Destination $FileName
@@ -587,8 +652,9 @@ function Install-PortableExecutable {
$backup = "$target.previous"
Remove-Item -LiteralPath $temporary -Force -ErrorAction SilentlyContinue
try {
Test-DownloadUri -Uri $Uri -AllowInsecureHttp:$AllowInsecureHttp
Invoke-ReliableDownload -Name $Name -Uri $Uri -Destination $temporary
if ((Get-Item -LiteralPath $temporary).Length -lt 64KB) { throw "$Name download is unexpectedly small." }
Test-DownloadedFile -Path $temporary -Name $Name -MinimumBytes 65536 -ExpectedSHA256 $ExpectedSHA256 -RequireAuthenticode:$RequireAuthenticode
Remove-Item -LiteralPath $backup -Force -ErrorAction SilentlyContinue
if (Test-Path -LiteralPath $target) { Move-Item -LiteralPath $target -Destination $backup -Force }
Move-Item -LiteralPath $temporary -Destination $target -Force
@@ -892,8 +958,17 @@ Complete-SetupPhase -Phase 'SharedPartitions' -Details "DataRoot=$SharedDataRoot
# 3. Portable applications are installed after WinGet so archive prerequisites are available.
# 4. Core applications. WinGet uses package manifests and each vendor's installer.
$CorePackages = $Configuration.CorePackages
$OptionalPackages = $Configuration.OptionalApps.Packages
$catalogPackages = if ($Configuration.AppCatalog) { @($Configuration.AppCatalog.Packages) } else { @() }
$CorePackages = if ($catalogPackages.Count -gt 0) {
Get-ProfileCatalogItems -Items $catalogPackages -Channel 'Core'
} else {
@($Configuration.CorePackages)
}
$OptionalPackages = if ($catalogPackages.Count -gt 0) {
Get-ProfileCatalogItems -Items $catalogPackages -Channel 'Optional'
} else {
@($Configuration.OptionalApps.Packages)
}
if (-not $SkipWinget) {
Invoke-Safe 'WinGet' 'Refresh package sources' {
@@ -948,11 +1023,13 @@ if (-not $SkipDownloads) {
$createShortcut = $null -eq $configuredApp.Shortcut -or [bool]$configuredApp.Shortcut
$flattenSingleDirectory = if ($configuredApp.PSObject.Properties['Flatten']) { [bool]$configuredApp.Flatten } else { -not $isDirectExe }
$downloadWithCurl = [bool]($configuredApp.PSObject.Properties['DownloadWithCurl'] -and $configuredApp.DownloadWithCurl)
$expectedSHA256 = if ($configuredApp.PSObject.Properties['ExpectedSHA256']) { [string]$configuredApp.ExpectedSHA256 } else { '' }
$requireAuthenticode = [bool]($configuredApp.PSObject.Properties['RequireAuthenticode'] -and $configuredApp.RequireAuthenticode)
if (-not $ForcePortableUpdates -and (Test-PortableInstallation -Destination $destination -ExpectedExecutable $configuredApp.Executable)) {
$PortableDefinitions.Add([pscustomobject]@{
Name=$configuredApp.Name; Type=if ($isDirectExe) { 'Exe' } else { 'Zip' }; Uri=''; Folder=$configuredApp.Folder;
Executable=$configuredApp.Executable; Archive=''; Flatten=$flattenSingleDirectory; Shortcut=$createShortcut;
DownloadWithCurl=$downloadWithCurl
DownloadWithCurl=$downloadWithCurl; ExpectedSHA256=$expectedSHA256; RequireAuthenticode=$requireAuthenticode
})
Add-Result 'PortableResolve' $configuredApp.Name 'Skipped' "Validated installation already exists: $destination"
Write-Log "$($configuredApp.Name) release lookup skipped because its portable installation is already validated." 'INFO'
@@ -963,7 +1040,8 @@ if (-not $SkipDownloads) {
$asset = Get-ChromeForTestingAsset -Platform $configuredApp.Platform
$PortableDefinitions.Add([pscustomobject]@{
Name=$configuredApp.Name; Type='Zip'; Uri=$asset.url; Folder=$configuredApp.Folder;
Executable=$configuredApp.Executable; Archive=$configuredApp.Archive; Flatten=[bool]$configuredApp.Flatten; Shortcut=$createShortcut
Executable=$configuredApp.Executable; Archive=$configuredApp.Archive; Flatten=[bool]$configuredApp.Flatten; Shortcut=$createShortcut;
ExpectedSHA256=$expectedSHA256; RequireAuthenticode=$requireAuthenticode
})
} | Out-Null
}
@@ -972,7 +1050,8 @@ if (-not $SkipDownloads) {
$asset = Get-GitHubReleaseAsset -Repository $configuredApp.Repository -AssetRegex $configuredApp.Regex
$PortableDefinitions.Add([pscustomobject]@{
Name=$configuredApp.Name; Type=if ($isDirectExe) { 'Exe' } else { 'Zip' }; Uri=$asset.browser_download_url; Folder=$configuredApp.Folder;
Executable=$configuredApp.Executable; Archive=if ($isDirectExe) { '' } else { $asset.name }; Flatten=(-not $isDirectExe); Shortcut=$createShortcut
Executable=$configuredApp.Executable; Archive=if ($isDirectExe) { '' } else { $asset.name }; Flatten=(-not $isDirectExe); Shortcut=$createShortcut;
ExpectedSHA256=$expectedSHA256; RequireAuthenticode=$requireAuthenticode
})
} | Out-Null
}
@@ -980,7 +1059,7 @@ if (-not $SkipDownloads) {
$PortableDefinitions.Add([pscustomobject]@{
Name=$configuredApp.Name; Type=if ($isDirectExe) { 'Exe' } else { 'Zip' }; Uri=$configuredApp.Uri; Folder=$configuredApp.Folder;
Executable=$configuredApp.Executable; Archive=$configuredApp.Archive; Flatten=$flattenSingleDirectory; Shortcut=$createShortcut;
DownloadWithCurl=$downloadWithCurl
DownloadWithCurl=$downloadWithCurl; ExpectedSHA256=$expectedSHA256; RequireAuthenticode=$requireAuthenticode
})
}
}
@@ -994,14 +1073,15 @@ if (-not $SkipDownloads) {
else {
Invoke-Safe 'PortableInstall' $app.Name {
if ($app.Type -eq 'Exe') {
Install-PortableExecutable -Name $app.Name -Uri $app.Uri -Destination $destination -FileName $app.Executable
Install-PortableExecutable -Name $app.Name -Uri $app.Uri -Destination $destination -FileName $app.Executable `
-ExpectedSHA256 $app.ExpectedSHA256 -RequireAuthenticode:$app.RequireAuthenticode
}
else {
$requestHeaders = if ($app.PSObject.Properties['Headers']) { $app.Headers } else { @{} }
$downloadWithCurl = $app.PSObject.Properties['DownloadWithCurl'] -and $app.DownloadWithCurl
Install-PortableArchive -Name $app.Name -Uri $app.Uri -Destination $destination `
-ExpectedExecutable $app.Executable -ArchiveName $app.Archive -FlattenSingleDirectory:$app.Flatten `
-Headers $requestHeaders -DownloadWithCurl:$downloadWithCurl
-Headers $requestHeaders -DownloadWithCurl:$downloadWithCurl -ExpectedSHA256 $app.ExpectedSHA256
}
} | Out-Null
}
@@ -1040,7 +1120,13 @@ if (-not $SkipDownloads) {
# Extensions are installed only after portable Code.exe and its data directory exist.
# They support offline binary inspection and embedded-module development only.
$vsCodeExtensions = @($Configuration.OptionalApps.VSCodeExtensions)
$vsCodeExtensions = if ($Configuration.AppCatalog -and @($Configuration.AppCatalog.VSCodeExtensions).Count -gt 0) {
@($Configuration.AppCatalog.VSCodeExtensions | Where-Object {
(-not $_.PSObject.Properties['Profiles']) -or @($_.Profiles) -contains $Profile.Folder
})
} else {
@($Configuration.OptionalApps.VSCodeExtensions)
}
try {
$installedVSCodeExtensions = Get-InstalledVSCodeExtensions -CodeExecutable (Join-Path $vsCodeRoot 'Code.exe')
Write-Log "Found $($installedVSCodeExtensions.Count) installed VS Code extensions."
@@ -1471,7 +1557,9 @@ Multi-PROG for the selected device, and preserve multiple verified original back
$multiProgSoftwareRoot = Join-Path $ProfileInstallerRoot 'Xhorse\Multi-PROG'
$null = New-Item -ItemType Directory -Path $multiProgSoftwareRoot -Force
$installerPath = Join-Path $multiProgSoftwareRoot 'Multi-PROG.exe'
Invoke-ReliableDownload -Name 'Xhorse Multi-PROG installer' -Uri $Configuration.Automotive.Installers[0].Uri -Destination $installerPath
$multiProg = $Configuration.Automotive.Installers | Where-Object { $_.Name -eq 'Multi-PROG' } | Select-Object -First 1
if (-not $multiProg) { throw 'Multi-PROG installer is not defined in automotive-resources.json.' }
Invoke-ReliableDownload -Name 'Xhorse Multi-PROG installer' -Uri $multiProg.Uri -Destination $installerPath -AllowInsecureHttp
if ((Get-Item -LiteralPath $installerPath).Length -lt 1MB) { throw 'Multi-PROG installer download is unexpectedly small.' }
Unblock-File -LiteralPath $installerPath -ErrorAction SilentlyContinue
Write-Log 'Multi-PROG installer downloaded. Launching interactive setup; connect the Multi-PROG dongle only when the wizard prompts for it.' 'WARN'
@@ -1483,11 +1571,13 @@ Multi-PROG for the selected device, and preserve multiple verified original back
$null = New-Item -ItemType Directory -Path $mvciSoftwareRoot -Force
$installerPath = Join-Path $mvciSoftwareRoot 'MVCI_PRO-J2534.exe'
# Xhorse's MVCI PRO CDN rejects HTTPS (403); HTTP is the vendor's only working transport for this asset.
Invoke-ReliableDownload -Name 'Xhorse MVCI PRO installer' -Uri $Configuration.Automotive.Installers[1].Uri -Destination $installerPath
$mvci = $Configuration.Automotive.CommunicationSoftware | Where-Object { $_.Name -eq 'MVCI PRO J2534' } | Select-Object -First 1
if (-not $mvci) { throw 'MVCI PRO J2534 is not defined in automotive-resources.json.' }
Invoke-ReliableDownload -Name 'Xhorse MVCI PRO installer' -Uri $mvci.Uri -Destination $installerPath -AllowInsecureHttp:$mvci.AllowInsecureHttp
if ((Get-Item -LiteralPath $installerPath).Length -lt 1MB) { throw 'MVCI PRO installer download is unexpectedly small.' }
$manualPath = Join-Path $mvciSoftwareRoot 'MVCI-PRO-User-Manual.pdf'
try {
Invoke-ReliableDownload -Name 'Xhorse MVCI PRO user manual' -Uri 'http://dl.xhorse.com/p/vd06/userManual.pdf' -Destination $manualPath
Invoke-ReliableDownload -Name 'Xhorse MVCI PRO user manual' -Uri 'http://dl.xhorse.com/p/vd06/userManual.pdf' -Destination $manualPath -AllowInsecureHttp
}
catch {
Write-Log "MVCI PRO user manual download failed (non-critical): $($_.Exception.Message)" 'WARN'
@@ -1508,7 +1598,8 @@ Multi-PROG for the selected device, and preserve multiple verified original back
$mvciRoot = Join-Path $ProfileInstallerRoot $mvci.Folder
$null = New-Item -ItemType Directory -Path $mvciRoot -Force
$mvciPath = Join-Path $mvciRoot $mvci.FileName
Invoke-ReliableDownload -Name $mvci.Name -Uri $mvci.Uri -Destination $mvciPath
if ($mvci.RequiresVpn) { Write-Log "$($mvci.Name) requires the vendor/VPN network path before downloading." 'WARN' }
Invoke-ReliableDownload -Name $mvci.Name -Uri $mvci.Uri -Destination $mvciPath -AllowInsecureHttp:$mvci.AllowInsecureHttp
if ((Get-Item -LiteralPath $mvciPath).Length -lt [int64]$mvci.MinimumBytes) { throw 'MVCI PRO installer is unexpectedly small.' }
Unblock-File -LiteralPath $mvciPath -ErrorAction SilentlyContinue
Write-Log 'MVCI PRO J2534 installer downloaded. Launching interactive setup for this Windows installation; connect the interface only when prompted.' 'WARN'
+41
View File
@@ -0,0 +1,41 @@
{
"SchemaVersion": "2.0",
"Packages": [
{ "Id": "7zip.7zip", "Name": "7-Zip", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "voidtools.Everything", "Name": "Everything Search", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Notepad++.Notepad++", "Name": "Notepad++", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Microsoft.VisualStudioCode", "Name": "Visual Studio Code", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Git.Git", "Name": "Git", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Python.Python.3.13", "Name": "Python 3.13", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Microsoft.PowerShell", "Name": "PowerShell 7", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Microsoft.PowerToys", "Name": "Microsoft PowerToys", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "PuTTY.PuTTY", "Name": "PuTTY", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "WinSCP.WinSCP", "Name": "WinSCP", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "WiresharkFoundation.Wireshark", "Name": "Wireshark", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Rufus.Rufus", "Name": "Rufus", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Ventoy.Ventoy", "Name": "Ventoy", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "CrystalDewWorld.CrystalDiskInfo", "Name": "CrystalDiskInfo", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "CPUID.CPU-Z", "Name": "CPU-Z", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "TechPowerUp.GPU-Z", "Name": "GPU-Z", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "GnuWin32.Make", "Name": "GNU Make", "Channel": "Optional", "Profiles": ["DailyTech-Tuning"] },
{ "Id": "Kitware.CMake", "Name": "CMake", "Channel": "Optional", "Profiles": ["DailyTech-Tuning"] },
{ "Id": "OpenJS.NodeJS.LTS", "Name": "Node.js LTS", "Channel": "Optional", "Profiles": ["DailyTech-Tuning"] },
{ "Id": "Postman.Postman", "Name": "Postman", "Channel": "Optional", "Profiles": ["DailyTech-Tuning"] },
{ "Id": "Microsoft.WindowsTerminal", "Name": "Windows Terminal", "Channel": "Core", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "Oracle.VirtualBox", "Name": "VirtualBox", "Channel": "Optional", "Profiles": ["DailyTech-Tuning"] },
{ "Id": "VideoLAN.VLC", "Name": "VLC", "Channel": "Optional", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "SumatraPDF.SumatraPDF", "Name": "SumatraPDF", "Channel": "Optional", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] }
],
"VSCodeExtensions": [
{ "Id": "ms-vscode.hexeditor", "Name": "Hex Editor", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "ms-vscode.vscode-serial-monitor", "Name": "Serial Monitor", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "ms-python.python", "Name": "Python", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "ms-vscode.cpptools", "Name": "C/C++", "Profiles": ["DailyTech-Tuning"] },
{ "Id": "ms-vscode.cmake-tools", "Name": "CMake Tools", "Profiles": ["DailyTech-Tuning"] },
{ "Id": "ms-vscode.makefile-tools", "Name": "Makefile Tools", "Profiles": ["DailyTech-Tuning"] },
{ "Id": "ms-vscode.powershell", "Name": "PowerShell", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "redhat.vscode-yaml", "Name": "YAML", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "redhat.vscode-xml", "Name": "XML", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] },
{ "Id": "tamasfe.even-better-toml", "Name": "Even Better TOML", "Profiles": ["DailyTech-Tuning", "ODIS-XENTRY", "PIWIS-ISTA"] }
]
}
+1 -2
View File
@@ -7,11 +7,10 @@
],
"Installers": [
{ "Name": "Multi-PROG", "FileName": "Multi-PROG.exe", "Folder": "Xhorse\\Multi-PROG", "Uri": "http://dl.xhorse.com/product/multiProg/Multi-PROG.exe" },
{ "Name": "MVCI PRO J2534", "FileName": "MVCI_PRO-J2534.exe", "Folder": "Xhorse\\MVCI-PRO", "Uri": "http://dl.xhorse.com/product/mvci/MVCI_PRO-J2534.exe" },
{ "Name": "VVDI-MLB", "FileName": "VVDI-MLB.exe", "Folder": "Xhorse\\VVDI-MLB", "Uri": "http://dl.xhorse.com/product/vvdi-mlb/VVDI-MLB.exe" }
],
"CommunicationSoftware": [
{ "Name": "MVCI PRO J2534", "FileName": "MVCI_PRO-J2534.exe", "Folder": "Xhorse\\MVCI-PRO", "Uri": "http://dl.xhorse.com/product/mvci/MVCI_PRO-J2534.exe", "MinimumBytes": 1048576 },
{ "Name": "MVCI PRO J2534", "FileName": "MVCI_PRO-J2534.exe", "Folder": "Xhorse\\MVCI-PRO", "Uri": "http://dl.xhorse.com/product/mvci/MVCI_PRO-J2534.exe", "MinimumBytes": 1048576, "AllowInsecureHttp": true, "RequiresVpn": true },
{ "Name": "Autel Maxi PC Suite", "FileName": "MaxiPCSuite_V1.50.zip", "Folder": "Autel\\Maxi-PC-Suite", "Uri": "https://autel.us/wp-content/uploads/MaxiPCSuite_V1.50.zip", "DownloadPage": "https://autel.us/software-downloads/", "MinimumBytes": 1048576 }
],
"References": [