Adam the Automator and Friends

I’ve recently joined Adam Betram on his Adam the Automator site as a contributor. My ATA page has a list of my articles which is automatically updated as I produce new content. This doesn’t mean the end of the Mad Scientist blog; I will be producing more commercial content for ATA – my personal musings, e-books etc. will continue to appear here.

Posted in Uncategorized | Leave a comment

I have published a Kindle book – PowerShell and Windows Event Logs

Front Cover

I’m happy to announce that my second Kindle book is published!

As the title suggests, PowerShell and Windows Event Logs covers accessing and managing Windows Event Logs using PowerShell.

As well as covering the two families of eventlog cmdlets available in Windows I also introduce the underlying .Net classes and how they can be used, along with our old friend WMI. I also talk a little bit about the history of Windows Event Logs (yes there is a screenshot of Windows NT 3.51).

There is information on using XML and XPath to filter for the records you are interested in, as well as an approach to extracting data from event logs – a task that is not so easy as it might first appear.

There are also a number of ‘Task Helpers’ that cover the use of .Net from PowerShell where the cmdlets cannot be used directly to achieve a given results as well as some common XPath patterns you can use to build your own event log queries.

PowerShell and Windows Event Logs is available now from the Amazon kindle book store. You can preview the book or view the book page on Amazon.

Posted in My Books, PowerShell | Leave a comment

PowerShell and OneNote for Windows 10

I have long been a fan of OneNote. I have always wanted a way of using it with PowerShell. My initial work in this area focused on the Windows desktop version, but there is now a REST API available via the Microsoft Graph.

OneNoteUtilitiesGraph is a PowerShell module designed to be used either in scripts or at the command line. Its purpose is to allow both read and write access to your OneNote data. For example:

Get-ONPages "starts with(title,'August')"

Will return a list of pages whose title starts with the word ‘August’.

The module also has the capability to create new NoteBooks, Sections, SectionGroups and Pages.

This module is available at

Future plans:

  • Page templates (script-side)
  • Support for Tags
  • HTML Templates for Pages
  • Merge-to-OneNote
  • Out-ONPage
  • New Graph REST features as they are released
Posted in My Software, PowerShell | Leave a comment

Liverpool Football Club Season Review 2018-19

My history with Liverpool Football Club (LFC) is documented elsewhere on this blog.

This season ended as did the last one, with a Champions league final, but first things first…

The years since my previous report have seen the development of Jurgen Klopp’s vision for LFC and also the departure of some significant players, including Phillipe Coutinho and Raheem Stirling. Finishing 8th in the English Premier League (EPL) for the 2015-16 season was a low point, but there has been gradual improvement, with successive 4th place finishes in 2016-17 and 2017-18. The arrival of Mané and Salah have boosted our attacking threat, and the development of a world class defence around van Dijk, Matip, Robinson and Alexander-Arnold have made us difficult to beat, home or away. The 2018-19 season seemed unlikely to replicate the ‘Heavy Metal’ football of the previous season which saw LFC scoring many goals – Salah being top scorer with an amazing 44 goals in all competitions – but confidence was high that we could achieve something special, something to counter the heartbreak of the Champions League final loss of the previous year.

Liverpool were different this year – not perfect, but almost so. Losing only one EPL game, drawing 7 and winning the remaining 30 for a total of 97 points. The team’s approach seemed more clinical, more determined, calmer. In the end they scored more goals (89) than the previous season, but also conceded fewer too. The team’s style of football was praised as exciting by pundits (some more grudging in their praise than others).

Unfortunately there was another team enjoying (another) great season. Manchester City’s all-stars finished one point ahead of Liverpool, 98 points to 97. The race to the end of the season was the most enthralling for many years, but again Liverpool fell short.

At the same time as the EPL campaign Liverpool were taking part in the 27th season of the UEFA Champions’ League. In honesty Liverpool struggled in Group C, winning three games and losing three and coming second in the group behind Paris Saint-Germain. Once in the knock-out stages though, things were different. Bayern Munich and FC Porto were brushed aside. Barcelona awaited in the Semi-final.

The first leg at the Camp Nou would have been considered a disaster in previous seasons. Liverpool defeated 3-0 including the obligatory magical free-kick from Lionel Messi. Somehow it didn’t feel like the end of the world, not this season, not with this team. The second, home leg was still to come.

The 7th of May 2019 saw one of the most remarkable Liverpool performances I have ever seen, topped only by that night in Istanbul. Braces of goals from Divock Origi and Georginio Wijnaldum, and one of the quickest-thinking corners I have ever seen resulted in Messi, Coutinho, Suarez and associates leaving the competition and Liverpool advancing to the final. They would be joined by Tottenham Hotspur, who managed their own recovery from a losing position the following day.

June the 1st 2019 at the Stadio Metropolitano, Madrid, Spain was the venue for the final, the first to be contested between two English teams for a decade. Confidence was high that Liverpool could win, given that they had defeated Spurs at both meetings during the EPL season. All expectations were exceeded early on, following a penalty awarded only thirty seconds or so into the game, which Salah duly dispatched. From then on the game settled into a strange pattern. Both teams were clearly lacking sharpness, possibly due to the three week break from the end of the EPL, possibly due to the heat and humidity in Spain. Spurs retained the majority of the possession. The first half finished at 1-0 to Liverpool.

The second half saw Spurs increase their intensity – forcing Alisson Becker to make a number of excellent saves, but the final word fell to Liverpool, via the boot of Divock Origi, scorer of the decisive goal against Barcelona. His quick-witted finish, a low driven shot across the keeper in the 87th minute, meant that the contest was effectively over. Liverpool were crowned European Champions for the 6th time, placing them third on the all-time list of winners, and the top English team. Once again an English team, captained by an English player raised the European Cup in Triumph.

This season in statistics:

  • Beat every EPL team at least once except Manchester City
  • Beat French Ligue 1 Champions 2018-19 – Paris Saint-Germain
  • Beat German Bundeslige Champions – Bayern Munich
  • Beat Spanish La Liga Champions 2018-19 – Barcelona
  • Beat Italian Serie A 2nd Placed Team 2018-19 – Napoli
  • Two players shared the EPL Golden Boot – Sadio Mane and Mohamed Salah (22 goals each)
  • EPL Golden Glove – Alisson Becker (21 clean sheets)
  • Premier League Player of the Season – Virgil van Dijk
  • PFA Players’ Player of the Year – Virgil van Dijk

After all the statistics are analysed, all of the emotions have subsided, one thing that Michael Owen said during the TV commentary stuck in my mind – I’ll try to paraphrase it.

Liverpool played brilliant football in the Premier League, gained 97 points and ended up with nothing. Liverpool played poorly today and still came away with the trophy.

Michael Owen, BT Sport

That’s the difference between Liverpool 2017-18 and 2018-19: the ability to take a difficult situation and still come through triumphant.

Here’s to the Red Men:

Fabinho, Virgil van Dijk, Georginio Wijnaldum, Dejan Lovren, James Milner, Naby Keïta, Roberto Firmino, Sadio Mané, Mohamed Salah, Joe Gomez, Alisson Becker, Jordan Henderson, Daniel Sturridge, Alberto Moreno, Adam Lallana, Alex Oxlade-Chamberlain, Simon Mignolet, Xherdan Shaqiri, Andrew Robertson, Divock Origi, Joël Matip, Curtis Jones, Ki-Jana Hoever, Rafael Camacho, Trent Alexander-Arnold, Nathaniel Clyne

and of course

Jürgen Klopp

See you next season.

#YNWA #SixTimes

Posted in Football | Tagged , | Leave a comment

Offline Windows Update Scans using PowerShell

It’s important to keep your Windows systems up to date. Your computer is just as much at risk from other devices on your network as it is from threats on the internet. So even if your computer isn’t accessing the internet, if it shares a network with others that are, it should be kept up to date.

There are a number of offerings that can help with this. Microsoft’s WSUS and SCCM can both act as a source of updates for internet disconnected machines, but what if you don’t have that infrastructure in place? Enter Offline Update Scanner.

Offline Update Scanner is a PowerShell script which leverages the Windows Update Agent COM object, the Microsoft Offline Update scan package CAB file and the Windows Scheduled Tasks COM object (I know about the Scheduled Tasks cmdlets but not all versions of Windows in circulation have these).

The current version of this tool is available on GitHub.

Offline Update Scanner (henceforth OUS) is designed to give you a list of updates that are required on a given machine. It is designed to run locally, or can be triggered via some built-in scheduled task functionality if you need to run it in a PSSession or via Invoke-Command, thus getting around the limitations of remotely managing Windows Updates.

OUS uses two parameter sets, one using -AddTask, the other using -Run.

OUS and Scheduled Tasks

Running OUS with -AddTask creates a Scheduled Task that will run as System on the computer. The task’s job is to run OUS with the -Run parameter to trigger the actual scan. This is useful because you cannot use a lot of the functionality of the Windows Update Agent COM object via any kind of remote command – see Using WUA from a Remote Computer on the Microsoft docs site. Running the script from a Scheduled Task makes it a local action, so the COM object is happy to oblige. Once the task has completed it deletes itself from the Task Scheduler.

Components of a Scheduled Task

In order to register a Scheduled Task we need to set up a number of components:

  • A connection to the Scheduled Task service
  • A Task Definition
  • Registration Information
  • Settings
  • An Action
  • A Trigger
  • A Principal

Connect to the Scheduled Task service

Connecting to the service involves creating a Schedule.Service object and calling its Connect method.

$STService = New-Object -ComObject Schedule.Service

A new Task Definition

Once we have a connection, we can create the other objects that we need. First comes a new Task Definition.

$NewTaskDef = $STService.NewTask(0)

Registration Information

Then from the new Task Definition we create some Registration Information.

$RegInfo = $NewTaskDef.RegistrationInfo
$RegInfo.Description = "Offline Update Scan"
$RegInfo.Author = "Stuart Squibb"

Security Principal

Next we create the security principal under which the scheduled task will run. This is important to ensure that the Schedule Task runs under an account with the correct level of access to do its job.

$Principal = $NewTaskDef.Principal
$Principal.LogonType = [TASK_LOGON_TYPE]::Task_Logon_Service_Account
$Principal.UserId = 'NT AUTHORITY\SYSTEM'
$Principal.Id = 'System'

Here I’ve used an Enum to define the types of logon available to Scheduled Tasks and chosen the value that specifies a Service Account. I want to use the local SYSTEM account, so that’s the UserId I’ve specified.


Next I’m going to define some general settings for the Task.

$Settings = $NewTaskDef.Settings
$Settings.Enabled = $True
$Settings.DisallowStartIfOnBatteries = $False

The DisallowStartIfOnBatteries property caught me out. I do a lot of work on a laptop. I couldn’t work out why the tasks I was creating were not running. By default DisallowStartIfOnBatteries is set to True.

The Enabled property specifies whether the task can run or not.


Next we need to create a Trigger for our task.

$Trigger = $NewTaskDef.Triggers.Create([TASK_TRIGGER_TYPE2]::TASK_TRIGGER_TIME)

Here I’m using an Enum to specify a time-based trigger. Here it is:

public enum TASK_TRIGGER_TYPE2
        TASK_TRIGGER_TIME	= 1,
        TASK_TRIGGER_IDLE	= 6,
        TASK_TRIGGER_BOOT	= 8,

Unrelated to Windows Updates, one of the interesting Trigger types is TASK_TRIGGER_SESSION_STATE_CHANGE. Here’s the Enum for the different types of session change that can be acted on:

        TASK_SESSION_LOCK	= 7,

Scheduled tasks can be triggered by console and RDP connections and disconnections as well as when a session is locked or unlocked.

Anyway, now that we have our Trigger we can define when we want the task to run.

$Trigger.StartBoundary = $StartTime
$Trigger.EndBoundary = $EndTime
$Trigger.ExecutionTimeLimit = "PT5M"
$Trigger.Id = "TimeTriggerId"
$Trigger.Enabled = $True 

The $StartTime and $EndTime variables are defined elsewhere in the script. By default I set the task to start 45 seconds after it is created. I also set an execution time limit of 5 minutes using the string format defined for this purpose. At this point I also set the Enabled property.


Next I create the Action – the actual thing I want the task to do.

$Action = $NewTaskDef.Actions.Create([TASK_ACTION_TYPE]::TASK_ACTION_EXEC)
$Action.Path = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$Action.Arguments = "-ExecutionPolicy ByPass -NoProfile -NonInteractive -File C:\OfflineUpdateScan\OfflineUpdateScan.ps1 -Run -Format $Format -Path $Path"
$Action.WorkingDirectory = "C:\OfflineUpdateScan"

Here I create the Action object and assign the Path, Arguments and WorkingDirectory properties. Notice that I’m using variable substitution to create a dynamic set of arguments based on arguments passed to the script.

Registering the Task

The last step is to register the task with a folder.

$RootFolder = $STService.GetFolder("\")
[Void]$RootFolder.RegisterTaskDefinition($ScriptGuid, $NewTaskDef,[TASK_CREATION]::TASK_CREATE_OR_UPDATE,$Null,$Null,$Null)

The $ScriptGuid variable is used as the name of the Task and is defined elsewhere. I pass in the TaskDefinition object and tell the service to create a new task or update an existing one. The Task is registered. Note the use of [Void] – this is because the RegisterTaskDefinition method usually echoes an XML verison of the Task to the screen.

OUS and the Windows Update Agent

Running OUS with -Run begins a scan of the computer using the Microsoft Offline Update CAB file ( which is available here . Currently it is 560MB in size. You can specify the report file format (CSV, HTML or XML) and the file path using the -Format and -Path parameters. If you are running the script interactively you can also choose Console as a format.

The end result should be a file containing a list of the updates that you need to install on the machine.

Creating an Offline Scan

In order to run a Windows Updates scan we need to create a few objects.

  • An Update Service Manager
  • An Update Service
  • An Update Session
  • An Update Searcher
  • An Update Search Result Collection

Creating an Update Service Manager and Service

To create a Service Manager we create a new Microsoft.Update.ServiceManager object. We then create a new UpdateService object by calling the AddScanPackageService method with the path to the CAB file and a descriptive name.

$UpdateServiceManager = New-Object -ComObject "Microsoft.Update.ServiceManager"
$UpdateService = $UpdateServiceManager.AddScanPackageService("Offline Sync Service", $CabLocation, 1)

Creating an Update Session and Searcher

Next we create a new Microsoft.Update.Session object, then call its CreateUpdateSearcher method to create a new Searcher.

$UpdateSession = New-Object -ComObject "Microsoft.Update.Session"
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()

Joining up the Objects

Before we can search we need to link the Searcher to the Service.

$UpdateSearcher.ServerSelection = [ServerSelection]::SSOthers
$UpdateSearcher.ServiceID = $UpdateService.ServiceID

The [ServerSelection]::SSOthers constant is required for the Searcher to accept the Service when configured for offline scanning.


We actually search by calling the Search method of the Searcher, passing in a query. The query syntax can be found here. The result is a SearchResult object. The list of updates is stored in the Updates property of the SearchResult as an UpdateCollection object. We can use this to export data about the updates to a file.

$SearchResult = $UpdateSearcher.Search("IsInstalled=0")
$Updates = $SearchResult.Updates

Exporting the data

Once we’ve got a collection of updates we need to collect the properties of each update that we wish to export. The script exports the MsrcSeverity, Title, MaxDownloadSize and MinDownloadSize properties, along with a computed field. This joins up the possibly multiple values stored in an update’s KBArticleIds field into a single semicolon (;) delimited string. The computed field is created using:

@{Name="KBs";Expression={$_.KBArticleIds -join ';'}}

Lastly, we use a switch statement to decide what to do with our results.

Re-Purposing the code

Of course there’s nothing to stop you from using this code to do an online scan, simply remove the lines that set up the Offline Service. By default you will be connected to Windows Update online.


Using the Windows Update API

Using the Task Scheduler

Posted in PowerShell | Tagged , | Leave a comment

My Amazon Author Page

Now that ‘PowerShell and Active Directory’ is out and beginning to sell, I have begun to set up my Author Page on Amazon. This will be home to all of my Kindle books.

Posted in My Books | Leave a comment

I have published a Kindle book – PowerShell and Active Directory

I’m happy to announce that my first Kindle book is published!
Front Cover 0f

PowerShell and Active Directory gives the reader help in bringing these two Microsoft technologies together. The subtitle Getting the job done, with or without the Active Directory cmdlets is a hint as to my agenda in creating the book.

Sometimes you just need to get the job done. You might or might not have access to the PowerShell AD cmdlets, depending on the computer, your policies, any number of things. You can use classes built in to .Net to do a lot of the same things the cmdlets do, bearing in mind a set of caveats.

I see a lot of people on the forums or /r/PowerShell asking the same questions and making the same mistakes. Hopefully this book will help.

PowerShell and Active Directory is available now from the Amazon kindle book store. You can preview the book or view the book page on Amazon.

Posted in My Books, PowerShell | Leave a comment