Setup-CoreutilsLinks.ps1
· 4.5 KiB · PowerShell
Raw
<#
.SYNOPSIS
Automates the setup of uutils/coreutils on Windows by creating batch file shims.
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[string]$ShimsDirectory = (Join-Path $env:LOCALAPPDATA "uutils-shims"),
[switch]$ForceInstall,
[switch]$ForcePathAddition,
[switch]$SkipPathCheck
)
$ErrorActionPreference = "Stop"
function Show-Menu ([string]$Title, [string]$PromptMessage)
{
Write-Host "`n--- $Title ---"
$options = @(
[System.Management.Automation.Host.ChoiceDescription]::new("&Yes", "Proceed.")
[System.Management.Automation.Host.ChoiceDescription]::new("&No", "Skip.")
)
return (0 -eq $host.UI.PromptForChoice($Title, $PromptMessage, $options, 0))
}
function Find-CoreutilsExecutable
{
Write-Verbose "Searching for coreutils.exe..."
$coreutilsCmd = Get-Command coreutils -ErrorAction SilentlyContinue
if ($coreutilsCmd -and (Test-Path $coreutilsCmd.Source))
{
return $coreutilsCmd.Source
}
$wingetBase = Join-Path $env:LOCALAPPDATA "Microsoft\WinGet\Packages"
$pkgId = "uutils.coreutils_Microsoft.Winget.Source_8wekyb3d8bbwe"
if (Test-Path $wingetBase)
{
$path = Get-ChildItem (Join-Path $wingetBase $pkgId) -Recurse -Filter "coreutils.exe" |
Sort-Object LastWriteTime -Descending | Select-Object -ExpandProperty FullName -First 1
if ($path)
{ return $path
}
}
if ($ForceInstall -or (Show-Menu "Install Coreutils" "coreutils.exe not found. Install via winget?"))
{
Write-Host "Installing uutils via winget..." -ForegroundColor Cyan
Start-Process winget -ArgumentList "install uutils.coreutils --source winget -e --accept-package-agreements" -Wait
return Get-ChildItem (Join-Path $wingetBase $pkgId) -Recurse -Filter "coreutils.exe" | Select-Object -ExpandProperty FullName -First 1
}
return $null
}
function Get-CoreutilsCommands ([string]$CoreutilsExePath)
{
Write-Verbose "Parsing commands from $CoreutilsExePath"
$raw = (& $CoreutilsExePath --list | Out-String)
if ($raw -match "Currently defined functions:")
{
$clean = $raw -split "Currently defined functions:" | Select-Object -Last 1
$commands = $clean.Replace("[", "").Replace("]", "").Replace("`n", " ").Replace("`r", " ") -split '[, ]+' |
Where-Object { $_.Trim() -ne "" }
return $commands
}
return $raw -split '\s+' | Where-Object { $_ -ne "" }
}
function New-UtilityShim
{
[CmdletBinding(SupportsShouldProcess = $true)]
param([string]$CoreutilsExePath, [array]$Commands, [string]$TargetDir)
if (-not (Test-Path $TargetDir))
{
if ($PSCmdlet.ShouldProcess($TargetDir, "Create Directory"))
{
New-Item -Path $TargetDir -ItemType Directory -Force | Out-Null
}
}
$created = 0
foreach ($cmd in $Commands)
{
$fileName = if ($cmd -eq "[")
{ "bracket.bat"
} else
{ "$cmd.bat"
}
$path = Join-Path $TargetDir $fileName
$content = "@echo off`n`"$CoreutilsExePath`" $cmd %*"
if ($PSCmdlet.ShouldProcess("Shim for $cmd", "Create batch file at $path"))
{
Set-Content -Path $path -Value $content -Encoding Ascii
$created++
}
}
Write-Host "Created $created shims in $TargetDir" -ForegroundColor Cyan
}
function Update-UserPath
{
[CmdletBinding(SupportsShouldProcess = $true)]
param([string]$Dir, [switch]$ForcePathAddition)
$currentPath = [System.Environment]::GetEnvironmentVariable("Path", "User")
if ($currentPath -split ';' -contains $Dir)
{
Write-Host "Directory already in User PATH." -ForegroundColor Green
return
}
if ($ForcePathAddition -or (Show-Menu "Update PATH" "Add $Dir to User PATH?"))
{
$newPath = "$currentPath;$Dir".Trim(';')
if ($PSCmdlet.ShouldProcess("User PATH Environment Variable", "Append $Dir"))
{
[System.Environment]::SetEnvironmentVariable("Path", $newPath, "User")
Write-Host "PATH updated. Restart your terminal to apply changes." -ForegroundColor Yellow
}
}
}
Write-Host "--- uutils setup ---" -ForegroundColor Magenta
$exe = Find-CoreutilsExecutable
if ($exe)
{
$cmds = Get-CoreutilsCommands -CoreutilsExePath $exe
New-UtilityShim -CoreutilsExePath $exe -Commands $cmds -TargetDir $ShimsDirectory
if (-not $SkipPathCheck)
{
Update-UserPath -Dir $ShimsDirectory -ForcePathAddition:$ForcePathAddition
}
} else
{
Write-Error "Coreutils not found."
}
| 1 | <# |
| 2 | .SYNOPSIS |
| 3 | Automates the setup of uutils/coreutils on Windows by creating batch file shims. |
| 4 | #> |
| 5 | [CmdletBinding(SupportsShouldProcess = $true)] |
| 6 | param( |
| 7 | [string]$ShimsDirectory = (Join-Path $env:LOCALAPPDATA "uutils-shims"), |
| 8 | [switch]$ForceInstall, |
| 9 | [switch]$ForcePathAddition, |
| 10 | [switch]$SkipPathCheck |
| 11 | ) |
| 12 | |
| 13 | $ErrorActionPreference = "Stop" |
| 14 | |
| 15 | function Show-Menu ([string]$Title, [string]$PromptMessage) |
| 16 | { |
| 17 | Write-Host "`n--- $Title ---" |
| 18 | $options = @( |
| 19 | [System.Management.Automation.Host.ChoiceDescription]::new("&Yes", "Proceed.") |
| 20 | [System.Management.Automation.Host.ChoiceDescription]::new("&No", "Skip.") |
| 21 | ) |
| 22 | return (0 -eq $host.UI.PromptForChoice($Title, $PromptMessage, $options, 0)) |
| 23 | } |
| 24 | |
| 25 | function Find-CoreutilsExecutable |
| 26 | { |
| 27 | Write-Verbose "Searching for coreutils.exe..." |
| 28 | |
| 29 | $coreutilsCmd = Get-Command coreutils -ErrorAction SilentlyContinue |
| 30 | if ($coreutilsCmd -and (Test-Path $coreutilsCmd.Source)) |
| 31 | { |
| 32 | return $coreutilsCmd.Source |
| 33 | } |
| 34 | |
| 35 | $wingetBase = Join-Path $env:LOCALAPPDATA "Microsoft\WinGet\Packages" |
| 36 | $pkgId = "uutils.coreutils_Microsoft.Winget.Source_8wekyb3d8bbwe" |
| 37 | |
| 38 | if (Test-Path $wingetBase) |
| 39 | { |
| 40 | $path = Get-ChildItem (Join-Path $wingetBase $pkgId) -Recurse -Filter "coreutils.exe" | |
| 41 | Sort-Object LastWriteTime -Descending | Select-Object -ExpandProperty FullName -First 1 |
| 42 | if ($path) |
| 43 | { return $path |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | if ($ForceInstall -or (Show-Menu "Install Coreutils" "coreutils.exe not found. Install via winget?")) |
| 48 | { |
| 49 | Write-Host "Installing uutils via winget..." -ForegroundColor Cyan |
| 50 | Start-Process winget -ArgumentList "install uutils.coreutils --source winget -e --accept-package-agreements" -Wait |
| 51 | return Get-ChildItem (Join-Path $wingetBase $pkgId) -Recurse -Filter "coreutils.exe" | Select-Object -ExpandProperty FullName -First 1 |
| 52 | } |
| 53 | return $null |
| 54 | } |
| 55 | |
| 56 | function Get-CoreutilsCommands ([string]$CoreutilsExePath) |
| 57 | { |
| 58 | Write-Verbose "Parsing commands from $CoreutilsExePath" |
| 59 | $raw = (& $CoreutilsExePath --list | Out-String) |
| 60 | |
| 61 | if ($raw -match "Currently defined functions:") |
| 62 | { |
| 63 | $clean = $raw -split "Currently defined functions:" | Select-Object -Last 1 |
| 64 | $commands = $clean.Replace("[", "").Replace("]", "").Replace("`n", " ").Replace("`r", " ") -split '[, ]+' | |
| 65 | Where-Object { $_.Trim() -ne "" } |
| 66 | return $commands |
| 67 | } |
| 68 | |
| 69 | return $raw -split '\s+' | Where-Object { $_ -ne "" } |
| 70 | } |
| 71 | |
| 72 | function New-UtilityShim |
| 73 | { |
| 74 | [CmdletBinding(SupportsShouldProcess = $true)] |
| 75 | param([string]$CoreutilsExePath, [array]$Commands, [string]$TargetDir) |
| 76 | |
| 77 | if (-not (Test-Path $TargetDir)) |
| 78 | { |
| 79 | if ($PSCmdlet.ShouldProcess($TargetDir, "Create Directory")) |
| 80 | { |
| 81 | New-Item -Path $TargetDir -ItemType Directory -Force | Out-Null |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | $created = 0 |
| 86 | foreach ($cmd in $Commands) |
| 87 | { |
| 88 | $fileName = if ($cmd -eq "[") |
| 89 | { "bracket.bat" |
| 90 | } else |
| 91 | { "$cmd.bat" |
| 92 | } |
| 93 | $path = Join-Path $TargetDir $fileName |
| 94 | |
| 95 | $content = "@echo off`n`"$CoreutilsExePath`" $cmd %*" |
| 96 | |
| 97 | if ($PSCmdlet.ShouldProcess("Shim for $cmd", "Create batch file at $path")) |
| 98 | { |
| 99 | Set-Content -Path $path -Value $content -Encoding Ascii |
| 100 | $created++ |
| 101 | } |
| 102 | } |
| 103 | Write-Host "Created $created shims in $TargetDir" -ForegroundColor Cyan |
| 104 | } |
| 105 | |
| 106 | function Update-UserPath |
| 107 | { |
| 108 | [CmdletBinding(SupportsShouldProcess = $true)] |
| 109 | param([string]$Dir, [switch]$ForcePathAddition) |
| 110 | |
| 111 | $currentPath = [System.Environment]::GetEnvironmentVariable("Path", "User") |
| 112 | if ($currentPath -split ';' -contains $Dir) |
| 113 | { |
| 114 | Write-Host "Directory already in User PATH." -ForegroundColor Green |
| 115 | return |
| 116 | } |
| 117 | |
| 118 | if ($ForcePathAddition -or (Show-Menu "Update PATH" "Add $Dir to User PATH?")) |
| 119 | { |
| 120 | $newPath = "$currentPath;$Dir".Trim(';') |
| 121 | |
| 122 | if ($PSCmdlet.ShouldProcess("User PATH Environment Variable", "Append $Dir")) |
| 123 | { |
| 124 | [System.Environment]::SetEnvironmentVariable("Path", $newPath, "User") |
| 125 | Write-Host "PATH updated. Restart your terminal to apply changes." -ForegroundColor Yellow |
| 126 | } |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | Write-Host "--- uutils setup ---" -ForegroundColor Magenta |
| 131 | $exe = Find-CoreutilsExecutable |
| 132 | if ($exe) |
| 133 | { |
| 134 | $cmds = Get-CoreutilsCommands -CoreutilsExePath $exe |
| 135 | New-UtilityShim -CoreutilsExePath $exe -Commands $cmds -TargetDir $ShimsDirectory |
| 136 | |
| 137 | if (-not $SkipPathCheck) |
| 138 | { |
| 139 | Update-UserPath -Dir $ShimsDirectory -ForcePathAddition:$ForcePathAddition |
| 140 | } |
| 141 | } else |
| 142 | { |
| 143 | Write-Error "Coreutils not found." |
| 144 | } |
| 145 |