Tuesday, June 01, 2021

Resolving Hyper-V issues with WIn10 Insiders builds

 I have been a member of the Windows Insiders group since 2014, and have enjoyed testing out the updates and looking at some of the new features coming to a new Win10 release in due course. A very few Insiders builds were bad - and just did not work. But that was rare and for the most part, the new builds work well.

I recently encountered an issue whereby after the upgrade, no Hyper-V VM would start. The error log shows an error message about MCompute faults - which looks like this in the event log.

Faulting application name: vmcompute.exe, version: 10.0.21354.1, time stamp: 0x1aa49b37

Faulting module name: vmcompute.exe, version: 10.0.21354.1, time stamp: 0x1aa49b37

Exception code: 0xc0000005

Fault offset: 0x00000000001c065a

Faulting process ID: 0x23a8

Faulting application start time: 0x01d72d3e4d15903d

Faulting application path: C:\WINDOWS\system32\vmcompute.exe

Faulting module path: C:\WINDOWS\system32\vmcompute.exe

Report ID: f8375064-c2fc-4a89-a8f1-af662c551008

Faulting package full name: 

Faulting package-relative application ID:

I reported this error multiple times, but to no avail. Every week, Windows Update would offer a new build that would fail to restart Hyper-V.. I'd revert to a working build, report the issue - then wait a week and repeat. Despite multiple reports, I never got any response from MSFT. 

I decided to take a near-nuclear option - which worked! In hopes that someone else who encounters this issue and, using their search engine, finds this post - here is my solution:

  1. Start, then shut down all VMs.
  2. Took an inventory of the VMs.
  3. Remove all the un-needed VM snapshots - there were too many and all are now gone! 
  4. Export all the VMs to a backup drive (removing the snapshots helped reduce the time).
  5. Remove the Windows 10 Hyper-V feature - all of it.
  6. Reboot.
  7. Accept the latest Insiders update and let it install.
  8. Once the upgrade is complete, add the Hyper-V feature back in.
  9. Reboot.
  10. Open up the Hyper-V console and install the necessary VM switches (two in my case).
  11. Import the VMs specifying the location on the VM location on the host's disk of the VM (and not the backup!).
  12. For some VMs< i need to specify where the virtual hard disks were stored (I use a non-standard location).
  13. Start the VMs and enjoy.
Here is what I see now!

Once you are up and running, make sure to remove the backups.

From start to finish, it took me a couple of days elapsed time (the backup to an external USB2 drive was slow!). 

In step 2, I took inventory (including identifying the snapshots and working out how much data had to be backed up. One useful step wasn running this query and saving the output. 
PS C:\Foo> Get-VM | Format-Table -Property Name, Path

Name           Path
----           ----
***Cookham1    D:\VMs\Cookham1
CH1            D:\V8\CH1
DC1            d:\v8\DC1
DC2            d:\v8\DC2
HV1            D:\V8\HV1
HV2            d:\v8\HV2
Hyper-V Server D:\V7\HyperVServer\Hyper-V Server
Old - Bridge   D:\V7\Bridge
PSRV           D:\V8\PSRV
SMTP-2019      D:\V8\SMTP-2019\SMTP-2019
SRV1           D:\V8\SRV1
SRV2           D:\V8\SRV2
SS1            D:\V8\SS1

After all the updating, in step 11, I pointed the MMC's import wizard at the path noted above and most of the VMs came in fine. For the "V8" VMs, I had to specify the same path to let the wizard know where each of the disks was stored. 

Hope you never encounter this issue but if you do the is a workaround. 

Monday, January 11, 2021

Packt Publishers Sale on Through Jan 13 2021

In my morning email was a message from the publishers of two (and soon three) books. My books are on PowerShell, but as many of you know, they publish books, ebooks, and videos across the IT Spectrum. In my experience, some of their books are better than others. I'd like to think that some books, including mine, are in the 'good' category - but as ever Caveat Emptor.

Their reason for writing to me is that they currently have a sale on at the moment. This sale, which is on through Jan 13th 2021 offers certain WIndows/Linux books and ebooks for sale. 

I apologise for the short notice, but I only heard about this from a mail I got this morning.

Mastering Windows Server 2019 - https://www.packtpub.com/product/mastering-windows-server-2019-second-edition/9781789804539?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators

Mastering Windows Security and Hardening - https://www.packtpub.com/product/mastering-windows-security-and-hardening/9781839216411?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators

Windows Server 2019 Administration fundamentals, Second Edition - https://www.packtpub.com/product/windows-server-2019-administration-fundamentals-second-edition/9781838550912?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators

Mastering Linux Security and Hardening - https://www.packtpub.com/product/mastering-linux-security-and-hardening-second-edition/9781838981778?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators

Windows Subsystem for Linux 2 (WSL 2) Tips, Tricks, and Techniques -https://www.packtpub.com/product/windows-subsystem-for-linux-2-wsl-2-tips-tricks-and-techniques/9781800562448?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators

And what list of great books on offer would be incomplete without my latest book: 

Windows Server 2019 Automation with PowerShell Cookbook - Third Edition -https://www.packtpub.com/product/windows-server-2019-automation-with-powershell-cookbook-third-edition/9781789808537

Sunday, January 10, 2021

My Wiley PowerShell Book - Issues with the code samples

I recently posted (https://tfl09.blogspot.com/2020/12/my-latest-powershell-book-copies.html) about my latest PowerShell book, published by Wiley. I am proud of this book for many reasons. Most of the writing was done after the start of the Covid pandemic. Frankly, the writing helped keep me sane (well saner). 

Writing a book involves a lot of people. I write stuff  and then a good team of others help to turn this into a finished product. In particular, I was very happy with the excellent editing done by the Wiley team. The development process was laborious and my editors were a pedantic nightmare - but all in the Best Possible Way! I appreciated the almost anal nitpicking done and the total focus on quality. Everyone involved has my gratitude for their excellent work.


Today I received a mail from a wonderful reader in Italy. He complained that cutting and pasting from the e-book failed. He provided me with some examples. Yes, he is right that what he showed me is NOT what I wrote and submitted.

My apologies for this to him, and everyone reading my book. I can assure you that I did everything I could to avoid this very issue. Jim, my TE, was totally focused on helping me to avoid issues like this - every missing capital letter, every missing parameter name, and every other minor error was flagged and resolved. I did what I could, and am sorry for the resulting issues.

With that said, one of the things I insisted on was that I could publish these scripts on GitHub. You do not have to buy my book (although I hope you will) to use the scripts. You canfindt the scripts at GitHub account - https://github.com/doctordns/Wiley20.

So if you want to try out the book and the scripts contained in it, please do NOT cut/paste from an electronic version - use the scripts on Github. If you find errors there, PLEASE file an issue at https://github.com/doctordns/Wiley20/issues. I will do my best to fix anything that might be broken and republish the updated script.  You are welcome to fork this repo and I'll accept PRs that fix errors in the scripts.

Thanks for everyone who either both my book or uses my scripts.

Saturday, December 19, 2020

My Latest PowerShell Book - Copies Available


After a long development process, my latest PowerShell book has been published by Wiley

This book began before the Covid pandemic began and progress as a result of the virus was a lot slower than I would have liked, but thanks to some great people we got it done and this week I got my review copies.

As I announced on my Twitter (@DoctorDNS) feed, I have some copies of this book to give away. I am more than happy sign and send off copies of the physical book. I also want to find some reviewers and can provide them with an electronic copy for review if you contact me offline. 

I love the PowerShell community and nothing would please me more than to give a copy to anyone who asks. But that is not possible. So I am happy to give away some free copies, but to make it a bit more interesting, there is a little catch! :-)

 I will give away five signed copies of the physical book to the first FIVE people who ask and who donate to the Epilepsy Society (https://epilepsysociety.org.uk/). My daughter has severe epilepsy and I support this charity. So to get a copy, confirm a donation and EMAIL me. My email addresses DoctorDNS@Gmail.Com.

Owing to Covid restrictions announced today in the UK, physical copies may be delayed until I can get out to the Post Office. 

Friday, December 11, 2020

How To: Change the File Time for a Windows File

When using PowerShell in Windows, The Get-ChildItem (and other cmdlets) return objects of the type System.IO.FileInfo for files in the NTFS File system. Each of the returned objects contains six date/time objects:
  • CreationTime and CreationTimeUtc - the date/time that the file was created (in local time and UTC)
  • LastAccessTime and LastAccessTimeUtc - the date/time that the file was last accessed
  • LastWriteTime and LastWriteTimeUtc - the date/time that the file was last written
These properties allow you to check a file (or for that matter a folder) for when it was created and when it was last written to and read from. This is very useful to help IT Professionals to discover files that are underused and may be candidates for deletion. To cater for files being accessed in different time zones, the UTC variants provide time-zone proof times for comparison.

One challenge is that you may wish to change these times. There is no cmdlet that can change these times directly. Fortunately, there is a simple bit of PowerShell magic. Assume you have a file for which you wish to change date/times. 

Here is you can do it:

PSH [C:\Foo]: Remove-Item -Path C:\Foo\Foo.xxx -ea 0  
PSH [C:\Foo]: "FOO" | Out-File -Path C:\Foo\Foo.xxx
PSH [C:\Foo]: #    Find file and display
PSH [C:\Foo]: $File = Get-ChildItem -Path c:\foo\Foo.xxx
PSH [C:\Foo]: $File| Format-List -Property name,*time*

Name              : Foo.xxx
CreationTime      : 11/12/2020 10:09:57
LastAccessTime    : 11/12/2020 10:09:57
LastAccessTimeUtc : 11/12/2020 10:09:57
LastWriteTime     : 11/12/2020 10:09:57
LastWriteTimeUtc  : 11/12/2020 10:09:57

PSH [C:\Foo]: #    Get new date
PSH [C:\Foo]: $NewDate = Get-Date -Date '14/08/1950'
PSH [C:\Foo]: #    Change the date
PSH [C:\Foo]: $File.CreationTime      = $NewDate
PSH [C:\Foo]: $File.CreationTimeUTC   = $NewDate
PSH [C:\Foo]: $File.LastAccessTime    = $NewDate
PSH [C:\Foo]: $File.LastACcessTimeUTC = $NewDate
PSH [C:\Foo]: $File.LastWriteTime     = $NewDate
PSH [C:\Foo]: $File.LastWriteTimeUTC  = $NewDate
PSH [C:\Foo]: #    Recheck file to see changed date/time
PSH [C:\Foo]: $File = Get-ChildItem -Path C:\Foo\Foo.xxx
PSH [C:\Foo]: $File| Format-List -Property Name,*Time*

Name              : Foo.xxx
CreationTime      : 14/08/1950 01:00:00
CreationTimeUtc   : 14/08/1950 00:00:00
LastAccessTime    : 14/08/1950 01:00:00
LastAccessTimeUtc : 14/08/1950 00:00:00
LastWriteTime     : 14/08/1950 01:00:00
LastWriteTimeUtc  : 14/08/1950 00:00:00

Thursday, November 26, 2020

Creating a PowerShell Cmdlet Using C# and DotNet.eXE

As part of a book I am writing, I wanted to show how simple it could be to create your own cmdlet in C#. This was to be a part of an advanced look at the things you can do with PowerShell 7 and DotNet Core. 

Most IT professionals know about the .NET objects produced by cmdlets, how to discover details about those objects, and how to reach into the .NET BCLs to do things that cmdlets can't. You can also extend PowerShell using a .NET Language such as C# to create a class. You use Add-Type to import the class into your PowerShell session and use it just like any other .NET class. Creating a cmdlet turned out to be more complex.

The first question any sane person might ask is; WHY? Why would anyone want to write a cmdlet or create a class using C#? The obvious reason, per Jimmy The Swede, is because you can. As an IT professional, knowing how is just another tool on your tool belt. But aside from that, there really are some good reasons. Using C# is easier when you need to perform asynchronous operations or multi-threading, or if you wish to use Language-Integrated Query (LINQ). IN those cases, C# is a lot easier than trying to use PowerShell in those scenarios. Another use case is taking some ASP.NET code, such as a page which creates a list of out of stock items and re-purposing it for administrative use.  Admittedly, there are not a lot of use cases in the wild - but as a PowerShell person, you should know!

If you are a hardcore Windows developer, you probably have Visual Studio and know how to use it. But in this article, I'm going to use a different approach which is to use the .NET SDK and the dotnet.exe command. You can do most of this from the command line, although there seems no simple way to install the SDK. So here goes

1. Install the .Net Core SDK.  

This is almost the hardest part of the job. You need to install the Software Development Kit in order to get the tools you need to create the cmdlet. This involves using the GUI.

Navigate to the Dotnet download page: https://dotnet.microsoft.com/download/

From here, click on the download button. This leads to the downloading page:

The download takes a few seconds/minutes to download. Eventually, you can see in the bottom left corner that the download is complete and you can now click on the open file as you can see here:

Clicking on the open file link runs the installer to install the .NET Core SDK on your computer. Eventually, you see this:

Click on Close and you now have the SDK loaded on your system. From here it's fairly simple - here's the script:

# 2. Create the cmdlet folder
New-Item -Path C:\Foo\Cmdlet -ItemType Directory -Force
Set-Location C:\Foo\Cmdlet

# 3. Creating a class library project
dotnet new classlib --name SendGreetings

# 4. Viewing contents of new folder
Set-Location -Path .\SendGreetings

# 5. Creating global.json
dotnet new globaljson

# 6. Adding PowerShell package
dotnet add package PowerShellStandard.Library

# 7. Create the cmdlet source file
$Cmdlet = @"
using System.Management.Automation;  // Windows PowerShell assembly.
namespace Reskit
  // Declare the class as a cmdlet
  // Specify verb and noun = Send-Greeting
  [Cmdlet(VerbsCommunications.Send, "Greeting")]
  public class SendGreetingCommand : PSCmdlet
    // Declare the parameters for the cmdlet.
    public string Name
      get { return name; }
      set { name = value; }
    private string name;
    // Override the ProcessRecord method to process the
    // supplied name and write a geeting to the user by 
    // calling the WriteObject method.
    protected override void ProcessRecord()
      WriteObject("Hello " + name + " - have a nice day!");
$Cmdlet | Out-File .\SendGreetingCommand.cs

# 8. remove class file 
Remove-Item -Path .\Class1.cs

# 9. Build the cmdlet
dotnet build 

# 10. Importing the DLL holding the cmdlet
$DLLPath = '.\bin\Debug\net5.0\SendGreetings.dll'
Import-Module -Name $DLLPath
at that point, you can use the Send-Greeting command, like this:

Thanks to James O'Neil who got me started on this solution. Thanks also to Thomas Rayner's excellent PowerShell summit talk at  https://www.youtube.com/watch?v=O0lk92W799g&t=4s

Thursday, November 12, 2020

PowerShell 7.1 ships. And it's in the Store

 Yesterday, the PowerShell team announced that they had shipped PowerShell 7,1. This is the next version of the open-source, cross-platform version of PowerShell. This release is not a Long Term Support release, meaning support is limited. PowerShell 7.0 and the future 7,2 are LTS releases. The release was announced on a blog post by Joey Aiello Program Manager, PowerShell.

PowerShell 7.1 is focused on resolving community issues. You can read the release notes here: https://docs.microsoft.com/en-gb/powershell/scripting/whats-new/what-s-new-in-powershell-71?view=powershell-7.1/. While this is not an LTS release, the team have made some great strides forward in terms of the overall platform.

From an engineering point of view, the release of PowerShell moves to .NET 5.0. This major update to the .NET Core framework brings a lot of benefits for developers, including some performance improvements which you can read about at https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/. You may find that in complex scripts, this translates to shorter run times. 

One thing which is noteworthy is that PowerShell is now in the Windows store:

And for the adventurous, a preview of 7.2 is meant to drop soon.

Friday, October 02, 2020

Open Sourcing of PowerShell Documents is Awesome

Ever since the very first version of Windows PowerShell, the built-in help material has been awesome. Each cmdlet carefully documented with good examples to illustrate the most common use cases. Good English writing as well as best-practice PowerShell.

But every now and then there is an error. Some simple, some more complex. Some occasionally have some less than great grammar or miss out a useful example of the cmdlet. In the old, old days, you could file an issue somewhere that no one ever seemed to read. And then wait a year or longer before the next version of Windows PowerShell. It used to drive me nuts. I did rant a bit at the time (sorry Erin).

Then someone decided to Open Source the documentation and move it all to docs.microsoft.com. What a great idea. At first, it was a bit clumsy, as everyone involved slowly moved into the wonders of managing a complex repository at GitHub. The process was, again at first, a tad convoluted and frankly slow. BUT it worked. 

I recall the first time I saw an error. It was in class at Lab Center in Sweden. I was showing the delegates how to read the help text. A cmdlet parameters description said it did not take wild cards, but it did. Sok, in class, I filed an issue, edited the document, and issued a pull request. It was really cool although it took weeks to action.

Today, I saw an issue that arrived in my email in basket. You can read the issue on https://github.com/MicrosoftDocs/PowerShell-Docs/issues/6697. That message hit my email box at 7.23 this morning. I read it just after 10/ A few minutes later, I had edited the document and created a pull request. A 13:30 or thereabouts, I got an email to say that the issue was now closed as the PR had been accepted. 

So 6 hours from the time I got the email till the issue was resolved. It is going to take a few more days for the update to hit the web site, but I can live with that. 

TL;DR to me is that with the open sourcing of PowerShell documentation, errors need not persist. You can fix them easily. Or just report and let the community do the work. 

Monday, May 11, 2020

Draw.IO Integration with VS Code

Over the weekend, I saw a tweet announcing a new extension for VS Code. The extension "Draw.IO Integration "enables you to create good looking diagrams directly inside VS Code. Insane, I thought, then I downloaded it. I think a youthful view is that this is DOPE!

You install the extension directly from inside VS Code, create and open a new *.Drawio document and away you go. If you have used virtually any diagramming tool, the interface is immediately accessible.

Here is a screenshot of it working on my workstation:

As you can see, VS Code, up and running with my main workspace loaded and there in the module is a diagram too. It feels a LOT like Visio without (at least so far) the flakiness of Visio of late. The diagrams are not the nice polished ones you might be able to create using tools like PowerPoint, Visio, etc. But simple and BUILT-In.

When you are finished with the diagram, you can export it in various formats. The diagram above, rendered to PNG, looks like this;

There are many templates and, I'm sure, every possibility of more being added by the community over time.

Wednesday, April 01, 2020

Setting up an SMTP Relay using SendGrid

I have written several books - some of which have made use of SMTP to send mail. I am currently working on a Storage chapter for my next book. This chapter makes use of File Services Resource Manager (FSRM) to manage file storage. One neat feature of FSRM is its ability to send an email when events occur.

For many, the issue of how to test this has been a challenge, especially if you do not have a happy SMTP server you can use. A neat tool I have used is to use IIS and the SMTP email relay service offered by SendGrid. You can read more about the company here: https://sendgrid.com/

Setting up both IIS and the email relay service which SendGrid provides are straightforward to set up. In this blog post, I'll show you how to do this. 

There are 4 simple steps:
1. Setup a SendGrid account Ttheir free service allows you to send 100 emails a day, which should be more than enough for testing.
2. Create a SendGrid API key  The API key is, in essence, your user id and password for the site (so be careful). Make sure you copy/paste the key carefully!
3. Install IIS and configure an email relay using your SendGrid account The GUI is pretty easy to use. There's probably a way using PowerShell, but I've not worked it out yet.
4. Testing your relay And for that, there IS a PowerShell script.

Lets's look at these steps

Setup a SendGrid account

The first step in creating your SMTP relay is to sign up for a (free) account with SendGrid. Like this
1. Navigate to SendGrid.Com (http://Signup.SendGrid.Com) - Use your browser to go to SendGrid's sign up page and fill out your details:

Make sure you create a very strong password. then click ok OK. 

2. This takes you to a page for your personal details Obviously, you should use your real name:

Once you set these details, your account is setup. You should get email from SendGrid asking you to confirm your account. Please do NOT forget to do that.

Create a SendGrid API key

3. Once you have created your SendGrid account, navigate to the Email Integration Guide from SendGrid's Home page:

4. This brings you to the configuration page, where you click to set up your SMTP relay:

5. This takes you to a page where you specify an API Key name and click Generate:

Note that you can use any API Key name from this screen. The API Key name is not used as part of the relay security but is just FYI.

6. After you click on Create Key, SendGrid displays the key and provides some details on how to configure your client:
Please note that in this screenshot, I have obscured MY API key. Since that key is both a user name AND a password for your (or in this case my) account, you need to keep it safe. I recommend at this point cut/past the key form the web browser and save it to a text file. You can not retrieve the plaintext key again so be careful.

Now that you have your account setup and an API key generated, you now need to configure IIS to use this.

Install IIS and configure an Email Relay

The next step is to install IIS and configure the IIS SMTP relay. I assume you are using WIndow Sever 2019. If you need to, you can always download an eval version to use. That gives you 6 months use before you need to activate (or just install and configure a new server). 

7. Install IIS in Windows Server
You use the Add-WindowsFeature command to add IIS to your Windows Server host (e.g. on SRV1.Reskit.Org), like this:

For some reason, this needs a reboot - so go do it!

8. Configure IIS Relay on SRV1
The final step is to set up the SMTP Relay on SRV1. You use the IIS 6 MMC console for this. So start by bringing up the SMTP server tool either from the Start menu (Start/Windows Administrative Tools\Internet Information Server (IIS)  6 Manager or run the application:
C:\Windows\system32\inetsrv\InetMgr6.exe.And select the IIS SMTP Server:

Now bring up the SMTP Virtual Server properties dialog by right-clicking on the SMTP Virtual Server and selecting Properties then click on Access. And select Relay - here you configure which systems can connect. For testing, I set "All except the list below" and leave the list blank, like this:

Click OK.

Next click on the Delivery tab in the SMTP Virtual Server Properties:

From here, click on outbound security and set the user name and password. From this dialog box, select Basic Authentication then enters the user name and password. In this case, the user id is 'apikey' and the password is your API key you set up earlier. Configuring it looks like this:

After clicking OK, click on the Advanced Delivery button to bring up the Advanced Delivery dialog from which you enter the SendGrid server details like this:

And after clicking OK, your relay should be all set up and ready to go. You must need to test it.

Testing your relay

Once you have the relay working on SRV1, you can test it using this little script:

# Test-SendGrid.ps1 - script to test send grid

# Setup key variables
$To         = 'tfl@psp.co.uk'
$Fr         = 'SRV1@reskit.org'
$Subj       = 'Test Email via SendGrid'
$body       = "testing`ntesting`nTESTING"
$SmtpSrv    = 'SRV1.Reskit.Org'

# And send the email
Send-Mailmessage -To $To -From $Fr -Subj $Subj -Body $body -SmtpServer $SmtpSrv

After sending the mail, you can check in your email client to ensure the mail is sent. If you don't get it, as ever, check your junk mail folder. If that doesn't work do it over and do so very carefully! My personal experience is that API keys can be a challenge. You may need to generate another key.

After sending the mail, you should check in your email client to ensure the mail has been sent and you have received it (it may be in your Junk folder). If you do not get the mail, you need to do some SMTP relay troubleshooting. 


SendGrid provides a simple SMTP EMail Relay Service which you can use to test SMTP enabled applications or services like FSRM.

Thanks to those nice people at Sendgrid for a most useful service!

Thursday, March 12, 2020

PowerShell 7, VS Code, and the PowerShell 7 ISE Extension

Introduction and Background

Welcome to this post, a part of this #PS7NOW blog series - I hope you are enjoying them.  Before getting to my topic, I assume that you know what PowerShell 7 is and are familiar with Windows PowerShell. 

The Windows PowerShell ISE, a tool I used extensively ever since early beta versions in Windows PowerShell V2, does NOT feature in PowerShell 7.  You might say, it's pining for the fjords (although it's still shipped in Windows and is likely to be supported for years and years). But however you describe it - it's feature complete and is not going to support PowerSell 7.  Replacing the ISE is a new product: Visual Studio Code, or VS Code.

VS Code is light-weight, cross-platform (ie Linux, Mac, Windows), and open-source code editing tool. Which sounds like no big deal, but if you are an ISE user and are utilising Windows PowerShell, VS Code is in your future. For more details on VS Code, see https://code.visualstudio.com/docs.

VS Code

I must confess, the early versions of VS Code I used were under-whelming, and I much preferred the ISE. And given that PowerShell Core was also in the early days, sticking with the ISE and Windows PowerShell for day to day activities made sense.

But for me, the release of PowerShell 7 and the incredible velocity behind the both PowerShell 7 and VS Code product have changed my view. I now use VS Code for my day to day work. I still use the ISE, but only to install  PowerShell 7 and VS Code.

Some features I like in VS Code include:-
  • Workspaces - this is a set of related folders/files which makes it easy to keep things together even when they are spread out in filestore.
  • Side by Side edit windows - makes comparing files, and leveraging code from one into another so much simpler. 
  • Built-in spell check - yes it's an extension, but typos in comments are less likely. 
  • The extensibility and customizability - you really can have it your way.
  • PS Script analyzer is built in - so I get hints about poor code as I type.
And, and, and...

For more details on VS Code, see: https://code.visualstudio.com/docs.

VS Code Extensions

VS Code was built to be extended. An extension adds functionality, such as spell-checking or markdown checking. I originally authored this blog post using Markdown, with the Markdown All In One Extension. If I am to author in Markdown, VS Code is my go-to tool. 

I am working on a book and use Github Gists. To assist in managing my Gists, I also use the GistPad Extension.  It makes handling Gists so much easier. The integration between VS Code and GitHub, via the extension, is really useful.

To customise the colour scheme of VS Code - you can find many extensions providing additional themes. And as a hint, some of these themes are better than others! For details on the available extensions (and there are a lot) see https://marketplace.visualstudio.com/VSCode.

And of course, a great extension anyone using ISE is going to want to get is the PowerShell ISE extension that makes VS code feel more like the ISE, at least colour wise.

Installing VS Code

To install VS Code, well - there's a PowerShell script for that too. Naturally! It is called Install-VSCode and you download it from the PS Gallery. That script when you run it, downloads and installs the latest version of VS Code and provides you with flexibility over exactly what to install.

You can find any number of cute 1-liners, but here's a more workman-like, step by step, and hopefully clearer installation snippet: 

# Get and save Install-VSCode installation script
#    Assumes C:\Foo exists
Set-Location -Path C:\Foo
Save-Script -Name Install-VSCode -Path C:\Foo

# Create a list of extensions to add when installing
$Extensions =  'Streetsidesoftware.code-spell-checker',

# Now install VS Code
$InstallHT = @{
  BuildEdition         = 'Stable-System'
  AdditionalExtensions = $Extensions
  LaunchWhenDone       = $true
}.\Install-VSCode.ps1 @InstallHT

The install script is able to load different versions (Stable-System, Stable-User, Insider-System, Insider-User). Different builds provide more recent features but maybe less well tested and less reliable. I use Stable-System and have not had any issues whatsoever (aside from being able to get PSReadline to behave - but that is a rant for another day)

When you run this snippet, for example in the Windows PowerShell or the ISE, you may see some warning messages when VS Code adds the extensions. You can ignore these errors. FWIW It seems these warning messages have gone away with the latest builds of VS Code so you may not see these today.

This snippet takes around 30-40 seconds and rewards you, in the end, with VS Code open and ready for use.

You may have noticed reading that snippet that it did not explicitly mention the PowerShell extensions. The good news is that the script installs this extension by default.
It sure seems like a good idea to me! However, the ISE theme is not used by default - but there are scripts to fix that too.

Here are a two screenshots of VS code (with the ISE Theme) and the Windows PowerShell ISE.

For more details on setting up VS Code, see: https://code.visualstudio.com/docs/setup/setup-overview

Managing VS Code Extensions

You can manage and configure VS Code extensions inside VS Code or externally. In early versions of VS Code, you had to hand configure a JSON file to change settings, but today, there's a gui for that. And once you install VS Code, you can manage extensions (from PowerShell) like this:

#    Sets the root path for extensions
code --extensions-dir

#    Lists the installed extensions.
code --list-extensions

#    Uninstalls an extension.
code --uninstall-extension ( | )

VS Code PowerShell Extension

As I mentioned earlier, one extension most ISE users are going to want to get is the Powershell ISE extension. The PowerShell extension adds great language support and great features including: 
  • PowerShell Syntax highlighting
  • Tab completion
  • Code snippets
  • IntelliSense for cmdlets, parameters, and more
  • The rule-based analysis provided by PowerShell Script Analyzer
  • Definition tracking and a "Go to definition" for cmdlets and variables
  • Find references of commands and variables
  • Document and Workspace symbol discovery
  • Run the selected section of PowerShell code using F8
  • Launch online help for the symbol under the cursor using Ctrl + F1
  • Local script debugging and basic interactive console support
  • A colour scheme that looks familiar.
In my experience, VS Code is just different enough from the ISE to make those first few hours a tad painful.  But quickly, very quickly, VS Code begins to make the ISE look quite dated. I love having PS Script Analyzer run as I am entering code - it helps me to write better code And the side by side editing has made my book-writing task a lot simpler. 

For more details on the extension, see https://code.visualstudio.com/docs/languages/powershell.

Configuring the PowerShell Extension

You can update and configure extensions from within VS Code itself. In early versions of VS Code, any configuration had to be done by hand-editing a JSON file. Later versions added a configuration GUI meaning you can do most configuration simply using the GUI.
But you can also directly edit the **settings.json** file to update the configuration.

The VS Code user settings file is contained in the file:

My current settings.json file looks like this:

  "workbench.colorTheme": "PowerShell ISE",
  "window.zoomLevel": 1,
  "editor.fontFamily": "'Cascadia Code',Consolas,'Courier New'",
  "editor.tabCompletion": "on",
  "workbench.editor.highlightModifiedTabs": true,
  "powershell.codeFormatting.useCorrectCasing": true,
  "files.autoSave": "onWindowChange",
  "files.defaultLanguage": "powershell"

A neat feature of VS Code - if you update that file and save it, VS Code uses the newly created configuration automatically.

In the earlier snippet, you installed VS Code.
At the end of the configuration, you could do this to further configure VS Code:

# Download Cascadia Code font from GitHub
$CascadiaFont    = 'Cascadia.ttf'    # font name
$CascadiaRelURL  = 'https://github.com/microsoft/cascadia-code/releases'
$CascadiaRelease = Invoke-WebRequest -Uri $CascadiaRelURL # Get all of them
$CascadiaPath    = "https://github.com" + ($CascadiaRelease.Links.href | 
                      Where-Object { $_ -match "($cascadiaFont)" } | 
                        Select-Object -First 1)
$CascadiaFile   = "C:\Foo\$CascadiaFont"

# Download Cascadia Code font file
Invoke-WebRequest -Uri $CascadiaPath -OutFile $CascadiaFile

# Install Cascadia Code
$FontShellApp = New-Object -Com Shell.Application
$FontShellNamespace = $FontShellApp.Namespace(0x14)
$FontShellNamespace.CopyHere($CascadiaFile, 0x10)

# Install the font using Shell.Application COM object
$Destination = (New-Object -ComObject Shell.Application).Namespace(0x14)

# Create a short cut to VSCode
$SourceFileLocation  = "$env:ProgramFiles\Microsoft VS Code\Code.exe"
$ShortcutLocation    = "C:\foo\vscode.lnk"

# Create a  new wscript.shell object
$WScriptShell        = New-Object -ComObject WScript.Shell
$Shortcut            = $WScriptShell.CreateShortcut($ShortcutLocation)
$Shortcut.TargetPath = $SourceFileLocation

#Save the Shortcut to the TargetPath

# Create a short cut to PowerShell 7
$SourceFileLocation  = "$env:ProgramFiles\PowerShell\7-Preview\pwsh.exe"
$ShortcutLocation    = 'C:\Foo\pwsh.lnk'

# Create a  new wscript.shell object
$WScriptShell        = New-Object -ComObject WScript.Shell
$Shortcut            = $WScriptShell.CreateShortcut($ShortcutLocation)
$Shortcut.TargetPath = $SourceFileLocation

# Save the Shortcut to the TargetPath
$XML = @'
$XML | Out-File -FilePath C:\Foo\Layout.xml

# Import a startlayut.XML file
Import-StartLayout -LayoutPath C:\Foo\Layout.xml -MountPath C:\

# Update Local User Settings for VS Code
#    This step in particular needs to be run in PowerShell 7!
$JSON = @'
  "editor.fontFamily": "'Cascadia Code',Consolas,'Courier New'",
  "editor.tabCompletion": "on",
  "files.autoSave": "onWindowChange",
  "files.defaultLanguage": "powershell",
  "powershell.codeFormatting.useCorrectCasing": true,
  "window.zoomLevel": 1,
  "workbench.editor.highlightModifiedTabs": true,
  "workbench.colorTheme": "PowerShell ISE",
$JHT = ConvertFrom-Json -InputObject $JSON -AsHashtable
$PWSH = "C:\\Program Files\\PowerShell\\7\\pwsh.exe"
$JHT += @{
  "terminal.integrated.shell.windows" = "$PWSH"
$Path = $Env:APPDATA
$CP   = '\Code\User\Settings.json'
$Settings = Join-Path  $Path -ChildPath $CP
$JHT |
  ConvertTo-Json  |
    Out-File -FilePath $Settings

This snippet downloads and installs a new font, Cascadia Code and creates two new shortcuts for your toolbar. The snippet also updates the settings.json file with certain useful settings.


PowerShell 7, has shipped. If you are a Windows PowerShell, and particularly a fan of the ISE, VS Code is a tool to take on board. To assist you, the PowerShell extension makes VS Code easier to adopt. And the extensions available take VS Code to the next level.

TL;DR: PowerShell 7 with VS Code with PowerShell 7 rocks.
The PowerShell Extension to VS Code just rocks more!

What are you waiting for?