Using PowerShell to set the Num Lock state

During these work from home times, on the darkest timeline, I spent a lot of my day using my work PC over an RDP connection. For some reason, every time I connected, the Num Lock status would be set to off. Which is silly and annoying. 

When you are connected to a remote machine and you press the Num Lock key on your keyboard, it toggles the Num Lock state for both the client and guest machine. Which can get confusing if you are working with apps on both machines and the Num Lock state is different between the machines. Ideally, you want the Num Lock state to be the same on both machines.

For me, the preference was a command-line option for setting Num Lock. My shell of choice on Windows is PowerShell, so I decided to write a PowerShell script to set the Num Lock Status. The Num Lock key is a toggle switch, press once to turn on, press again to turn off. The script needed to be able to check the current state to be able to set a specified state correctly.

With a little trial and error, I came up with the following script. I put it on gist to make it easier to grab and make your own:

# One parameter, to set the Num Lock state to On or Off, with
# On as the default
[ValidateSet("On", "Off")]
[String[]] $onoff='On'
# Get the current state of the Num Lock key
$CurrentState = [console]::NumberLock
# the RequestedState, based in the command line param.
# On is true, Off is false
if ($onoff -eq 'On') {
$RequestedState = $true
else {
$RequestedState = $false
# If the requested state is the current state, we declare
# victory and go home
if ($RequestedState -eq $CurrentState) {
if ($CurrentState -eq $false)
Write-Host 'Num Lock is already off'
else {
Write-Host 'Num Lock is already on'
else {
if ($CurrentState -eq $false)
Write-Host 'Num Lock is off, turning on'
else {
Write-Host 'Num lock is on, turning off'
# If the requested state is not the current state, then
# we need to do a Num Lock press
# Create a new instance of the WScript object and send
# the NumLock key press to it
(New-Object ComObject WScript.Shell).SendKeys('{NUMLOCK}')
view raw num-lock.ps1 hosted with ❤ by GitHub


I put the comments inline, it should be pretty self-explanatory with the comments. While PowerShell is supported on macOS and Linux now, this is a Windows only script. The [console] ::NumberLock expression returns the following error message:

OperationStopped: Operation is not supported on this platform.

Which is odd, [console] is a shortcut for [system.console], a class that is accessible on the macOS Powershell. If you run the following command in a PowerShell on either Windows or macOS, you’ll get a list of static properties that should be readable from a POSH script.

[system.console] | Get-Member -Static -MemberType property | Format-Table 

And the NumberLock property is listed, but just not implemented. And that’s not even the real sticking point. This script creates an instance of a WScript object and uses it’s SendKeys method to pass in a Num Lock key press. WScript is the Windows Script Host, a technology that lets scripting languages make Windows API calls. A minor sticking point, I only need this Windows. You can get a list of the special keys that SendKeys can send from here.

That’s the heavy lifting. Because I am lazy, I don’t want to type in the name of the script. So I created an alias for it.

Set-Alias nl d:\scripts\num-lock.ps1

Now I can just run “nl” or “nl On” or “nl Off” to change the Num Lock state. I added the alias to the profile so it’s always available. Now when I connect to my work PC, I run “nl” and all is well.

Why I like working on Open Source (back to FocusUF)

About a month ago, I blogged about an update to a webcam hack that I did called FocusUF.  There wasn’t much to the code and I put it all up on GitHub.  Someone came along and submitted a pull request that added some cool functionality.  

My version was hardcoded to a single webcam.  Because that’s all I need it for.  At the time, I was using a Microsoft LifeCam HD-5000.  Someone else created an issue on my GitHub repo asking if I could add support for the HD-6000, which apparently suffers from the same annoyances with focus.

I was going to add a command-line parameter to FocusUF to allow you to specify all or part of the webcam name, but someone else beat me to it.  Cain Hopwood updated my code to add that and a bunch of other useful command-line switches.  And somehow, I had missed his PR when it was submitted a month ago.

So I tossed my changes out the window and accept the pull request.  It was pretty good.  After merging the changes, I added a couple of things.  Cain added code to list all of the webcams.  That would fail if you have any webcams that didn’t support the IAMCameraControl interface from the DirectShowLib.  If you have software that runs as a virtual webcam, it probably doesn’t support IAMCameraControl.   Now when you run it without any parameters, you get the following usage help:

Get the source at

Usage: FocusUF [--help | -?] [--list-cameras | -l]
[--focus-mode-manual | -fm] [--focus-mode-auto | -fa]
[--set-focus <value> | -f <value>]
[--exposure-mode-manual | -em] [--exposure-mode-auto | -ea]
[--set-exposure <value> | -e <value>]
[--camera-name <name> | -n <name>]


Now when you ask it to list the cameras, you get the following output:

❯ .\FocusUF.exe -l
Get the source at
Camera: c922 Pro Stream Webcam
    Focus Capability: Auto, Manual
    Focus Range: 0 - 250
    Focus Setting: Auto, 0
    Exposure Capability: Auto, Manual
    Exposure Range: -11 - -2
    Exposure Setting: Auto, -5
Camera: XSplit VCam
    Camera does not expose settings through DirectShowLib

I also made the search by name case insensitive.  That was low hanging fruit.  I also updated the compiled version of the code at  While I don’t support this as a product, it’s useful for people who don’t have the compiler installed.  And I updated the readme file to document the new changes.

And to go off on a tangent, I’ve been using a tool (Windows only) named Markdown Monster to edit the readme files.  Markdown Monster is written and supported by Rick Strahl.  You can try it for free and then buy a cheap license for it.  Working in Markdown is fairly easy, but it has its own syntax to learn.  Markdown Monster gives you a nice editor with full preview and it makes updating the readme file one less thing to think about.

And that’s one of the great things about open-source software.  Other people can jump in and contribute.  I wrote a little tool to fix something that was bugging me.  It sparked joy with someone and he added some additional joy to fix something that he needed.

When your Apple device refuses to be trusted

Back in July, I received a new Macbook Pro.  A lovely little device, but I had this one problem.  It wasn’t showing up as a trusted device under my iCloud account. 

When you log into a site or a service that requires Apple’s 2 factor authentication, you can use a Trusted Device to generate a 6 digit authentication code.  Most people use their iPhone, but I don’t have an iPhone.  Plenty of other Apple devices, just not the phone.  And 2 factor authentication works on my iPad, my old Macbook, and my Mac Mini.  Just not on the new Macbook. 

The 2 Factor Auth prompt

When I’m travelling, the only Apple device that I carry is the Macbook.  When I log into a service that needs the Apple auth, I want to be able to use my Macbook to provide that code.  That’s a pretty reasonable request.

This is what you should get

This has been frustrating me for a good month or so.  There is no switch or setting to enable.  Once you enable your iCloud account on an Apple device made in the last few years, that device is now a trusted device. That’s all you are supposed to have to do.

Except for my new Macbook.  It would not display the dialog that would prompt for the authentication code.  I tried Apple Support via email, but that proved to be fruitless.  I don’t think that they fully understood the problem.  I tried again today with Apple Support via phone.  It took the better part of an hour, but we finally resolved the problem.

Basically everything was setup correctly and should have worked.  But it didn’t.  With anything computer related, sometimes the best solution is to nuke the problem from a Low Earth Orbit.

It’s the only way to be sure

So we removed the iCloud account, rebooted, and added it back again.  That resolved the problem.  The Apple Support rep thinks that the iCloud auth token on the Macbook was corrupt. I have no idea how or why that happened, but that would explain what caused the problem.

Fix for “[Network & Virtual Switch] Failed to update DDNS “myQNAPcloud”

After Windows Home Server was more or less retired by Microsoft, I bought a new NAS server for home.  After some deliberation, I bought a QNAP TS-451+, a couple of years back.  It has been very reliable and is one of those things that Just Works.

Today I logged into it and it said that it had a firmware update, to version 4.3.5.  I haven’t had any issues at with firmware updates so I let it do it’s thing and went back to mucking around with the faulty CAT6 connections in my house.

After about a half hour, I started seeing emails coming in from the QNAP box.  When something goes it wrong, it does a nice job of sending me email notifications.  Every 10 minutes, I was getting the following error message

NAS Name: swan
Severity: Warning
Date/Time: 2018/10/15 23:26:17

App Name: Network & Virtual Switch
Category: Infrastructure
Message: [Network & Virtual Switch] Failed to update DDNS "myQNAPcloud".

OK, that’s a new one.  I took a cursory look at the settings and apps, but didn’t see anything amiss.  Fortunately, the Internet is now on computers and I pasted that error message into my browser and it found stuff.  I found a message thread on the QNAP forum (you are not a real product unless you have a support forum) that mentioned the problem.  Misery loves company and when it comes to computers, seeing other people with the same problem means that it’s probably Not Your Fault.

Other people had posted that this problem started after installing the 4.3.5 firmware upgrade.  I posted a “me too” post (not a #metoo post).  I then decided to see if there was something obvious that I could fix.  Under My Apps, I had a MyQNAPCloud app and it wasn’t running.  What this app provided was a mechanism where the QNAP box would punch a hole through your router and get you a domain name that would route down to your server.  With SSL via Lets Encrypt.  All in all, pretty cool.

If you are not familiar with QNAP servers, they are running some variant of Linux and there are apps that you can download and run to extend the functionality.  They do a very good job of hiding the nuts and bolts of the OS from you, you manage everything from a web based GUI.  It’s quite impressive.  You basically pick a name and you get and that takes you to the management portal of your server.  From anywhere.

When I drilled into the MyQNAPCloud app, it gave me the ever so useful error message of “MyQNAPCloud cannot start because of incorrect information in its configuration file”.  And there was no way of accessing that configuration file.  At least nothing that was immediately obvious.  So I deleted the app to see if I could download it again and reset the configuration.

After I deleted the app, I discovered it was no longer in the QNAP App Store.  Rut ro, Shaggy.  I fired up the Network & Virtual Switch app and selected the DDNS option.  When I doubled clicked on DDNS, it launched a myQNAPcloud window.

The thick plottens.  What used to be a downloadable app was now part of the OS.  I went in and had it verify that the router was configured correctly.  It’s 2018, UPnP actually works.  I forced the SSL Certificate module to update the Let’s Encrypt certificate.  If your site doesn’t use SSL, get a Let’s Encrypt cert.  It’s free and it works.

After futzing around with the myNAPCloud settings, I let the QNAP box do it’s own thing while I sent back to CAT6 things.  After 20 minutes, I noticed that the warning messages had stopped.  This is a good thing, I had addressed whatever the problem was.

This was one of the times where poking the beast with a sharp stick actually worked.  I like the QNAP boxes.  They are easy to work with, up-gradable, and the UI is actually useful.

FocusUF or how to turn off the autofocus setting of the LifeCam HD-5000 webcam

Welcome to the FuzzyCam

Note from the future: I updated the code and blogged about it here.

Why am I out of focus? It’s because I have a Microsoft LifeCam HD-5000 and I’m running Windows 10. The LifeCam HD-5000 webcam is a decent webcam with an annoying feature. The autofocus keeps shifting the focus around if you move your head slightly. It goes in and out of focus and locks in after a second or two.  When you are in a video chat, this can get very annoying (very quickly) for the other viewers. Your face will shift in and out of focus and it’s just a distraction.  Microsoft used to supply drivers for the HD-5000 and it had a control app where you could adjust the focus settings. Since Windows 8, they stopped as the OS directly supported the webcam.

I’m not able to sit motionless while on a webcam. I needed a work around. There is a registry hack that lets you turn off autofocus. I prefer to avoid hacks like that when it’s something that I could code around. So after seeing some stuff on StackOverflow on how to use the IAMCameraControl interface in DirectShow, I wrote a tiny command line app called FocusUF.

FocusUF uses the DirectShowLib library library to provide nice, friendly C# access to DirectShow. The DirectShowLib library maps the DirectShow Interfaces for use from a .NET app. With that library, it was little more than a handful of lines of code to access webcam controls. The app is hard coded to connect to a LifeCam HD-5000, but it would be easy enough to change the code for other webcam.

The code was written with Visual Studio 2017, it has not been tested with any other compiler. The source code is up on GitHub via this handy little URL.

How it works

To use the DirectShowLib library, I added it via nuget.

Install-Package DirectShowLib

The next step was to get access to the webcam. Using DsDevice from DirectShowLib, I was able to get the list of devices for the category of VideoInputDevice. Then I do a LINQ query to filter that list for the first match “Microsoft® LifeCam HD-5000”. If you are having a autofocus problem with a different brand or model of webcam, just replace that name with the name of your webcam. You can dump out the list of DsDevices and peek at the name property until you see your webcam.

Now that I have a DirectShow  sDevice that represents the webcam, I create a filter to expose the control interface of the web cam. DirectShow uses a module system called filters to expose device functionality. I create a new object that implements the IFilterGraph2 interface so that we can add a new filter. After getting that filter, I cast it to an IAMCameraControl to get access to the setter and getter methods. I get the current focus level and mode from the webcam.  I then set the focus to the current level and force the focus mode to manual.

How to use

Launch the app that will be using the webcam. Wait until it is in focus and then run FocusUF. It will detect the webcam and flip the autofocus setting to manual and lock it to the current focus setting. The setting will persist until the webcam is reset or another app changes the focus setting.

I probably looked better out of focus…

The name “FocusUF” is a tip of the hat to the YouTube channel AvE, where the host uses the phrase “Focus You F@*&” whenever his video camera loses focus.

Time to repave (slightly) my work machine

After lunch on Wednesday, I rebooted my work PC and it did not come back.  ADB had somehow lost the ability to see my actual Android devices.  I had tried a few things and was at the “Have you turned it off and on again” step.  I shutdown it and restarted it.   Windows 10 was not very happy.  I got the light blue screen of death.  It had a useless QR code and the ever so helpful message “critical service failure” message.

After a few rounds of rebooting and trying the standard self-repair options, I surrendered and handed it over to our IT guy.  I pretty much knew what the end game would be, but decided to let someone handle it.  He did pretty much the same things that I did and we decided to let Windows reset itself.

Windows Reset is both a good thing and a bad thing.  The good thing is that it basically says that your current Windows OS is rubbish and it will install a fresh one.  One that will be hopefully less damaged than the one that you are currently using. Or in my case, not using.  All of your data files are left intact.  Or at least in the condition that they were in before the SS Minnow goes for a  three hour tour.

I’m not sure what the root cause of the problem was.  I was nearly out of space on the primary drive and it’s been my experience that Windows doesn’t behave well when it runs out of room.  I had rebooted the day before and it was just fine then.  Today I had updated the Android SDK and that pretty much chewed through the remaining free space on the primary drive.  I could have probably used used Mike Halsey’s help.  Mike Halsey has xray vision for this sort of thing.

I’m due for a new machine at work and we had ordered it the day before.  So there really wasn’t much point in completely repaving this machine.  I just needed to install the stuff that I would need for the week or so until the new machine comes in.  So it’s time to install the bare minimum I need to get what I need to work on for the next week or so.

Office 2016
We have Office 365 so this wasn’t an optional installation

Android Studio
While I do nearly all of my Android development with Xamarin, there are times where it’s useful run some code in Android Studio.

Visual Studio 2017
This is where the good stuff happens.  I installed the latest preview bits.  I usually leave the preview versions to virtual machines, but this machine will be in my hands for a week or too.

Visual Studio Code
I have a few projects that are firmware that have their own C compilers, but no IDE.  Visual Studio Code is turning into my text editor of choice.  I like the latest and greatest, so I always install the Insiders edition.

SQL Server 2016 Developer Edition and SQL Server 2017 Management Studio
I have data needs.

It’s more useful to than Edge for most stuff.  I still use Edge, but most of the time I use Chrome.

For making a quick hack of the Windows 10 background.  Why isn’t this bundled with Windows?

Sometimes I need some music to help me concentrate.  I have the attention span of a mal-adjusted toddler, playing music with a good beat tends to keep me focused.

Since I installed Android Studio before Visual Studio, it installed the Android SDK and assorted tools first.  Visual Studio installs a second set and in a separate location.  Android Studio places it a user profile folder, Visual Studio in a Program Files x86 folder.  Since I’m using Intel’s HAXM kernel driver to accelerate Google’s Android emulator, I need to know which IDE’s Android SDK installed HAXM.  When I get the new machine, I’ll install the Android SDK first and set each IDE to use that SDK.

In the meantime, I’ll starting making a list of the tools that I need to install on a new machine.  There is considerable overlap with what I install on my Macbook these days, but there are still key differences.

Using console jQuery to scrape lists from Apple’s developer portal.

I needed to grab the lists of registered devices and developers from our company’s Apple Developer portal. Unless I’m being particularly obtuse (an outcome that I never rule out), Apple does not provide any means of exporting the lists.

Apple only allows 100 devices of each type (iPhone, iPad, iWhatever) to be registered as development devices. No matter how many iOS developers that you have at your company, 100 is the limit. And if you remove a device from that list, it still counts towards that total.  Once a year, you can reset the list and carry over the devices that you still need and drop off the ones that are not needed.  To make this easier to manage, I wanted to get a list of the devices and their ids and have the developers pick the ones that they still need.

So I wanted to export that list.  And Apple doesn’t let you export that list.  You can see it on the screen and work with the items in the list, but no export.  I figured that I wasn’t the only person dealing with that limitation so I did a quick search on Stack Overflow and found this little gem.

var ids = ["Device ID"];
var names = ["Device Name"];

var output = "";
for (var index = 0; index < ids.length; index++) {
    output += ids[index] + "\t" + names[index] + "\n";

To use that code, you would go to the list of devices in the browser. Then open up the developer tools for that browser. For example, in Chrome you would press F12 to open up the developer tools. Staying with the Chrome example, you would click on the Console tab in the developer tools and paste that Javascript code in and then press the Enter key. The code would execute within the domain of the page and generate a two column list of device ids and names.

To understand what that code does, you need to look at how the data is rendered on the page. The device list is stored in a HTML table, with each row looking like this

<tr id="1" tabindex="-1" role="row" class="ui-widget-content jqgrow ui-row-ltr">
    <td role="gridcell" style="text-align:center;display:none;width: 34px;" aria-describedby="grid-table_cb">
        <input role="checkbox" type="checkbox" id="jqg_grid-table_1" class="cbox" name="jqg_grid-table_1">
    <td role="gridcell" style="" class="ui-ellipsis bold" title="iPad" aria-describedby="grid-table_name">iPad</td>
    <td role="gridcell" style="display:none;" class="ui-ellipsis" title="c" aria-describedby="grid-table_status">c</td>
    <td role="gridcell" style="" class="ui-ellipsis" title="twletpb659m0ju078namuy8xnv2j0fzt1kytanfz" aria-describedby="grid-table_deviceNumber">twletpb659m0ju078namuy8xnv2j0fzt1kytanfz</td>

Looking at the highlighted lines 6 and 9, we can see the device name and device id as the text of table cell tag. Each cell has a aria-describedby attribute to identity the type of value being stored. We can search on the values of the attributes to locate the data that we want. Going back to the javascript, look at the following lines:

var names = ["Device Name"];

The first line declares a Javascript array with an initial array element of “Device Name”. The next line performs a jQuery select for all of the <td/> elements that have attribute of aria-describedby with the value grid-table_name. The next part of the statement iterates over the list of matching <td/> elements and uses the jQuery html() to get the text value of the cell and add it to the array. We then can then do the same technique to get the device id and then build a list as a string and finally dump it to the browser’s console.

I also needed to the email addresses of all of our registered developers. The email addresses were not in a table, but part of a list. Each email address is wrapped inside a section element like this

<section class="col-100 ng-scope">
  <p ng-bind="::person.fullName" class="ng-binding">First Last</p>
  <a class="smaller ng-binding" 

I just needed the text part from the <a/> element. Getting the email addresses was a simpler version of the code to get the devices. I just a jQuery select on the ng-bind attribute and matched on the value “”. That ended up being a single line of code to run in the browser’s developer console


And that’s how you can screen scrape data from a web page that doesn’t provide any support for exporting the data.

Bonus round
The aria-describedby attribute is a commonly used accessibility element used to describe the element that the tag is part of. The “aria” part of the attribute name is an acronym for Accessible Rich Internet Applications. Among other things, it was designed to allow assisted reading devices help parse a page for users with visual difficulties. It’s a good technology to use on your web pages.