New-ShellWrappers.psm1
<# .SYNOPSIS Creates shell (PowerShell, Bash, CMD) scripts to launch the given Python/PowerShell file without typing an extension. .DESCRIPTION For Python files, creates: .ps1, used in: Windows PowerShell 5 (built-in to Windows 10) Windows PowerShell 7 Linux Bash Linux PowerShell 7 For Python and PowerShell files, creates: .bat, used in: Windows Command Shell (CMD) Windows PowerShell 5 (built-in to Windows 10) Windows PowerShell 7 no extension, used in: Linux Bash Linux PowerShell 7 .PARAMETER FileToWrap The PowerShell (.ps1) or Python (.py) file that will be run by the created shell wrappers. .INPUTS None. You cannot pipe objects to New-ShellWrappers .OUTPUTS Creates .ps1 (if FileToWrap is .py), .bat, extension-less shell wrappers in the same location as given FileToWrap. #> function New-ShellWrappers { Param([Parameter(Mandatory=$true)][ValidateScript({Test-Path $PSItem})]$FileToWrap) $version = "1.0.0" # wrapper generater version $FileToWrap = Convert-Path $FileToWrap # convert to full path $gi = Get-Item $FileToWrap $dir = $gi.DirectoryName $base = $gi.BaseName $ext = $gi.Extension $crlf = "`r`n" # Windows line ending $lf = "`n" # Linux line ending $pwshContents = '#!/bin/pwsh-preview' + $crlf $pwshContents += '# DO NOT EDIT' + $crlf $pwshContents += '# Autogenerated by $PSCommandPath' + $crlf $pwshContents += '# Version: $version' + $crlf $pwshContents += '`$gi = Get-Item `$PSCommandPath' + $crlf $pwshContents += '`$dir = `$gi.DirectoryName' + $crlf $pwshContents += '`$base = `$gi.BaseName' + $crlf $pwshContents += '`$script = Join-Path `$dir "`$base$ext"' + $crlf $pwshContents += '$app `$script `$args' $cmdContents = '@REM DO NOT EDIT' + $crlf $cmdContents += '@REM Autogenerated by $PSCommandPath' + $crlf $cmdContents += '@REM Version: $version' + $crlf $cmdContents += '@$app %~dpn0$ext %*' $bashContents = '#!/usr/bin/env bash' + $lf $bashContents += '# DO NOT EDIT' + $lf $bashContents += '# Autogenerated by $PSCommandPath' + $lf $bashContents += '# Version: $version' + $lf $bashContents += 'filename=`$(basename -- "`$0")' + $lf $bashContents += 'base=`${filename%.*}' + $lf $bashContents += 'dir="`$( cd "`$(dirname "`$0")" ; pwd -P )"' + $lf $bashContents += '$app "`$dir/`$base$ext" $@' $wrappers = @{ '.py' = @{ pwsh = @{ext = '.ps1'; contents = $pwshContents; app = 'python'} cmd = @{ext = '.bat'; contents = $cmdContents; app = 'python'} bash = @{ext = ''; contents = $bashContents; app = 'python'} } '.ps1' = @{ cmd = @{ext = '.bat'; contents = $cmdContents; app = 'pwsh-preview'} bash = @{ext = ''; contents = $bashContents; app = 'pwsh-preview'} } } if (!$wrappers[$ext]) { Write-Host "Do not know how to create wrapper for given file extension '$ext'" -ForegroundColor Yellow } else { foreach ($shell in $wrappers[$ext].keys) { $wrapperContents = $wrappers[$ext][$shell].contents $wrapperExt = $wrappers[$ext][$shell].ext $app = $wrappers[$ext][$shell].app $value = $ExecutionContext.InvokeCommand.ExpandString($wrapperContents) $path = Join-Path $dir "$base$wrapperExt" Write-Host "# Creating $shell wrapper $version to run '$app $base$ext' - $path" Set-Content -Path $path -Value $value } } Write-Host "# Done" -ForegroundColor Green <# # Copy/paste the following into PowerShell to generate test files. # # Use test files to validate wrappers work. Things to check... # Verify arguments are passed correctly (testPython.ps1 a b c) # Verify generated .ps1 works on... # Windows PowerShell 5 # Windows PowerShell 7 # Linux Bash # Linux PowerShell 7 # Verify generated .bat works on... # Windows CMD # Windows PowerShell 5 # Windows PowerShell 7 # Verify generated extension-less file works on... # Linux Bash # Linux PowerShell 7 # For Linux, verify CentOS7 and Ubuntu $testPwshContents = @' #!/usr/bin/env pwsh-preview "Greetings from PowerShell" "Args..." foreach ($a in $args) {$a} '@ Set-Content -Path testPwsh.ps1 -Value $testPwshContents $testPythonContents = @' import sys print("Greetings from Python") print("Args...") for a in sys.argv: print(a) '@ Set-Content -Path testPython.py -Value $testPythonContents #> } |