ps-arch-wsl.psm1
function Get-WSLInstallStatus { <# .SYNOPSIS Checks if WSL is installed on the system. #> $wsl = wsl.exe --status if (!$wsl) { return $false } else { return $true } } function Convert-LineEndings { <# .SYNOPSIS Converts the line endings of a file to LF. This is useful when running scripts in WSL. #> param ( [Parameter(Mandatory = $true)] [string]$Path ) # Check if the file exists if (!(Test-Path $Path)) { throw "Failed to convert line endings: File not found at $Path." return } $content = Get-Content -Path $Path -Raw $content = $content -replace "`r`n", "`n" Set-Content -Path $Path -Value $content -NoNewline } function Get-ReleaseAsset { <# .SYNOPSIS Downloads the latest version of an asset attached to a GitHub release and returns the path to the downloaded file in the temp directory. #> param ( [Parameter(Mandatory = $true)] [string]$Repository, [Parameter(Mandatory = $true)] [string]$AssetFilter ) try { $releaseInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repository/releases/latest" } catch { throw "$Repository doesn't exist or has no releases." return } $destination = $null foreach ($asset in $releaseInfo.assets) { if ($asset.name -like "*$AssetFilter") { # Clean up the destination path $destination = "$env:TEMP\$($asset.name)" Write-Verbose "Destination: $destination" break } } if (!$destination) { throw "Failed to find an asset matching the filter '$AssetFilter' from the latest release of $Repository." } if (Test-Path $destination) { Remove-Item $destination -Force } $url = $asset.browser_download_url Write-Verbose "Downloading asset from $url" Invoke-WebRequest -Uri $url -OutFile $destination | Out-Null if (Test-Path $destination) { Write-Verbose "Asset downloaded successfully." return $destination break } else { throw "Failed to download an asset matching the filter '$AssetFilter' from the latest release of $Repository." } } function Install-ArchCertificate { <# .SYNOPSIS Installs the latest ArchWSL certificate into the users "Trusted People" store. #> $certificate = Get-ReleaseAsset -Repository "yuk7/ArchWSL" -AssetFilter "cer" if ($certificate) { try { $installed = Import-Certificate -FilePath $certificate -CertStoreLocation Cert:\LocalMachine\TrustedPeople } catch { throw "Failed to install the ArchWSL certificate: $_" return } if ($installed) { Write-Output "Successfully installed the ArchWSL certificate." } } else { throw "Failed to install the ArchWSL certificate: Certificate not found." } } function Invoke-ArchScript { <# .SYNOPSIS Invokes a script in the ArchWSL distribution. #> param ( [Parameter(Mandatory = $true)] [string]$Script ) if (!(Get-WSLInstallStatus)) { throw "Failed to invoke script: WSL is not installed. Run 'wsl --install', restart your system and try again." return } try { wsl.exe --distribution arch --exec /bin/bash -c $Script } catch { throw "Failed to invoke script: $_" } } function Install-ArchWSL { <# .SYNOPSIS Installs the latest appx package of ArchWSL. #> param ( [Parameter(Mandatory = $false)] [PSCredential]$Credential, [Parameter(Mandatory = $false)] [string]$PostInstallScript ) if (!(Get-WSLInstallStatus)) { throw "Failed to update ArchWSL: WSL is not installed. Run 'wsl --install', restart your system and try again." return } $appx = Get-ReleaseAsset -Repository "yuk7/ArchWSL" -AssetFilter "appx" if ($appx) { try { Add-AppxPackage -Path $appx -ForceApplicationShutdown } catch { throw "Failed to install ArchWSL: $_" return } } else { throw "Failed to install ArchWSL: Appx package not found." } Write-Verbose "Registering ArchWSL distribution." Write-Output "" | arch Write-Verbose "Setting up keyring." try { Invoke-ArchScript -Script "pacman-key --init && pacman-key --populate archlinux && pacman -Syu --noconfirm archlinux-keyring" } catch { throw "Failed to set up keyring: $_" return } Write-Verbose "Installing pacman dependencies." try { Invoke-ArchScript -Script "pacman -Syu --noconfirm git base-devel" } catch { throw "Failed to install pacman dependencies: $_" } Clear-Host if ($Credential) { Write-Verbose "Creating ArchWSL user." New-ArchUser -Credential $Credential } Write-Output "Successfully installed ArchWSL." if ($PostInstallScript) { try { Convert-LineEndings -Path $PostInstallScript } catch { throw "Failed to invoke post-install script: $_" } Convert-LineEndings -Path $PostInstallScript try { wsl.exe --distribution arch -e $PostInstallScript } catch { throw "Failed to invoke post-install script: $_" } } } function Uninstall-ArchWSL { <# .SYNOPSIS Uninstalls ArchWSL. #> Write-Verbose "Checking for existing ArchWSL distribution." wsl.exe --unregister arch | Out-Null try { Get-AppxPackage -Name "yuk7.archwsl" | Remove-AppxPackage } catch { throw "Failed to uninstall ArchWSL: $_" } Write-Output "Successfully uninstalled ArchWSL." } function New-ArchUser { <# .SYNOPSIS Creates a new user in the ArchWSL distribution. #> param ( [Parameter(Mandatory = $true)] [PSCredential]$Credential ) try { Invoke-ArchScript "echo `"%wheel ALL=(ALL) ALL`" > /etc/sudoers.d/wheel && useradd -m -G wheel $($Credential.GetNetworkCredential().UserName) && echo `"$($Credential.GetNetworkCredential().Password)`" | passwd $($Credential.GetNetworkCredential().UserName) --stdin" } catch { throw "Failed to create user $($Credential.GetNetworkCredential().UserName): $_" } # Set the newly created user as the default login try { arch config --default-user $($Credential.GetNetworkCredential().UserName) } catch { throw "Failed to set default user: $_" } } Export-ModuleMember -Function Install-ArchWSL, Uninstall-ArchWSL |