Monthly Archive

Categories

PowerShell 7

Get-Counter

The Get-Counter cmdlet returns in PowerShell v7 preview 6. Its only Get-Counter though the Import/Export-Counter cmdlets aren’t available. Get-Counter isn’t experimental feature so its available as soon as you install preview 6.

PS> Get-Command Get-Counter -Syntax

Get-Counter [[-Counter] <string[]>] [-SampleInterval <int>] [-MaxSamples <long>] [-Continuous] [-ComputerName <string[]>] [<CommonParameters>]

Get-Counter [-ListSet] <string[]> [-ComputerName <string[]>] [<CommonParameters>]

 

There’s a default set of counters available:

PS> Get-Counter

Timestamp CounterSamples
--------- --------------
30/11/2019 11:44:52 \\w510w10\network interface(intel[r] 82577lm gigabit network connection)\bytes total/sec : 0

\\w510w10\network interface(11b_g_n wireless lan mini-pci express adapter ii)\bytes total/sec : 150.691579544147

\\w510w10\processor(_total)\% processor time :
0.9798448232225421

\\w510w10\memory\% committed bytes in use :
25.227649888309568

\\w510w10\memory\cache faults/sec :
18.961192128071477

\\w510w10\physicaldisk(_total)\% disk time :
0.30062706236372333

\\w510w10\physicaldisk(_total)\current disk queue length :
0

 

To see the available list of counter sets

PS> Get-Counter -ListSet * | select CounterSetName

 

To see the counters in a set

PS> Get-Counter -ListSet Processor | select -ExpandProperty Counter

 

To view a counter

PS> Get-Counter -Counter '\Processor(*)\% Processor Time'

 

The SampleInterval, MaxSamples and Continuous parameters can be used to control the number of samples and the time of recording.

Clipboard cmdlets

The clipboard cmdlets return in PowerShell v7 preview 6

Get-Clipboard and Set-Clipboard are back and according to the release notes work cross platform.

PS> Get-Command Get-Clipboard -Syntax

Get-Clipboard [-Raw] [<CommonParameters>]

 

PS> Get-Clipboard
Clipboard test

 

The Raw parameter makes Get-Clipboard ignore new line characters and get the entire contents of the clipboard.

PS> Get-Clipboard -Raw
Clipboard test

Clipboard test2

 

Putting values onto the clipboard:

PS> Get-Command Set-Clipboard -Syntax

Set-Clipboard [-Value] <string[]> [-Append] [-WhatIf] [-Confirm] [<CommonParameters>]

 

PS> Set-Clipboard -Value 'new clipboard' –Append

PS> Get-Clipboard -Raw
Clipboard test

Clipboard test2
new clipboard

 

The clipboard can be cleared – more or less – with a blank string

Set-Clipboard -Value ' '

 

On Linux, Set-Clipboard requires the xclip utility to be in the path.

Clear-RecycleBin

The Clear-RecycleBin cmdlet returns in PowerShell v7 preview 6 on Windows

PS> Get-Command Clear-RecycleBin -Syntax
Clear-RecycleBin [[-DriveLetter] <string[]>] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>]

 

To use

PS> Clear-RecycleBin

 

Will ask for confirmation you want to perform the action

PS> Clear-RecycleBin -Force

or

PS> Clear-RecycleBin -Confirm:$false

 

Will bypass the need for confirmation

PowerShell v7 preview 6

PowerShell v7 preview 6 has arrived - https://github.com/PowerShell/PowerShell/releases

Its the last preview, as the Release candidate should appear next month, so this version is a good indication of what’ll be available in PowerShell v7.

 

Test-Connection finally works properly and is usable

 

Some graphical based cmdlets are now available

Out-GridView

Show-Command

Get-Help –ShowWindow

 

A number of other cmdlets return:

Get-Counter

Get- , Set-Clipboard  (now cross platform)

Out-Printer

Update-List

Clear-RecycleBin

 

Some of these are Windows only as the features don’t exist on other platforms

 

New experimental features include the null-conditional operators and using non-compatible Windows PowerShell modules in PowerShell core (no more WindowsCompatibility module)

 

I’ll look at some these in more depth in future posts.

I’ll try and put together a summary of all the major changes between PowerShell v6.2 and v7

Get-Hotfix

Get-Hotfix returns to PowerShell in PowerShell v7 preview 5 – at least on Windows.

 

PS> Get-Command Get-HotFix -Syntax

Get-HotFix [[-Id] <string[]>] [-ComputerName <string[]>] [-Credential <pscredential>] [<CommonParameters>]

Get-HotFix [-Description <string[]>] [-ComputerName <string[]>] [-Credential <pscredential>] [<CommonParameters>]

 

It still uses the Win32_QuickFixEngineering CIM class under the covers which is why its Windows only.

 

My preferred way of using Get-Hotfix is

PS> Get-HotFix | Sort-Object -Property InstalledOn –Descending

 

That way I see the most recent fixes at the top of the list and its easier to determine if the system is up to date.

Pipeline Chain operators

Another experimental feature from PowerShell v7 preview 5 brings pipeline chain operators to PowerShell.

PS> Get-ExperimentalFeature -Name PSPipelineChainOperators | Format-List Name, Description

Name : PSPipelineChainOperators
Description : Allow use of && and || as operators between pipeline invocations

 

The operators work as follows

<command1> && <command2> means that command2 will fire if command1 completes without errors

 

You could write that in PowerShell now as

<command1>; if ($?) { <command2> }

 

If command1 works and $? is $true (no errors) fire command2

 

<command1> || <command2> means that command2 will fire if command1 has errors

i.e.

<command1>; if (-not $?) { <command2> }

 

Like all experimental features it has to be enabled and PowerShell restarted

PS> Enable-ExperimentalFeature -Name PSPipelineChainOperators
WARNING: Enabling and disabling experimental features do not take effect until next start of PowerShell.

 

The best way to explain these operators is to show some examples

This is from the RFC

PS> 1,2,3 | ForEach-Object { $_ + 1 } && Write-Output 'Hello'
2
3
4
Hello

 

PS> Get-Item -Path c:\nosuchfile -ErrorAction SilentlyContinue || Write-Output 'ERROR'
ERROR

The message is written because the file isn’t found

 

PS> $path = 'C:\test\DebugJob2.ps1'
PS> Get-Item -Path $path -ErrorAction SilentlyContinue && Remove-Item -Path $path

results in the file being deleted

 

Subsequently running

PS> Get-Item -Path $path -ErrorAction SilentlyContinue || Write-Output 'No such file'
No such file

 

generates the message because the file isn’t there.

 

The chain operators work if there’s an error or not with the execution of command1 so you can’t use the test cmdlets such as Test-Path because they return booleans.

 

These operators follow the bash model of working on errors which isn’t necessarily the way PowerShell will work for you. I’m in two minds as to whether these operators are useful or not as the examples above feel contrived and I’m not convinced at the moment that the mental gymnastics required to accommodate these operators in my code are worth it. Time will tell.

Get-Error

One of the experimental features new PowerShell v7 preview 5 is the Get-Error cmdlet. The features description states:

Enable Get-Error cmdlet that displays detailed information about ErrorRecords included nested objects

 

Enable the feature:

PS> Enable-ExperimentalFeature -Name Microsoft.PowerShell.Utility.PSGetError
WARNING: Enabling and disabling experimental features do not take effect until next start of PowerShell.

 

It would be better for users if the naming of experimental features became more consistent and ideally a single word rather than a fully qualified name including the module as this and some other new experimental features have.

 

The cmdlet has a simple syntax:

PS> Get-Command Get-Error -Syntax

Get-Error [-Newest <int>] [<CommonParameters>]

Get-Error [[-InputObject] <psobject>] [<CommonParameters>]

 

Generate some errors:

PS> 1/ 0
RuntimeException: Attempted to divide by zero.
PS> Get-ChildItem -Path c:\nosuchfile
Get-ChildItem: Cannot find path 'C:\nosuchfile' because it does not exist.

 

Using Get-Error gives a very comprehensive view of the errors

PS> Get-Error

Exception :
ErrorRecord :
Exception :
Message : Cannot find path 'C:\nosuchfile' because it does not exist.
HResult : -2146233087
TargetObject : C:\nosuchfile
CategoryInfo : ObjectNotFound: (C:\nosuchfile:String) [], ParentContainsErrorRecordException
FullyQualifiedErrorId : PathNotFound
ItemName : C:\nosuchfile
SessionStateCategory : Drive
TargetSite :
Name : GetChildItems
DeclaringType : System.Management.Automation.SessionStateInternal
MemberType : Method
Module : System.Management.Automation.dll
StackTrace :
at System.Management.Automation.SessionStateInternal.GetChildItems(String path, Boolean recurse, UInt32 depth,
CmdletProviderContext context)
at System.Management.Automation.ChildItemCmdletProviderIntrinsics.Get(String path, Boolean recurse, UInt32 depth,
CmdletProviderContext context)
at Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()
Message : Cannot find path 'C:\nosuchfile' because it does not exist.
Source : System.Management.Automation
HResult : -2146233087
TargetObject : C:\nosuchfile
CategoryInfo : ObjectNotFound: (C:\nosuchfile:String) [Get-ChildItem], ItemNotFoundException
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
InvocationInfo :
MyCommand : Get-ChildItem
ScriptLineNumber : 1
OffsetInLine : 2
HistoryId : 5
Line : Get-ChildItem -Path c:\nosuchfile
PositionMessage : At line:1 char:2
+ Get-ChildItem -Path c:\nosuchfile
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
InvocationName : Get-ChildItem
CommandOrigin : Internal
ScriptStackTrace : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo :

 

This is the latest error in the error collection. You’ll see the same information if you use

PS> $error[0]

 

If you use the Newest parameter you’ll also see the Error Index

PS> Get-Error -Newest 2

ErrorIndex: 0

Exception :
ErrorRecord :
Exception :
Message : Cannot find path 'C:\nosuchfile' because it does not exist.
HResult : -2146233087
TargetObject : C:\nosuchfile
CategoryInfo : ObjectNotFound: (C:\nosuchfile:String) [], ParentContainsErrorRecordException
FullyQualifiedErrorId : PathNotFound
ItemName : C:\nosuchfile
SessionStateCategory : Drive
TargetSite :
Name : GetChildItems
DeclaringType : System.Management.Automation.SessionStateInternal
MemberType : Method
Module : System.Management.Automation.dll
StackTrace :
at System.Management.Automation.SessionStateInternal.GetChildItems(String path, Boolean recurse, UInt32 depth,
CmdletProviderContext context)
at System.Management.Automation.ChildItemCmdletProviderIntrinsics.Get(String path, Boolean recurse, UInt32 depth,
CmdletProviderContext context)
at Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()
Message : Cannot find path 'C:\nosuchfile' because it does not exist.
Source : System.Management.Automation
HResult : -2146233087
TargetObject : C:\nosuchfile
CategoryInfo : ObjectNotFound: (C:\nosuchfile:String) [Get-ChildItem], ItemNotFoundException
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
InvocationInfo :
MyCommand : Get-ChildItem
ScriptLineNumber : 1
OffsetInLine : 2
HistoryId : 5
Line : Get-ChildItem -Path c:\nosuchfile
PositionMessage : At line:1 char:2
+ Get-ChildItem -Path c:\nosuchfile
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
InvocationName : Get-ChildItem
CommandOrigin : Internal
ScriptStackTrace : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo :

ErrorIndex: 1

Exception :
ErrorRecord :
Exception :
Message : Attempted to divide by zero.
HResult : -2146233087
CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException
FullyQualifiedErrorId : RuntimeException
InvocationInfo :
ScriptLineNumber : 1
OffsetInLine : 2
HistoryId : -1
Line : 1/ 0
PositionMessage : At line:1 char:2
+ 1/ 0
+ ~~~~
CommandOrigin : Internal
ScriptStackTrace : at <ScriptBlock>, <No file>: line 1
TargetSite :
Name : Divide
DeclaringType : System.Management.Automation.IntOps
MemberType : Method
Module : System.Management.Automation.dll
StackTrace :
at System.Management.Automation.IntOps.Divide(Int32 lhs, Int32 rhs)
at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
Message : Attempted to divide by zero.
Data : System.Collections.ListDictionaryInternal
InnerException :
Message : Attempted to divide by zero.
HResult : -2147352558
Source : System.Management.Automation
HResult : -2146233087
CategoryInfo : NotSpecified: (:) [], RuntimeException
FullyQualifiedErrorId : RuntimeException
InvocationInfo :
ScriptLineNumber : 1
OffsetInLine : 2
HistoryId : -1
Line : 1/ 0
PositionMessage : At line:1 char:2
+ 1/ 0
+ ~~~~
CommandOrigin : Internal
ScriptStackTrace : at <ScriptBlock>, <No file>: line 1

 

This seems to give a concise view of the Index and the error

PS> Get-Error -Newest 2 | Select PSErrorIndex, @{N='Error'; E={$_}} | Format-List

PSErrorIndex : 0
Error : Cannot find path 'C:\nosuchfile' because it does not exist.

PSErrorIndex : 1
Error : Attempted to divide by zero.

 

I think I’d rather see Get-Error by itself supply a list of current errors and their index. There should also be an Index parameter that enables you to pick a specific error. Otherwise this looks like a useful addition.

Returning cmdlets

If I’m interpreting the email updates coming from the PowerShell project the next code release of PowerShell v7 should see the following returning cmdlets:

Get-Counter

Update-List

Clear-RecycleBin

Out-Printer

All but Update-List are Windows only as far as I can ell

Error view

Error view is another experimental feature introduced with PowerShell v7 preveiw 5. The experimental feature needs to be enabled and PowerShell restarted.

PS> Enable-ExperimentalFeature -Name PSErrorView
WARNING: Enabling and disabling experimental features do not take effect until next start of PowerShell.

 

At the PowerShell prompt you’d normally see an error in this form

PS> 1 / 0
Attempted to divide by zero.
At line:1 char:1
+ 1 / 0
+ ~~~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException

 

The PSErrorview feature changes this to a more concise one line error

PS> 1 / 0
RuntimeException: Attempted to divide by zero.

 

Enabling the experimental feature sets the $errorview preference variable to ConciseView

PS> $errorview
ConciseView

 

You can set the error view manually

PS> $errorview = [System.Management.Automation.ErrorView]::NormalView
PS> 1/0
Attempted to divide by zero.
At line:1 char:1
+ 1/0
+ ~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException

 

Possible values for $errorview are

PS> [enum]::GetValues([System.Management.Automation.ErrorView])
NormalView
CategoryView
ConciseView

 

In Normal view an error in a script looks like this

PS> .\test.ps1
Attempted to divide by zero.
At C:\Scripts\test.ps1:1 char:2
+ 1 / 0
+ ~~~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException

 

In Concise view you get this

PS> $errorview = [System.Management.Automation.ErrorView]::ConciseView
PS> .\test.ps1
RuntimeException: C:\Scripts\test.ps1
Line |
1       | 1 / 0
| ^ Attempted to divide by zero.

 

The concise view supplies a more obvious indication of where the error is occurring.

 

This is a new feature that looks useful especially if you spend a lot of time working interactively.

Test-Connection

In PowerShell v7 preview Test-Connection sees some improvements:

PS> Test-Connection -TargetName 127.0.0.1 | Format-List

Source : W510W10
Destination : 127.0.0.1
Replies : {System.Net.NetworkInformation.PingReply, System.Net.NetworkInformation.PingReply,
System.Net.NetworkInformation.PingReply, System.Net.NetworkInformation.PingReply}

 

The progress bar has been removed as has the unrequired text displayed with each ping.

The replies are still wrapped up in a collection of objects each of which looks like this

PS> Test-Connection -TargetName 127.0.0.1 -Count 1 | select -ExpandProperty Replies

Status : Success
Address : 127.0.0.1
RoundtripTime : 0
Options : System.Net.NetworkInformation.PingOptions
Buffer : {97, 98, 99, 100…}

 

Using the Quiet parameter

PS> Test-Connection -TargetName 127.0.0.1 -Quiet
True

Works exactly as expected

 

TargetName is called ComputerName in Windows PowerShell versions of the cmdlet though the PowerShell v7 versions supplies ComputerName as an alias.

 

The preview 5 version of Test-Connection is starting to become usable though to be considered truly fit for purpose the Replies objects need to be unravelled and the output should consist of one object per ping NOT just a single object.