New script to generate ventoy's menu system.
This commit is contained in:
parent
71b1c70596
commit
0c06a1483c
1 changed files with 360 additions and 0 deletions
360
generate-ventoy-json.ps1
Normal file
360
generate-ventoy-json.ps1
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
# generate-ventoy-json.ps1
|
||||
# Scans the iso-library directory tree and produces a ventoy.json menu structure.
|
||||
# Usage: .\generate-ventoy-json.ps1 [-IsoRoot <path>] [-OutFile <path>] [-VentoyDrive <letter>]
|
||||
|
||||
param(
|
||||
[string]$IsoRoot = ".\iso-library",
|
||||
[string]$OutFile = ".\ventoy.json",
|
||||
[string]$VentoyDrive = "E" # drive letter of your Ventoy USB
|
||||
)
|
||||
|
||||
# ── Friendly display names for OS canonical slugs ──────────────────────────────
|
||||
$displayNames = @{
|
||||
'windows' = 'Windows'
|
||||
'windows-server' = 'Windows Server'
|
||||
'ms-dos' = 'MS-DOS'
|
||||
'reactos' = 'ReactOS'
|
||||
'rhel' = 'Red Hat Enterprise Linux'
|
||||
'centos' = 'CentOS'
|
||||
'centos-stream' = 'CentOS Stream'
|
||||
'rocky' = 'Rocky Linux'
|
||||
'almalinux' = 'AlmaLinux'
|
||||
'oraclelinux' = 'Oracle Linux'
|
||||
'scientific' = 'Scientific Linux'
|
||||
'eurolinux' = 'EuroLinux'
|
||||
'fedora' = 'Fedora'
|
||||
'qubes' = 'Qubes OS'
|
||||
'opensuse-leap' = 'openSUSE Leap'
|
||||
'opensuse-tumbleweed' = 'openSUSE Tumbleweed'
|
||||
'opensuse-microos' = 'openSUSE MicroOS'
|
||||
'opensuse' = 'openSUSE'
|
||||
'sles' = 'SUSE Linux Enterprise'
|
||||
'debian' = 'Debian'
|
||||
'ubuntu' = 'Ubuntu'
|
||||
'ubuntu-mate' = 'Ubuntu MATE'
|
||||
'ubuntu-budgie' = 'Ubuntu Budgie'
|
||||
'ubuntu-kylin' = 'Ubuntu Kylin'
|
||||
'ubuntu-studio' = 'Ubuntu Studio'
|
||||
'ubuntu-unity' = 'Ubuntu Unity'
|
||||
'lubuntu' = 'Lubuntu'
|
||||
'kubuntu' = 'Kubuntu'
|
||||
'xubuntu' = 'Xubuntu'
|
||||
'linuxmint' = 'Linux Mint'
|
||||
'lmde' = 'Linux Mint Debian Edition'
|
||||
'pop_os' = 'Pop!_OS'
|
||||
'elementary' = 'elementary OS'
|
||||
'zorin' = 'Zorin OS'
|
||||
'kali' = 'Kali Linux'
|
||||
'parrot' = 'Parrot OS'
|
||||
'backbox' = 'BackBox'
|
||||
'tails' = 'Tails'
|
||||
'whonix' = 'Whonix'
|
||||
'raspios' = 'Raspberry Pi OS'
|
||||
'armbian' = 'Armbian'
|
||||
'devuan' = 'Devuan'
|
||||
'mx' = 'MX Linux'
|
||||
'antix' = 'antiX'
|
||||
'deepin' = 'Deepin'
|
||||
'pureos' = 'PureOS'
|
||||
'grml' = 'GRML'
|
||||
'libreelec' = 'LibreELEC'
|
||||
'arch' = 'Arch Linux'
|
||||
'manjaro' = 'Manjaro'
|
||||
'endeavouros' = 'EndeavourOS'
|
||||
'garuda' = 'Garuda Linux'
|
||||
'artix' = 'Artix Linux'
|
||||
'cachyos' = 'CachyOS'
|
||||
'gentoo' = 'Gentoo'
|
||||
'void' = 'Void Linux'
|
||||
'nixos' = 'NixOS'
|
||||
'alpine' = 'Alpine Linux'
|
||||
'solus' = 'Solus'
|
||||
'clearlinux' = 'Clear Linux'
|
||||
'flatcar' = 'Flatcar'
|
||||
'coreos' = 'Fedora CoreOS'
|
||||
'slackware' = 'Slackware'
|
||||
'pfsense' = 'pfSense'
|
||||
'opnsense' = 'OPNsense'
|
||||
'ipfire' = 'IPFire'
|
||||
'vyos' = 'VyOS'
|
||||
'openwrt' = 'OpenWrt'
|
||||
'proxmox-ve' = 'Proxmox VE'
|
||||
'proxmox-bs' = 'Proxmox Backup Server'
|
||||
'proxmox-mg' = 'Proxmox Mail Gateway'
|
||||
'esxi' = 'VMware ESXi'
|
||||
'vsphere' = 'VMware vSphere'
|
||||
'xcp-ng' = 'XCP-ng'
|
||||
'xenserver' = 'XenServer'
|
||||
'harvester' = 'Harvester'
|
||||
'freebsd' = 'FreeBSD'
|
||||
'openbsd' = 'OpenBSD'
|
||||
'netbsd' = 'NetBSD'
|
||||
'dragonflybsd' = 'DragonFly BSD'
|
||||
'truenas-scale' = 'TrueNAS SCALE'
|
||||
'truenas-core' = 'TrueNAS CORE'
|
||||
'truenas' = 'TrueNAS'
|
||||
'ghostbsd' = 'GhostBSD'
|
||||
'openindiana' = 'OpenIndiana'
|
||||
'omnios' = 'OmniOS'
|
||||
'smartos' = 'SmartOS'
|
||||
'haiku' = 'Haiku'
|
||||
'freedos' = 'FreeDOS'
|
||||
'clonezilla' = 'Clonezilla'
|
||||
'systemrescue' = 'SystemRescue'
|
||||
'gparted' = 'GParted Live'
|
||||
'memtest' = 'Memtest+'
|
||||
'memtest86' = 'Memtest86'
|
||||
'rescuezilla' = 'Rescuezilla'
|
||||
'hirens' = "Hiren's BootCD"
|
||||
'winpe' = 'WinPE'
|
||||
'dban' = 'DBAN'
|
||||
'kaspersky-rescue' = 'Kaspersky Rescue Disk'
|
||||
'bitdefender-rescue'= 'Bitdefender Rescue'
|
||||
'eset-rescue' = 'ESET SysRescue'
|
||||
}
|
||||
|
||||
# ── Category groupings — slug prefix -> menu group ────────────────────────────
|
||||
$categoryMap = [ordered]@{
|
||||
'windows' = 'Windows'
|
||||
'windows-server'= 'Windows'
|
||||
'ms-dos' = 'Windows'
|
||||
'reactos' = 'Windows'
|
||||
'rhel' = 'RHEL Family'
|
||||
'centos' = 'RHEL Family'
|
||||
'rocky' = 'RHEL Family'
|
||||
'almalinux' = 'RHEL Family'
|
||||
'oraclelinux' = 'RHEL Family'
|
||||
'scientific' = 'RHEL Family'
|
||||
'eurolinux' = 'RHEL Family'
|
||||
'navylinux' = 'RHEL Family'
|
||||
'fedora' = 'Fedora Family'
|
||||
'qubes' = 'Fedora Family'
|
||||
'coreos' = 'Fedora Family'
|
||||
'opensuse' = 'SUSE Family'
|
||||
'sles' = 'SUSE Family'
|
||||
'geckolinux' = 'SUSE Family'
|
||||
'debian' = 'Debian Family'
|
||||
'ubuntu' = 'Ubuntu Family'
|
||||
'lubuntu' = 'Ubuntu Family'
|
||||
'kubuntu' = 'Ubuntu Family'
|
||||
'xubuntu' = 'Ubuntu Family'
|
||||
'linuxmint' = 'Ubuntu Family'
|
||||
'lmde' = 'Debian Family'
|
||||
'pop_os' = 'Ubuntu Family'
|
||||
'elementary' = 'Ubuntu Family'
|
||||
'zorin' = 'Ubuntu Family'
|
||||
'kali' = 'Security'
|
||||
'parrot' = 'Security'
|
||||
'backbox' = 'Security'
|
||||
'tails' = 'Security'
|
||||
'whonix' = 'Security'
|
||||
'blackarch' = 'Security'
|
||||
'raspios' = 'Debian Family'
|
||||
'armbian' = 'Debian Family'
|
||||
'devuan' = 'Debian Family'
|
||||
'mx' = 'Debian Family'
|
||||
'antix' = 'Debian Family'
|
||||
'deepin' = 'Debian Family'
|
||||
'pureos' = 'Debian Family'
|
||||
'grml' = 'Debian Family'
|
||||
'libreelec' = 'Media'
|
||||
'osmc' = 'Media'
|
||||
'arch' = 'Arch Family'
|
||||
'manjaro' = 'Arch Family'
|
||||
'endeavouros' = 'Arch Family'
|
||||
'garuda' = 'Arch Family'
|
||||
'artix' = 'Arch Family'
|
||||
'cachyos' = 'Arch Family'
|
||||
'arcolinux' = 'Arch Family'
|
||||
'gentoo' = 'Gentoo Family'
|
||||
'funtoo' = 'Gentoo Family'
|
||||
'calculate' = 'Gentoo Family'
|
||||
'void' = 'Independent Linux'
|
||||
'nixos' = 'Independent Linux'
|
||||
'alpine' = 'Independent Linux'
|
||||
'solus' = 'Independent Linux'
|
||||
'clearlinux' = 'Independent Linux'
|
||||
'flatcar' = 'Independent Linux'
|
||||
'slackware' = 'Slackware Family'
|
||||
'salix' = 'Slackware Family'
|
||||
'porteus' = 'Slackware Family'
|
||||
'pfsense' = 'Network & Firewall'
|
||||
'opnsense' = 'Network & Firewall'
|
||||
'ipfire' = 'Network & Firewall'
|
||||
'vyos' = 'Network & Firewall'
|
||||
'openwrt' = 'Network & Firewall'
|
||||
'ddwrt' = 'Network & Firewall'
|
||||
'proxmox-ve' = 'Virtualisation'
|
||||
'proxmox-bs' = 'Virtualisation'
|
||||
'proxmox-mg' = 'Virtualisation'
|
||||
'esxi' = 'Virtualisation'
|
||||
'vsphere' = 'Virtualisation'
|
||||
'xcp-ng' = 'Virtualisation'
|
||||
'xenserver' = 'Virtualisation'
|
||||
'harvester' = 'Virtualisation'
|
||||
'freebsd' = 'BSD Family'
|
||||
'openbsd' = 'BSD Family'
|
||||
'netbsd' = 'BSD Family'
|
||||
'dragonflybsd' = 'BSD Family'
|
||||
'truenas' = 'BSD Family'
|
||||
'ghostbsd' = 'BSD Family'
|
||||
'openindiana' = 'Solaris & illumos'
|
||||
'omnios' = 'Solaris & illumos'
|
||||
'smartos' = 'Solaris & illumos'
|
||||
'solaris' = 'Solaris & illumos'
|
||||
'haiku' = 'Exotic'
|
||||
'freedos' = 'Exotic'
|
||||
'reactos' = 'Exotic'
|
||||
'clonezilla' = 'Rescue & Tools'
|
||||
'systemrescue' = 'Rescue & Tools'
|
||||
'gparted' = 'Rescue & Tools'
|
||||
'memtest' = 'Rescue & Tools'
|
||||
'memtest86' = 'Rescue & Tools'
|
||||
'rescuezilla' = 'Rescue & Tools'
|
||||
'hirens' = 'Rescue & Tools'
|
||||
'winpe' = 'Rescue & Tools'
|
||||
'dban' = 'Rescue & Tools'
|
||||
'ubcd' = 'Rescue & Tools'
|
||||
'kaspersky-rescue' = 'Rescue & Tools'
|
||||
'bitdefender-rescue' = 'Rescue & Tools'
|
||||
'eset-rescue' = 'Rescue & Tools'
|
||||
}
|
||||
|
||||
function Get-Category { param([string]$slug)
|
||||
# exact match first
|
||||
if ($categoryMap.Contains($slug)) { return $categoryMap[$slug] }
|
||||
# prefix match for variant slugs (e.g. opensuse-leap -> SUSE Family)
|
||||
foreach ($key in $categoryMap.Keys) {
|
||||
if ($slug -like "$key*") { return $categoryMap[$key] }
|
||||
}
|
||||
return 'Other'
|
||||
}
|
||||
|
||||
function Get-DisplayName { param([string]$slug, [string]$version, [string]$arch, [string]$filename)
|
||||
$base = if ($displayNames.Contains($slug)) { $displayNames[$slug] } else {
|
||||
# Title-case the slug as fallback
|
||||
(Get-Culture).TextInfo.ToTitleCase($slug.Replace('-', ' ').Replace('_', ' '))
|
||||
}
|
||||
$archLabel = if ($arch -ne 'noarch') { " [$arch]" } else { '' }
|
||||
return "$base $version$archLabel"
|
||||
}
|
||||
|
||||
# ── Scan directory tree and build entries ─────────────────────────────────────
|
||||
# Expected structure: $IsoRoot\<os>\<version>\<arch>\*.iso
|
||||
|
||||
$entries = @()
|
||||
|
||||
Get-ChildItem -Path $IsoRoot -Recurse -Filter "*.iso" | ForEach-Object {
|
||||
$isoFile = $_
|
||||
|
||||
# Derive relative path from IsoRoot for the Ventoy menu path
|
||||
$relativePath = $isoFile.FullName.Substring((Resolve-Path $IsoRoot).Path.Length).TrimStart('\')
|
||||
|
||||
# Extract os/version/arch from directory structure
|
||||
$parts = $relativePath -split '\\'
|
||||
if ($parts.Count -ge 4) {
|
||||
# Structure: os\version\arch\file.iso
|
||||
$slug = $parts[0]
|
||||
$version = $parts[1]
|
||||
$arch = $parts[2]
|
||||
} elseif ($parts.Count -ge 3) {
|
||||
$slug = $parts[0]
|
||||
$version = $parts[1]
|
||||
$arch = 'noarch'
|
||||
} else {
|
||||
$slug = 'unknown'
|
||||
$version = 'unknown'
|
||||
$arch = 'noarch'
|
||||
}
|
||||
|
||||
$entries += [PSCustomObject]@{
|
||||
Slug = $slug
|
||||
Version = $version
|
||||
Arch = $arch
|
||||
Category = Get-Category $slug
|
||||
Label = Get-DisplayName $slug $version $arch $isoFile.Name
|
||||
Path = '/' + $relativePath.Replace('\', '/')
|
||||
File = $isoFile.Name
|
||||
}
|
||||
}
|
||||
|
||||
# ── Build ventoy.json structure ───────────────────────────────────────────────
|
||||
# Group into categories, then sort categories and entries within them
|
||||
|
||||
$menuItems = [ordered]@{}
|
||||
|
||||
foreach ($entry in ($entries | Sort-Object Category, Slug, Version)) {
|
||||
$cat = $entry.Category
|
||||
if (-not $menuItems.Contains($cat)) {
|
||||
$menuItems[$cat] = @()
|
||||
}
|
||||
$menuItems[$cat] += $entry
|
||||
}
|
||||
|
||||
# Preferred category order — anything not listed lands at the end alphabetically
|
||||
$categoryOrder = @(
|
||||
'Windows',
|
||||
'RHEL Family',
|
||||
'Fedora Family',
|
||||
'SUSE Family',
|
||||
'Debian Family',
|
||||
'Ubuntu Family',
|
||||
'Arch Family',
|
||||
'Gentoo Family',
|
||||
'Slackware Family',
|
||||
'Independent Linux',
|
||||
'Security',
|
||||
'Network & Firewall',
|
||||
'Virtualisation',
|
||||
'BSD Family',
|
||||
'Solaris & illumos',
|
||||
'Media',
|
||||
'Exotic',
|
||||
'Rescue & Tools',
|
||||
'Other'
|
||||
)
|
||||
|
||||
$sortedCategories = @()
|
||||
foreach ($cat in $categoryOrder) {
|
||||
if ($menuItems.Contains($cat)) { $sortedCategories += $cat }
|
||||
}
|
||||
foreach ($cat in ($menuItems.Keys | Sort-Object)) {
|
||||
if ($sortedCategories -notcontains $cat) { $sortedCategories += $cat }
|
||||
}
|
||||
|
||||
# Build the menu array ventoy expects
|
||||
$menuArray = @()
|
||||
foreach ($cat in $sortedCategories) {
|
||||
$subItems = @()
|
||||
foreach ($entry in $menuItems[$cat]) {
|
||||
$subItems += [ordered]@{
|
||||
image = $entry.Path
|
||||
menu_alias = $entry.Label
|
||||
}
|
||||
}
|
||||
$menuArray += [ordered]@{
|
||||
name = $cat
|
||||
image = $subItems
|
||||
}
|
||||
}
|
||||
|
||||
$ventoyJson = [ordered]@{
|
||||
"menu_alias" = $menuArray
|
||||
}
|
||||
|
||||
# ── Write output ──────────────────────────────────────────────────────────────
|
||||
$json = $ventoyJson | ConvertTo-Json -Depth 10
|
||||
$json | Set-Content -Path $OutFile -Encoding UTF8
|
||||
|
||||
Write-Host "Written: $OutFile"
|
||||
Write-Host ""
|
||||
Write-Host "Menu structure:"
|
||||
foreach ($cat in $sortedCategories) {
|
||||
Write-Host " [$cat]" -ForegroundColor Cyan
|
||||
foreach ($entry in $menuItems[$cat]) {
|
||||
Write-Host " $($entry.Label)" -ForegroundColor Gray
|
||||
Write-Host " $($entry.Path)" -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "Copy ventoy.json to the ventoy\ folder on your Ventoy USB drive."
|
||||
Loading…
Add table
Add a link
Reference in a new issue