PSWsl.psm1
<#
.SYNOPSIS Run some PowerShell on your WSL Distributions. .DESCRIPTION Run some PowerShell on your WSL Distributions. .PARAMETER DistributionName The distribution of WSL you want to run against. .PARAMETER Command The PowerShell command you want to run. .PARAMETER Scriptblock The PowerShell script block you want to run. .PARAMETER ScriptPath The PowerShell script file you want to run. .PARAMETER Sudo A switch to decide whether you run pwsh with sudo. .EXAMPLE Invoke-WslCommand -Scriptblock { $PSVersionTable } # uses default wsl.exe .EXAMPLE Invoke-WslCommand -Command '$PSVersionTable' .EXAMPLE Invoke-WslCommand -ScriptFile ./foo.ps1 .EXAMPLE Invoke-WslCommand -Scriptblock { $PSVersionTable } -Distribution debian # uses debian.exe .EXAMPLE $version = Invoke-WslCommand -Scriptblock { $PSVersionTable } $version.GetType() # you get back a deserialized object from the invocation .NOTES You must have pwsh and the WSL distribution installed already. #> function Invoke-WslCommand { [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [string[]] $DistributionName = @("wsl"), [Parameter(Mandatory=$true, ParameterSetName="Command", ValueFromPipelineByPropertyName=$true)] [string] $Command, [Parameter(Mandatory=$true, ParameterSetName="ScriptBlock", ValueFromPipelineByPropertyName=$true)] [scriptblock] $Scriptblock, [Parameter(Mandatory=$true, ParameterSetName="ScriptPath", ValueFromPipelineByPropertyName=$true)] [string] $ScriptPath, [Parameter()] [switch] $Sudo ) begin {} process { # Test if distribution exists where.exe $DistributionName | Out-Null if ($LASTEXITCODE -eq 1) { throw "Could not find distribution: $DistributionName" } # Start with pwsh template. Command will go on the right, WSL invocation will go on the left $commandString = "pwsh -OutputFormat xml -EncodedCommand " # We convert the script into a base64 string so we can easily pass it to the pwsh process in WSL switch ($PSCmdlet.ParameterSetName) { Command { $commandString += [convert]::tobase64string([text.encoding]::unicode.getbytes( "`$VerbosePreference = '$VerbosePreference'; { $Command }.Invoke() *>&1")) } Scriptblock { $commandString += [convert]::tobase64string([text.encoding]::unicode.getbytes( "`$VerbosePreference = '$VerbosePreference'; { $($Scriptblock.ToString()) }.Invoke() *>&1")) } ScriptPath { if (-not (Test-Path $ScriptPath)) { throw "No path found: $ScriptPath" } $commandString += [convert]::tobase64string([text.encoding]::unicode.getbytes( "`$VerbosePreference = '$VerbosePreference'; . $ScriptPath *>&1")) } } # If the you want to run pwsh with sudo, add 'sudo' if ($Sudo) { $commandString = "sudo $commandString" } # wsl.exe and specific_distro.exe have a different API. The Specific distros have a run command that you # put your command after, wsl.exe does not have said 'run' command so we need to factor that into our string if (!$DistributionName.Trim().ToLower().Equals("wsl")) { $commandString = "run $commandString" } # Add the distribution $commandString = "$DistributionName $commandString" Write-Verbose "Running: $commandString" return (Invoke-Expression "$commandString") } end {} } <# .SYNOPSIS Get the WSL distribution objects. Supports wildcards. .DESCRIPTION Get the WSL distribution objects. Supports wildcards. Wraps wslconfig.exe .PARAMETER DistributionName The distribution of WSL you want to get. Supports wildcard. .PARAMETER Default Get the default WSL distribution .EXAMPLE Get-WslDistribution # get all distros .EXAMPLE Get-WslDistribution -Default # get the default distro .EXAMPLE # pipe it into something else Get-WslDistribution -DistributionName "ubun*" | Set-WslDistributionDefault .EXAMPLE # pipe an array into it @("ubun*", "debian") | Get-WslDistribution .NOTES You must have the WSL distribution installed already. #> function Get-WslDistribution { [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$true)] [string[]] $DistributionName = "*", [Parameter()] [switch] $Default ) begin { # parse $array = [System.Text.Encoding]::Unicode.GetString([System.Text.Encoding]::UTF8.GetBytes((wslconfig.exe /l))).Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries) | Select-Object -Skip 1 -Unique $distributionArray = $array | ForEach-Object { if ($_.Contains(' (Default)')) { return [PSCustomObject]@{ DistributionName = $_.Split(" (Default)", [System.StringSplitOptions]::RemoveEmptyEntries)[0] Default = $true } } else { return [PSCustomObject]@{ DistributionName = $_ Default = $false } } } } process { $Filter = [scriptblock]::Create( ( '( ' + ( $DistributionName.ForEach( { "`$_.DistributionName -like `"$_`"" } ) -join ' -or ' ) + ' )') ) if ($Default) { return $distributionArray.Where( { $_.Default } ) } else { return $distributionArray.Where( $Filter ) } } end {} } <# .SYNOPSIS Set the default WSL distribution. .DESCRIPTION Set the default WSL distribution. Wraps wslconfig.exe. .PARAMETER DistributionName The name of the WSL distribution you want to make the default. .PARAMETER Distribution The distribution of WSL you want to make the default. .EXAMPLE Set-WslDistribution -DistributionName Ubuntu # get all distros .EXAMPLE # pipe it into something else Get-WslDistribution -DistributionName "ubun*" | Set-WslDistributionDefault .NOTES You must have the WSL distribution installed already. #> function Set-WslDistributionDefault { [CmdletBinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="DistributionName")] [string] $DistributionName, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="DistributionObject")] [PSCustomObject] $Distribution ) begin {} process { switch ($PSCmdlet.ParameterSetName) { DistributionName { wslconfig.exe /s $DistributionName } DistributionObject { wslconfig.exe /s $Distribution.DistributionName } } } end {} } <# .SYNOPSIS Enter a PowerShell session within a WSL distribution. .DESCRIPTION Enter a PowerShell session within a WSL distribution. .PARAMETER DistributionName The name of the WSL distribution you want to make the default. .PARAMETER Distribution The distribution of WSL you want to make the default. .EXAMPLE Enter-WslDistribution -DistributionName Ubuntu # get all distros .EXAMPLE # pipe it into something else Get-WslDistribution -DistributionName "ubun*" | Enter-WslDistribution .NOTES You must have the WSL distribution installed already. #> function Enter-WslDistribution { [CmdletBinding(DefaultParameterSetName="DistributionName")] param ( [Parameter(ValueFromPipeline=$true, ParameterSetName="DistributionName")] [string] $DistributionName = "*", [Parameter(ValueFromPipeline=$true, ParameterSetName="DistributionObject")] [PSCustomObject] $Distribution ) begin { } process { switch ($PSCmdlet.ParameterSetName) { DistributionName { $distro = Get-WslDistribution -DistributionName $DistributionName if (-not $distro) { throw "Could not find distribution: $DistributionName" } else { Invoke-Expression "$($distro[0].DistributionName) run pwsh" } } DistributionObject { Invoke-Expression "$($Distribution.DistributionName) run pwsh" } } } end { } } |