Tuesday, 29 December 2020

Open Source HTML to PDF converter

The software I inherited included a function for converting an HTML quote into a PDF.

It used a library from a 3rd party vendor, Winnovative Software. As I was re-hosting the server from IaaS to Azure App Services, I found that the library didn't work under the sandboxed App Service environment.

A different component was required, but it was covered under my license. But then I discovered that my license was for V14 and the new version was V15.

Could I download the previous version - the one I paid for? No. "It was over 2 years old" the company told me. They no longer provided download links. I would have to pay to upgrade.

So 2 years old is deemed too old to support now. And I would have to pay to get the later version to get features I didn't need nor want.

I thought this was rather unfair practice and so I did some more research.

And I stumbled across the excellent open source wkhtmltopdf tool. And even better, Adam Hockemeyer provided a docker image that did exactly what I needed - it hosted the tool as a .NET Core Web service in Azure App Service.

Max Kudos to Adam - you saved me hours and hours of effort, and prevented me rewarding bad support behaviour.

Wednesday, 23 December 2020

ASP.NET Core: FileNotFoundException: Could not load file or assembly

 I had a complex solution with multiple projects and NuGet references.

To debug one troublesome Nuget package, I removed the Nuget reference and added a project reference so I could step through the code.

However when the website ran, it would throw the error:

FileNotFoundException: Could not load file or assembly <troublesome assembly>


  1. procmon.exe indicated that the website wasn't even loading the assembly - or trying to
  2. <website>.deps.json didn't have a reference to the assembly
  3. Visual Studio Resharper was showing the following popup:


The problem was that I had added the project to the solution, but the project was located in a folder outside of the root solution folder. By taking a copy inside of the root solution folder and re-adding the reference, the <website>.deps.json then included the reference and the assembly loaded.

  1. Check your <website>.deps.json 
  2. Use ProcMon
  3. Make sure that the project referenced is inside your solution folder.

Tuesday, 24 November 2020

Move To iOS - transfer interrupted problem

A common problem described on the reviews of the "Move to iOS" app is that people are being constantly disconnected when transferring files and settings.


What is happening is your Android connects to a local hotspot created on the iPhone. You will notice that the Wifi indicator on the Android has an exclamation mark. This is because it detects it cannot reach the internet, so it disconnects and tries your home LAN again.

Go to Network Settings and FORGET YOUR EXISTING WIFI connections so it cannot reconnect to your home wifi. Then it is forced to stay on the iPhone hotspot.

Sunday, 8 November 2020

Git Difftool with Beyond Compare 3

 git config --global diff.tool bc

git config --global difftool.bc.path "C:\Program Files (x86)\Beyond Compare 3\BComp.exe"

git config --global difftool.prompt false

git config --global merge.tool bc

git config --global mergetool.bc.path "C:\Program Files (x86)\Beyond Compare 3\BComp.exe"

git config --global alias.mydiff "difftool --dir-diff --tool=bc --no-prompt"

Wednesday, 28 October 2020

Search filters for Outlook Web


Thursday, 22 October 2020

VSIX install location

 Custom VSIX extensions are saved to


Tuesday, 29 September 2020

Docker Cheat Sheet

To access networking tools

 docker run --rm -it praqma/network-multitool bash

Saturday, 5 September 2020

The history of the Service Bus SDK

 An interesting article on the history of the Service Bus SDK:


Tuesday, 18 August 2020

VPN passthrough on Virgin Media Superhub 3.0

 I upgraded to the Virgin Media Superhub 3.0 and discovered VPN passthrough was not working.

The solution was to put it into cable modem mode.

Friday, 31 July 2020

.NET Core doesn't work on a Pi Zero

.NET Core doesn't work on a Pi Zero. The Pi Zero is armv6 whereas .NET core supports amrv7. The Pi Zero uses the Thumb instruction set (16 bits rather than the normal ARM 32 bit) which the Core CLR JIT compiler does not support.

Command alias in Ubuntu

f you haven’t previously installed xclip simply run the following command in your terminal window:
Edit your BASH settings file using your favourite text editor.  I’ll be using nano, but feel free to use Gedit or Vim etc.
Then create an alias for pbcopy and pbpaste:
Close and save the file then just refresh your bash to import your new settings

Saturday, 4 July 2020

docker i/o timeout on raspberry pi

I was getting an i/o timeout when pulling images on a raspberry pi.
To resolve it I had to change the nameservers on the pi to
This involved setting the primary nameserver on the router and editing /etc/resolv.conf

Friday, 3 July 2020


Raspbian on a SanDisk 16GB

Device         Boot  Start      End  Sectors  Size Id Type
/dev/mmcblk0p1        8192   532479   524288  256M  c W95 FAT32 (LBA)
/dev/mmcblk0p2      532480 31116287 30583808 14.6G 83 Linux

Disk /dev/mmcblk0 - 15 GB / 14 GiB
     CHS 486192 4 16 - sector size=512

Current partition structure:
     Partition                  Start        End    Size in sectors

Warning: number of heads/cylinder mismatches 64 (FAT) != 4 (HD)
Warning: number of sectors per track mismatches 32 (FAT) != 16 (HD)
 1 P FAT32 LBA              128   0  1  8319   3 16     524288 [boot]

Warning: Bad ending sector (CHS and LBA don't match)
 2 P Linux                 8320   0  1 486191   3 16   30583808 [rootfs]

Thursday, 2 July 2020

File and disk recovery

TestDisk and PhotoRec are open source file/disk recovery programs. They are install as part of the same suite and must be compiled before use.

Git source

Sunday, 24 May 2020

Creating a multiboot USB CD

Work on an Ubuntu machine.



Insert the USB into an Ubuntu computer. Make sure all partitions have been deleted.
Make sure it has GPT tables installed.

Use gdisk

This configuration is useful for creating a universal USB key, bootable everywhere. First of all you must create a GPT partition table on your device. You need at least 3 partitions:
  1. A BIOS boot partition (gdisk type code EF02). This partition must be 1 MiB in size
  2. An EFI System partition (gdisk type code EF00 with a FAT32 filesystem). This partition can be as small as 50 MiB.
  3. Your data partition (use a filesystem supported by GRUB). This partition can take up the rest of the space of your drive.

Command (? for help): n
Partition number (1-128, default 1): 1
First sector (34-60088286, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-60088286, default = 60088286) or {+-}size{KMGTP}: +1M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): l
0700 Microsoft basic data  0c01 Microsoft reserved    2700 Windows RE          
3000 ONIE boot             3001 ONIE config           3900 Plan 9              
4100 PowerPC PReP boot     4200 Windows LDM data      4201 Windows LDM metadata
4202 Windows Storage Spac  7501 IBM GPFS              7f00 ChromeOS kernel     
7f01 ChromeOS root         7f02 ChromeOS reserved     8200 Linux swap          
8300 Linux filesystem      8301 Linux reserved        8302 Linux /home         
8303 Linux x86 root (/)    8304 Linux x86-64 root (/  8305 Linux ARM64 root (/)
8306 Linux /srv            8307 Linux ARM32 root (/)  8400 Intel Rapid Start   
8e00 Linux LVM             a000 Android bootloader    a001 Android bootloader 2
a002 Android boot          a003 Android recovery      a004 Android misc        
a005 Android metadata      a006 Android system        a007 Android cache       
a008 Android data          a009 Android persistent    a00a Android factory     
a00b Android fastboot/ter  a00c Android OEM           a500 FreeBSD disklabel   
a501 FreeBSD boot          a502 FreeBSD swap          a503 FreeBSD UFS         
a504 FreeBSD ZFS           a505 FreeBSD Vinum/RAID    a580 Midnight BSD data   
a581 Midnight BSD boot     a582 Midnight BSD swap     a583 Midnight BSD UFS    
a584 Midnight BSD ZFS      a585 Midnight BSD Vinum    a600 OpenBSD disklabel   
a800 Apple UFS             a901 NetBSD swap           a902 NetBSD FFS          
a903 NetBSD LFS            a904 NetBSD concatenated   a905 NetBSD encrypted    
a906 NetBSD RAID           ab00 Recovery HD           af00 Apple HFS/HFS+      
af01 Apple RAID            af02 Apple RAID offline    af03 Apple label         
Press the <Enter> key to see more codes: 
af04 AppleTV recovery      af05 Apple Core Storage    af06 Apple SoftRAID Statu
af07 Apple SoftRAID Scrat  af08 Apple SoftRAID Volum  af09 Apple SoftRAID Cache
b300 QNX6 Power-Safe       bc00 Acronis Secure Zone   be00 Solaris boot        
bf00 Solaris root          bf01 Solaris /usr & Mac Z  bf02 Solaris swap        
bf03 Solaris backup        bf04 Solaris /var          bf05 Solaris /home       
bf06 Solaris alternate se  bf07 Solaris Reserved 1    bf08 Solaris Reserved 2  
bf09 Solaris Reserved 3    bf0a Solaris Reserved 4    bf0b Solaris Reserved 5  
c001 HP-UX data            c002 HP-UX service         e100 ONIE boot           
e101 ONIE config           ea00 Freedesktop $BOOT     eb00 Haiku BFS           
ed00 Sony system partitio  ed01 Lenovo system partit  ef00 EFI System          
ef01 MBR partition scheme  ef02 BIOS boot partition   f800 Ceph OSD            
f801 Ceph dm-crypt OSD     f802 Ceph journal          f803 Ceph dm-crypt journa
f804 Ceph disk in creatio  f805 Ceph dm-crypt disk i  fb00 VMWare VMFS         
fb01 VMWare reserved       fc00 VMWare kcore crash p  fd00 Linux RAID          
Hex code or GUID (L to show codes, Enter = 8300): ef02
Changed type of partition to 'BIOS boot partition'

Command (? for help): n
Partition number (2-128, default 2): 2
First sector (34-60088286, default = 4096) or {+-}size{KMGTP}: 
Last sector (4096-60088286, default = 60088286) or {+-}size{KMGTP}: +50M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI System'

Command (? for help): n
Partition number (3-128, default 3): 3
First sector (34-60088286, default = 106496) or {+-}size{KMGTP}: 
Last sector (106496-60088286, default = 60088286) or {+-}size{KMGTP}: 
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING

Do you want to proceed? (Y/N): y

OK; writing new GUID partition table (GPT) to /dev/sdc.

Format the partitions :

# mkfs.fat -F32 /dev/sdX2
# mkfs.ext4 /dev/sdX3

You can now install GRUB to support both EFI + GPT and BIOS + GPT/MBR. The GRUB configuration (--boot-directory) can be kept in the same place.

First, you need to mount the EFI system partition and the data partition of your USB drive.

An example of this would be as follows:

# mount /dev/sdX3 /mnt
# mkdir -p /mnt/boot/EFI
# mount /dev/sdX2 /mnt/boot/EFI

Then, you can install GRUB for UEFI with:

In most cases EFI_MOUNTPOINT will correspond to the /mnt/boot/EFI subdirectory on your mounted USB disk.

# grub-install --target=x86_64-efi --recheck --removable --efi-directory=/EFI_MOUNTPOINT --boot-directory=/DATA_MOUNTPOINT/boot
And for BIOS with:

# grub-install --target=i386-pc --recheck --boot-directory=/DATA_MOUNTPOINT/boot /dev/sdX
As an additional fallback, you can also install GRUB on your MBR-bootable data partition:

# grub-install --target=i386-pc --recheck --boot-directory=/DATA_MOUNTPOINT/boot /dev/sdX3

If you get:
grub-install: error: /usr/lib/grub/x86_64-efi/modinfo.sh doesn't exist. Please specify --target or --directory.

It may be necessary to install EFI support for grub:
apt-get install grub-efi

Testing is very quick and simple using the qemu virtual machine:

qemu-system-x86_64 -enable-kvm -rtc base=localtime -m 2G -vga std -drive file=/dev/sdb,readonly,cache=none,format=raw,if=virtio

Saturday, 23 May 2020

FreeNAS 0.7.2 - GEOM: adn: the secondary GPT table is corrupt or invalid

On booting FreeNAS 0.72 you may see the message: "the secondary GPT table is corrupt or invalid".

This can be ignored. According to this article:

"This error is caused by a basic flaw in the software used in FreeBSD and XigmaNAS to create and manage RAID arrays. Until FreeBSD version 7x the OS ignored / did not report the error. Now it and XigmaNAS, since it is based on FreeBSD, do report it. In the future, this may be fixed in FreeBSD, until then let's all continue blissfully ignoring it like we did prior to version 7x"

Wednesday, 20 May 2020

Rsync with SystemRescueCD

Using the SystemRescueCD:

mkdir /mnt/usb
mkdir /mnt/Data

Mount the NTFS USB disk
ntfs-3g /dev/sdc1 /mnt/usb

Mount the UFS disk
mount -t ufs -o ufstype=ufs2,ro /dev/sda1 /mnt/Data

then use grsync to copy the data

Source: /mnt/Data
Destination: /mnt/usb
This will copy the Data folder and its subdirectories to the mounted USB drive.

Tuesday, 19 May 2020

Rebuild a RAID 1 in FreeNAS 0.7.2

Determine the disk that has failed: is it ad0 or ad1?

Go to Disks > Software RAID > Tools
Select the failed drive, select Forget and click Send
Insert the new drive
Select the inserted drive, select Insert and click Send
Wait 5 minutes, select the drive and hit Status. You should see a percentage next to the new drive: this is it rebuilding.

Wednesday, 22 April 2020

Saturday, 14 March 2020

crontab doesn't run script

If crontab doesn't run a script and if the output is redirected to a zero length file, it may be because it is missing the #!/bin/bash or #!/bin/sh directive.

Another reason may be that the path is required.
change dotnet to /opt/dotnet/dotnet

Remember that crontab runs under a reduced environment. It may not have the necessary environment variables. For example echo @DOTNET_ROOT is empty when running as crontab. If you run it as su it returns /opt/dotnet

Consider the user you are running the crontab under. Does it need to be su?

In the end another approach was required: execute bash to run the script. This is the full crontab:
# Added dotnet to the path
# It is necessary to execute bash in order to access the environment variables required for dotnet
* */12 * * * bash -l -c '/home/pi/SmartHome/easy-weatherstation/scripts/publishreadings.sh' > /home/pi/SmartHome/easy-weatherstation/scripts/logs/publishreadings.log 2>&1
*/30 * * * * bash -l -c '/home/pi/SmartHome/easy-weatherstation/scripts/onereading.sh' > /home/pi/SmartHome/easy-weatherstation/scripts/logs/onereading.log 2>&1

Sunday, 1 March 2020

the required library libhostfxr.so could not be found

Problem: Running .net core 3.1 app on a Raspberry Pi returns
"the required library libhostfxr.so could not be found."

dotnet --version

if the second line is empty then the environment variable needs to be set at startup.

Add a file set_dotnetroot.sh to /etc/profile.d
sudo nano /etc/profile.d/set_dotnet.sh

export DOTNET_ROOT="/opt/dotnet"

save and reboot

If you want it to run for su too, especially if running a su crontab,
edit /etc/bash.bashrc and add it there too.

Sunday, 9 February 2020

Raspberry Pi screen blanking

I have a Raspberry Pi 4b running Raspbian 4.

After 10 minutes the screen blanks an it is very hard to get it to return: even plugging in a keyboard and mouse and using them doesn't restore the display. Here are some of my findings:

"xset s activate" recreates the problem.

X11 is a client/server Windows Manager.
Raspbian 4 is running Pixel, a derivative of LXDE.

You can see the default display manager with:

cat /etc/X11/default-display-manager

"sudo service lightdm restart" doesn't fix it.

Accessing the X11 tools differs if you use SSH out of the box from the local terminal connected directly to the Pi. For example I was getting errors such as xset:  unable to open display ""

returns :0.0 on the local terminal

but it returns a blank line on SSH unless you turn on X11 forwarding on the Putty console, then it displays:

X11 also has security controls.
"xhost +" disables the controls and allows everyone to access it.


Friday, 10 January 2020

Can't install Minecraft on Twitch

I had a weird problem where whenever I tried to Install Minecraft on Twitch the screen would flash quickly then it would return you back.

I fixed it by changing the install location from my user profile folder (my username had a dot in it) to C:\Temp and then it seemed to work. Even more strangely the folder seem to revert back to the user profile folder.