diff --git a/.assets/docker/Dockerfile b/.assets/docker/Dockerfile index c8b8f9ab..462bf4f6 100644 --- a/.assets/docker/Dockerfile +++ b/.assets/docker/Dockerfile @@ -22,7 +22,7 @@ RUN \ && apt-get update && apt-get install --no-install-recommends -y eza \ # setup PS modules && pwsh -nop -c \ - 'Install-Module Microsoft.PowerShell.PSResourceGet -AllowPrerelease -Scope AllUsers -Force \ + 'Install-Module Microsoft.PowerShell.PSResourceGet -Scope AllUsers -Force \ && Set-PSResourceRepository -Name PSGallery -Trusted \ && Install-PSResource -Name posh-git -Scope AllUsers \ && Update-Help -ErrorAction SilentlyContinue || $true' \ diff --git a/.assets/provision/setup_profile_allusers.ps1 b/.assets/provision/setup_profile_allusers.ps1 index 50e2bd1e..7019cade 100755 --- a/.assets/provision/setup_profile_allusers.ps1 +++ b/.assets/provision/setup_profile_allusers.ps1 @@ -85,15 +85,15 @@ process { # install Microsoft.PowerShell.PSResourceGet for ($i = 0; -not (Get-Module Microsoft.PowerShell.PSResourceGet -ListAvailable) -and $i -lt 5; $i++) { Write-Host 'installing PSResourceGet...' - Install-Module Microsoft.PowerShell.PSResourceGet -AllowPrerelease -Scope AllUsers + Install-Module Microsoft.PowerShell.PSResourceGet -Scope AllUsers } # install/update modules if (Get-InstalledModule -Name Microsoft.PowerShell.PSResourceGet -ErrorAction SilentlyContinue) { # update Microsoft.PowerShell.PSResourceGet try { - Update-Module Microsoft.PowerShell.PSResourceGet -AllowPrerelease -Scope AllUsers -ErrorAction Stop + Update-Module Microsoft.PowerShell.PSResourceGet -Scope AllUsers -ErrorAction Stop } catch { - Install-Module Microsoft.PowerShell.PSResourceGet -AllowPrerelease -Scope AllUsers -Force -SkipPublisherCheck + Install-Module Microsoft.PowerShell.PSResourceGet -Scope AllUsers -Force -SkipPublisherCheck } # uninstall old versions Get-InstalledModule -Name Microsoft.PowerShell.PSResourceGet -AllVersions ` diff --git a/.assets/provision/setup_profile_user.ps1 b/.assets/provision/setup_profile_user.ps1 index 6ffcf6d7..e7741934 100755 --- a/.assets/provision/setup_profile_user.ps1 +++ b/.assets/provision/setup_profile_user.ps1 @@ -33,6 +33,11 @@ if (Get-InstalledModule -Name Microsoft.PowerShell.PSResourceGet) { if (Get-Command oh-my-posh -CommandType Application) { oh-my-posh disable notice } +# install PSReadLine +for ($i = 0; ((Get-Module PSReadLine -ListAvailable).Count -eq 1) -and $i -lt 5; $i++) { + Write-Host 'installing PSReadLine...' + Install-PSResource -Name PSReadLine +} $kubectlSet = try { Select-String '__kubectl_debug' -Path $PROFILE -Quiet } catch { $false } if ((Test-Path /usr/bin/kubectl) -and -not $kubectlSet) { diff --git a/.assets/scripts/modules_update.ps1 b/.assets/scripts/modules_update.ps1 index 95ca88b1..16e15414 100644 --- a/.assets/scripts/modules_update.ps1 +++ b/.assets/scripts/modules_update.ps1 @@ -3,6 +3,9 @@ .SYNOPSIS Update repository modules from ps-modules. +.PARAMETER Refresh +Check if repository is up to date and reset to origin if necessary. + .EXAMPLE .assets/scripts/modules_update.ps1 .assets/scripts/modules_update.ps1 -Refresh @@ -43,6 +46,7 @@ begin { common = @( 'ConvertFrom-Cfg' 'ConvertTo-Cfg' + 'Get-ArrayIndexMenu' 'Invoke-ExampleScriptSave' ) } diff --git a/modules/SetupUtils/Functions/common.ps1 b/modules/SetupUtils/Functions/common.ps1 index b733214b..da665f4b 100644 --- a/modules/SetupUtils/Functions/common.ps1 +++ b/modules/SetupUtils/Functions/common.ps1 @@ -100,6 +100,95 @@ function ConvertTo-Cfg { } } +function Get-ArrayIndexMenu { + [CmdletBinding()] + param ( + [Parameter(Mandatory, Position = 0, ValueFromPipeline)] + [object[]]$Array, + + [Parameter(Position = 1)] + [string]$Message, + + [switch]$Value, + + [switch]$List, + + [switch]$AllowNoSelection + ) + begin { + # instantiate generic list to store the input array + $lst = [System.Collections.Generic.List[object]]::new() + } + + process { + # determine if the input array has multiple properties + if (-not $arrayType) { + $arrayType = ($Array | Select-Object * | Get-Member -MemberType NoteProperty).Count -gt 1 ? 'object' : 'string' + } + # add input array items to the generic list + $Array.ForEach({ $lst.Add($_) }) + } + + end { + # return if the input array has less then 2 items + if ($lst.Count -eq 0) { + return + } elseif ($lst.Count -eq 1) { + $indexes = [System.Collections.Generic.HashSet[int]]::new([int[]]0) + } else { + # create selection menu + $menu = switch ($arrayType) { + object { + $i = 0 + $lst ` + | Select-Object @{ N = '#'; E = { $lst.IndexOf($_) } }, @{ N = ' '; E = { '-' } }, * ` + | Format-Table -AutoSize ` + | Out-String -Stream ` + | ForEach-Object { $i -lt 3 ? "`e[1;92m$_`e[0m" : $_; $i++ } ` + | Out-String + continue + } + string { + $lst.ToArray().ForEach({ [PSCustomObject]@{ '#' = $lst.IndexOf($_); ' ' = '-'; 'V' = $_ } }) ` + | Format-Table -AutoSize -HideTableHeaders ` + | Out-String + continue + } + } + + # create prompt message + if (-not $Message) { + $Message = $List ? 'Enter comma/space separated selection list' : 'Enter selection' + } + $msg = "`n`e[4m$Message`e[0m:`n$menu" + + # read and validate input + do { + # instantiate indexes collection + $indexes = [System.Collections.Generic.HashSet[int]]::new() + # prompt for a selection from the input array + (Read-Host -Prompt $msg).Split([char[]]@(' ', ','), [StringSplitOptions]::RemoveEmptyEntries).ForEach({ + try { $indexes.Add($_) | Out-Null } catch { } + } + ) + # calculate stats for returned indexes + $stat = $indexes | Measure-Object -Minimum -Maximum + # evaluate if the Read-Host input is valid + $continue = if ($stat.Count -eq 0) { + $AllowNoSelection + } elseif ($stat.Count -eq 1 -or ($List -and $stat.Count -gt 0)) { + $stat.Minimum -ge 0 -and $stat.Maximum -lt $lst.Count + } else { + $false + } + } until ($continue) + } + + # return result + return $Value ? $indexes.ForEach({ $lst[$_] }) : [int[]]$indexes.ForEach({ $_ }) + } +} + function Invoke-ExampleScriptSave { [CmdletBinding()] param ( diff --git a/modules/SetupUtils/SetupUtils.psd1 b/modules/SetupUtils/SetupUtils.psd1 index d1f2ed9d..57f5848b 100644 --- a/modules/SetupUtils/SetupUtils.psd1 +++ b/modules/SetupUtils/SetupUtils.psd1 @@ -12,7 +12,7 @@ RootModule = 'SetupUtils.psm1' # Version number of this module. - ModuleVersion = '0.2.1' + ModuleVersion = '0.2.2' # Supported PSEditions CompatiblePSEditions = @('Core') @@ -76,6 +76,7 @@ # common 'ConvertFrom-Cfg' 'ConvertTo-Cfg' + 'Get-ArrayIndexMenu' 'Invoke-ExampleScriptSave' # wsl 'Get-WslDistro' diff --git a/modules/SetupUtils/SetupUtils.psm1 b/modules/SetupUtils/SetupUtils.psm1 index 79960567..d24f94a0 100644 --- a/modules/SetupUtils/SetupUtils.psm1 +++ b/modules/SetupUtils/SetupUtils.psm1 @@ -12,6 +12,7 @@ $exportModuleMemberParams = @{ # common 'ConvertFrom-Cfg' 'ConvertTo-Cfg' + 'Get-ArrayIndexMenu' 'Invoke-ExampleScriptSave' # wsl 'Get-WslDistro' diff --git a/wsl/wsl_install.ps1 b/wsl/wsl_install.ps1 index a20f5e4e..ccbcf4ea 100644 --- a/wsl/wsl_install.ps1 +++ b/wsl/wsl_install.ps1 @@ -69,7 +69,7 @@ process { wsl.exe --update # *Check the current default version - $wslDefaultVersion = Get-ItemPropertyValue -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss' -Name 'DefaultVersion' -ErrorAction SilentlyContinue + $wslDefaultVersion = (Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss').DefaultVersion if ($wslDefaultVersion -ne 2) { Write-Warning 'You are currently using WSL version 1 as default.' if ((Read-Host -Prompt 'Would you like to switch to WSL 2 (recommended)? [Y/n]') -ne 'n') { diff --git a/wsl/wsl_setup.ps1 b/wsl/wsl_setup.ps1 index 03fe1726..75eb13c5 100644 --- a/wsl/wsl_setup.ps1 +++ b/wsl/wsl_setup.ps1 @@ -67,6 +67,8 @@ wsl/wsl_setup.ps1 $Distro -r $Repos -s $Scope -o $OmpTheme -AddCertificate # :update all existing WSL distros wsl/wsl_setup.ps1 #> +using namespace System.Management.Automation.Host + [CmdletBinding(DefaultParameterSetName = 'Update')] param ( [Parameter(Mandatory, Position = 0, ParameterSetName = 'Setup')] @@ -116,9 +118,9 @@ begin { # set location to workspace folder Push-Location "$PSScriptRoot/.." # import InstallUtils for the Invoke-GhRepoClone function - Import-Module (Resolve-Path './modules/InstallUtils') + Import-Module (Convert-Path './modules/InstallUtils') # import SetupUtils for the Set-WslConf function - Import-Module (Resolve-Path './modules/SetupUtils') + Import-Module (Convert-Path './modules/SetupUtils') # check if repository is up to date Write-Host "`nchecking if the repository is up to date..." -ForegroundColor Cyan @@ -140,7 +142,7 @@ begin { # install online distro if ($Distro -in $onlineDistros.Name) { Write-Host "`nspecified distribution not found ($Distro), proceeding to install..." -ForegroundColor Cyan - $cmd = "wsl.exe --install --distribution $Distro" + $cmd = "wsl.exe --install --distribution $Distro --web-download" try { Get-Service LxssManagerUser*, WSLService | Out-Null Write-Host "`nSetting up user profile in WSL distro. Type 'exit' when finished to proceed with WSL setup!`n" -ForegroundColor Yellow @@ -160,21 +162,50 @@ begin { Write-Warning "The specified distro does not exist ($Distro)." exit 1 } + } elseif ($lxss.Where({ $_.Name -eq $Distro }).Version -eq 1) { + Write-Host '' + Write-Warning "The distribution `"$Distro`" is currently using WSL1!" + $caption = 'It is strongly recommended to use WSL2.' + $message = 'Select your choice:' + $choices = @( + @{ choice = '&Replace the current distro'; desc = "Delete current '$Distro' distro and install it as WSL2." } + @{ choice = '&Select another distro to install'; desc = 'Select from other online distros to install as WSL2.' } + @{ choice = '&Continue setup of the current distro'; desc = "Continue setup of the current WSL1 '$Distro' distro." } + ) + [ChoiceDescription[]]$options = $choices.ForEach({ [ChoiceDescription]::new($_.choice, $_.desc) }) + $choice = $Host.UI.PromptForChoice($caption, $message, $options, -1) + if ($choice -ne 2) { + # check the default WSL version and change to 2 if necessary + if ((Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss').DefaultVersion -ne 2) { + wsl.exe --set-default-version 2 + } + switch ($choice) { + 0 { + Write-Host "`nunregistering current distro..." -ForegroundColor Cyan + wsl.exe --unregister $Distro + continue + } + 1 { + for ($i = 0; $i -lt 5; $i++) { + if ($onlineDistros = Get-WslDistro -Online) { + $onlineDistros = $onlineDistros.Name | Where-Object { + $_ -ne $Distro -and $_ -match 'ubuntu|debian' + } + break + } + } + $Distro = Get-ArrayIndexMenu $onlineDistros -Message 'Choose distro to install' -Value + Write-Host "`ninstalling selected distro ($Distro)..." -ForegroundColor Cyan + continue + } + } + Write-Host "`nSetting up user profile in WSL distro. Type 'exit' when finished to proceed with WSL setup!`n" -ForegroundColor Yellow + wsl.exe --install --distribution $Distro --web-download + } } # *perform initial distro setup # disable appending Windows path inside distro to fix mounting issues $lxss = Get-WslDistro -FromRegistry | Where-Object Name -EQ $Distro - # check if current version is V2 - if ($lxss.Version -eq 1) { - Write-Warning "The distribution `"$Distro`" is currently using version 1." - if ((Read-Host -Prompt 'Would you like to convert it to version 2 (recommended)? [Y/n]') -ne 'n') { - Write-Host 'Converting the distro to version 2.' - wsl --set-version $Distro 2 - $lxss.Version = 2 - } else { - Write-Host 'Keeping the version 1 for the distribution.' - } - } # enable automount in wsl.conf $param = @{ Distro = $Distro