Thomas Lee's collection of random interesting items, views on things, mainly IT related, as well as the occasional rant
Saturday, December 19, 2020
My Latest PowerShell Book - Copies Available
Friday, December 11, 2020
How To: Change the File Time for a Windows File
- 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
PSH [C:\Foo]: Remove-Item -Path C:\Foo\Foo.xxx -ea 0PSH [C:\Foo]: "FOO" | Out-File -Path C:\Foo\Foo.xxxPSH [C:\Foo]: # Find file and displayPSH [C:\Foo]: $File = Get-ChildItem -Path c:\foo\Foo.xxxPSH [C:\Foo]: $File| Format-List -Property name,*time*Name : Foo.xxxCreationTime : 11/12/2020 10:09:57LastAccessTime : 11/12/2020 10:09:57LastAccessTimeUtc : 11/12/2020 10:09:57LastWriteTime : 11/12/2020 10:09:57LastWriteTimeUtc : 11/12/2020 10:09:57PSH [C:\Foo]: # Get new datePSH [C:\Foo]: $NewDate = Get-Date -Date '14/08/1950'PSH [C:\Foo]: # Change the datePSH [C:\Foo]: $File.CreationTime = $NewDatePSH [C:\Foo]: $File.CreationTimeUTC = $NewDatePSH [C:\Foo]: $File.LastAccessTime = $NewDatePSH [C:\Foo]: $File.LastACcessTimeUTC = $NewDatePSH [C:\Foo]: $File.LastWriteTime = $NewDatePSH [C:\Foo]: $File.LastWriteTimeUTC = $NewDatePSH [C:\Foo]: # Recheck file to see changed date/timePSH [C:\Foo]: $File = Get-ChildItem -Path C:\Foo\Foo.xxxPSH [C:\Foo]: $File| Format-List -Property Name,*Time*Name : Foo.xxxCreationTime : 14/08/1950 01:00:00CreationTimeUtc : 14/08/1950 00:00:00LastAccessTime : 14/08/1950 01:00:00LastAccessTimeUtc : 14/08/1950 00:00:00LastWriteTime : 14/08/1950 01:00:00LastWriteTimeUtc : 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/
# 2. Create the cmdlet folderNew-Item -Path C:\Foo\Cmdlet -ItemType Directory -ForceSet-Location C:\Foo\Cmdlet# 3. Creating a class library projectdotnet new classlib --name SendGreetings# 4. Viewing contents of new folderSet-Location -Path .\SendGreetingsGet-ChildItem# 5. Creating global.jsondotnet new globaljson# 6. Adding PowerShell packagedotnet 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.[Parameter(Mandatory=true)]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 fileRemove-Item -Path .\Class1.cs# 9. Build the cmdletdotnet build# 10. Importing the DLL holding the cmdlet$DLLPath = '.\bin\Debug\net5.0\SendGreetings.dll'Import-Module -Name $DLLPath
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
Monday, May 11, 2020
Draw.IO Integration with VS Code
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
There are 4 simple steps:
Lets's look at these steps
Make sure you create a very strong password. then click ok OK.
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.
Thursday, March 12, 2020
PowerShell 7, VS Code, and the PowerShell 7 ISE Extension
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.
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',
'yzhang.markdown-all-in-one',
'davidanson.vscode-markdownlint',
'vsls-contrib.gistfs'
# 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
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.
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:
**C:\Users\
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)
$Destination.CopyHere($CascadiaFile,0x10)
# 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
$Shortcut.Save()
# 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
$Shortcut.Save()
$XML = @'
xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
Version="1">
'@
$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.
Summary
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?
Tuesday, March 10, 2020
PowerShell 7 Chain and Ternary Operators
Welcome to this post as part of this PowerShell 7's #PSBlogWeek! I hope you are enjoying the many posts.
As I started to think about this topic, an old Grateful Dead song kept running through my mind "Operator, Can you help m? Help me if you please..." For a live version, listen to https://www.youtube.com/watch?v=TytIqm_d7uE.
So here is some information about a couple of the great new features in PowerShell 7, in particular, the Pipeline Chain Operators and the Ternary Operators.
In the days of Windows PowerShell, extending the PowerShell language was done by the Microsoft Windows PowerShell team. With the move to open source, more developers can, and have, made it possible to do a lot more in PowerShell 7. PowerShell's language was modelled on C# - Jeff Snover has often said that PowerShell is on the glide scope to C#.
With PowerShell 7 comes two new operator sets: The Pipeline Chain Operators and the Ternary operators.
The Pipeline Chain operators (|| and &&) enable you to allow conditional execution of commands depending on whether the previous command succeeded for failed. You use the Ternary operators (? and :) as a short-hand way of implementing if/else type statements. These are popular among C# developers and Bash users and have long been requested within PowerShell.
These operators add new functionality to PowerShell 7. They are nice when used carefully, but can reduce the clarity of production code. Let's look at them in more detail.
PIpeline Chain Operators
The pipeline Chain operators enable conditional execution of commands depending on whether a previous command succeeded or failed. There are two pipeline chain operators: && and ||. These operators were added to PowerShell 7 Preview 5. Prior to PowerShell 7, you could have used If/Else to do the same thing,
These operators come originally from Posix. POSIX shells call this as AND-OR lists. The idea is that depending on whether a command is successful, you can do different things.
What is it used for?
If a pipeline is successful, this operator allows you to run some other pipeline. But if the first pipeline is unsuccessful, you can run a different pipeline.
For example:
# Create an SSH key pair - if successful copy
# the public key to clipboard
ssh-keygen -t rsa -b 2048 && Get-Content -Raw ~\.ssh\id_rsa.pub || clip
If the keys are generated successfully using SSH-KEYGEN (and content returned from Get-Content), then the command copies it to the clipboard. Without these operators you would have used if/else and/or try/catch - the chain operators make things a bit shorter.
Ternary Operators
The ternary operator evaluates a Boolean expression and returns the result of one of the two expressions, depending on whether the Boolean expression evaluates to true or false.
This sounds more complex than it is (see the example below!) These operators were added to PowerShell 7 Preview 4.
What Is It Used For?
You typically use this operator mainly to create a string depending on the value of a boolean variable or expression. For example, you could create a string that displayed whether an AD user account was enabled based on the user's Enabled property or display whether a user is using PowerShell on a Mac. Like this:
# Is User Enabled?
# Create 2 strings
$UEMsg1 = "This user IS enabled in AD"
$UEMsg2 = "This user IS NOT enabled in AD"
# Get Details
$UserEnabled = (Get-ADUser -Identity $UserName).Enabled
# Set Enabled/Disable String
$UserEnabledStr = $UserEnabled ? $UEMsg1 : $UEMsg2
# What does this show for an enabled user:
$UserEnabledStr
This user IS enabled in AD
#
# Anotehr example
$IsMacOS ? 'Yes' : 'No'
You Can but Should You?
I like these new operators but am not likely to use them in code I write. Except maybe to demonstrate them. I really do not, yet, see a great use case, except at the console. As an example of this, look at the chain operator example above. That snippet executes a command, and if successful copies a file to the clipboard.
Personally, I'd have written it more like this:
# Create an SSH key pair - if successful, copy
# the public key to clipboard
try {
ssh-keygen -t rsa -b 2048
}
Catch {
# handle terminating error - left as an exercise for the reader
}
# then
Get-Content -Raw ~\.ssh\id_rsa.pub | clip
If I was running this from the console, I'd just run ssh-keygen. If it ran ok, then I'd type Get-Content and pipe the output to the clipboard. Typing longer lines of code is almost certain to introduce typos, especially given my lousy typing. I find doing things step by step is easiest - both to write and to understand months later when the code needs modification.
These operators have the potential to reduce the clarity of production code. Unless you know these operators, their meaning is not easy to discern. Operators like -Contains, -Eq, and -Match are both named so as to give at least some clue to their use. The '?' character an alias for Where-Object and the ':' used in PSDrive letters leading to overloaded operators. And that can diminish the readability of production code. I am sure mileage varies - and would love to hear comments as well as seeing more great use cases.
Summary
TL;DR: Great new operators that bring requested C# Features to PowerShell - Just use them wisely.