Monthly Archive

Categories

Monthly Archives: April 2018

PowerShell v6.1 Range Operator

The PowerShell v6.1 Rang Operator has been enhanced to deal with letters as well as numbers.

The range operator has always been available in PowerShell. It can be used to generate a range of integers for example:

PS>  (1..10) -join ','
1,2,3,4,5,6,7,8,9,10
PS>  (10..1) -join ','
10,9,8,7,6,5,4,3,2,1
PS>  (-10..10) -join ','
-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10
PS>  (10..-10) -join ','
10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10

 

In PowerShell v6.1 the range operator can also produce sequences of letters

PS>  'a'..'z' -join ','
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
PS>  'z'..'a' -join ','
z,y,x,w,v,u,t,s,r,q,p,o,n,m,l,k,j,i,h,g,f,e,d,c,b,a

PS>  'A'..'Z' -join ','
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
PS>  'Z'..'A' -join ','
Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A

 

Be careful with mixing case

PS>  'Z'..'a' -join ','
Z,[,\,],^,_,`,a
PS>  'a'..'Z' -join ','
a,`,_,^,],\,[,Z
PS>  'z'..'A' -join ','
z,y,x,w,v,u,t,s,r,q,p,o,n,m,l,k,j,i,h,g,f,e,d,c,b,a,`,_,^,],\,[,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A
PS>  'A'..'z' -join ','
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,[,\,],^,_,`,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z

 

As you might get more than you wanted  🙂

-Contains or -In

PowerShell has two operators that do very similar jobs –contains and –in. So which should you use –contains or –in.

From the help file.

-Contains: Tells whether a collection of reference values includes a single test value.

-In: Tells whether a test value appears in a collection of reference values

OK – they’re subtly different.

 

The real difference comes in how you use them

-Contains has been available since PowerShell v1. Its used like this

<reference values> –contains <value>

for example

PS> $rb = 'Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet'
PS> $rb -contains 'yellow'
True
PS> $rb -contains 'black'
False

 

True or false is returned depending if the value is part of the collection or not

 

By contrast –In (introduced in PowerShell v3) uses this syntax

<value> –in <reference values>

for example

PS> $rb = 'Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet'
PS> 'Blue' -in $rb
True
PS> 'Black' -in $rb
False

 

The difference between the two is the order of the operands.

-In was introduced for use with the short hand syntax of Where-Object

where <property value> operator <value>

so try this

$rb = 'Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet'
$colours = 'Black', 'White', 'Red'

$co = foreach ($colour in $colours) {
New-Object -TypeName psobject -Property @{
Colour = $colour
}
}

 

Then run

$co | where Colour -in $rb

$co | where Colour -contains $rb

$co | where $rb -contains colour

$co | where {$rb -contains $_.colour}

 

You’ll see the correct answer from the first and fourth options and nothing from the second because the values are the wrong way round. The third option errors

Where-Object : A positional parameter cannot be found that accepts argument
'System.Object[]'.
At line:1 char:7
+ $co | where $rb -contains colour
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Where-Object], ParameterBi
ndingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell
.Commands.WhereObjectCommand

Installing PowerShell v6.1 preview 2

The MSI for installing PowerShell v6.1 preview 2 has a screen for optional actions:

Add PowerShell to Path environment variable
Register Windows Event Logging Manifest
Enable PowerShell remoting
Add 'open here' context menus to Explorer

 

The 6.1 preview installs side by side with PowerShell v6.0.x

 

Test-Connection in v6.1

PS> Get-Command Test-Connection -Syntax

Test-Connection [-TargetName] <string[]> [-Ping] [-IPv4] [-IPv6] [-ResolveDestination] [-Source <string>] [-MaxHops <int>] [-Count <int>] [-Delay <int>] [
-BufferSize <int>] [-DontFragment] [-TimeoutSeconds <int>] [-Quiet] [<CommonParameters>]

Test-Connection [-TargetName] <string[]> [-Ping] [-IPv4] [-IPv6] [-ResolveDestination] [-Source <string>] [-MaxHops <int>] [-Delay <int>] [-BufferSize <int>] [-DontFragment] [-Continues] [-TimeoutSeconds <int>] [-Quiet] [<CommonParameters>]

Test-Connection [-TargetName] <string[]> -MTUSizeDetect [-IPv4] [-IPv6] [-ResolveDestination] [-TimeoutSeconds <int>] [-Quiet] [<CommonParameters>]

Test-Connection [-TargetName] <string[]> -Traceroute [-IPv4] [-IPv6] [-ResolveDestination] [-Source <string>] [-MaxHops <int>] [-TimeoutSeconds <int>] [-Quiet] [<CommonParameters>]

Test-Connection [-TargetName] <string[]> -TCPPort <int> [-IPv4] [-IPv6] [-ResolveDestination] [-Source <string>] [-TimeoutSeconds <int>] [-Quiet] [<Common
Parameters>]

is very different to Test-Connection in v5.1

Test-Connection [-ComputerName] <string[]> [-AsJob] [-DcomAuthentication <AuthenticationLevel>] [-WsmanAuthentication <s
tring>] [-Protocol <string>] [-BufferSize <int>] [-Count <int>] [-Impersonation <ImpersonationLevel>] [-ThrottleLimit <i
nt>] [-TimeToLive <int>] [-Delay <int>] [<CommonParameters>]

Test-Connection [-ComputerName] <string[]> [-Source] <string[]> [-AsJob] [-DcomAuthentication <AuthenticationLevel>] [-W
smanAuthentication <string>] [-Protocol <string>] [-BufferSize <int>] [-Count <int>] [-Credential <pscredential>] [-Impe
rsonation <ImpersonationLevel>] [-ThrottleLimit <int>] [-TimeToLive <int>] [-Delay <int>] [<CommonParameters>]

Test-Connection [-ComputerName] <string[]> [-DcomAuthentication <AuthenticationLevel>] [-WsmanAuthentication <string>] [
-Protocol <string>] [-BufferSize <int>] [-Count <int>] [-Impersonation <ImpersonationLevel>] [-TimeToLive <int>] [-Delay
<int>] [-Quiet] [<CommonParameters>]

 

You’ll need to experiment to see the differences and to determine which works best for you.

 

Test –json I’m not sure if its working correctly or not – it throws an exception with a JSON file I’ve used many times and also with this

PS> Get-Process p* | ConvertTo-Json | Test-Json
Test-Json : Cannot parse the JSON.
At line:1 char:35
+ Get-Process p* | ConvertTo-Json | Test-Json
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: ([
{
"Sa...rocess"
}
]:String) [Test-Json], Exception
+ FullyQualifiedErrorId : InvalidJson,Microsoft.PowerShell.Commands.TestJsonCommand

needs some investigation.

Access module and functions

A long time ago I wrote a module for working with Access databases. I also added a couple of independent functions. The  Access module and functions are now available on github.

People have asked about getting the module and while its had a number of temporary homes its permanent home is now the github repsoitory - https://github.com/RichardSiddaway/AccessFunctions

 

The module comprises the following functions:

Add-AccessRecord
Close-AccessDatabase
Get-AccessData
Get-AccessStoredProcedure
Get-AccessTableDefinition
Invoke-AccessStoredProcedure
New-AccessColumn
New-AccessDatabase
New-AccessIndex
New-AccessStoredProcedure
New-AccessTable
Open-AccessDatabase
Remove-AccessColumn
Remove-AccessData
Remove-AccessIndex
Remove-AccessStoredProcedure
Remove-AccessTable
Reset-Autonum
Set-AccessData
Test-AccessConnection

 

The independent functions are:

bulkload.ps1
new-table.ps1

 

All of the functions are supplied as is without warranty or guarantee.

PowerShell v6.1 preview 2

PowerShell v6.1 preview 2 is now available for download from https://github.com/PowerShell/PowerShell/releases

 

The breaking changes shouldn’t affect your code as they’re for telemetry and installation

 

Test-Connection is now available in v6

Export-FormatData will pretty print the XML rather than just giving you a single string

There’s now a Test-Json cmdlet and a –Not parameter has been added to Where-Object

 

OpenSSH has moved to https://github.com/PowerShell/openssh-portable but releases are managed through https://github.com/PowerShell/Win32-OpenSSH/releases

Confused? So am I.

This may be linked to the fact that OpenSSH is appearing as an optional install in Windows 10 and Windows Server (post v1709) though the server only had the option for the client last time I looked.

The OpenSSH story is becoming more confusing every time I look at it. It needs to be sorted if remoting between Linux and Windows is to become a thing.

 

ScriptBlocks Decoded

My second talk at the PowerShell Summit 2018 was ScriptBlocks Decoded.

 

Starting from the basic explanation of what is a scriptblock and why they’re important it progressed through to proxy functions at the end.

 

The slides and code are available at https://github.com/RichardSiddaway/Summit2018ScriptBlocksDecoded

 

The recording of the session should be on the powershell.org youtube channel sometime in May

Troubleshooting #2

Last time I covered the PowerShell Troubleshooting pack. This time in Troubleshooting #2 I want to show you how to use Pester when troubleshooting.

 

When you’re troubleshooting you ideally want to follow a repeatable process so that you can do it again if necessary and teach others to do the same task.

By wrapping the troubleshooting tests as Pester tests you achieve these aims.

 

If you’ve not used Pester its a PowerShell module that was originally conceived for performing unit tests on your code. You can use Pester for testing your infrastructure is correctly built and configured as well.

 

I created a set of Pester tests for various scenarios where remoting has gone wrong. For example

Describe 'Listener' {
## tests listener available
It 'Listener is available' {
Test-Path -Path WSMan:\localhost\Listener\listener* |
Should Be $true
}
}

 

tests if the remoting listener is available

and

Describe 'Port' {
## tests listening on correct remoting port
It 'Remoting Port is 5985' {
Get-Item  "$path\Port" |
select -ExpandProperty Value |
Should Be '5985'
}
}

 

tests the port that remoting is using.

 

I wanted the troubleshooting script to stop when it hit a problem so I used a second script to execute the tests. Normally  Pester would execute all tests in a file.

$tests = 'WinRM', 'Listener', 'Listener Enabled', 'Transport', 'Address',
'Port', 'EndPoint Exists', 'EndPoint Enabled', 'Firewall Enabled', 'Firewall Allows',
'Remoting Enabled'

$data = foreach ($test in $tests) {
$result = $null
$result = Invoke-Pester -Script @{Path = '.\RemotingTests.ps1'} -PassThru -TestName "$test" -Show None #-EnableExit

$props = [ordered]@{
'Test' = $result.TestResult.Name
'Result' = $result.TestResult.Result
'Failue Message' = $result.TestResult.FailureMessage
}
New-Object -TypeName PSObject -Property $props

if ($result.FailedCount -gt 0) {break}
}

$data | Format-Table -AutoSize -Wrap

 

List the tests I want to run and foreach test run it. Output the results of the test and if the test failed break out of the loop and dump the results to screen.

 

if everything works you see something like this

PS>  .\Test-Remoting.ps1

Test                        Result Failue Message
----                        ------ --------------
WinRM should be running     Passed
Listener is available       Passed
Listener is Enabled         Passed
Transport is HTTP           Passed
Address is *                Passed
Remoting Port is 5985       Passed
End Point Exists            Passed
EndPoint is Enabled         Passed
Firewall rule is enabled    Passed
Firewall rule set to Allow  Passed
PowerShell Remoting Enabled Passed

 

If at any stage the test fails the testing process stops and you get a display showing the tests that passed and a message explaining the test that failed.  You can fix that and then rerun.

 

The code is available at

https://github.com/RichardSiddaway/Summit2018TroubleShootingRemoting

 

There are also a number of scripts that break remoting so you can test the methodology. For each breaking script there is the corresponding fix. The demo script I used in the talk is also available.

 

Its currently a proof of concept for the Summit talk but I think the approach has strong possibilities as troubleshooting methodology that could be applied to many troubleshooting scenarios.

 

Enjoy, use and adapt to meet your needs

Troubleshooting #1

How do you go about troubleshooting a problem?

 

There are two ends to the spectrum of solutions to troubleshooting a problem. At one end you have the click and pray brigade who will manically click round all the menus on all the tools they can think of using to try and find something that will fix the problem. I’ve watched people like this in action and while it looks like they’re working incredibly hard in reality they are achieving nothing  - in fact less than nothing because their manic activities get in the way of actually discovering a solution to the problem.

 

At the other end you have the people who have a process – usually manual – to work through solving the problem. In this case they methodically work through the process eliminating possible issues until they arrive at the cause of the problem. The classic problem solving routine for network connectivity is a classic example:

- ping the loop back adapter 127.0.0.1

- ping the local IP address

- ping the default gateway

- ping one or more routers

- ping destination address

You find out where the problem lies and can then address how to fix it.

 

One problem with the second approach is that it requires experience. Experience in administration and troubleshooting and  keeping calm and methodically working through the process when people are shouting at you for a solution. Junior admins usually don’t have this experience.

 

For a number of versions (I can’t remember when it first appeared) Windows PowerShell has carried a Troubleshooting module – its NOT available in Powershell v6.

There a number of troubleshooting packs in C:\Windows\Diagnostics\system\

Name
----
AERO
Apps
Audio
BITS
BlueScreen
Bluetooth
Device
DeviceCenter
HomeGroup
Internet
Keyboard
Networking
PCW
Performance
Power
Printer
Search
speech
UsbCore
Video
WindowsMediaPlayerConfiguration
WindowsMediaPlayerMediaLibrary
WindowsMediaPlayerPlayDVD
WindowsUpdate

 

You can view the individual packs – for instance

PS> Get-TroubleshootingPack -Path C:\Windows\Diagnostics\system\BITS | fl

Path              : C:\Windows\Diagnostics\system\BITS
Id                : BITSDiagnostic
Version           : 3.5
Publisher         : Microsoft Windows
Name              : Background Intelligent Transfer Service
Description       : Find and fix problems that may prevent background downloads from working
MinimumVersion    : 6.0
PrivacyLink       : https://go.microsoft.com/fwlink/?LinkId=534597
SupportsClient    : True
SupportsServer    : True
SupportsX86       : True
SupportsAmd64     : True
SupportsIA64      : True
RequiresElevation : True
Interactive       : True
RootCauses        : {Service registration is missing or corrupt, Check for missing or corrupt files, Some security
settings are missing or have been changed}
FoundRootCauses   :
Interactions      : {Check for missing or corrupt files, Restart your PC}
ExtensionPoint    : #document

 

And you can fire off the troubleshooting pack

PS> Get-TroubleshootingPack -Path C:\Windows\Diagnostics\system\BITS | Invoke-TroubleshootingPack
Initialising the diagnostic  -1

Check for missing or corrupt files
:
Checking security descriptor…  -1
Starting Bits service  -1

No problems were detected

 

In this case the BITS service was stopped and the troubleshooting pack restarted it to solve the problem.

 

The major issue with the TroubleShooting module is that there are only a very limited number of troubleshooting packs as you’ve seen. There’s no documentation that I’ve been able to find that deals with writing new packs.

 

One of my recent talks at the PowerShell Summit was about troubleshooting Powershell WinRM based remoting. I wanted to show how to automate troubleshooting as well as how to actually troubleshoot remoting issues.

 

I eventually had the idea to use Pester – the code testing module. I’ve used it to test code and infrastructure but I’d never seen anyone talk about using it as a general troubleshooting  tool.

 

Next time I’ll show you how to use Pester to create an expandable troubleshooting tool that can be adapted for almost any scenario.

CIM references and associations

Way back in 2011, when I were just a young lad, I wrote about WMI or CIM references and associations - https://wordpress.com/read/blogs/16267735/posts/1673

ASSOCIATORS show the end point of the link between CIM classes and REFERENCES shows the linking class.

I used the Win32_NetworkAdapter class in the example because it has a known association with Win32_NetworkAdapterConfiguration.

 

One thing I appear to have not made clear is that you have to use the key to the CIM class in the query for the reference or association. The key for a Win32_networkadapter class is DeviceID.

This became clear when a reader pointed out that this won’t work:

PS> Get-WmiObject -Query "REFERENCES OF {win32_printer.name = 'fax'}"
Get-WmiObject : Invalid object path
At line:1 char:1
+ Get-WmiObject -Query "REFERENCES OF {win32_printer.name = 'fax'}"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

 

But that

Get-WmiObject -Query "REFERENCES OF {Win32_Printer.DeviceID='Fax'}"

works. Again DeviceId is the key to the class.

 

Usually its better to go straight to the association and bypass the reference.

A better approach than writing WQL queries is to use the CIM cmdlets

$p = Get-CimInstance -ClassName Win32_Printer -Filter "Name='Fax'"

Get-CimAssociatedInstance -InputObject $p

will show you the data from the associated classes.

 

If you just want to see the associated class names

PS> Get-CimAssociatedInstance -InputObject $p | select CIMclass

CimClass
--------
root/cimv2:Win32_PrinterDriver
root/cimv2:Win32_PrinterConfiguration
root/cimv2:Win32_ComputerSystem
root/cimv2:CIM_DataFile

 

And if you just want the data for a particular associated class

PS> Get-CimAssociatedInstance -InputObject $p -ResultClassName Win32_PrinterDriver

Caption :
Description :
InstallDate :
Name : Microsoft Shared Fax Driver,3,Windows x64
Status :
CreationClassName : Win32_PrinterDriver
Started :
StartMode :
SystemCreationClassName : Win32_ComputerSystem
SystemName :
ConfigFile : C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSUI.DLL
DataFile : C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSUI.DLL
DefaultDataType :
DependentFiles : {C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSWZRD.DLL,
C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSTIFF.DLL,
C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSRES.DLL,
C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSAPI.DLL}
DriverPath : C:\WINDOWS\system32\spool\DRIVERS\x64\3\FXSDRV.DLL
FilePath :
HelpFile :
InfName :
MonitorName :
OEMUrl :
SupportedPlatform : Windows x64
Version : 3
PSComputerName :

Change a function definition

Functions in PowerShell are based on scriptblocks and as I showed in my session at the recent PowerShell Summit its possible to change a function definition.

Let’s start with a simple function:

PS> function f1 {
>> $x = 1
>> $y = 2
>> $x + $y
>> }
PS> f1
3

Our function just adds two numbers and outputs the result.

Digging into functions

PS> Get-Item -Path function:\f1 | Format-List *

PSPath : Microsoft.PowerShell.Core\Function::f1
PSDrive : Function
PSProvider : Microsoft.PowerShell.Core\Function
PSIsContainer : False
HelpUri :
ScriptBlock :
$x = 1
$y = 2
$x + $y

CmdletBinding : False
DefaultParameterSet :
Definition :
$x = 1
$y = 2
$x + $y

Options : None
Description :
Verb :
Noun :
HelpFile :
OutputType : {}
Name : f1
CommandType : Function
Source :
Version :
Visibility : Public
ModuleName :
Module :
RemotingCapability : PowerShell
Parameters : {}
ParameterSets : {}

You’ll see a scriptblock property that is the equivalent of the function definition

This means you can change the function definition by changing the scriptblock

PS> $function:f1 = {
>> $x = 2
>> $y = 3
>> $x * $y
>> }
PS> f1
6

The function has been changed to output the product of the two numbers instead of the sum.

Just one of the many things that scriptblocks can do for you