Getting Started with PowerShell Core on Windows, Mac, and Linux

Today we have a guest post from Honorary Script Guy and Microsoft Premier Field Engineer Ashley McGlone, also known as GoateePFE.

This is deeper than Coke vs. Pepsi or Ford vs. Chevy. We are breaking down the barriers. Cats and dogs living together. Are you ready for this?

What is PowerShell Core?

The next release of PowerShell (6.0) was open-sourced last year and is currently in beta. However, it is PowerShell Core designed to run cross-platform on Windows, Mac, and Linux. PowerShell Core runs on top of .NET Core, a cross-platform, open-source version of the code base powering most of the Windows world. This version of PowerShell will be different than the Windows PowerShell edition you see built into Windows today.

My Mac Demo Rig

I have the coolest job, and I love my Microsoft Surface Pro 4. But now in my bag I also carry a MacBook Pro running VMs of Windows and Linux for one ultimate demo machine. Now I can demo PowerShell Core 6 and Visual Studio Code side-by-side on three different operating systems. I can even demo PowerShell remoting between all three operating systems.
How cool is that?!

The beta release of PowerShell Core 6 supports a significant list of Linux distributions. For my demos I chose Ubuntu Desktop so that I could do both PowerShell Core and Visual Studio Code. According to this is one of the most popular Linux flavors.

Every customer who has seen this Microsoft guy demo PowerShell on three operating systems from a MacBook Pro has been impressed with the direction Microsoft is taking. Customers are excited about the cross-platform administrative opportunities now with PowerShell everywhere.

What do I need?

To get started with PowerShell Core you want to install and configure these three items on your operating system(s) of choice:

I was surprised how quickly I was up-and-running following the installation instructions. Each process involved relatively little tweaking for a beta experience.

If you are a Linux person you might be thinking, “OK. I already have OpenSSH installed.” Please read the OpenSSH link above for the step of editing the sshd_config file for PowerShell remoting support.

Validate the install

From Mac or Linux simply open the terminal window and type powershell. You should see the copyright banner (no year for beta) and get the PS prompt. Type $PSVersionTable to see your version.

goatee@ub:~$ powershell
Copyright (C) Microsoft Corporation. All rights reserved.

PS /home/goatee> $PSVersionTable                                             

Name                           Value                                           
----                           -----                                           
PSVersion                      6.0.0-beta                                      
PSEdition                      Core                                            
GitCommitId                    v6.0.0-beta.1                                   
OS                             Linux 4.4.0-78-generic #99-Ubuntu SMP Thu Apr...
Platform                       Unix                                            
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                         
PSRemotingProtocolVersion      2.3                                             
WSManStackVersion              3.0

Type Get-Command to see what cmdlets are available in your session.

PS /home/goatee> Get-Command

You might find it tricky to launch PowerShell Core 6 on a Windows VM that already has PowerShell natively installed. Here is one way to launch it:

  • Navigate to the beta install directory: C:\Program Files\PowerShell*beta_directory*\
  • Type $PSVersionTable to see the native version of PowerShell
  • Now type .\powershell.exe and press Enter
  • Type $PSVersionTable again to see that PSEdition is shown as Core and with a different version number

Note the trick here is the .\ in front of the EXE, otherwise it will find the native EXE for Windows PowerShell.

Now for something new! Try this:

Get-Variable Is*

Notice that you now have built-in variables indicating the operating system version. These variables enable you to check the current OS and perform different behaviors from within a script.

PS /home/goatee> Get-Variable Is*

Name                           Value
----                           -----
IsCoreCLR                      True
IsLinux                        True
IsOSX                          False
IsWindows                      False

Things to know

  • Case-sensitivity
    Windows is not case-sensitive, so neither is PowerShell on Windows. However, Linux is case-sensitive. PowerShell commands on Mac and Linux are not case-sensitive, but sometimes the operating system-specific values (e.g. the names of environment variables like PATH) are case-sensitive.
  • Slashes
    PowerShell on Windows has always allowed forward slashes and backward slashes in paths, so moving to Mac and Linux has minimal issues with the direction of the slashes. (However, it’s always a best practice to use variables like $pwd and $PSScriptRoot, and cmdlets like Split-Path/Join-Path to generate paths which conform to any given platform.)
  • Aliases
    PowerShell on Windows has always had Linux aliases like ls, cat, man, etc. However, these PowerShell aliases do not exist on Mac and Linux to avoid conflict with the native binary equivalents.

Now what can I do?

For Windows people trying Mac or Linux

  • Get a list of available modules:
      PS /home/goatee> Get-Module -ListAvailable                                   
          Directory: /home/goatee/.local/share/powershell/Modules
      ModuleType Version    Name                                ExportedCommands     
      ---------- -------    ----                                ----------------     
      Manifest    Microsoft.PowerShell.Archive        {Compress-Archive,...
      Manifest    Microsoft.PowerShell.Host           {Start-Transcript,...
      Manifest    Microsoft.PowerShell.Management     {Add-Content, Clea...
      Manifest    Microsoft.PowerShell.Security       {Get-Credential, G...
      Manifest    Microsoft.PowerShell.Utility        {Format-List, Form...
      Script    PackageManagement                   {Find-Package, Get...
      Script     3.3.9      Pester                              {Describe, Context...
      Script    PowerShellGet                       {Install-Module, F...
      Script     0.0        PSDesiredStateConfiguration         {ThrowError, Get-P...
      Script     1.2        PSReadLine                          {Get-PSReadlineKey...
  • PowerShell commands and pipelines work like they always have:
    PS /home/goatee> Get-Process | Sort-Object CPU -Descending | Select-Object -First 5
    NPM(K)    PM(M)      WS(M)     CPU(s)     Id  SI ProcessName
    ------    -----      -----     ------     --  -- -----------                  
         0     0.00      38.65       8.04   1259 259 Xorg                         
         0     0.00      64.11       4.79   1985 985 compiz                       
         0     0.00     101.68       3.42   2104 949 gnome-software               
         0     0.00      90.87       2.86   2693 568 powershell                   
         0     0.00       9.47       2.36   2110 949 prlcc
  • Use Windows aliases on Mac and Linux:
  • Because PowerShell Core is based on .NET Standard, you can do .NET stuff from the console just like on Windows:
    PS /home/goatee> [math]::pi
    PS /home/goatee> [math]::pow(2,8)
    PS /home/goatee> (Get-Date).AddDays(7)
    Monday, May 29, 2017 3:51:47 PM
  • PSReadline and tab completion work as well, but the default EditMode is set to Emacs, resulting in slightly different behavior: when you hit Tab, if you have not typed enough characters to match a single completion, you will get a list of available commands starting with those characters instead of a full completion.

For Mac or Linux people trying PowerShell

The cmdlet Get-Command will tell you all the commands available in your session. Then pass the command name to Get-Help just like man:

PS /home/goatee> Get-Command

PS /home/goatee> Get-Help Get-Process

You will find that PowerShell help looks much like familiar man pages. You should first download the help file content on any new install like this:

PS /home/goatee> Update-Help

Notice that you can blend native commands and PowerShell in a single, object-oriented pipeline.

cat /etc/passwd | ConvertFrom-Csv -Delimiter ':' -Header Name,Passwd,UID,GID,Description,Home,Shell | Sort-Object Name | Format-Table

Here are some of the many similarities between PowerShell and bash (with more here):

Linux PowerShell
compgen / man builtin Get-Command
man Get-Help
ls Get-ChildItem
cat / tail Get-Content
ps / top Get-Process
wc Measure-Object
sort Sort-Object
tee Tee-Object
grep Select-String
touch New-Item
tar Compress-Archive / Expand-Archive
history Get-History / Invoke-History
cd ~ cd ~ / cd $home
pwd $pwd
env Get-ChildItem env:\

These command all have a wide assortment of parameters viewable with Get-Help. In PowerShell, parameter names are intuitive, verbose, and largely shared across commands for uniformity.

Here is an example of tail in PowerShell:

# Linux
tail -f my.log

# PowerShell
Get-Content -Path my.log -Tail 10 -Wait

Here is an example of wc in PowerShell. Note that the results are slightly different, because the output of ps is different than Get-Process.

PS /home/goatee> ps aux | wc                                                 
    191    2240   19045

PS /home/goatee> Get-Process | Measure-Object                                
Count    : 190
Average  : 
Sum      : 
Maximum  : 
Minimum  : 
Property : 

PS /home/goatee> Get-Process | Measure-Object -Line -Word -Character         

Lines Words Characters Property
----- ----- ---------- --------
  188   376       7394

CTRL+R will let you search and execute command history in PowerShell on all operating systems. This functionality is just one feature of the PSReadline module automatically loaded for you.

PowerShell Remoting over SSH

PowerShell Core 6 includes new parameters for remoting over SSH. This is why you had to install and configure OpenSSH on each box.

Enter-PSSession -Hostname <IP or FQDN> -Username <username> -SSHTransport

This area required a bit of tweaking to get working for me, so pay close attention to the steps in the guide. Windows people will need to learn a bit of vi or nano to edit the sshd_config file on Linux with the entries from the guide.

Here is what it looks like to browse a Windows machine from a Linux SSH remoting session:

PS /home/goatee> Enter-PSSession -HostName -UserName goatee10\testadmin -SSHTransport                                                            
goatee10\testadmin@'s password: 
[]: PS C:\Users\testadmin\Documents> cd\                             
[]: PS C:\> dir                                                      

    Directory: C:\

Mode                LastWriteTime         Length Name                          
----                -------------         ------ ----                          
d-----         5/3/2017   8:20 PM                MSOTraceLite                  
d-----        3/18/2017   5:03 PM                PerfLogs                      
d-r---        4/27/2017   1:38 PM                Program Files                 
d-r---        4/19/2017  11:57 AM                Program Files (x86)           
d-----        5/13/2017   3:24 PM                Source                        
d-r---         5/2/2017   7:50 AM                Users                         
d-----         5/5/2017   9:24 AM                Windows  

[]: PS C:\> exit                                                     

PS /home/goatee>

Visual Studio Code

After installing Visual Studio Code, you want to add the PowerShell extension. Open Code, click the square on the left bar, type powershell, and install the extension. It will ask you to click to reload the window.

With the release of the PowerShell v1.x extension for Visual Studio Code it is now possible to have a cross-platform PowerShell editing experience very similar to the ISE on Windows boxes:

  • F5 and F8 will run all or selection of a script.
  • You have the interactive output window at the bottom.
  • Intellisense and tab-completion make coding faster. CTRL+SPACE works here also.
  • The debugger has breakpoints and stepping.

And it is also better than the ISE in many ways:

  • Typing paired punctuation is automatic ( () [] {} ” “”).
  • Select some code, right click, and choose Format Selection or Format Document to format your code according to standard practices. (My favorite new feature!)
  • Right click a function and choose Go To Definition or Find All References.
  • Searching highlights results in the scroll bar.
  • Script Analyzer provides coding best practices alerts.

If you are editing a new file in Code you need to trigger the PowerShell experience in one of two ways:

  • Save the file with a .ps1 or .psm1 extension.
  • In the bottom right corner click on Plain Text and then choose PowerShell for the language mode.

These steps trigger the interactive output window and syntax completion. It is amazing to have full parity in the editing experience across Windows, Mac, and Linux.

If you would like to learn more about editing PowerShell with VS Code, check out David Wilson’s presentation to the AZPosh user group or his presentation from the PowerShell and DevOps Global Summit 2017.

Desired State Configuration

This blog post is getting quite long, so I will not get into Desired State Configuration today. However, you can read Get started with Desired State Configuration (DSC) for Linux in the documentation site.

Truly Cross-Platform Code

Depending on the task at hand we can run the exact same code on PowerShell Core on all three platforms. For example, on the operating system of your choice run this REST call and process the JSON response:

(Invoke-WebRequest -Uri '' -Method Get).Content | ConvertFrom-Json

It is remarkable to see the same code run on all platforms. This paints a bright future for sysadmins everywhere.

Your Turn

I hope you have enjoyed this quick tour of the new cross-platform PowerShell scripting experience. Try it today on your favorite operating system. If you find things that do not work as you expected, then please submit an issue on GitHub.