-
Notifications
You must be signed in to change notification settings - Fork 0
/
winDirect.sh
executable file
·272 lines (220 loc) · 9.39 KB
/
winDirect.sh
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
#!/bin/bash
# shellcheck disable=SC2086
# winDirect.sh
# Usage: ./winDirect.sh <target_volume_id> <iso_file_path>
# Author : @naveenkrdy
# Discription: Script to install Windows OS from within macOS without using a USB stick or bootcamp.
VERSION=1.1
# set -e
error_exit() {
echo "[Error]: $1"
echo "[Error]: Exiting.."
exit 1
}
print_seperator() {
local length=65
local symbol="="
for ((i = 1; i <= length; i++)); do
echo -n "$symbol"
done
echo
}
copy() {
local src="$1"
local dst="$2"
if [[ -e "$src" ]]; then
if [[ -d "$src" ]]; then
if [[ ! -d "$dst" ]]; then
mkdir -p "$dst" || error_exit "Failed to create destination directory: $dst"
fi
cp -R "$src"/* "$dst" || error_exit "Failed to copy $src to $dst"
else
if [[ -d "$dst" ]]; then
dst="$dst/$(basename "$src")"
fi
mkdir -p "$(dirname "$dst")" || error_exit "Failed to create destination directory: $(dirname "$dst")"
cp "$src" "$dst" || error_exit "Failed to copy $src to $dst"
fi
else
error_exit "$src file or directory doesn't exist"
fi
}
move() {
local src="$1"
local dst="$2"
if [[ -e "$src" ]]; then
if [[ -d "$src" ]]; then
if [[ ! -d "$dst" ]]; then
mkdir -p "$dst" || error_exit "Failed to create destination directory: $dst"
fi
mv "$src"/* "$dst" || error_exit "Failed to move $src to $dst"
else
if [[ -d "$dst" ]]; then
dst="$dst/$(basename "$src")"
fi
mkdir -p "$(dirname "$dst")" || error_exit "Failed to create destination directory: $(dirname "$dst")"
mv "$src" "$dst" || error_exit "Failed to move $src to $dst"
fi
else
error_exit "$src file or directory doesn't exist"
fi
}
move() {
local src="$1"
local dst="$2"
if [[ -e "$src" ]]; then
if [[ ! -d "$dst" ]]; then
mkdir -p "$dst" || error_exit "Failed to create destination directory: $dst"
fi
mv "$src" "$dst" || error_exit "Failed to move $src to $dst"
else
error_exit "$src file or directory doesn't exist"
fi
}
check_iso() {
echo "[Info]: ISO Path: $iso_file_path"
if ! [[ -e "${iso_mount_point}/sources/install.wim" || -e "${iso_mount_point}/sources/install.esd" ]]; then
error_exit "Provided Windows installer ISO is not valid"
fi
echo "[Info]: Provided Windows installer ISO is valid"
echo "[Info]: Installer volume name is $iso_mount_point"
echo "[Info]: Installer disk Id is $iso_disk_id"
}
check_target() {
if ! diskutil list | grep -q "$target_disk_id"; then
error_exit "Target disk $target_disk_id not found"
fi
if diskutil info "$target_disk_id" | grep -q "GUID_partition_scheme"; then
echo "[Info]: Target disk $target_disk_id is GUID/GPT scheme"
else
error_exit "Target disk $target_disk_id is not GUID/GPT scheme"
fi
if ! diskutil list "$target_disk_id" | grep -q "$target_volume_id"; then
error_exit "Target volume $target_volume_id not found"
fi
if diskutil info "$target_volume_id" | grep -q "EFI"; then
error_exit "Target volume $target_volume_id should not be EFI"
fi
if diskutil info "$target_volume_id" | grep -q "APFS"; then
error_exit "Target volume $target_volume_id should not be of type APFS. Please format it as ExFAT or FAT32 or JHFS+"
fi
local disk_size
disk_size=$(diskutil info "$target_volume_id" | grep "Disk Size:" | awk '{print $5}' | tr -d '()')
if [[ $disk_size -le 21474836480 ]]; then
error_exit "Target volume $target_volume_id doesn't have enough space (Min: 20Gb)"
fi
}
mount_efi_partition() {
local target_volume_id="$1"
local efi_mount_point
if ! efi_mount_point=$(./scripts/mount_efi.sh "$target_volume_id"); then
error_exit "Unable to mount EFI volume on target volume $target_volume_id"
fi
echo "$efi_mount_point"
}
mount_target_volume() {
local target_volume_id="$1"
local target_volume_mount_point
if ! diskutil info "$target_volume_id" >/dev/null | grep -q "*Mounted: *No*"; then
diskutil mount "$target_volume_id" >/dev/null || error_exit "Unable to mount target volume $target_volume_id"
else
error_exit "Target volume info is missing"
fi
target_volume_mount_point=$(diskutil info "$target_volume_id" | sed -n 's/.*Mount Point: *//p')
echo "$target_volume_mount_point"
}
unmount_target_volume() {
local target_volume_id="$1"
if diskutil unmount $target_volume_id 2>&1 | grep -q "failed"; then
error_exit "Failed to unmount target volume $target_volume_id"
fi
echo "[Info]: Successfully unmounted target volume $target_volume_id"
}
install_windows() {
echo "[Info]: Provided Windows installer ISO has the following editions: "
print_seperator
./bin/wiminfo ${iso_mount_point}/sources/install.* | grep 'Display Name:' | grep -v 'Boot' | sed -e 's/Display Name: //' | awk '{$1=$1};1' | nl -s '. ' | sed 's/^[[:space:]]*//' || error_exit "Failed to get windows editions list"
print_seperator
read -p "[Input] Enter the edition number: " edition_index
echo
sudo -v
echo
echo "[Install]: Preparing target volume $target_volume_id:"
print_seperator
diskutil eraseVolume exFAT WIN_TEMP "$target_volume_id" || error_exit "Failed to erase volume to exFAT"
print_seperator
part_start=$(sudo gpt show "$target_disk_id" 2>&1 | grep "$y GPT part" | awk '{ print $1 }') || error_exit "Failed to get volume start value"
echo "[Info]: Target volume starts at $part_start"
echo "[Install]: Unmounting target volume $target_volume_id"
unmount_target_volume $target_volume_id
echo "[Install]: Formatting target volume $target_volume_id to NTFS"
print_seperator
sudo ./bin/mkntfs -p "$part_start" -S 63 -H 255 -f -L Windows /dev/${target_volume_id} || error_exit "Unable to format target volume $target_volume_id to NTFS"
print_seperator
echo "[Install]: Installing Windows on target volume $target_volume_id"
print_seperator
sudo ./bin/wimapply ${iso_mount_point}/sources/install.* "$edition_index" /dev/${target_volume_id} || error_exit "Unable to install Windows on target volume $target_volume_id"
print_seperator
mount_target_volume "$target_volume_id" >/dev/null
echo "[Info]: Windows successfully installed on target volume $target_volume_id"
}
install_bootloader() {
echo "[Info]: Installing Windows bootloader on target disk $target_disk_id"
efi_mount_point=$(mount_efi_partition "$target_volume_id")
target_volume_mount_point=$(mount_target_volume "$target_volume_id")
if [[ -d "${efi_mount_point}/EFI/Microsoft" ]]; then
echo "[Install]: Removing existing Windows bootloader"
rm -rf "${efi_mount_point}/EFI/Microsoft" && echo "done" || error_exit
fi
echo "[Install]: Creating Windows bootloader files on $efi_mount_point"
copy "${target_volume_mount_point}/Windows/Boot/EFI" "${efi_mount_point}/EFI/Microsoft/BOOT"
copy "${target_volume_mount_point}/Windows/Boot/Fonts" "${efi_mount_point}/EFI/Microsoft/BOOT"
copy ./misc/BCD_rcv "${efi_mount_point}/EFI/Microsoft/Recovery/BCD"
copy ./misc/BCD ~/BCD
echo "[Info]: Preparing patch for Windows bootloader"
target_disk_guid=$(ioreg -l | grep -ow -A40 "$target_disk_id" | grep -w UUID | sed 's/UUID//' | tr -d ' |="-')
s=$target_disk_guid
target_disk_guid_patch="${s:6:2}${s:4:2}${s:2:2}${s:0:2}${s:10:2}${s:8:2}${s:14:2}${s:12:2}${s:16:16}"
echo "[Info]: Target disk $target_disk_id GUID is $target_disk_guid"
echo "[Info]: Target disk $target_disk_id patched GUID is $target_disk_guid_patch"
target_volume_uuid=$(diskutil info "$target_volume_id" | grep "Disk / Partition UUID:" | awk '{ print $5 }' | tr -d ' |=\"-')
s=$target_volume_uuid
target_volume_uuid_patch="${s:6:2}${s:4:2}${s:2:2}${s:0:2}${s:10:2}${s:8:2}${s:14:2}${s:12:2}${s:16:16}"
echo "[Info]: Target volume '$target_volume_id' UUID is $target_volume_uuid"
echo "[Info]: Target volume '$target_volume_id' patched UUID is $target_volume_uuid_patch"
target_disk_guid_patch=$(echo -n "$target_disk_guid_patch" | sed 's/../\\x&/g')
target_volume_uuid_patch=$(echo -n "$target_volume_uuid_patch" | sed 's/../\\x&/g')
echo "[Install]: Applying patch to Windows bootloader"
sudo perl -pi -e "s|\x17\x18\x19\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x30\x31\x32|$target_disk_guid_patch|g" ~/BCD
sudo perl -pi -e "s|\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16|$target_volume_uuid_patch|g" ~/BCD
move ~/BCD "${efi_mount_point}/EFI/Microsoft/BOOT"
if ! [[ -e "${efi_mount_point}/EFI/Clover" || -e "${efi_mount_point}/EFI/OC" ]]; then
echo "[Info]: Opencore/Clover bootloader not found on target disk $target_disk_id"
echo "[Info]: Installing Windows Bootstrap"
copy "${efi_mount_point}/EFI/Microsoft/BOOT/bootmgfw.efi" "${efi_mount_point}/EFI/BOOT/bootx64.efi"
fi
echo "[Info]: Successfully installed Windows bootloader on target disk $target_disk_id"
}
# START
echo "[Info]: winDirect.sh $VERSION"
echo "[Info]: Script by @naveenkrdy"
print_seperator
if [ $# -ne 2 ]; then
error_exit "Usage: $0 <target_volume_id> <iso_file_path>"
fi
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$script_dir" || error_exit "Unable to change the current directory to the script source folder"
target_volume_id=$1
x="${target_volume_id:4:1}"
y="${target_volume_id:6:1}"
target_disk_id="disk${x}"
iso_file_path=$2
iso_mount_output=$(hdiutil mount "$iso_file_path") || error_exit "Failed to mount ISO file"
iso_disk_id=$(echo "$iso_mount_output" | grep -o '/dev/disk[0-9]*')
iso_mount_point=$(echo "$iso_mount_output" | grep -o '/Volumes/.*' | cut -f 1- | sed 's/ /\\ /g')
check_iso
check_target
install_windows
install_bootloader
diskutil unmount "$efi_mount_point" >/dev/null
diskutil unmount "$iso_mount_point" >/dev/null