PowerShell 7.1 Preview 6

Avatar

Steve

Today, we are releasing the sixth preview of the PowerShell 7.1 release!

Further in this blog post I’ll provide details on some important changes you should be aware of as you starting trying out this preview.

PowerShell 7.1 Roadmap update

We are planning the last preview release around the first week of September. This will allow us to get in the last of our significant code changes before we start minimizing risk (and code churn) for our Release Candidate.

We expect our first Release Candidate in the second half of September. Release Candidates are “go-live” meaning they are supported in production. If there is a critical security or blocking issue, we will provide an updated servicing release for a Release Candidate. We would like users to start deploying the Release Candidate so that we can address any major issues as we head towards a General Availability release at the end of this year.

Unlike preview releases, Release Candidates will not have Experimental Features enabled by default. Some Experimental Features will be taken out of experimental state and their designs will be considered final while others will stay in experimental state and will need to be explicitly enabled to continue use.

As a reminder, Experimental Features are not considered design complete. This means that the design may change based on real world usage feedback and such changes are not considered breaking changes. Production code should not depend on experimental features.

Noteworthy Changes

There are some changes in PowerShell 7.1 Preview 6 that are worth going into detail and some are breaking changes.

Rename -FromUnixTime to -UnixTimeSeconds on Get-Date to allow Unix time input

Unix time is the number of seconds since January 1st, 1970 at 00:00:00 UTC. In Preview 2 of PowerShell 7.1, we merged a community submitted pull request to add -FromUnixTime to the Get-Date cmdlet. However, it was discovered later that the prefix From was inconsistent with existing parameters on that cmdlet. So a change was accepted to simply call it -UnixTimeSeconds which accepts a value in Unix time similar to how -Date accepts a value in date time format.

get-date -UnixTimeSeconds 1597615564
Sunday, August 16, 2020 3:06:04 PM

This feature was added by community member aetos382!

Make $ErrorActionPreference not affect stderr output of native commands

Native commands support three streams: stdin, stdout, and stderr. stdin is for sending input to a native command. stdout is for any output from a native command you might want to pass further down the pipeline. stderr (despite “error” being in the name) is used for all other output.

stderr can include error messages, but also text content equivalent to PowerShell verbose, debug, and information streams as well as progress information or help text.

The de facto standard way to determining if a native command has succeeded or failed is by looking at the exit code (in PowerShell this is by the $LASTEXITCODE automatic variable). Since stderr typically contains non-error information, it is not a reliable way to detect errors from native commands.

Text output from stderr are wrapped as ErrorRecords but tagged to indicate it is from stderr. Prior to this change, because these are ErrorRecord instances, they would get added to the $Error automatic variable which is a running log of errors. If you set $ErrorActionPreference to a value that affects execution (like Stop or Inquire) then any text written to stderr would cause your script execution to be impacted.

With this change, stderr is just treated like an information stream (although it is still stream number 2 for redirection) and is not affected by $ErrorActionPreference which also means stderr output does not show up in $Error nor does it cause $? to be $false indicating the last command failed.

There is an existing RFC to allow script execution to be impacted by native command exit code that we hope to be in a future version of PowerShell.

Allow explicitly specified named parameter to supersede the same one from hashtable splatting

Splatting is a feature in PowerShell allowing passing parameters to commands defined in a hashtable. For example, if you have a script that calls the same or different cmdlets multiple times where the parameters and their values are the same, then instead of typing it multiple times you can define it once and pass the same hashtable to each cmdlet. If a parameter or value changes, you would then just update the hashtable.

$myParams = @{
  Uri = 'https://api.github.com/repos/powershell/powershell/releases'
  Method = 'Get'
  FollowRelLink = $true
}

Invoke-RestMethod @myParams

Note: The above example shows how to pass the -FollowRelLink switch using splatting

In some scripts, you may want to override one of the values in the hashtable for a specific instance. Previously, you would get an error that the parameter was already specified:

Invoke-RestMethod @myParams -Uri https://api.github.com/repos/dotnet/runtime
Invoke-RestMethod: Cannot bind parameter because parameter 'Uri' is specified more than once. To provide multiple values to parameters that can accept multiple values, use the array syntax. For example, "-parameter value1,value2,value3".

With this change, the above example now works as one would expect in that the -Uri parameter value will be the one explicitly specified in the command line and not the one in the hashtable.

Experimental Feature: PSManageBreakpointsInRunspace

PowerShell has powerful built-in scripting debugging capabilities. However, previously the debugging cmdlets would only allow you to manage breakpoints in the current PowerShell session (called a runspace). Community member Kirk Munro added the ability to specify a different runspace to the breakpoint management cmdlets!

$job = Start-Job { $pid; Start-Sleep -Seconds 5; Write-Verbose "Hello" }

# wait until the job process starts
while ($job.ChildJobs[0].Runspace.RunspaceStateInfo.State -ne 'Opened') {
    Start-Sleep -Milliseconds 50
}
Set-PSBreakpoint -Command Write-Verbose -Action { break } -Runspace $job.ChildJobs[0].Runspace

# wait until the job is waiting at the breakpoint
while ($job.State -ne 'AtBreakpoint') {
    Start-Sleep -Seconds 1
}

# get the job process id to debug it later
$jobpid = $job | Receive-Job
$job | Get-Job

Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 7 Job7 BackgroundJob AtBreakpoint True localhost Start-Sleep -Seconds 5;…
# Connect to the running job process
Enter-PSHostProcess -id $jobpid

# Find the runspace where the running script is stopped at the breakpoint and attach debugger to it
Get-Runspace | Where-Object { $_.Debugger.InBreakpoint -eq $true } | Debug-Runspace
Debugging Runspace: RemoteHost
To end the debugging session type the 'Detach' command at the debugger prompt, or type 'Ctrl+C' otherwise.

Hit Command breakpoint on 'Write-Verbose'

At line:1 char:32
+  $pid; Start-Sleep -Seconds 5; Write-Verbose "Hello"
+                                ~~~~~~~~~~~~~~~~~~~~~

Here you see that execution stopped exactly where we set the breakpoint.

Note: As the script is stopped at the breakpoint, it will wait indefinitely for a debugger to be attached

Built in Pager for Get-Help

As part of additional work to improve the PowerShell help experience (more on this later!), we wrote our own pager to provide a consistent experience across platforms.

This is a work in progress so a bit limited in functionality currently. Contributions and issues are certainly welcome in the Pager repo.

You can try it out using the new -Paged switch with Get-Help:

Get-Help -Paged Get-Command

PSReadLine will leverage this pager for its new “Dynamic Help” feature where you can use a keyboard combination to get help while in the middle of typing out a command-line and being able to return to exactly where you left off!

New -MaskInput switch for Read-Host

This was a community requested feature to hide the input the user types. Normally, you would use -AsSecureString for sensitive information that you would not want echoed onto the screen or end up in logs/transcripts. However, there are scenarios where you don’t want to deal with a SecureString and prefer to get plain text. This switch will still mask the input the user types, but returns a string.

$input = Read-Host -MaskInput -Prompt "Tell me a secret"

Summary

There are, of course, many bug fixes and smaller improvements not mentioned in this blog post provided by both the community as well as the PowerShell team. We have a few more important changes to get into the PowerShell 7.1 release before we hit our first Release Candidate in September.

Early this month, the majority of PowerShell usage (not including Windows PowerShell) switched from PowerShell Core 6.2 to PowerShell 7.0! We hit a high point of 4.5 million startups of pwsh in a single day! See more data at our public PowerBI dashboard. Reminder that PowerShell Core 6.2 support ends next month!

2 comments

Leave a comment

  • Avatar
    Jim Lear
    With this change, the above example now works as one would expect in that the -Uri parameter value will be the one explicitly specified in the command line and not the one in the hashtable.

    Wouldn’t you want the precedent to be whichever parameter was last? This would allow the user to use the explicit as a default and splatting as an override, if the order is reversed.