Last active
October 8, 2020 07:13
-
-
Save bender-the-greatest/9b46c4b66b00e36176e20b7f44cec511 to your computer and use it in GitHub Desktop.
Configure a new wine prefix. A bit convoluted since I wanted this to set up a shared Wine directory, but Wine doesn't support multiuser scenarios. Run Set-WineEnv, the other two functions are helpers used in that function.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-CanWriteDirectory { | |
[CmdletBinding()] | |
Param( | |
[Parameter(Mandatory, Position=0)] | |
[ValidateScript( | |
{ Test-Path -PathType Container $_ }, | |
ErrorMessage = "Could not find the path or it is not a directory: {0}" | |
)] | |
[string]$Path | |
) | |
# Make sure temp file doesn't already exist (we clean it up) | |
$index = 0 | |
$tempFilePath = Join-Path $Path "$($MyInvocation.MyCommand -replace '-')Check$(( $index )).txt" | |
while( Test-Path -PathType Leaf $tempFilePath ) { | |
Write-Verbose "${tempFilePath} already exists. Incrementing index..." | |
$tempFilePath = Join-Path $Path "$($MyInvocation.MyCommand -replace '-')Check$(( ++$index )).txt" | |
} | |
# Write temp file to see if we can | |
$checkPermArgs = @{ | |
Path = $tempFilePath | |
ErrorAction = 'Stop' | |
} | |
Write-Verbose "Writing file ${tempFilePath}" | |
try { | |
"$($MyInvocation.MyCommand) check $([DateTime]::Now)" | Out-File @checkPermArgs | |
} catch { | |
Write-Verbose "Error writing ""${tempFilePath}"": $($_.Exception.Message)" | |
return $false | |
} | |
# Clean up our messy handiwork | |
$removeItemArgs = @{ | |
Path = $tempFilePath | |
ErrorAction = 'Stop' | |
Force = $true | |
} | |
Write-Verbose "Removing file ${tempFilePath}" | |
try { | |
Remove-Item @removeItemArgs | |
} catch { | |
Write-Warning "Error removing temp file ""${tempFilePath}"": $($_.Exception.Message)" | |
} | |
$true | |
} | |
function Invoke-Executable { | |
[CmdletBinding()] | |
Param( | |
[Parameter(Mandatory, Position=0)] | |
[string]$Command, | |
[Parameter(Position=1, ValueFromRemainingArguments)] | |
[string[]]$Arguments, | |
[int[]]$ExitCode = 0 | |
) | |
try { | |
& $Command @Arguments | |
} catch [System.Management.Automation.CommandNotFoundException] { | |
$message = "Command ${Command} not found. If an argument is mistaken for a named parameter of this function, prefix positional arguments with --. ", | |
"`te.g. ``Invoke-Executable ping -- www.google.com -c 2``" -join [System.Environment]::NewLine | |
throw [System.Management.Automation.RuntimeException]::new([string]$message, $_.Exception) | |
} | |
if( $LASTEXITCODE -notin $ExitCode ) { | |
Write-Error "Command failed with exit code ${LASTEXITCODE}. Use -ExitCode to specify expected exit codes." | |
} | |
} | |
function Set-WineEnv { | |
[Alias('SetWine')] | |
[CmdletBinding()] | |
Param( | |
[ValidateSet('win32', 'win64')] | |
[Parameter(Position=0,Mandatory)] | |
[Alias('Arch')] | |
[string]$WineArch, | |
[Alias('Wine', 'Root', 'Prefix')] | |
[string]$WinePrefix, | |
[switch]$CreateIfMissing = $true, | |
[switch]$Configure = $false, | |
[switch]$SetACLs = $true, | |
[ValidateScript( | |
{ $_ -notmatch '\s' }, | |
ErrorMessage = 'Whitespace not allowed in the WineGroup' | |
)] | |
[string]$WineGroup = 'wineusers', | |
[ValidateScript( | |
{ $_ -notmatch '\s' }, | |
ErrorMessage = 'Whitespace not allowed in the WineUser' | |
)] | |
[string]$WineUser = $env:USER | |
) | |
if( !( Get-Command wine ) ){ | |
throw "Wine executable is not on the path. Bailing." | |
} | |
# Set the wineprefix if not set | |
if( !$WinePrefix ) { | |
$useWinePrefix = switch( $WineArch ) { | |
'win32' { '/wineroot/win32'; break; } | |
'win64' { '/wineroot/win64'; break; } | |
default { throw "Invalid winarch detected while setting WINEPREFIX: ${WineArch}" } | |
} | |
} else { | |
$useWinePrefix = $WinePrefix | |
} | |
# Make sure prefix exists, create if missing and directed to | |
if( !( Test-Path -PathType Container -Path $useWinePrefix ) ) { | |
switch( $CreateIfMissing ) { | |
$false { throw "WINEPREFIX ""${useWinePrefix}"" doesn't exist, and CreateIfMissing set to false" } | |
default { | |
Write-Verbose "WINEPREFIX ""${useWinePrefix}"" doesn't exist, creating..." | |
if( Get-CanWriteDirectory -Path $useWinePrefix ) { | |
New-Item -ItemType Directory $useWinePrefix -ErrorAction Stop | |
} else { | |
Invoke-Executable sudo -- mkdir -p $useWinePrefix | |
} | |
} | |
} | |
} | |
Write-Verbose "Changing mode of to 2770" | |
Invoke-Executable -ErrorAction Stop sudo -- chmod 2770 $useWinePrefix | |
Write-Verbose "Adding group ""${WineGroup}"" if it doesn't already exist..." | |
Invoke-Executable -ErrorAction Stop sudo -- groupadd -f $WineGroup | |
Write-Verbose "Changing owner to ${WineUser}:${WineGroup}" | |
Invoke-Executable -ErrorAction Stop sudo -- chown -R "${WineUser}:${WineGroup}" $useWinePrefix | |
Write-Verbose "Adding current user $(whoami) to ${WineGroup}..." | |
Invoke-Executable -ErrorAction Stop sudo -- usermod -a -G $WineGroup ( whoami ) | |
if( $SetACLs ) { | |
$prefixDevice = ( df -P $useWinePrefix | Select-Object -Skip 1 ) -Split '\s+' | Select-Object -First 1 | |
Write-Warning 'Setting default ACLs and updating existing ACLs on WinePrefix and subdirectories' | |
Write-Warning 'It is up to you to ensure your filesystem is mounted with ACLs enabled' | |
Invoke-Executable -ErrorAction Stop sudo -- setfacl -dm "u:${WineUser}:rwx,g:${WineGroup}:rwx,o::-" $useWinePrefix | |
Invoke-Executable -ErrorAction Stop sudo -- setfacl -Rm "u:${WineUser}:rwx,g:${WineGroup}:rwx,o::-" $useWinePrefix | |
} | |
$env:WINEPREFIX = $useWinePrefix | |
$env:WINEARCH = $WineArch | |
if( $Configure ) { | |
Invoke-Executable winecfg | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment