Tuesday, December 24, 2019

Changing Default Parameter Values - Yet Another User for Hash Tabales

In PowerShell, the hash table is an amazingly useful .NET class - for all sorts of things: With hash tables, you can:

  • Pass a hash table and an object to Select-Object, and have the cmdlet add a calculated property to the object for later use
  • Push a hash table to Format-* and have the command create and display a new property and have it look just the way you want it.
  • Splatting, splatting, and more spatting. What a great use of hash tables.
  • Specifying property values for obscure properties in Set-ADUser/Set-ADComputer, and Set-AD-Object.
  • And many more!
But one of my favourite uses is to change the default values for certain properties within a PowerShell session or even a script.

Herre's something I am sure you have all faced. If you run a PowerShell job, you receive the output generated by using Receive-Job. By default, once you run that command, the output is removed from memory and is no longer available. Of course, you could use the -Keep parameter - if you remembered to, which I often don't.  My muscle memory is kind of not yet that well developed in this regard. So I often find my self losing output (which takes time to reproduce). I'd like to do better!

There are other commands too, that I just prefer a different value for some parameters. I'm not saying that the developers were wrong with the defaults they chose, it's just that I prefer different values. For each of these, for example -Wrap with Format-Table, I'd like to tell PowerShell to use a different default setting for a parameter on one more command. 

As ever with PowerShell - you can have it your way, and of course, there's a script for that!

The basic hashtable class is System.Collections.Hashtable. Developers across the Windows and increasingly the Linux also create specific objects derived from the hashtable class. You can read about the hash table class at: https://docs.microsoft.com/en-us/dotnet/api/system.collections.hashtable?view=netcore-3.1. The class is broadly the same in the full .NET and .NET core.

So how does this help to set default command values? When Windows PowerShell and PowerShell startup, the engine creates a variable: $PSDefaultParameterValues.  This variable is of type
System.Management.Automation.DefaultParameterDictionary which you can read about at: https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.defaultparameterdictionary?view=pscore-6.2.0. This object is a hash table with some improvements when used for parameter caching.

You add rows to this hash table to describe the command name, parameter name, and the new value you want PowerShell to use subsequently. For the key name, you specify the command and parameter as "<Command name>: then specify the value you want for that parameter. And of course, you can use wild cards to specify the command or property names.  You build this hash table either in a script (meaning that all commands in that script have a different default value) or stick it in the profile as I so.  So, for example, if you wanted to ensure that Receive-Job always used the -KEEP parameter, you would specify:
$PSDefaultParameterValues  @{Receive-Job:Keep = $true}
My standard profile on my laptop sets this and other values:
$PSDefaultParameterValues = @{'*:AutoSize'=$true;  '*:Wrap'=$true;'Receive-Job:Keep'=$true}
This way, any command that has an AutoSize parameter (eg Format-Table, always uses -AutoSize, likewise for any command that uses the  -Wrap parameter).

I just love hash tables - and this is another great example of where you can use one to have it your way.  


Monday, December 23, 2019

PowerShell Core/7 - Velocity

When the open-source PowerShell team shipped the first two releases of PowerShell Core 6.x, I tweeted that this was a little bit like what I remember of PowerShell V1. A product with incredible potential, a release that is a fantastic proof of concept, but with a loooooong way to go. Jeffrey Snover, in a reply tweet, agreed but made the point that PowerShell Core had a much better velocity. 

As I use PowerShell 7 RC1, I realise just how true his words were. For me, this is kind of like going from PowerShell 1 to PowerShell 5 - it's that big of an improvement in functionality, usability, and performance. 


If you navigate there you see a dashboard like this:


There are two interesting things, to me, about this dashboard. The first is that the bulk of usage is Linux with a small bit of Windows and tiny bit of Mac. But even more interesting, is the spike of usage over weekends for Linux.

As you can see from the overall graphs, usage is growing - I would expect a big increase in Windows come the new year. We'll see!

PowerShell 7 - Background Job Operator

PowerShell 7 is weeks away from release, with a Release Candidate published a few days ago. A cool new feature of PowerShell 7 is the background job operator, or &.  If you append this operator to the end of a line of code, PowerShell runs that line as a background job. Like this:


In this screenshot, I ran the Update-Help command but appended it with a "&" character. With this,  PowerShell runs the job in the background. Of course, if you exit the PowerShell session that is running this background job, the job is terminated immediately. 

This is a neat new feature. You could add the Update-Help to your PowerShell profile and every time you start PowerShell 7, the profile would ensure your help files are up to date. And unlike doing it in the foreground, updating help as a job means it's transparent -you probably would never notice the job running!


Tuesday, December 17, 2019

PowerShell 7 RC1 Has Been Released - Get It Now!

So typical of the PowerShell team - I go off to a lovely yoga class, and they ship something important. Namely the first release candidate for what is to become PowerShell 7. In a perfect world, RC1 would be the final release, except as in any sufficiently large software product there are bound to be a few minor issues that need to be ironed out. But the product is functionally complete, what you see now is that is going to ship (minus any bugs). AND - this release is fully supported in production which is important for many enterprise customers. 

You can read more here: https://devblogs.microsoft.com/powershell/announcing-the-powershell-7-0-release-candidate/. The team should be congratulated on the clear and concise manner with which they communicate, both on the blog and on social media. 

So why do RC1 and PowerShell 7 matter? Does anyone care about a release candidate of a scripting language? I see two main reasons for IT Pros and larger enterprises to begin to transition, or at the very least start the planning for that transition. 

First, it is a significant upgrade to PowerShell itself. It feels more significant than going from Windows PowerShell V2 to V3. There are a host of new features and some tremendous performance improvements, especially for very large workloads. So if you are processing all the AD computer or user accounts in a large multinational or testing connectivity to a large number of hosts using Test-Connection you are going to love PowerShell 7.

Today, many (most?) larger organisations manage production systems using suites of large and complex PowerShell scripts. For such organisations, the performance improvements alone probably justify the switch. Not mention how many little things are added that make it a joy to use.

A second reason is that Windows PowerShell is feature complete. It is not going to be improved or extended. So what works today is going to carry on being supported. All the improvements have been added to PowerShell 7. That also means leaving behind the ISE. A great tool, now in effect replaced by VS Code which is also a huge improvement.

As with any major change, there are a few things that just do not work - and won't work in PowerShell 7 when it ships early in 2020. There is a great backwards compatibility story for most of the commands that are not explicitly built using .NET Core. In the main, they work pretty well. But there are a few Windows Server modules whose command do not work and are highly unlikely to work at RTM. Two modules I'm aware of at the moment are Best Practices and the WSUS module. The WSUS module will need a major redevelopment and at this time there is no word from the team (but feel free to vote on this suggestion:  https://windowsserver.uservoice.com/forums/304618-installation-and-patching/suggestions/39267028-wsus-server-should-be-manageable-using-powershell).  

So if you are not doing so already, start using RC1. 

Thursday, December 12, 2019

Setting up the Console in PowerShell 7

I am using the latest versions of PowerShell, PowerShell 7, and loving it. Loads of new features, new operators, and better performance. I find myself using both Windows PowerShell 5.1, as well as PowerShell 7 (both preview and daily builds). This is a good environment for me as I am embarking on a book writing project on PowerShell.

Like most long-time PowerShell users, I have made use of my $Profile file to customise and optimise the environment for me. With both daily builds and preview builds and release builds - it gets hard to keep track when I'm inside a PowerShell console window. To help me out, I've added a bit of code to my profile:
If ($Host.Name -eq 'ConsoleHost') {
  $Me = whoami
  $Vn  = $PSVersionTable.PSVersion.Major
  $VNM = $PSVersionTable.PSVersion.Minor
  If ($Host.UI.RawUI.WindowTitle -match 'Administrator') {
     $WindowTitle = "ADMINISTRATOR: PowerShell $Vn.$VNM Rocks!" 
   } 
  else {
     $WindowTitle = "$Me - PowerShell $Vn.$VNM Rocks!" 
  }

If ($PSVersionTable.PSVersion.PreReleaseLabel) {
  $WindowTitle +=  "   ** $($PSVersionTable.PSVersion.PreReleaseLabel.toupper()) **" 
}

# Set it in the $Host
$Host.Ui.RawUi.WindowTitle = $WindowTitle

#  New in 5.1 - Setup PSReadline to be 'better' - For PSReadline V2.

Set-PSReadLineOption -Colors @{
  Command            = 'Cyan'
  Number             = 'White'
  Member             = 'Green'
  Operator           = 'Yellow'
  Type               = 'DarkGreen'
  Variable           = 'Yellow'
  Parameter          = 'Cyan'
  ContinuationPrompt = 'Cyan'
  String             = 'Yellow'
  Default            = 'White'}
}
This fragment, a part of my normal profile for the console hosts, sets the console host window title, based on who I am (ie is this console run as Administrator?) and it it's is a preview version build then which one (daily build vs released preview). Then uses Set-PSReadLIneOption to set the colours for my console.

These additions to my profile make it easy to see which specific version of PowerShell is running and will set the console colours to my tastes.

Wednesday, December 04, 2019

Getting the Job Done - Despite the UI

Most IT Pros are likely to want to manage various setting within Windows - both on Windows 10 and Windows Server (with the Desktop Experience!) - things like power management, a network setting, etc. Doing so means in many cases means weaving one's way through the UI to hit some window to facilitate the issue at hand. For example, if I want to set the DNS server IP address on a NIC, I have to figure out how to get, eventually to the Network Connections applet, from where I can select the NIC and make the change.

One might say. just do it with PowerShell. PowerShell is great for routine things - automation makes sense. But for one-off issues, the GUI is often just faster and easier. The issue is navigating the Windows UI. The migration of things form the Control Panel into Settings has not helped.

Almost all of the lower level applets you need to manage Windows from the UI are available to you by running a specific program. For example, to get to the Network Connections applet, just run ncpa.cpl. And if you run it from PowerShell, there is tab completion of the applet's name.

There are around 40 commands you can fun to do useful things. These commands are implemented as *.CPL and *.MSC programs. You can discover then for your self by running this:

Get-Command *.CPL, *.MSC
Here's what you should find:

Command Name What Is It?
appwiz.cpl                   Uninstall or Change A Program
azman.msc                    Authorization Manager
bthprops.cpl                 Bluetooth & Other Devices
certlm.msc                   Certificate Manager for Local Computer
certmgr.msc                  Certificate Manager for Current User
comexp.msc                   Component Services, Event Viewer, Services 
compmgmt.msc                 Computer Management, System Tools, Storage and Services
desk.cpl                     Display layout
devmgmt.msc                  Device Manager 
DevModeRunAsUserConfig.msc   Start Menu Configuration
diskmgmt.msc                 Disk Management
eventvwr.msc                 Event Viewer
Firewall.cpl                 Firewall Manager
fsmgmt.msc                   Shared Folder Management
gpedit.msc                   Local GPO Editor
hdwwiz.cpl                   Device Manager (again!)
inetcpl.cpl                  Internet Properties
intl.cpl                     Region Settings
irprops.cpl                  InfraRed - on systems with IR
joy.cpl                      Game Controller
lusrmgr.msc                  Local User Manger
main.cpl                     Mouse Properties
mmsys.cpl                    Sound Properties
ncpa.cpl                     Network Interface properties
perfmon.msc                  Performance Monitor
powercfg.cpl                 Power Configuration
printmanagement.msc          Printer Manament
rsop.msc                     Resultant Set of Policy
secpol.msc                   Local Securityh Policy
services.msc                 Services
sysdm.cpl                    System Properties
TabletPC.cpl                 Tablet and Pen Settings
taskschd.msc                 Task Scheduler
telephon.cpl                 Phone Location Information
timedate.cpl                 Time and Date
tpm.msc                      Trusted Platform Module
WF.msc                       Defender Firewall
WmiMgmt.msc                  WMI Management
wscui.cpl                    Security and Maintenance

Enjoy