Office Volume License Keys (VLK)

I keep having to look these up, so I stored them here.

Office 2019

Product KMS Client Setup Key
Office Professional Plus 2019 NMMKJ-6RK4F-KMJVX-8D9MJ-6MWKP
Office Standard 2019 6NWWJ-YQWMR-QKGCB-6TMB3-9D9HK
Project Professional 2019 B4NPR-3FKK7-T2MBV-FRQ4W-PKD2B
Project Standard 2019 C4F7P-NCP8C-6CQPT-MQHV9-JXD2M
Visio Professional 2019 9BGNQ-K37YR-RQHF2-38RQ3-7VCBB
Visio Standard 2019 7TQNQ-K3YQQ-3PFH7-CCPPM-X4VQ2
Access 2019 9N9PT-27V4Y-VJ2PD-YXFMF-YTFQT
PowerPoint 2019 RRNCX-C64HY-W2MM7-MCH9G-TJHMQ
Publisher 2019 G2KWX-3NW6P-PY93R-JXK2T-C9Y9V
Skype for Business 2019 NCJ33-JHBBY-HTK98-MYCV8-HMKHJ

Office 2016

Product KMS Client Setup Key
Office Professional Plus 2016 XQNVK-8JYDB-WJ9W3-YJ8YR-WFG99
Office Standard 2016 JNRGM-WHDWX-FJJG3-K47QV-DRTFM
Project Professional 2016 YG9NW-3K39V-2T3HJ-93F3Q-G83KT
Project Standard 2016 GNFHQ-F6YQM-KQDGJ-327XX-KQBVC
Visio Professional 2016 PD3PC-RHNGV-FXJ29-8JK7D-RJRJK
Visio Standard 2016 7WHWN-4T7MP-G96JF-G33KR-W8GF4
Excel 2016 9C2PK-NWTVB-JMPW8-BFT28-7FTBF
OneNote 2016 DR92N-9HTF2-97XKM-XW2WJ-XW3J6
Outlook 2016 R69KK-NTPKF-7M3Q4-QYBHW-6MT9B
PowerPoint 2016 J7MQP-HNJ4Y-WJ7YM-PFYGF-BY6C6
Publisher 2016 F47MM-N3XJP-TQXJ9-BP99D-8K837
Skype for Business 2016 869NQ-FJ69K-466HW-QYCP2-DDBV6
Word 2016 WXY84-JN2Q9-RBCCQ-3Q3J3-3PFJ6


To activate office with the above keys, see this reference on Microsoft’s site (backup here).

Finding and killing stuck or mistyped postgresql queries

I’ve found these useful during development:

Listing running queries:

SELECT pid, now() - pg_stat_activity.query_start AS duration, query FROM pg_stat_activity WHERE state = 'active' AND pid <> pg_backend_pid();

Listing queries that have run for more than a full minute:

SELECT pid, now() - pg_stat_activity.query_start AS duration, query FROM pg_stat_activity WHERE state = 'active' AND pid <> pg_backend_pid() AND (now() - pg_stat_activity.query_start) > interval '1 minute';

Try to cancel a single query:

SELECT pg_cancel_backend(<pid>);

Force kill a single query:

SELECT pg_terminate_backend(<pid>);

Force kill all queries that have been running for over 10 minutes:

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'active' AND pid <> pg_backend_pid() AND (now() - pg_stat_activity.query_start) > interval '10 minutes';

Force kill all queries using the user_accounts table (or mentioning user_accounts at all, this isn’t limited to table names):

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'active' AND pid <> pg_backend_pid() AND query LIKE '%user_accounts%';

Hope someone finds this useful.

Web Echo Service for developers

I recently had need of a service that would return your exact query to you for web client (or proxy) development purposes, in a case where using Fiddler, Wireshark, tcpdump was proving difficult for various reasons. The solution became the C-Net Echo Service, available at (and over plain HTTP if you need it). Feel free to use this for whatever.

Example usage:

$ curl -X PUT -d "Hello World!" -H "User-Agent: Fake Agent" -H "CUSTOM-HEADER: foo" -H "X-Forwarded-For:" ""
PUT / HTTP/1.1
Accept: */*
User-Agent: Fake Agent
Content-Type: application/x-www-form-urlencoded
Connection: Keep-Alive
Content-Length: 12

Hello World!

Generating a C# library from swagger.json using Docker for Windows

Just a short reference for myself (and maybe for you). How to run Docker for Windows, mount a local file system drive inside of the container, grab the swagger.json file off of a URL, and generate a library:

Using swagger-codegen-cli (old):

docker run -it -v //c/temp/swagger:/local --network host --rm swaggerapi/swagger-codegen-cli generate -i "" -l csharp -o /local

Using openapi-generator-cli (new):

docker run -it -v //c/temp/swagger:/local --network host --rm openapitools/openapi-generator-cli generate -i "" -g csharp -o /local

In the examples, the generators connect to a webserver running on the local Windows host at port 5000, and outputs “csharp”. Change this as appropriate.

Oh, and another thing: To make NSwag generate the swagger.json correctly in a .Net project, the <GenerateDocumentationFile> property needs to be set.


Remote Desktop (RDP) to a computer that’s enrolled in Azure AD

If you attempt to connect to a machine that’s enrolled in Azure AD from a workstation that’s not part of the domain, like your desktop or laptop at home, you’ve likely encountered this issue.

Firstly, we should get a few basics out of the way. You need a correct username and password. When your user is in AzureAD, you need to specify your username as such:

You also need to log into the target machine and allow remotely showing the login screen through RDP, which means disabling the requirement to use Network Level Authentication. This will allow you to log in interactively:

Note that the checkbox must be deselected for interactive login sessions to work.

Now we need to go about modifying our .rdp files. You can get a .rdp file by pressing “Save As” in the Remote Desktop Connection window. Open the file with Notepad (or your favorite editor), and you’ll get lines such as these:

At the end of the file, we need to enable support for CredSSP if you want to connect to an AzureAD enrolled machine. Add a line like this:


You can also put your username in the file, with the domain, as such:


You can also put your password in the file, though I don’t recommend the latter. This is likely to be a company computer, after all. Check your IT policies and proceed at your own risk.

Here be monsters.

Passwords in the .rdp file can be encrypted as SecureStrings. You can generate them with PowerShell. Keep in mind that SecureStrings are encrypted using your current account, so you have to do this while logged in on the machine on which you want to use the .rdp file. The client, not the remote machine.

> "Hunter2" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString

All of that garble is your encrypted password (Hunter2). Your password is now also stored in your PowerShell. Not good. If you do this without specifying the password, it’ll ask you. Better. Slightly.

ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString

You can put the password (if you really want to) into your .rdp file as such:

password 51:b:01000000d08c9ddf0115d1118c7a00c04fc297eb010000000f16d2079232d84babe49f4bac6617ef0000000002000000000003660000c000000010000000e686a1ac13248c81a2c9abb56082452f0000000004800000a0000000100000002a071ce0035f888093d04bdc4d8716aa100000005590842a9ba86481072a0e444971e7e014000000871ea7bed2d1abdc67222644e9a4c98addb76b7b

Note: The syntax is “password 51:b:encryptedpasswordhere“. There’s a space, not a newline. Don’t trust your browser.

Happy remote working!

curl SSL fails even with ca-certificates installed

curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here:

So curl fails to access sites over https, even if ca-certificates is installed in your Docker container? You need to force a certificate rehash. Why this is not done by default escapes me.


curl should be happy now. Enjoy!

Perl one-liner to create random passwords

Just wrote this thing. Putting it here, in case anyone needs it.

perl -e 'my @c = (('a'..'z'), ('A'..'Z'), (0..9)); for(1..128) {print $c[int(rand($#c+1))]}'

It creates random passwords, with the length specified by the number following “1..”, which is 128, in this example.

Example outputs:




Disable the “Other people are logged on to this computer” message on a Windows VM

If you’re logged on with Remote Desktop (and probably in several other cases) Windows will not respond appropriately to the power button being pressed. Instead of shutting down, it will display a message asking you if that’s what you really want to do, as if holding the same button for 5 seconds to force the damn thing to shut down isn’t your next move.

This solution may or may not be Windows XP specific, as that’s where I encountered the issue, but I’ve confirmed that setting the following registry key removes this message and shuts down when a simulated ACPI button is pressed:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Error Message Instrument]

How to use Invoke-WebRequest in PowerShell without having to first open Internet Explorer

So, you get this error message:

Invoke-WebRequest : The response content cannot be parsed because the Internet Explorer engine is not available, or Internet Explorer’s first-launch configuration is not complete. Specify the UseBasicParsing parameter and try again.

..and sure, you could use -UseBasicParsing but, depending on your use case, you might then have to write a lot of functionality yourself that’s already handled for you if you avoid basic parsing.

Luckily, the Internet Exporer First Run wizard can be disabled in the registry, and if your script runs as a privileged user, you can do this from PowerShell:

$keyPath = 'Registry::HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Internet Explorer\Main'
if (!(Test-Path $keyPath)) { New-Item $keyPath -Force | Out-Null }
Set-ItemProperty -Path $keyPath -Name "DisableFirstRunCustomize" -Value 1


It’s worth noting that if your computers are in a domain, there’s also an easy to use GPO for this, at Computer Configuration => Policies => Administrative Templates => Windows Components => Internet Explorer, called Prevent running First Run wizard.

More about that over here (local archive).