PowerShell on Linux
PowerShell for Linux is, at least at the time of writing, in alpha. The current release is still worth installing even if only to see what having a unified shell may look like.
Note
What about Cygwin?
PowerShell is not the first to give a hint of a single shell across different operating systems. However, until PowerShell matured, it was a serious challenge to manage Windows and Microsoft-based systems from the command line alone.
Some familiarity with Linux is assumed during this process.
Installing PowerShell
This installation is based on PowerShell 6, alpha 12 as the latest at the time of writing. The package can be downloaded from GitHub with yum
, which will also install the dependencies (https://github.com/PowerShell/PowerShell/releases/latest):
- The following command will install PowerShell and any dependencies (
libicu
,libunwind
, anduuid
):
sudo yum install https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.12/powershell-6.0.0_alpha.12-1.el7.centos.x86_64.rpm
alpha 12 is the latest release but it may not be when you read this.
- PowerShell can be immediately started by running the following command:
powershell
- Create a few files in the
home
directory as a test:
Set-Location ~
1..10 | ForEach-Object { New-Item $_ -ItemType File }
- The previous command creates
10
empty files named1
to10
(with no file extension). Ensure that the new files are now visible usingGet-ChildItem
:
Get-ChildItem
Note
ls versus Get-ChildItem
:
On Windows, ls
(list) in PowerShell is an alias for Get-ChildItem
. On Linux, ls
is the original command. See Get-Alias -Definition Get-ChildItem
to view what still is.
Where are the PowerShell files?
Several of the following used paths are specific to the installed release (in this case, alpha 12).
As with PowerShell on Windows, the PSHOME
variable shows where PowerShell itself has been installed:
PS> $PSHOME
/opt/microsoft/powershell/6.0.0-alpha.12
The paths for module installation may be viewed using the environment variables:
PS> $env:PSMODULEPATH -split ':'
/home/psuser/.local/share/powershell/Modules
/usr/local/share/powershell/Modules
/opt/microsoft/powershell/6.0.0-alpha.12/Modules
Note
Case sensitivity
Linux has a much higher regard for case than Windows. Environment variables, file paths, executables, and so on, are case sensitive. The previously used variable name must be written in uppercase.
Use Get-ChildItem
to list all of the environment variables using the following command:Get-ChildItem env:
Changing the shell
Once installed, PowerShell is visible in the list of available shells:
chsh -l
Set PowerShell as the default shell
for the current user:
chsh
New shell [/bin/bash]: /usr/bin/powershell
Profiles
The current user profile on Linux resides under the home directory:
~/.config/powershell
Two profiles can be created: CurrentUserCurrentHost
(Microsoft.PowerShell_profile.ps1
) and Current User
(profile.ps1
). Inspecting the automatic variable, $PROFILE
shows the first of these:
- The directory will need to be created prior to use; the following command creates it:
New-Item ~/.config/powershell -ItemType Directory
- Create a simple profile file by sending a string to a file:
‘Write-Host “Welcome to PowerShell” -ForegroundColor Green’ | Out-File .config/powershell/profile.ps1
- The
AllUser
profile may be created under PowerShell's installation directory, in this case, alpha 12, as this is the version I have installed:
/opt/microsoft/powershell/6.0.0-alpha.12
- Writing to this area of the filesystem requires the
root
privileges:
sudo vi /opt/microsoft/powershell/6.0.0-alpha.12/profile.ps1
- Inside
vi
, pressi
to enter insert mode and then type the following:
Write-Host 'This is the system profile' -ForegroundColor Yellow
- Once completed, press Esc, then type
:wq
to save and quitvi
. - As with PowerShell on Windows, this will be executed before a user-level
profile
that shows the following in the console when the shell is started:
This is the system profile
Welcome to PowerShell
Multiplatform scripting
PowerShell on Linux (and macOS) has a long way to go to reach maturity. Our experience writing for these systems has to make a similar journey.
One of the most important facets is that Linux and macOS run PowerShell Core. It lacks some features we may have become used to when writing for Windows.
Line endings
Windows editors, including ISE, tend to use a carriage return followed by linefeed (\r\n
or `r`n
) at the end of each line. Linux editors use linefeed only (\n
or `n
).
Line endings are less important if the only thing reading the file is PowerShell (on any platform). However, if a script is set to executable on Linux, a sha-bang must be included and the line-ending character used must be linefeed only.
For example, a created as follows named test.ps1
must use \n
to end lines:
#!/usr/bin/env powershell
Get-Process
The first line is the sha-bang and lets Linux know which parser to use when executing the shell script.
Once created, chmod
may be used to make the script executable outside of PowerShell:
chmod +x test.ps1
After being made executable, the script may be executed from bash
with the full path or a relative path:
./test.ps1
Note
Editor defaults
PowerShell ISE uses carriage return followed by line feed (\r\n
). This behavior is by design and cannot be changed.
Visual Studio Code uses \r\n
for line endings by default. This may be changed in User Settings
by adding the following command:"files.eol": "\n"
File encoding
Windows editors, including ISE, tend to save files using what is commonly known as ANSI encoding; this is more correctly known as Windows-1252.
As Windows-1252 is a Microsoft native format, it may be more appropriate to save files in a universally accepted format such as UTF8.
Note
Editor defaults
PowerShell ISE defaults to saving files in UTF8 with a Byte Order Mark (BOM).
Visual Studio Code saves files using UTF8 (without a BOM) by default. The setting may be changed in User Settings
by adding "files.encoding": "utf8bom"
.
Path separator
Testing shows that PowerShell on Linux is forgiving about path separators; that is, Microsoft Windows uses the backslash (\
), where Linux uses a forward slash (/
).
If anything outside of PowerShell (including native commands) is to be used, a correct separator should be chosen.
The Join-Path
command will merge path elements using the correct separator for each platform. Manual path construction (based on merging strings) should be avoided.
Example
The following function uses the System.Net.NetworkInformation
namespace to discover IPv4 address information. This allows us to return the same thing whether it is run on Windows or Linux.
If it were Windows only, we might have used WMI or the Get-NetIPConfiguration
command. Creating something to work on both operating systems is more challenging:
function Get-IPConfig { [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() | ForEach-Object { $ipProperties = $_.GetIPProperties() $addresses = $ipProperties.UnicastAddresses | Where-Object { $_.Address.AddressFamily -eq 'InterNetwork' } | ForEach-Object { "$($_.Address) $($_.IPv4Mask)" } $gateway = $ipProperties.GatewayAddresses.Address | Where-Object { $_.AddressFamily -eq 'InterNetwork' -and $_ -ne '0.0.0.0' } [PSCustomObject]@{ Name = $_.Name Id = $_.Id Addresses = $addresses Gateway = $gateway } } | Where-Object { $_.Addresses } } Get-IPConfig