Skip to content

Commit

Permalink
Add winget support
Browse files Browse the repository at this point in the history
The winget.ps1 script is currently not working. Microsoft is still doing
work on this front so I'm going to wait until the dust settles here.

If you need non-interactive installation of WinGet now then see here:
https://github.com/asheroto/winget-installer/blob/master/winget-install.ps1

WinGet GitHub issues to track:
microsoft/winget-cli#401
microsoft/winget-cli#2434

Also, perhaps MSIX Core so we can get Windows 7 support:
https://learn.microsoft.com/en-us/windows/msix/msix-core/msixcore
However, that's only MSIX, MS isn't targeting WinGet for below Windows
10 1809 (but maybe someone will build a small compatability layer):
microsoft/winget-cli#1686 (comment)
  • Loading branch information
ElliotKillick committed Jun 13, 2023
1 parent 9f68dd9 commit 854f1f9
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 26 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Qvm-Create-Windows-Qube is a tool for quickly and conveniently installing fresh

The project emphasizes correctness, security and treating Windows as an untrusted guest operating system throughout the entire process. The installation takes place 100% air gapped and features optional [Whonix integration](https://github.com/elliotkillick/qvm-create-windows-qube#whonix-recommendations-for-windows-whonix-workstation) on the finished Windows qube for added privacy.

It also features other niceties such as automatic installation of packages including Firefox, Office 365, Notepad++, Visual Studio and more using Chocolatey to get you up and running quickly in your new environment.
It also features other niceties such as automatic installation of packages including Firefox, Office 365, Notepad++, Visual Studio and more using WinGet or Chocolatey to get you up and running quickly in your new environment.

**As featured on: [<img width="15" src="https://news.ycombinator.com/favicon.ico" alt="Hacker News Favicon" /> Hacker News](https://news.ycombinator.com/item?id=28900125)** | *Proudly ranked in the top 10 on the front page of Hacker News as well as first place for Show HN*

Expand Down Expand Up @@ -66,7 +66,8 @@ Usage: qvm-create-windows-qube [options] -i <iso> -a <answer file> <name>
-o, --optimize Optimize Windows by disabling unnecessary functionality for a qube
-y, --spyless Configure Windows telemetry settings to respect privacy
-w, --whonix Apply Whonix recommended settings for a Windows-Whonix-Workstation
-p, --packages <packages> Comma-separated list of packages to pre-install (see available packages at: https://chocolatey.org/packages)
--winget-pkgs <packages> Comma-separated list of WinGet packages to pre-install (see available packages at: https://winget.run)
--choco-pkgs <packages> Comma-separated list of Chocolatey packages to pre-install (see available packages at: https://community.chocolatey.org/packages)
-P, --pool <name> LVM storage pool to install Windows on (https://www.qubes-os.org/doc/secondary-storage/)
-i, --iso <file> Windows media to automatically install and setup
-a, --answer-file <xml file> Settings for Windows installation
Expand All @@ -88,9 +89,9 @@ For advanced readers: Qvm-Create-Windows-Qube takes a generic approach to handli

*[Video demonstration](https://www.youtube.com/watch?v=cCi2MOUwS_Q)*

`qvm-create-windows-qube -n sys-firewall -oyp firefox,notepadplusplus,office365proplus -i win10x64.iso -a win10x64-pro.xml work-win10`
`qvm-create-windows-qube -n sys-firewall -oy --winget-pkgs Mozilla.Firefox,Notepad++.Notepad++ --choco-pkgs office365proplus -i win10x64.iso -a win10x64-pro.xml work-win10`

`qvm-create-windows-qube -n sys-firewall -oyp steam -i win10x64.iso -a win10x64-pro.xml game-console`
`qvm-create-windows-qube -n sys-firewall -oy --winget-pkgs Valve.Steam -i win10x64.iso -a win10x64-pro.xml game-console`

#### Windows Server 2019

Expand All @@ -101,17 +102,17 @@ For advanced readers: Qvm-Create-Windows-Qube takes a generic approach to handli
- A more stable, minified, secure and private version of Windows 10 officially provided by Microsoft
- This version of Windows 10 is recommended for those who need the best in Windows security and privacy

`qvm-create-windows-qube -n sys-firewall -oyp firefox,notepadplusplus,office365proplus -i win10x64-ltsc-eval.iso -a win10x64-ltsc-eval.xml work-win10`
`qvm-create-windows-qube -n sys-firewall -oy --winget-pkgs Mozilla.Firefox,Notepad++.Notepad++ --choco-pkgs office365proplus -i win10x64-enterprise-ltsc-eval.iso -a win10x64-enterprise-ltsc-eval.xml work-win10`

`qvm-create-windows-qube -n sys-whonix -oyw -i win10x64-ltsc-eval.iso -a win10x64-ltsc-eval.xml anon-win10`
`qvm-create-windows-qube -n sys-whonix -oyw -i win10x64-enterprise-ltsc-eval.iso -a win10x64-enterprise-ltsc-eval.xml anon-win10`

#### Windows 7

- Not recommended because Windows 7 is [no longer supported](https://github.com/elliotkillick/qvm-create-windows-qube#advisories) by Microsoft, however, it's the only desktop OS the Qubes GUI driver (in Qubes Windows Tools) supports if seamless window integration or dynamic resizing is required

*[Video demonstration](https://www.youtube.com/watch?v=duUM1VLrXIQ)*

`qvm-create-windows-qube -n sys-firewall -soyp firefox,notepadplusplus,office365proplus -i win7x64-ultimate.iso -a win7x64-ultimate.xml work-win7`
`qvm-create-windows-qube -n sys-firewall -soy --winget-pkgs Mozilla.Firefox,Notepad++.Notepad++ --choco-pkgs office365proplus -i win7x64-ultimate.iso -a win7x64-ultimate.xml work-win7`

## Security

Expand Down Expand Up @@ -274,11 +275,12 @@ Once the Windows qube gets up and running though, community reports have proven
- [x] Support Windows 10 Enterprise LTSC (Long Term Support Channel)
- Provides security updates for 10 years, very stable and less bloat than stock Windows 10
- [ ] Support Windows 11
- Qvm-Create-Windows-Qube was made to be Windows version independent, the only real work to do here is creating an answer file (probably just slightly modifying the Windows 10 one) and adding it `mido.sh` (which will not be a problem now that I've extended it's functionality to download from behind the gated Microsoft ISO download API)
- Qvm-Create-Windows-Qube was made to be Windows version independent, I've already added a Windows 11 download to Mido, and added answer files for Windows 11 (just slightly modifying the Windows 10 ones)
- The real question is whether Qubes Windows Tools is going to work under Windows 11
- Microsoft has a fantastic track record for backwards compatibility even at the kernel API level though (because businesses love backwards compatibility) so it's possible it works just fine
- Help wanted, testers welcome
- [x] Provision Chocolatey
- [x] Provision WinGet
- [x] Add an option to slim down Windows as documented for Qubes [here](https://www.qubes-os.org/doc/windows-template-customization/)
- [x] Make `windows-mgmt` air gapped
- [x] Extend functionality of `download-windows.sh` (now `mido.sh` to download ISOs from behind Microsoft's gated ISO download API
Expand Down
7 changes: 5 additions & 2 deletions post/packages.ps1 → post/choco.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.SYNOPSIS
Install Chocolatey and specified packages
.PARAMETER Packages
Comma-separated list of packages to install (see available packages at: https://chocolatey.org/packages)
Comma-separated list of packages to install
#>

# Copyright (C) 2019 Elliot Killick <[email protected]>
Expand All @@ -15,7 +15,10 @@ Param (
$host.UI.RawUI.WindowTitle = $PSCommandPath

# Force Powershell 2 to use TLS 1.2
[System.Net.ServicePointManager]::SecurityProtocol = [Enum]::ToObject([System.Net.SecurityProtocolType], 3072)
if ([System.Net.SecurityProtocolType]::Tls12 -eq $null) {
Write-Host "Enabling TLS 1.2 for PowerShell 2 (please ignore Chocolatey if it claims that TLS 1.0 is in use)..."
[System.Net.ServicePointManager]::SecurityProtocol = [Enum]::ToObject([System.Net.SecurityProtocolType], 3072)
}

# https://chocolatey.org/install
Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Expand Down
55 changes: 55 additions & 0 deletions post/winget.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<#
.SYNOPSIS
Install WinGet (if required) and specified packages
.PARAMETER Packages
Comma-separated list of packages to install
#>

# Copyright (C) 2023 Elliot Killick <[email protected]>
# Licensed under the MIT License. See LICENSE file for details.

Param (
[Parameter(Mandatory=$true)][String[]]$Packages
)

$host.UI.RawUI.WindowTitle = $PSCommandPath

if (!(Get-Command -ErrorAction SilentlyContinue winget)) {
# Force Powershell 2 to use TLS 1.2
if ([System.Net.SecurityProtocolType]::Tls12 -eq $null) {
Write-Host "Enabling TLS 1.2 for PowerShell 2..."
[System.Net.ServicePointManager]::SecurityProtocol = [Enum]::ToObject([System.Net.SecurityProtocolType], 3072)
}

$wc = New-Object System.Net.WebClient

# GitHub API always blocks empty user agents (default for WebClient)
# Set a common user agent to avoid figerprinting
if ([Microsoft.PowerShell.Commands.PSUserAgent] -ne $null) {
$wc.Headers.Add('User-Agent', [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome)
else {
# PowerShell 2
# Set user agent of most up-to-date Internet Explorer (before EOL) on Windows 7
# Even the 64-bit iexplore.exe in "C:\Program Files" has a "WOW64" user agent
$wc.Headers.Add('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko')
}

# Download and extract WinGet MSIX bundle link
# We could parse the JSON, but this is more secure
$wc.DowloadString('https://api.github.com/repos/microsoft/winget-cli/releases/latest') -match 'https://github.com/microsoft/winget-cli/releases/download/v[0-9.]+/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle'
$url = matches[0]

# Create temporary file
$file = [IO.Path]::GetTempFileName()

(New-Object System.Net.WebClient).DownloadFile($url, $file)

Add-AppxPackage -Path $file

Remove-Item -Path $file
}

winget install --accept-source-agreements --accept-package-agreements --exact --id $Packages

# Install from terminal: https://github.com/microsoft/winget-cli/issues/2222
# MSIX Core: https://learn.microsoft.com/en-us/windows/msix/msix-core/msixcore
44 changes: 28 additions & 16 deletions qvm-create-windows-qube
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,19 @@ usage() {
echo " -o, --optimize Optimize Windows by disabling unnecessary functionality for a qube"
echo " -y, --spyless Configure Windows telemetry settings to respect privacy"
echo " -w, --whonix Apply Whonix recommended settings for a Windows-Whonix-Workstation"
echo " -p, --packages <packages> Comma-separated list of packages to pre-install (see available packages at: https://chocolatey.org/packages)"
echo " --winget-pkgs <packages> Comma-separated list of WinGet packages to pre-install (see available packages at: https://winget.run)"
echo " --choco-pkgs <packages> Comma-separated list of Chocolatey packages to pre-install (see available packages at: https://community.chocolatey.org/packages)"
echo " -P, --pool <name> LVM storage pool to install Windows on (https://www.qubes-os.org/doc/secondary-storage/)"
echo " -i, --iso <file> Windows media to automatically install and setup"
echo " -a, --answer-file <xml file> Settings for Windows installation"
}

# Option strings
short="hc:tn:soywp:P:i:a:"
long="help,count:,template,netvm:,seamless,optimize,spyless,whonix,packages:,pool:,iso:,answer-file:"
short_opts="hc:tn:soyw:P:i:a:"
long_opts="help,count:,template,netvm:,seamless,optimize,spyless,whonix,winget-pkgs:,choco-pkgs:,pool:,iso:,answer-file:"

# Read options
if ! opts=$(getopt --options=$short --longoptions=$long --name "$0" -- "$@"); then
if ! opts=$(getopt --options=$short_opts --longoptions=$long_opts --name "$0" -- "$@"); then
exit 1
fi
eval set -- "$opts"
Expand Down Expand Up @@ -89,11 +90,14 @@ while true; do
;;
-w | --whonix)
whonix="true"
;;
--winget-pkgs)
winget_pkgs="$2"
shift
;;
-p | --packages)
packages="$2"
shift 2
--choco-pkgs)
choco_pkgs="$2"
shift
;;
-P | --pool)
pool="$2"
Expand Down Expand Up @@ -192,14 +196,14 @@ if ! qvm-check --running "$resources_qube" &> /dev/null; then
fi
fi
# Validate packages
if [ "$packages" ]; then
# Validate winget-pkgs and choco-pkgs
if [ "$winget_pkgs" ] || [ "$choco_pkgs" ]; then
if ! [ "$netvm" ]; then
echo -e "${RED}[!]${NC} A NetVM must be configured to use packages" >&2
exit 1
fi
if qvm-tags "$netvm" list anon-gateway &> /dev/null; then
if [ "$choco_pkgs" ] && qvm-tags "$netvm" list anon-gateway &> /dev/null; then
echo -e "${RED}[!]${NC} Due to Chocolatey blocking Tor, packages cannot be used with NetVM: $netvm" >&2
exit 1
fi
Expand Down Expand Up @@ -401,15 +405,23 @@ for (( counter = 1; counter <= count; counter++ )); do
fi
# Let Windows connect to the Internet earlier for package installation
if [ "$packages" ]; then
if [ "$winget_pkgs" ] || [ "$choco_pkgs" ]; then
break_airgap
fi
if [ "$packages" ]; then
echo -e "${BLUE}[i]${NC} Installing packages..." >&2
qvm-run -p "$qube" "cd $post_incoming_dir && powershell -ExecutionPolicy Bypass -Command .\\packages.ps1 $packages <nul" || true
if [ "$winget_pkgs" ]; then
echo -e "${BLUE}[i]${NC} Installing WinGet packages..." >&2
# <nul is for a Windows 7 bug that causes PowerShell not to exit when run from CMD
qvm-run -p "$qube" "cd $post_incoming_dir && powershell -ExecutionPolicy Bypass -Command .\\winget.ps1 $winget_pkgs <nul" || true
fi
if [ "$choco_pkgs" ]; then
echo -e "${BLUE}[i]${NC} Installing Chocolatey packages..." >&2
qvm-run -p "$qube" "cd $post_incoming_dir && powershell -ExecutionPolicy Bypass -Command .\\choco.ps1 $choco_pkgs <nul" || true
fi
# Add new apps to app menu
# Add new apps from packages to app menu
if [ "$winget_pkgs" ] || [ "$choco_pkgs" ]; then
qvm-sync-appmenus "$qube" &> /dev/null
fi
Expand Down Expand Up @@ -442,7 +454,7 @@ for (( counter = 1; counter <= count; counter++ )); do
qvm-prefs "$qube" memory 2048
# Let Windows connect to the Internet with the user selected NetVM later when package installation is disabled
if [ "$netvm" ] && [ ! "$packages" ]; then
if [ "$netvm" ] && ! { [ "$winget_pkgs" ] || [ "$choco_pkgs" ]; }; then
break_airgap
fi
Expand Down

0 comments on commit 854f1f9

Please sign in to comment.