windows: 优化 iso 查找

This commit is contained in:
bin456789
2026-08-04 21:10:05 +08:00
parent b941221ec1
commit 27dd00c078
3 changed files with 220 additions and 110 deletions
+212 -104
View File
@@ -874,7 +874,9 @@ is_have_arm_version() {
'enterprise ltsc 2021' | 'iot enterprise ltsc 2021') return ;;
esac
;;
11) return ;;
11)
return
;;
esac
return 1
}
@@ -893,9 +895,13 @@ find_windows_iso() {
full_lang=$(english)
case "$basearch" in
x86) # 备用,查找功能目前不支持 32 位
arch_win=x86
arch_win_vlsc='32-?bit'
;;
x86_64)
arch_win=x64
arch_win_vlsc=64bit
arch_win_vlsc='64-?bit'
;;
aarch64)
arch_win=arm64
@@ -908,82 +914,125 @@ find_windows_iso() {
get_windows_iso_link() {
get_label_msdn() {
if [ -n "$server" ]; then
case "$version" in
2019 | 2022 | 2025)
case "$edition" in
serverstandard | serverstandardcore) echo _ ;;
serverdatacenter | serverdatacentercore) echo _ ;;
esac
case "$version" in
8 | 8.1)
case "$edition" in
'') # windows 8.x core
echo _
;;
pro | enterprise)
echo "$edition"
;;
esac
else
case "$version" in
10)
case "$edition" in
home | 'home single language') echo consumer ;;
pro | enterprise) echo business ;;
education | 'pro education' | 'pro for workstations')
case "$arch_win" in
arm64) echo consumer ;;
x64) echo business ;; # iso 更小
esac
;;
# iot
'iot enterprise') echo 'iot enterprise' ;;
# iot ltsc
'iot enterprise ltsc 2021') echo "$edition" ;;
# ltsc
'enterprise ltsc 2021')
# arm64 的 enterprise ltsc 2021 要下载 iot enterprise ltsc 2021 iso
case "$arch_win" in
arm64) echo 'iot enterprise ltsc 2021' ;;
x86 | x64) echo 'enterprise ltsc 2021' ;;
esac
;;
;;
10)
case "$edition" in
home | 'home single language')
echo 'consumer editions'
;;
pro | enterprise)
echo 'business editions'
;;
education | 'pro education' | 'pro for workstations')
case "$arch_win" in
arm64) echo 'consumer editions' ;; # 只能从 consumer 获取
x86 | x64) echo 'business editions' ;; # iso 更小
esac
;;
11)
# iot
'iot enterprise')
echo 'iot enterprise'
;;
# ltsc
'enterprise 2015 ltsb' | 'enterprise 2016 ltsb' | 'enterprise ltsc 2019' | 'enterprise ltsc 2021')
case "$arch_win" in
arm64) echo "iot $edition" ;; # 只能从 iot ltsc iso 获取
x86 | x64) echo "$edition" ;;
esac
;;
# iot ltsc
'iot enterprise 2015 ltsb' | 'iot enterprise 2016 ltsb' | 'iot enterprise ltsc 2019' | 'iot enterprise ltsc 2021')
echo "$edition"
;;
esac
;;
11)
case "$edition" in
home | 'home single language')
echo 'consumer editions'
;;
pro | enterprise)
echo 'business editions'
;;
education | 'pro education' | 'pro for workstations')
# arm business iso 都没有 education, pro education, pro for workstations
# 即使它的名字包含 EDU
# SW_DVD9_Win_Pro_10_22H2.31_Arm64_English_Pro_Ent_EDU_N_MLF_X24-05074.ISO
# en-us_windows_11_business_editions_version_25h2_arm64_dvd_8afc9b39.iso
case "$edition" in
home | 'home single language') echo consumer ;;
pro | enterprise) echo business ;;
education | 'pro education' | 'pro for workstations')
case "$arch_win" in
arm64) echo consumer ;;
x64) echo business ;; # iso 更小
esac
;;
# iot
'iot enterprise' | 'iot enterprise subscription') echo 'iot enterprise' ;;
# iot ltsc
'iot enterprise ltsc 2024' | 'iot enterprise subscription ltsc 2024') echo 'iot enterprise ltsc 2024' ;;
# ltsc
'enterprise ltsc 2024')
# arm64 的 enterprise ltsc 2024 要下载 iot enterprise ltsc 2024 iso
case "$arch_win" in
arm64) echo 'iot enterprise ltsc 2024' ;;
x64) echo 'enterprise ltsc 2024' ;;
esac
;;
case "$arch_win" in
arm64) echo 'consumer editions' ;; # 只能从 consumer 获取
x64) echo 'business editions' ;; # iso 更小
esac
;;
# iot
'iot enterprise' | 'iot enterprise subscription')
echo 'iot enterprise'
;;
# ltsc
'enterprise ltsc 2024')
case "$arch_win" in
arm64) echo "iot $edition" ;; # 只能从 iot ltsc iso 获取
x64) echo "$edition" ;;
esac
;;
# iot ltsc
'iot enterprise ltsc 2024' | 'iot enterprise subscription ltsc 2024')
echo 'iot enterprise ltsc 2024'
;;
esac
fi
;;
2019 | 2022 | 2025)
case "$edition" in
serverstandard | serverstandardcore | serverdatacenter | serverdatacentercore)
echo _
;;
esac
;;
esac
}
get_label_vlsc() {
case "$version" in
10 | 11)
# SW_DVD9_Win_Pro_11_25H2_Arm64_Arabic_Pro_Ent_EDU_N_MLF_X24-13113.iso
# SW_DVD5_WIN_ENT_LTSB_10_2015_64BIT_Arabic_MLF_X20-26578.ISO
# SW_DVD5_WIN_ENT_LTSB_2016_64BIT_Arabic_MLF_X21-07425.ISO
# SW_DVD5_WIN_ENT_LTSC_2019_64-bit_Arabic_MLF_X21-96407.ISO
# SW_DVD9_WIN_ENT_LTSC_2021_64BIT_ChnSimp_MLF_X22-84402.ISO
# SW_DVD9_WIN_ENT_LTSC_2024_64-bit_Arabic_MLF_X23-70037.ISO
# SW_DVD5_Win_10_IOT_Enterprise_2015_LTSB_64Bit_EMB_English_OEM_X20-20063.IMG
# SW_DVD5_Win10_IoT_Enterprise_LTSB_1607_64-bit_EMB_English_OEM_X21-05293.IMG
# SW_DVD9_Win_11_IoT_Enterprise_LTSC_24H2_64-Bit_English_X23-70076.ISO
10)
case "$edition" in
pro | education | enterprise | 'pro education' | 'pro for workstations') echo pro ;;
'enterprise 2015 ltsb') echo 'ent ltsb 10 2015' ;;
'enterprise 2016 ltsb') echo 'ent ltsb 2016' ;;
'enterprise ltsc 2019') echo 'ent ltsc 2019' ;;
'enterprise ltsc 2021') echo 'ent ltsc 2021' ;;
'iot enterprise 2015 ltsb') echo 'iot enterprise 2015 ltsb' ;; # √
'iot enterprise 2016 ltsb') echo 'iot enterprise ltsb 1607' ;; # √
'iot enterprise ltsc 2019') echo 'iot enterprise ltsc 2019' ;; # 没找到
'iot enterprise ltsc 2021') echo 'iot enterprise ltsc 2021' ;; # 没找到
esac
;;
2025)
echo SrvSTDCORE
11)
case "$edition" in
pro | education | enterprise | 'pro education' | 'pro for workstations') echo pro ;;
'enterprise ltsc 2024') echo 'ent ltsc 2024' ;;
'iot enterprise ltsc 2024' | 'iot enterprise subscription ltsc 2024') echo 'iot enterprise ltsc 24h2' ;; # √
esac
;;
esac
}
@@ -997,20 +1046,26 @@ get_windows_iso_link() {
:
}
get_page() {
if [ "$arch_win" = arm64 ]; then
echo arm
elif is_ltsc; then
echo ltsc
get_page_url() {
local page=
if is_ltsc; then
page=ntriver/ltsc
elif [ "$server" = 'server' ]; then
echo server
page=massgrave/server
else
case "$version" in
10 | 11)
echo "$version"
8 | 8.1 | 10 | 11)
page=ntriver/$version
;;
esac
fi
case "$page" in
massgrave/server) echo https://massgrave.dev/windows-server-links ;;
massgrave/*) echo https://massgrave.dev/windows_${page#*/}_links ;;
ntriver/*) echo https://ntriver.org/download-windows-${page#*/} ;;
esac
}
is_ltsc() {
@@ -1021,13 +1076,7 @@ get_windows_iso_link() {
label_msdn=$(get_label_msdn)
label_msdl=$(get_label_msdl)
label_vlsc=$(get_label_vlsc)
page=$(get_page)
if [ "$page" = server ]; then
page_url=https://massgrave.dev/windows-server-links
else
page_url=https://massgrave.dev/windows_${page}_links
fi
page_url=$(get_page_url)
info "Find windows iso"
echo "Version: $version"
@@ -1035,7 +1084,7 @@ get_windows_iso_link() {
echo "Label msdn: $label_msdn"
echo "Label msdl: $label_msdl"
echo "Label vlsc: $label_vlsc"
echo "List: $page_url"
echo "Page: $page_url"
echo
# 先判断是否能自动查找该版本
@@ -1043,7 +1092,7 @@ get_windows_iso_link() {
# 这样可以在输入错误 Edition 时例如 windows 11 enterprise ltsc 2021
# 显示名称错误,而不是显示该版本不支持 arm
if [ -z "$page" ] || { [ -z "$label_msdn" ] && [ -z "$label_msdl" ] && [ -z "$label_vlsc" ]; }; then
if [ -z "$page_url" ] || { [ -z "$label_msdn" ] && [ -z "$label_msdl" ] && [ -z "$label_vlsc" ]; }; then
error_and_exit "Not support find this iso. Check if --image-name is wrong. Or set --iso manually."
fi
@@ -1056,26 +1105,32 @@ get_windows_iso_link() {
else
http_to_host=$(get_scheme_and_host_by_url "$page_url")
http_to_current_dir=$(dirname "$page_url")
curl -L "$page_url" |
tr -d '\n' | sed -e 's,<a ,\n<a ,g' -e 's,</a>,</a>\n,g' | # 使每个 <a></a> 占一行
grep -Ei '\.(iso|img)</a>$' | # 找出是 iso 或 img 的行
# 提取文件名和链接
curl -L "$page_url" | tr -d '\n' | # 合成一行
if [[ "$page_url" =~ massgrave.dev ]]; then
sed -e 's,<a ,\n<a ,g' -e 's,</a>,</a>\n,g' | # 使每个 <a></a> 占一行
grep -Ei '\.(iso|img)</a>$' | # 找出是 iso 或 img 的行
sed -E 's,<a href="?([^" ]+)"?.+>(.+)</a>,\2 \1,' # 提取文件名和链接
else
sed -e 's,<td><strong>,\n<td><strong>,g' -e 's,</a>,</a>\n,g' | # 使每个镜像占一行
grep -Ei '\.(iso|img)</strong>' | # 找出是 iso 或 img 的行
sed -E 's,<td><strong>([^<]+).+<a href="?([^" ]+)"?.+,\1 \2,' # 提取文件名和链接
fi |
# 如果链接是 / 开头,则补全域名
# 如果链接非 https:// 开头,则补全域名和目录
sed -E -e 's,<a href="?([^" ]+)"?.+>(.+)</a>,\2 \1,' \
-e "s, (/), $http_to_host\1," |
awk '{if ($2 !~ /^https?:\/\//) $2 = "'$http_to_current_dir/'" $2; print}' >$tmp/win.list
sed -E "s, (/), $http_to_host\1," |
awk '{if ($2 !~ /^https?:\/\//) $2 = "'$http_to_current_dir/'" $2; print}' |
# 如果不是 ltsc ,应该先去除 ltsc 链接,否则最终链接有 ltsc 的
# 例如查找 windows 10 iot enterprise,会得到
# en-us_windows_10_iot_enterprise_ltsc_2021_arm64_dvd_e8d4fc46.iso
# en-us_windows_10_iot_enterprise_version_22h2_arm64_dvd_39566b6b.iso
# sed -Ei 和 sed -iE 是不同的
if is_ltsc; then
sed -Ei '/ltsc|ltsb/!d' $tmp/win.list
else
sed -Ei '/ltsc|ltsb/d' $tmp/win.list
fi
# 如果不是 ltsc ,应该先去除 ltsc 链接,否则最终链接有 ltsc 的
# 例如查找 windows 10 iot enterprise,会得到
# en-us_windows_10_iot_enterprise_ltsc_2021_arm64_dvd_e8d4fc46.iso
# en-us_windows_10_iot_enterprise_version_22h2_arm64_dvd_39566b6b.iso
if is_ltsc; then
grep -Ei '_lts[bc]_'
else
grep -Ei -v '_lts[bc]_'
fi >$tmp/win.list
get_windows_iso_link_inner
fi
@@ -1090,6 +1145,29 @@ get_shortest_line_by_field() {
awk "(NR == 1 || length(\$$field) < length(field)) { line = \$0; field = \$$field } END { print line }"
}
get_best_windows_iso_line() {
local lines
lines=$(cat)
# 在所有符合的 iso 中
# 先选择 win10/11 大版本更新的 (version 26h1) 或者有 sp 版本的 (sp1, windows_8.1_with_update_)
# 再选择有日期更新的 (updated_july_2026)
# 再选择 vl
# 再按版本号排序选择最新版
# 但是也有例外
# zh-cn_windows_server_2019_x64_dvd_19d65722.iso 2022-11-15
# cn_windows_server_2019_updated_april_2021_x64_dvd_a6dae187.iso 2021-04-20
for key in '(version|sp[0-9]|update)' 'updated' 'vl'; do
if grep_lines=$(grep -E "_${key}_" <<<"$lines"); then
lines=$grep_lines
fi
done
echo "$lines" | sort -Vr | head -1
}
get_windows_iso_link_inner() {
regexs=()
@@ -1099,14 +1177,29 @@ get_windows_iso_link_inner() {
label_msdn=
fi
for lang in $langs; do
regex=
# en_windows_vista_sp2_x64_dvd_342267.iso
# cn_windows_vista_with_sp2_x64_dvd_x15-36322.iso
# en_windows_8_x64_dvd_915440.iso
# en_windows_8.1_pro_vl_with_update_x64_dvd_6050880.iso
# en_windows_8.1_with_update_x64_dvd_6051480.iso
# en_windows_8.1_n_with_update_x64_dvd_6051677.iso
# en-us_windows_10_iot_enterprise_version_22h2_arm64_dvd_39566b6b.iso
# en-us_windows_11_consumer_editions_version_26h1_updated_july_2026_x64_dvd_f69a9a1e.iso
# en-us_windows_server_2025_updated_july_2026_x64_dvd_4e6f5a42.iso
local prefix=
for i in ${lang} windows ${server} ${version} ${label_msdn}; do
if [ -n "$i" ]; then
regex+="${i}_"
prefix+="${i}_"
fi
done
regex+=".*${arch_win}.*.(iso|img)"
regexs+=("$regex")
# 用于准确匹配,例如防止 2012 匹配到 2012 r2
# 首先匹配 label 后面紧接着这些关键字的
# 然后匹配 label 后面紧接着 x64/arm64 的
# 最后模糊匹配
regexs+=("${prefix}(version|vl|with|updated|sp[0-9])_.*${arch_win}.*\.(iso|img)")
regexs+=("${prefix}${arch_win}.*\.(iso|img)")
regexs+=("${prefix}.*${arch_win}.*\.(iso|img)")
done
fi
@@ -1118,8 +1211,14 @@ get_windows_iso_link_inner() {
# 先判断 full_lang 是否为空
# 因为假如用户输入的 lang 不正确,full_lang 就为空,正则表达式就无法只匹配当前语言
if [ -n "$label_vlsc" ] && [ -n "$full_lang" ]; then
regex="sw_?dvd[59]_win_?${label_vlsc}_?${version}.*${arch_win_vlsc}_${full_lang}.*.(iso|img)"
regexs+=("$regex")
regexs+=("sw_?dvd[59]_win_?${label_vlsc}_?${version}_.*${arch_win_vlsc}.*_${full_lang}.*.(iso|img)")
regexs+=("sw_?dvd[59]_win_?${version}_${label_vlsc}_?.*${arch_win_vlsc}.*_${full_lang}.*.(iso|img)")
# LTSC 没有 windows 主版本号
# SW_DVD5_WIN_ENT_LTSB_10_2015_64BIT_Arabic_MLF_X20-26578.ISO # 将 ENT_LTSB_10_2015 视为 label
# SW_DVD5_WIN_ENT_LTSB_2016_64BIT_Arabic_MLF_X21-07425.ISO # 将 ENT_LTSB_2016 视为 label
if is_ltsc; then
regexs+=("sw_?dvd[59]_win_?${label_vlsc}_?.*${arch_win_vlsc}.*_${full_lang}.*.(iso|img)")
fi
fi
# 查找
@@ -1127,10 +1226,16 @@ get_windows_iso_link_inner() {
regex=${regex// /_}
echo "looking for: $regex" >&2
if line=$(grep -Ei "^$regex " "$tmp/win.list" | get_shortest_line_by_field 1 | grep .) &&
iso=$(awk '{print $2}' <<<"$line" | grep .); then
echo "Selected: $line" >&2
return
local matched_lines
if matched_lines=$(grep -Ei "^$regex " "$tmp/win.list"); then
info "ISO Matched"
cat -n <<<"$matched_lines" >&2
if line=$(echo "$matched_lines" | get_best_windows_iso_line | grep .) &&
iso=$(awk '{print $2}' <<<"$line" | grep .); then
info "ISO Selected"
echo " $line" >&2
return
fi
fi
done
@@ -1531,7 +1636,8 @@ Continue?
else
iso_is_tested=false
if $auto_find_iso; then
if test_url_grace "$iso" iso 2>/dev/null; then
# 目前自动获取 iso 肯定不是直连,因此先关闭直连测试
if false && test_url_grace "$iso" iso 2>/dev/null; then
iso_is_tested=true
else
# 需要用户输入 massgrave.dev 直链
@@ -1548,6 +1654,8 @@ Continue?
IFS= read -r -p "Direct Link: " iso
if [ -z "$iso" ]; then
error_and_exit "ISO Link is empty."
elif ! grep -Eiq '^https?://' <<<"$iso"; then
error_and_exit "ISO Link is invalid."
fi
fi
fi