|
1 |
| -# This script automates Sbnb Linux bootable USB creation process on Windows. |
2 |
| -# It downloads and installs the sbnb.efi file onto a selected disk. |
3 |
| -# It also allows the user to provide a Tailscale key and a custom script to be executed during Sbnb Linux boot. |
4 |
| -# |
5 |
| -# More info at https://github.com/sbnb-io/sbnb |
6 |
| - |
7 |
| -param ( |
8 |
| - [string]$SbnbEfiPath |
9 |
| -) |
10 |
| - |
11 |
| -Write-Output "Welcome to Sbnb Linux bootable USB creation" |
12 |
| - |
13 |
| -# Step 1: Find latest release and download sbnb.efi.zip if not provided |
14 |
| -if (-not $SbnbEfiPath) { |
15 |
| - $repoUrl = "https://api.github.com/repos/sbnb-io/sbnb/releases/latest" |
16 |
| - $releaseInfo = Invoke-RestMethod -Uri $repoUrl |
17 |
| - $latestRelease = $releaseInfo.tag_name |
18 |
| - $downloadUrl = $releaseInfo.assets | Where-Object { $_.name -eq "sbnb.efi.zip" } | Select-Object -ExpandProperty browser_download_url |
19 |
| - |
20 |
| - Write-Output "Sbnb Linux latest release: $latestRelease" |
21 |
| - Write-Output "Download URL: $downloadUrl" |
22 |
| - |
23 |
| - # Get the size of the download |
24 |
| - $webRequest = Invoke-WebRequest -Uri $downloadUrl -Method Head |
25 |
| - $fileSize = [math]::Round($webRequest.Headers['Content-Length'] / 1MB, 2) |
26 |
| - |
27 |
| - # Ask user if they agree to continue |
28 |
| - $confirmation = Read-Host "The file size is $fileSize MB. Do you want to continue with the download? (y/n)" |
29 |
| - if ($confirmation -ne "y") { |
30 |
| - Write-Output "Download cancelled." |
31 |
| - exit |
32 |
| - } |
33 |
| - |
34 |
| - Write-Output "Downloading sbnb.efi.zip..." |
35 |
| - $wc = New-Object net.webclient |
36 |
| - $wc.DownloadFile($downloadUrl, "sbnb.efi.zip") |
37 |
| - |
38 |
| - # Step 2: Decompress sbnb.efi.zip to a temporary directory |
39 |
| - $tempDir = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) |
40 |
| - [System.IO.Directory]::CreateDirectory($tempDir) |
41 |
| - |
42 |
| - Write-Output "Decompressing sbnb.efi.zip to $tempDir..." |
43 |
| - Add-Type -AssemblyName System.IO.Compression.FileSystem |
44 |
| - [System.IO.Compression.ZipFile]::ExtractToDirectory("sbnb.efi.zip", $tempDir) |
45 |
| - |
46 |
| - $SbnbEfiPath = "$tempDir\sbnb.efi" |
47 |
| -} else { |
48 |
| - Write-Output "Using provided sbnb.efi file: $SbnbEfiPath" |
49 |
| -} |
50 |
| - |
51 |
| -# Step 3: Enumerate all disks and ask user to input disk number |
52 |
| -$disks = Get-WmiObject -Query "SELECT * FROM Win32_DiskDrive" | Sort-Object -Property Model |
53 |
| -for ($i = 0; $i -lt $disks.Count; $i++) { |
54 |
| - $diskInfo = "${i}: $($disks[$i].DeviceID) - $($disks[$i].Model) - $($disks[$i].Name)" |
55 |
| - Write-Host $diskInfo |
56 |
| -} |
57 |
| - |
58 |
| -$selectedDiskNumber = Read-Host "Enter the number of the disk to flash into" |
59 |
| -$selectedDrive = $disks[$selectedDiskNumber].Index |
60 |
| - |
61 |
| -# Step 4: Double confirm user agrees with selection |
62 |
| -$confirmation = Read-Host "You have selected disk $($disks[$selectedDiskNumber].Model) (Index: $selectedDrive). All data on this disk will be destroyed. Are you sure you want to proceed? (y/n)" |
63 |
| -if ($confirmation -ne "y") { |
64 |
| - Write-Output "Operation cancelled." |
65 |
| - exit |
66 |
| -} |
67 |
| - |
68 |
| -# Step 5: Remove all existing partitions and create ESP partition |
69 |
| -Write-Output "Removing all existing partitions on disk $($disks[$selectedDiskNumber].Model) (Index: $selectedDrive)..." |
70 |
| -Get-Disk -Number $selectedDrive | Clear-Disk -RemoveData -Confirm:$false |
71 |
| - |
72 |
| -# Get the size of the selected disk |
73 |
| -$disk = Get-Disk -Number $selectedDrive |
74 |
| -$diskSize = $disk.Size |
75 |
| - |
76 |
| -# Determine the partition size |
77 |
| -$maxSize = 16GB |
78 |
| -$partitionSize = if ($diskSize -lt $maxSize) { $diskSize } else { $maxSize } |
79 |
| - |
80 |
| -Write-Output "Creating ESP partition on disk $($disks[$selectedDiskNumber].Model) (Index: $selectedDrive) with a size of $partitionSize bytes..." |
81 |
| -$partition = New-Partition -DiskNumber $disk.Number -Size $partitionSize -AssignDriveLetter |
82 |
| -Start-Sleep -Seconds 5 |
83 |
| -Format-Volume -FileSystem FAT32 -NewFileSystemLabel "sbnb" -DriveLetter $partition.DriveLetter |
84 |
| -Write-Output "Partition created and formatted with drive letter: $($partition.DriveLetter)" |
85 |
| - |
86 |
| -# Step 6: Decompress and place sbnb.efi on the ESP partition |
87 |
| -$espDriveLetter = $partition.DriveLetter |
88 |
| -if (-not [string]::IsNullOrEmpty($espDriveLetter)) { |
89 |
| - $espPath = "$($espDriveLetter):\EFI\Boot" |
90 |
| - [System.IO.Directory]::CreateDirectory($espPath) |
91 |
| -} else { |
92 |
| - Write-Output "Error: Unable to determine the ESP drive letter." |
93 |
| - exit |
94 |
| -} |
95 |
| - |
96 |
| -Write-Output "Copying sbnb.efi to $espPath\bootx64.efi..." |
97 |
| -Copy-Item -Path $SbnbEfiPath -Destination "$espPath\bootx64.efi" |
98 |
| - |
99 |
| -# Step 7: Ask user to provide Tailscale key and place it on the ESP partition |
100 |
| -$tailscaleKey = Read-Host "Please provide your Tailscale key (press Enter to skip)" |
101 |
| -if (-not [string]::IsNullOrEmpty($tailscaleKey)) { |
102 |
| - $tailscaleKeyPath = "$($espDriveLetter):\sbnb-tskey.txt" |
103 |
| - [System.IO.File]::WriteAllText($tailscaleKeyPath, $tailscaleKey) |
104 |
| - Write-Output "Tailscale key saved to $tailscaleKeyPath" |
105 |
| -} else { |
106 |
| - Write-Output "No Tailscale key provided. Skipping this step." |
107 |
| -} |
108 |
| - |
109 |
| -# Step 7.1: Ask user to provide the path to a script file and place it on the ESP partition |
110 |
| -$scriptFilePath = Read-Host "Please provide the path to your script file (this script will be saved to sbnb-cmds.sh and executed during Sbnb Linux boot) (press Enter to skip)" |
111 |
| -$scriptFilePath = $scriptFilePath.Trim('"') |
112 |
| -if (-not [string]::IsNullOrEmpty($scriptFilePath) -and (Test-Path $scriptFilePath)) { |
113 |
| - $scriptContent = Get-Content -Path $scriptFilePath -Raw |
114 |
| - # Convert to Unix format by replacing Windows line endings with Unix line endings |
115 |
| - $scriptContent = $scriptContent -replace "`r`n", "`n" |
116 |
| - |
117 |
| - $scriptPath = "$($espDriveLetter):\sbnb-cmds.sh" |
118 |
| - [System.IO.File]::WriteAllText($scriptPath, $scriptContent) |
119 |
| - Write-Output "Script saved to $scriptPath" |
120 |
| -} else { |
121 |
| - Write-Output "No valid script file provided. Skipping this step." |
122 |
| -} |
123 |
| - |
124 |
| -# Step 8: Set GPT partition type |
125 |
| -Write-Output "Setting GPT partition type to C12A7328-F81F-11D2-BA4B-00A0C93EC93B..." |
126 |
| -Set-Partition -DiskNumber $disk.Number -PartitionNumber $partition.PartitionNumber -GptType "{C12A7328-F81F-11D2-BA4B-00A0C93EC93B}" |
127 |
| - |
128 |
| -Write-Output "Operation completed successfully." |
| 1 | +# This script automates Sbnb Linux bootable USB creation process on Windows. |
| 2 | +# It downloads, decompresses, and installs the sbnb.raw file onto a selected disk. |
| 3 | +# It also allows the user to provide a Tailscale key and a custom script to be executed during Sbnb Linux boot. |
| 4 | +# More info at https://github.com/sbnb-io/sbnb |
| 5 | + |
| 6 | +param ( |
| 7 | + [string]$SbnbRawPath |
| 8 | +) |
| 9 | + |
| 10 | +Write-Host "=========================================" -ForegroundColor Cyan |
| 11 | +Write-Host " Welcome to Sbnb Linux Bootable USB Creation " -ForegroundColor Cyan |
| 12 | +Write-Host "=========================================" -ForegroundColor Cyan |
| 13 | + |
| 14 | +# Step 1: Find latest release and download sbnb.raw.zip if not provided |
| 15 | +if (-not $SbnbRawPath) { |
| 16 | + $repoUrl = "https://api.github.com/repos/sbnb-io/sbnb/releases/latest" |
| 17 | + $releaseInfo = Invoke-RestMethod -Uri $repoUrl |
| 18 | + $latestRelease = $releaseInfo.tag_name |
| 19 | + $downloadUrl = $releaseInfo.assets | Where-Object { $_.name -eq "sbnb.raw.zip" } | Select-Object -ExpandProperty browser_download_url |
| 20 | + |
| 21 | + Write-Host "Sbnb Linux latest release: $latestRelease" -ForegroundColor Green |
| 22 | + Write-Host "Download URL: $downloadUrl" -ForegroundColor Green |
| 23 | + |
| 24 | + # Get the size of the download |
| 25 | + $webRequest = Invoke-WebRequest -Uri $downloadUrl -Method Head |
| 26 | + $fileSize = [math]::Round($webRequest.Headers['Content-Length'] / 1MB, 2) |
| 27 | + |
| 28 | + # Ask user if they agree to continue |
| 29 | + $confirmation = Read-Host "The file size is $fileSize MB. Do you want to continue with the download? (y/n)" |
| 30 | + if ($confirmation -ne "y") { |
| 31 | + Write-Host "Download cancelled." -ForegroundColor Red |
| 32 | + exit |
| 33 | + } |
| 34 | + |
| 35 | + Write-Host "Downloading sbnb.raw.zip..." -ForegroundColor Yellow |
| 36 | + $wc = New-Object net.webclient |
| 37 | + $wc.DownloadFile($downloadUrl, "sbnb.raw.zip") |
| 38 | + |
| 39 | + # Step 2: Decompress sbnb.raw.zip to a temporary directory |
| 40 | + $tempDir = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) |
| 41 | + [System.IO.Directory]::CreateDirectory($tempDir) |
| 42 | + |
| 43 | + Write-Host "Decompressing sbnb.raw.zip to $tempDir..." -ForegroundColor Yellow |
| 44 | + Add-Type -AssemblyName System.IO.Compression.FileSystem |
| 45 | + [System.IO.Compression.ZipFile]::ExtractToDirectory("sbnb.raw.zip", $tempDir) |
| 46 | + |
| 47 | + $SbnbRawPath = "$tempDir\sbnb.raw" |
| 48 | +} else { |
| 49 | + Write-Host "Using provided sbnb.raw file: $SbnbRawPath" -ForegroundColor Green |
| 50 | +} |
| 51 | + |
| 52 | +# Step 3: Enumerate all disks and ask user to input disk number |
| 53 | +$disks = Get-WmiObject -Query "SELECT * FROM Win32_DiskDrive" | Sort-Object -Property Model |
| 54 | +Write-Host "Available Disks:" -ForegroundColor Cyan |
| 55 | +for ($i = 0; $i -lt $disks.Count; $i++) { |
| 56 | + $diskInfo = "${i}: $($disks[$i].DeviceID) - $($disks[$i].Model) - $($disks[$i].Name)" |
| 57 | + Write-Host $diskInfo -ForegroundColor Green |
| 58 | +} |
| 59 | + |
| 60 | +$selectedDiskNumber = Read-Host "Enter the number of the disk to flash into" |
| 61 | +$selectedDrive = $disks[$selectedDiskNumber].Index |
| 62 | + |
| 63 | +# Step 4: Double confirm user agrees with selection |
| 64 | +Write-Host "WARNING: You have selected disk $($disks[$selectedDiskNumber].Model) (Index: $selectedDrive)." -ForegroundColor Red -BackgroundColor Yellow |
| 65 | +Write-Host "ALL DATA ON THIS DISK WILL BE DESTROYED!" -ForegroundColor Red -BackgroundColor Yellow |
| 66 | +$confirmation = Read-Host "Are you absolutely sure you want to proceed? (y/n)" |
| 67 | +if ($confirmation -ne "y") { |
| 68 | + Write-Host "Operation cancelled." -ForegroundColor Red |
| 69 | + exit |
| 70 | +} |
| 71 | + |
| 72 | +# Step 5: Write sbnb.raw to the selected disk |
| 73 | +Write-Host "Writing sbnb.raw to disk $($disks[$selectedDiskNumber].Model) (Index: $selectedDrive)..." -ForegroundColor Yellow |
| 74 | +$disk = Get-Disk -Number $selectedDrive |
| 75 | +$disk | Clear-Disk -RemoveData -Confirm:$false |
| 76 | +$disk | Set-Disk -IsOffline $false |
| 77 | +$disk | Set-Disk -IsReadOnly $false |
| 78 | + |
| 79 | +$rawFile = [System.IO.File]::OpenRead($SbnbRawPath) |
| 80 | +$diskStream = [System.IO.FileStream]::new("\\.\PhysicalDrive$selectedDrive", [System.IO.FileMode]::Open, [System.IO.FileAccess]::Write) |
| 81 | +$rawFile.CopyTo($diskStream) |
| 82 | +$rawFile.Close() |
| 83 | +$diskStream.Close() |
| 84 | + |
| 85 | +# Reread partitions from disk after writing sbnb.raw |
| 86 | +Write-Host "Rereading partitions from disk $($disks[$selectedDiskNumber].Model) (Index: $selectedDrive)..." -ForegroundColor Yellow |
| 87 | +$disk | Update-Disk |
| 88 | + |
| 89 | +# Step 6: Change first partition GPT type to normal data GUID |
| 90 | +Write-Host "Changing first partition GPT type to normal data GUID..." -ForegroundColor Yellow |
| 91 | +Set-Partition -DiskNumber $selectedDrive -PartitionNumber 1 -GptType "{EBD0A0A2-B9E5-4433-87C0-68B6B72699C7}" |
| 92 | + |
| 93 | +$partition = Get-Partition -DiskNumber $selectedDrive | Select-Object -First 1 |
| 94 | + |
| 95 | +# Assign a drive letter to the first partition |
| 96 | +Write-Host "Assigning drive letter to the first partition..." -ForegroundColor Yellow |
| 97 | +$driveLetter = (66..90 | ForEach-Object {[char]$_} | Where-Object { -not (Get-Volume -FileSystemLabel $_ -ErrorAction SilentlyContinue) })[0] |
| 98 | + |
| 99 | +if (-not $partition.DriveLetter) { |
| 100 | + $accessPath = "$driveLetter`:\" |
| 101 | + Add-PartitionAccessPath -DiskNumber $selectedDrive -PartitionNumber $partition.PartitionNumber -AccessPath $accessPath |
| 102 | + Write-Host "Assigned drive letter $driveLetter to the first partition." -ForegroundColor Green |
| 103 | +} else { |
| 104 | + Write-Host "Drive letter $($partition.DriveLetter) is already assigned to the first partition." -ForegroundColor Green |
| 105 | +} |
| 106 | + |
| 107 | +# Step 7: Place sbnb-tskey.txt and sbnb-cmds.sh on the first partition |
| 108 | +$partition = Get-Partition -DiskNumber $selectedDrive | Select-Object -First 1 |
| 109 | +$espDriveLetter = $partition.DriveLetter |
| 110 | +if (-not [string]::IsNullOrEmpty($espDriveLetter)) { |
| 111 | + $espPath = "$($espDriveLetter):\" |
| 112 | +} else { |
| 113 | + Write-Host "Error: Unable to determine the ESP drive letter." -ForegroundColor Red |
| 114 | + exit |
| 115 | +} |
| 116 | + |
| 117 | +# Step 7.1: Ask user to provide Tailscale key and place it on the ESP partition |
| 118 | +$tailscaleKey = Read-Host "Please provide your Tailscale key (press Enter to skip)" |
| 119 | +if (-not [string]::IsNullOrEmpty($tailscaleKey)) { |
| 120 | + $tailscaleKeyPath = "$($espDriveLetter):\sbnb-tskey.txt" |
| 121 | + Write-Host "Tailscale key saving to $tailscaleKeyPath" -ForegroundColor Yellow |
| 122 | + [System.IO.File]::WriteAllText($tailscaleKeyPath, $tailscaleKey) |
| 123 | + Write-Host "Tailscale key saved to $tailscaleKeyPath" -ForegroundColor Green |
| 124 | +} else { |
| 125 | + Write-Host "No Tailscale key provided. Skipping this step." -ForegroundColor Yellow |
| 126 | +} |
| 127 | + |
| 128 | +# Step 7.2: Ask user to provide the path to a script file and place it on the ESP partition |
| 129 | +$scriptFilePath = Read-Host "Please provide the path to your script file (this script will be saved to sbnb-cmds.sh and executed during Sbnb Linux boot) (press Enter to skip)" |
| 130 | +$scriptFilePath = $scriptFilePath.Trim('"') |
| 131 | +if (-not [string]::IsNullOrEmpty($scriptFilePath) -and (Test-Path $scriptFilePath)) { |
| 132 | + $scriptContent = Get-Content -Path $scriptFilePath -Raw |
| 133 | + # Convert to Unix format by replacing Windows line endings with Unix line endings |
| 134 | + $scriptContent = $scriptContent -replace "`r`n", "`n" |
| 135 | + |
| 136 | + $scriptPath = "$($espDriveLetter):\sbnb-cmds.sh" |
| 137 | + [System.IO.File]::WriteAllText($scriptPath, $scriptContent) |
| 138 | + Write-Host "Script saved to $scriptPath" -ForegroundColor Green |
| 139 | +} else { |
| 140 | + Write-Host "No valid script file provided. Skipping this step." -ForegroundColor Yellow |
| 141 | +} |
| 142 | +# Step 7.3: Remove the drive letter from the first partition |
| 143 | +Write-Host "Removing drive letter from the first partition..." -ForegroundColor Yellow |
| 144 | +Remove-PartitionAccessPath -DiskNumber $selectedDrive -PartitionNumber $partition.PartitionNumber -AccessPath "$($partition.DriveLetter):\" |
| 145 | +Write-Host "Drive letter removed from the first partition." -ForegroundColor Green |
| 146 | + |
| 147 | +# Step 8: Change GPT type to EFI |
| 148 | +Write-Host "Changing GPT partition type to EFI..." -ForegroundColor Yellow |
| 149 | +Set-Partition -DiskNumber $selectedDrive -PartitionNumber $partition.PartitionNumber -GptType "{C12A7328-F81F-11D2-BA4B-00A0C93EC93B}" |
| 150 | + |
| 151 | +Write-Host "=========================================" -ForegroundColor Cyan |
| 152 | +Write-Host " Operation completed successfully. " -ForegroundColor Cyan |
| 153 | +Write-Host "=========================================" -ForegroundColor Cyan |
0 commit comments