Showing posts with label PowerShell 7. Show all posts
Showing posts with label PowerShell 7. Show all posts

Tuesday, October 19, 2021

Patching and PowerShell 7

 Many of you reading that blog know I'm a big supporter of PowerShell 7. I hope that many of you share my enthusiasm. After writing several books on PowerShell, and two on PowerShell 7, I find it a pretty good product.

One of the challenges which PowerShell brings to the enterprise is updates. Like most software products, there are bugs and vulnerabilities in PowerShell. I was reminded again of this fact reading an article from my Powershell Paper.Li paper. Today the top article comes from Bleeping Computer: https://www.bleepingcomputer.com/news/microsoft/microsoft-asks-admins-to-patch-powershell-to-fix-wdac-bypass/.

The team do a great job in updating the code as soon as the vulnerabilities are found. In some (many) cases, the issue is not in PowerShell itself, but in one of the components, such as .NET. Once the team releases an update, you need to ensure that the update is rolled out everywhere you use PowerShell 7.

The method you use to keep PowerShell 7 up to date depends on how you installed PowerShell 7 in the first place. And here you have (at least) 3 options:

  • Use Install-PowerShell.ps1 - this is a script you download from GitHub which enables you to install the latest production version of PowerShell, the latest next version Preview and (for the very brave) today's daily builds. If you use this, then you must manually update the software yourself. I love this as I am in control!
  • Use the Microsoft store - you get the released version directly from the store. This should automatically keep your version up to date as the PowerShell team. At present, there is no Store application for Windows Server. You can also get the Preview version from the store (although I do not know how that plays if you also have the released version installed). 
  • Use a third-party repository - you could download PowerShell directly from Github and install it (and manually update it as new versions get pushed out). You can also use Chocolatey although technically that is not supported.
So you have options. Personally, I update the daily build once or twice a week and update the preview and production versions once I get a warning about an updated version the next time I start PowerShell.  

So no matter how you install PowerShell 7, make sure you have a patch strategy in place. And if you have read this far, make sure you have installed 7.1.5 (or 7.0.8 if you are still on 7.0).

Friday, January 17, 2020

PowerShell 7 - Release Candidate 2 has shipped

So there I was, totally relaxed after a lovely yoga class, and at home when Twitter, well actually Steve Lee via Twitter, informed the world that RC2 had shipped. My immediate reaction was, weall as expected, to download/install it NOW!



The Install-PowerShell command from GitHub installs PowerShell for Linux, Mac, and Windows.  You can also use it to download the RTM version as well as Preview version such as Release Candidate 2. I  saved it locally and run it more or less daily to get the latest daily build. 



So what IS as Release Candidate?. In theory, an RC is a set of software that should be the final version except for some bugs. The idea of an RC is to test it and to find those bugs before the final release.; Again, in theory, an RC build should be feature complete - but sometimes 'fixes' do rather look like new features. But for the most part, RC2 is what PowerShell 7 is going to be, minus a few bugs. 

And why does this RC matter? Well - for almost all IT pros (at least Windows IT Pros), Windows PowerShell has been a core tool for a decade. For many, if not most of you, PowerShell 7 is an upgraded replacement tool. It is now fully supported in Production and is really the future of PowerShell. EVERY IT Pro that presently uses Windows PowerShell should take a close look. Speaking personally, I now use  PowerShell 7 for just about everything.

If you are an IT Pro, and if you use Windows PowerShell now. With so many neat new features, you are likely to be pleased, even if you can, today, use PowerShell 7 for everything.

Wednesday, January 15, 2020

Background Jobs in PowerShell 7

The PowerShell background jobs feature allows you to run scripts or script blocks in the background. You use the Start-Job command to start a job, and Get-Job ane Receive-Job to view jobs and to get the output of a job.

With PowerShell 7, you have the option of running a job using either PowerShell 7 (ie the default) or using Windows PowerShell 5.1. You indicate it using the -PSVersion parameter and specifying "5.1". Such jobs then run under Windows PowerShell, which can be useful if you are using PowerShell 7 but have scripts that are not yet compatible (eg using WSUS). You can kick off these scripts using background jobs, have that script run in Windows PowerShell, and then incorporate the results in a PowerShell 7 script.

Here's an example:


In this screenshot, you see I am running this in today's build of the day. I then run a simple job and view the job results. By default, PowerShell runs the script in the same version of PowerShell (ie today's daily build). Then I ran that same script but explicitly asked for Window PowerShell 5.1, what the results you can see.

This is a nice feature to assist with backwards compatibility. PowerShell 7 provides great forward compatibility but it's not yet a perfect replacement for Windows PowerShell. Features like this provide a great workaround when a command is not supported natively. 

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.

Tuesday, November 26, 2019

Installing the Cascadia Code Font (using PowerShell)

In a recent article, I wrote about the new font Microsoft has created, Cascadia Code. I just love the new font and am using it with PowerShell, VS Code and more. I also use it in a variety of VMs, so automating the download and installation is important.

It turns out that downloading and installing a new font is relatively straightforward, like this:

# Install Cascadia Code
# 1. Download Cascadia Code font from GitHub
$DLPath = 'https://github.com/microsoft/cascadia-code/releases/'+
          'download/v1911.20/Cascadia.ttf'
$DLFile = 'C:\Foo\Cascadia.TTF'
Invoke-WebRequest -Uri $DLPath -OutFile $DLFile

# 2. Now Install the Font 
$Font = New-Object -Com Shell.Application
$Destination = (New-Object -ComObject Shell.Application).Namespace(0x14)
$Destination.CopyHere($DLFile,0x10)

Simples as they say.

One thing - the URL download path is hardcoded. You may need to adjust it going forward. Maybe someone can show me how to work out the latest version programmatically.

[Later]
I noticed that Blogger' editor had mangled the code - sorry but thanks for the heads up.

Friday, November 22, 2019

PowerShell 7 Preview 6 ships - Get It Now!

The PowerShell team have released another preview of PowerShell 7. This release, which I expect to be the final preview before release of PowerShell 7 early in 2020, comes with a number of fantastic new features. Over on the PowerShell blog, super-star Steve Lee notes the cool features. A total smorgasbord of wonderfulness. Read Steve's excellent post here: https://devblogs.microsoft.com/powershell/powershell-7-preview-6/.

One particular feature that caught my eye was the improvements in Test-NetConnection. As many of you know, Ping.Exe, which has been around pretty much since the dawn of IP  (as in TCP/IP). uses ICMP echo request/reply. Due to ICMP attacks, many organisations turn off ICMP - thus using Ping would show no system, even though port 80 is open and working just fine. Test-NetConnection allows you to both ping (eg using ICMP) as well as test the connection to a specific port This is a huge improvement, although the command is very slow due to it being based on WMI.

In P.6 this has been re-implemented using not WMI but .NET. And the results are pretty awesome! Here is what it looked like in PowerShell 5.1:


But take a look at the performance of PowerShell 7 P6:


That is a pretty significant improvement! And by way of comparison, using Ping.Exe would have taken over 3 seconds!

This is another example of how PowerShell 7 is set to become a worthy successor to Windows PowerShell 5.1. 

Monday, November 11, 2019

Displaying Errors in PowerShell 7 - It Gets Better

In a recent blog post, I described the new approach taken in PowerShell 7 to displaying errors. In that post, I concentrated on the new look and feel of error messages as well as the use of $ErrorView built-in variable. One thing I missed in that post was the new look for run time errors.

To demonstrate the new method of displaying run time errors, consider this script:


Ok - nothing overly exciting but that's not the point. The script should generate two errors.

In Windows PowerShell (OR if you are running PowerShell 7 with $ErrorView set to "NormalView"), running this script looks like this:


That old familiar Wall of Red Ink! Hard to see the wood for the trees. But you can see the information if you read.

Now - PowerShell 7,. if you are set $ErrorView to "ConciseView" and rerun the script you still get the terrors (or course!), but PowerShell displays them like this:


I hope you'd agree this is a great improvement in displaying runtime errors. And you can always use the new Get-Error command to get all the nitty-gritty if you need it.

As I said in that prior post, I have always loved how PowerShell displays error messaged. I have enough practice to read through that first Wall of Red Ink to see the errors quickly and easily. PowerShell 7 just makes significantly easier. 

Sunday, November 10, 2019

Viewing Errors in PowerShell 7 - Improving on Greatness

As a very long time PowerShell fan, I've always been impressed with the way PowerShell displays errors that occur in scripts or at the command line. PowerShell users are well-acquainted with the "Wall of Red Ink, as I call it:


But once you get over the visual shock and start to actually READ the error message, you begin to appreciate how good these error message actually are. They tell you what the error is and where it happened. I have long evangelised how good these messages are, once you learn to read them. B

But that is not to say things can't be improved. And indeed, in PowerShell 7, you'll find some nice improvements. NB: This blog post is being written using the latest build of the day. By the time PowerShell 7 ships, things may look the same - or different. As an aside, the daily build of PowerShell 7 in incredibly stable - hats off to the engineering team for managing that!

So in PowerShell 7, we have a new built-in variable and a new way of displaying errors. The Variable is $ErrorView which holds an object of the type: System.Management.Automation.ErrorView. This variable can hold one of three values: NormalView, CategoryView, ConciseView. With PowerShell 7, any time an error message is to be displayed, you see different views based on the value of $ErrorView.

A value of  'NormalView' results in the traditional display. But the new default setting, ConciseView, results in just the error message itself, like this:


For day to day use, ConciseView is awesome. BUT, I hear you say, where's all that detail gone. Do you HAVE to use the $Error error record collection?  NO - there's now a cmdlet for that: Get-Error.


With Get-Error you get ALL the error information inside each error record all expanded out nicely. ALL the information without having to expand error records to get to the exception details, etc.

This new feature allows you to limit the Wall of Red Ink to a Line Of Red Ink, and get the error information when you need more details.

What a great new feature!


Tuesday, October 29, 2019

PowerShell 7 Preview 5 Ships

The PowerShell team has shipped another Preview release of PowerShell 7, dubbed Preview 5 (aka P5). P5 both brings great new features and takes us a big step closer to the release of PowerShell 7. Steve Lee posted details of what is in PowerShell V5 in a blog article.

For me there are a couple of notable additions:

The new Pipeline Chain Operators allow conditional execution of commands depending on whether the previous command succeeded for failed:
##  The code:
"Hello" && "There"
# # Produces
Hello
There
## The code
"Hello" || "There"
## Produces
Hello
I suspect we'll see a lot of code starting to use this. But: be careful I suspect a lot of 3AM confusions unless usage is well documented in your scripts.

An interesting feature is the New PowerShell Version notification. When you run PowerShell (P5 or later), during startup PowerShell detects that a newer version is available for download. 


Another cool feature added is adding emphasis to the output of Select-String. Select-String enables you to parse strings using regular expressions. With P5, the matches of the regular expression is highlighted like this:


My favourite new feature is the new condenses error view combined with the Get-Error cmdlet that expands the error report (it is a lot easier than $Error[0] | FL * -Force). Here is an example of what you are going to see:


Why does this matter?
That is one of my favourite questions - after all, it;'s a preview so why should you care? Well for a start, PowerShell 7 is shaping up to be aa huge improvement on the PowerShell experience with Windows PowerShell 5.1. I use it today in my day to day operations and find all the myriad of improvements large and small (I LOVE the CD - feature). If you are using Windows PowerShell today, you should download the Preview (or, if you are brave, the daily build) and start to experiment. 

One significant ad as yet not fully addressed issue with PowerShell 7 is around Cmdlet Coverage. There is no use in a fantastic shell if the cmdlets you use do not work, The change from using the full .NET framework to using .NET Core means that many cmdlets just do not work (and many never will).

The Windows Compatibility module provides partial relief. For example, you can easily use it to load the Server Manager module to allow you to manage Windows Features (i.e. on a Windows Server system). But some modules are not supported this way. For example, the WSUS module is not usable with Windows Compatibility. It's easy to say that the WSUS cmdlet design was poor (it relies on method calls vs using actual cmdlets) - but you are not going to be able to manage WSUS with PowerShell 7 for some time. But this IS a work in progress and I am certain the PowerShell team are taking the feedback on board to enable a better solution to backwards compatibility (although in some cases, the real solution is for the cmdlet designers to re-implement their cmdlets using .NET Core).


Wednesday, October 02, 2019

PowerShell 7's Ternary Operator

The PowerShell 7 team have just released a new PowerShell 7 Preview build. This contains a new, and interesting, new operator, the ternary operator.

This operator is, in effect, a short cut to If/Else. Thus, instead of:

$Message = If ($IsWindows) {"Is Windows"} Else {"Is NOT Windows"}
The Ternary operator allows you to simplify


$Message = $IsWIndows ? "Is Windows" : "Is NOT Windows" 

So a cool new feature coming to PowerShell 7. It is available in the latest Preview but as an Experimental feature. Experimental features in PowerShell 7 are features you turn ON and OFF as you like. By default, experimental features are turned off until you turn them on. To view them and turn them on is simple - just use Get-ExperimentalFeature and Set-ExperimentalFeature like this. 


A relevant question is whether you SHOULD use this operator. For simple things, such as the snippets above, it does enable a more compact script. at the expense of potential confusion by folks not versed in the new syntax. It may not pass the "Three AM test" (ie can you easily and simply work out a bug in this code when woken up at 3 in the morning?). 

Additionally, in my testing, this operator is sometimes a little faster than the old fashioned approach, but there is not a lot in it:

So a new operator, which you have to enable explicitly. It does offer some small performance gains in some cases. Coming soon to a Powershell 7 near you!

Friday, September 20, 2019

Cascadia Code - A New Font On The Block

Microsoft has released a new font, called Cascadia Code. See Thomas Maurer's article for the details.

But so what? Well - this is a font to use in PowerShell or VS Code. Or any Development Environment. It just makes the code easier to read. Here's a look at the font itself:


And here's what it looks like in PowerShell 7's console:


I like it!

To get the font, get it at the Github Repo:https://github.com/microsoft/cascadia-code/blob/master/CascadiaCode-Regular-VTT.ttf

Enjoy

Monday, August 26, 2019

ForEach-Object -Parallel - Comes to PowerShell 7 in P.3

The latest preview edition of PowerShell 7 (itself due for full release at end of Sept or thereabouts) contains a long-awaited feature - the ability to run invocations of a given script block in parallel natively.

An example: Suppose you had a script that used WMI remotely to gather/update information on a number of remote servers. Instead of doing the required operations on one server at a time, running each invocation of the script block in parallel. The ability to run script blocks in parallel has been a huge reason many folks use Workflows (which are not part of PowerShell 7). Foreach -Parallel does away with the need to use workflows just to get parallelism.

Consider the following snippet:

'Non-parallel' $Sb1 = { 1..100 | foreach-object { start-sleep -Milliseconds 100 }} Measure-command { ICM -ScriptBlock $Sb1 } $len = 0

In this sample, you run a script block 100 times. Admittedly the actual script block is not all that exciting but it's an operation that is being done in each iteration of ForEach-Object. The output shows this:

With the third preview of PowerShell 7, the ForEach-Object cmdlet has two new parameters. The first -Parallel which says to run things in parallel. The second, -Throttlelimit tells PowerShell how many separate parallel invocations are allowed. 

Let's rerun that script block but using parallelism and varying the throttle limit:



As you can see, without parallelism, this "script" takes 11.07 seconds. With parallelism, the script takes 4.93 seconds (using throttle limit of 4), 3.70 seconds (throttle limit of 8) and just 2.92 seconds (throttle limit of 12). My system is a dual-processor 6-core system by way of comparison. If you try this, you may get different results depending on your hardware.



Sunday, August 18, 2019

Many Things Go Well with PowerShell 7 - But Not All!

Introduction 

I am currently working on a PowerShell 7 book for those nice people at Wiley (https://blackwells.co.uk/bookshop/product/PowerShell-7-and-NET-Core-3-0-for-IT-Pros-by-Thomas-Lee-author/9781119644729). I'm meant to finish up by December and have the book out in 2020. For me, one of the key questions around PowerShell 7, in the Window space at least, is how well PowerShell 7 can be used to manage an enterprise. If it can, then IT Pros can move towards it with increasing confidence.

PowerShell 7, at the time this is written is at Preview-3 stage with an expectation of shipping sometime in September. If you find I am wrong on any of the points below please let me know. This is a work in progress as we approach PowerShell 7 RTW.

What Works and What Doesn't

In working on the book, I have found that commands, modules, and .NET classes fall into 3 distinct bands:
  • Stuff that works. 
  • Stuff that can work using WindowsCompatibility module
  • Stuff that does not work and probably won't work 

Stuff that works is, well, stuff that works. Most of the basic day to day commands/modules work fine. Which I think is to be expected. A big win here is that the ActiveDirectory module works great (although sadly, the AD Deployment module does not work natively).

The Windows Compatibility module (WCM) is a solution to some compatibility issues. WCM uses a combination of implicit remoting and PowerShell remoting sessions. For each module you want to use - you use Import-WinModule to load the commands in the current PowerShell session. WCM, under the cover, creates a remoting session into PowerShell 5.x on the local machine and imports the underlying module using implicit remoting. Thus you can import the ADDeployment module using this technique and access the commands natively.

Stuff that doesn't work and never well should be a small subset of overall PowerShell functionality. An example is workflows - these depend on Windows Workflow Foundation and thus far at least, there is no interest in porting the necessary .NET classes to .NET Core.

While I never say never, I think if you want to use anything that doesn't work today - you either stick with PowerShell 5.x for the foreseeable future or evaluation alternatives.

Stuff that Doesn't Work and May Never Work

Here is my list of PowerShell 5.x features that are (probably) not ever going to work in PowerShell 7:
  • Workflows - Workflows in PowerShell depends on the Windows Workflow Foundation and that is not in .NET Core. As far as can be told at the time of writing, this is not going to happen. See the release notes at https://docs.microsoft.com/en-us/powershell/scripting/whats-new/breaking-changes-ps6?view=powershell-6.
  • PowerShell Snap-ins - Snap-ins was an earlier approach to add-ins, but were replaced by Modules in Windows PowerShell 2.  Some Microsoft modules were affected but these are being updated. In many cases, you can convert the Snap-in into a module - but many modules delivered by third parties may not be so easy to modify. If you are still using an old snap-in, consider migrating it to a module. 
  • Desired State Configuration - this too is not going forward. At least not yet. Having said that, there might be some updates on this shortly. We'll see.
  • Windows Update - the issue here is that much functionality of WSUS is delivered via methods, not via cmdlets. The WSUS object methods do not work via Windows Compatibility. It turns out that the module also makes use of SOAP which causes more issues with future support. This is unlikely to be supported in PowerShell 7.
  • Best Practices Module - I would have expected this module to have been fully supported.

Things That Work Using the Windows Compatibility Module

There are a number of Windows PowerShell cmdlets and modules which are not supported natively in PowerShell 7 but can be used by way of the WindowsCompatibility module. You load these modules using the Import-WinModule command.

The modules I've found that do not work natively in PowerShell 7 but do work with Windows Compatibility Module include:

  • ADDSDeployment module 
  • AppLocker module
  • BITSTransfer module
  • ConfigCI module
  • DFSR module
  • DHCP Server module 
  • GroupPolicy module
  • IscsiTarget module
  • MsDtc  module
  • NetworkController module
  • NetworkControllerDiagnostics module
  • NetworkLoadBalancingClusters module
  • ServerManager module
  • Storage Replica module
  • The *-Computer commands in Microsoft.PowerShell.Management specifically Add‑Computer, Checkpoint-Computer, Remove‑Computer, and Restore-Computer commands.
  • The *-Counter commands - these are used to obtain Windows performance counters.
  • The WMI cmdlets. I was kind of surprised at this - but still, the CIM cmdlets are just a better way to leverage WMI.
NB: this is a work in progress. I'll update it as I find out more:
1. (20/8) Removed Print Management from a list of modules that do not work - all seems fine with Preview.2 and beyond
2. (21/8) Updated modules that need remediation. 
3. (21/08) Retested and updated based on Preview 3.
4. (2/09) Added issue with Windows Update, added BITS module to remediated list.









Monday, July 22, 2019

Windows Forms - working in PowerShell 7 Preview2

One long-anticipated feature of what is soon to be PowerShell 7 is the use of Windows Forms. Technically, it is the .NET Framework that provides for form handling, but with the latest Preview.2 of PowerShell 7, this is now possible!

Here is a Windows Forms-based script that now works just fine in Powershell 7 Preview 2.

First, here is the code:

# Get-Shares Windows Forms Script
#

# Load System.Windows.Forms
Add-Type -Assembly System.Windows.Forms

# Get PowerShell version details
$Maj = $PSVersionTable.PSVersion.Major
$Min = $PSVersionTable.PSVersion.Minor
$Ver = "$Maj.$Min"

# Create form
$Form = New-Object Windows.Forms.Form 
$Form.Width = 750
$Form.Height = 650
$Form.Text = "My First Windows Forms Application - PowerShell Version $ver"

# Create a "computer name" label control and add it to the form
# Set label location, text, size, etc
$Label1 = New-Object Windows.Forms.Label
$Label1.Location = New-Object Drawing.Point 50, 50
$Label1.Text     = "Computer Name:"
$Label1.Visible  = $true
$Form.Controls.Add($Label1)

# Create a text box to get computer name and add to form
$Text1 = new-object windows.forms.textbox
$Text1.Location = New-Object system.drawing.point 150, 50
$Text1.Text     = "Localhost"
$Text1.Visible  = $true
$Form.Controls.add($text1)

# Create a label to output stuff
$Label2 = New-Object Windows.Forms.Label
$Label2.Location = New-Object Drawing.Point 50, 100
$Label2.Width    = 750
$Label2.Height   = 360
$Label2.Text     = ""
$Label2.Visible  = $true
$Form.Controls.Add($Label2)

# Create a button to get the shares
$Button1          = New-Object Windows.Forms.Button
$Button1.text     = "Push To Get Shares"
$Button1.width    = 150
$Button1.location = new-object drawing.point 350, 50

# Define Getting Shares Button Click handler
$Button1_OnClick = {
  $Label1.Text = "Getting Shares"
  $Shares = Get-CimInstance WIn32_Share -ComputerName $Text1.Text
  $Label2.Font = [System.Drawing.Font]::new('Courier New', 10)

  $Label2.Text = "Shares on $($Text1.Text):`n"
  Foreach ($Share in $Shares) {
    $Name = $Share.Name
    If ($Name.Length -gt 17) {
      $name = $($Name.substring(0,17)+'...').padright(16)
      }

    $Path = $share.Path
    $Label2.Text += "{0,-20}  {1}`n" -f $Name, $Path
  }
  $Label1.Text = "Computer Name:"
}
    
# Add the script block handler
$Button1.Add_Click($Button1_Onclick)    
$Form.Controls.Add($button1)

# Now create a button to close window
$Button2          = New-Object Windows.Forms.Button
$Button2.Text     = "Push To Close Form"
$Button2.Width    = 150
$Button2.Location = New-Object drawing.point 160, 550

# Define Button Click handler
$Button2_OnClick = {
  $Form.Close() 
}

# Add the script block handler
$Button2.Add_Click($Button2_Onclick)    
$Form.Controls.add($Button2)

# finally, show the form as dialog box.
$Form.ShowDialog()


And here you can see the results. First against first a work station:


And here a DC



Success. A working Windows.Forms script that runs great on Windows PowerShell now runs fine in PowerShell 7 Preview.2 (and beyond into infinity....)



Monday, July 01, 2019

Windows Terminal Is Here (in Preview) and it Rocks!

In Windows, PowerShell and CMD.Exe both run inside a console. That console is where programs interact with a command line application. The console inside Windows has not had a lot of love, although has improved of late. But that has just changed big time with the release of the Windows Terminal. If you are running Windows 10 - just go the Windows Store and get it - it's free.

The installation does a great job of detecting the console applications including CMD.EXE, PowerShell.Exe, PWSH.EXE, and the versions of WSL you are running, By default, the terminal installer does not find PowerShell 7.

Configuration of the WIndows terminal is, today, done via hand editing the Profiles.JSON file. On My workstation, this file is: C:\Users\tfl\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\RoamingState\profiles.json - You may need to adjust it based on your userid.

To enable PowerShell 7,. I just added a new section at the top of the profiles section inside the profiles.json file. I added the following:

 {
   "acrylicOpacity": 0.75,
   "closeOnExit": true,
   "colorScheme": "Solarized Light",
   "commandline": "C:\\Program Files\\PowerShell\\7-preview\\pwsh.exe",
   "cursorColor": "#FFFFFF",
   "cursorShape": "bar",
   "fontFace": "Consolas",
   "fontSize": 12,
   "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff4442}",
   "historySize": 9001,
   "icon": "ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png",
   "name": "Windows PowerShell 7.0.0 Core Preview",
   "padding": "5, 5, 5, 5",
   "snapOnInput": true,
   "startingDirectory": "%USERPROFILE%",
  "useAcrylic": false
  },

If you wish to add PowerShell 7, as I do, you need to do is to ensure the guid value inside this profile block is unique. You can just munge an existing GUID, as I did, or use New-Guid cmdllet create one know to be unique.

Since I plan to use Pwsh 7 mainly, I also wanted the default shell to default to using PowerShell 7. That also involves updating the Profiles.JSON file. At the top of the file, in the Globals section, change the value of the defaultProfile to the GUID of Pwsh 7. Mine looks like this


{
 "globals" : 
  {
   "alwaysShowTabs" : true,
   "defaultProfile" : "{61c54bbd-c2c6-5271-96e7-009a87ff4442}",
   "initialCols" : 120,
   "initialRows" : 30,
 ... etc


Once I have set these values in the Profile.JSON file, my terminal looks like this:


And away we go. There is far more you can do with the JSON file and I sure hope that by release later this year, there is a GUI to help configure the settings. I don't mind in the least having to deal with the JSON file and can live with this for now. 

Tuesday, June 04, 2019

First Steps with With PowerShell 7

In my last blog post, PowerShell 7 Is Here - Getting Started, I showed how you can install PWSH 7 and associated tools. I have had some good feedback on that post so it all seems to work (today!).

Having run the Install-PWSH7 script, which you can find at: https://community.spiceworks.com/scripts/show/4638-install-powershell7, you should now have PowerShell 7 Preview 1 on your system.

The first thing to notice is that the executable is now pwsh.exe. Also, the home directory, aka $PSHOME is now: C:\Program Files\PowerShell\7-preview. What this provides is a mechanism to run multiple versions of PowerShell side by side. On my system, I have PowerShell 5.1, 6.2 and 7.0. If you use the MSI to install PowerShell 7, the installer updates your environment path so you can easily find PWSH.EXE.

The next thing to notice is that there are a lot fewer modules immediately available. Since PowerShell 7 is installed in a different folder, modules you may have with PowerShell 5.1 are not visible. One thing I had to do was copy over my personal modules.

The next thing I found is that some modules do not load naturally. So for example, you can not just use Import-Module to import the ServerManager module. The solution to this is to use the Windowscompatibility module you can find on the PowerShell Gallery. Amongst other things, this module uses implicit remoting to access Windows PowerShell cmdlets from PowerShell7, for those modules that are not compatible directly. 

An example of using this is the Get-EventLog cmdlet. By default, running this cmdlet results in errors. But by using the Import-WinModule Microsoft.PowerShell. Management command you can access the windows event log, like this:


For more information on this module, see https://github.com/powershell/windowscompatibility.

So far, the following modules need to be loaded using Import-WinModule:
  • ServerManager
  • ADDSDeployment (and even then some cmdlets do not work properly).
  • DHCPServer
And finally, there are some things that are either not going to be supported or, arguably, are broken. So far, Windows.Forms, DSC and Workflows are not supported. Support for forms should come in later releases, prior to RTM.

With respect to Active Directory, I've worked out how to promote a server to be the first DC in a new forest but so far, I can not add a second DC to that initial domain. Still playing with that.

Another thing I found that is, arguably broken, is that the System.IO.DirectoryInfo object, returned from Get-ChildItem/GetItem cmdlets has changed the way it returns the parent directory. In PowerShell 5.1, the Parent property is just a relative path,, whereas in later versions this property returns the full path.  This will break some scripts.