QRCodeGenerator

The module QRCodeGenerator generates a variety of QR codes. All QR codes are generated offline and not shared with any service. The module works cross-platform (Windows PowerShell, PowerShell Core).

The module QRCodeGenerator generates a variety of QR codes. All QR codes are generated offline and not shared with any service. The module works cross-platform (Windows PowerShell, PowerShell Core).

Installing

To install QRCodeGenerator, download it from the PowerShell Gallery:

Install-Module -Name "QRCodeGenerator" -Scope CurrentUser -Repository PSGallery -Force

When you run Install-Module for the first time, you will be asked to download the “nuget” binaries first which drive the download process. Next, QRCodeGenerator is automatically downloaded, unblocked, unpacked and copied to the appropriate destination (specified via -Scope). You are all set.

We are adding new things to our modules every now and then, so it may be worth checking for updates every once in a while using Update-Module -Name QRCodeGenerator.

Creating QR Codes

Currently, QRCodeGenerator ships with these commands:

Command QR Code Action
New-PSOneQRCodeTwitter opens Twitter profile
New-PSOneQRCodeVCard adds person to Contacts
New-PSOneQRCodeGeolocation opens location in Google Maps
New-PSOneQRCodeWifi adds a Wifi Connection

For backwards compatibility, the module also adds aliases to the command names used in previous versions: New-QRCodeTwitter, New-QRCodeVCard, New-QRCodeGeoLocation, and New-QRCodeWifiAccess.

Using -Show and -OutPath

Each command has a switch parameter -Show: when specified, the generated QR code is opened in a picture viewer. By default, QR codes are generated as file in your $env:temp folder. Use -OutPath to specify a path to a PNG file name of your choice.

All other parameters are mandatory, so you get prompted. Try this to create a QR code with your personal data:

New-PSOneQRCodeVCard -Show

PowerShell will prompt you for all of your details, then display the QR code.

Scanning QR Codes

Most modern smart devices have built-in QR code support: open the camera in your smart phone, and scan a QR code. Most likely, your smart code will recognize the QR code and offer some action, i.e. adding a vCard to your list of contacts, or opening a location in a map.

Source Code

All source codes for this module can be found here.

Improving and New QR Codes

It’s really simple to add new QR code types, or enhance the existing types. Simply take a look at the code: it contains a string that contains the payload of your QR code:

$vcard = @"
BEGIN:VCARD
VERSION:3.0
KIND:individual
N:$LastName;$FirstName
FN:$Name
ORG:$Company
EMAIL;TYPE=INTERNET:$Email
END:VCARD
"@

So you can easily add new fields, i.e. add a phone number to your vCard.

Just make sure you stick to the QR code standards for the given type. When you expand a vCard for example, look up the definition for a vCard QR code, and add only approved keywords. Else, devices won’t know how to deal with your information.

If you do add new functions or enhancements, please let us know and share back. The best would be forking the github repo.

Learning Points

QRCodeGenerator comes with important learning points:

  • It illustrates how you can ship binaries (DLL files) within your PowerShell scripts.
  • It shows how you can use a free GeoCode webservice that unlike Google does not require API keys to work

Shipping Binaries as String

When you look at version 1.2 of QRCodeGenerator, you’ll see that it used the classic way of distributing binary dependencies: it ships a DLL file and loads this file via Add-Type so PowerShell can use functions defined in that DLL.

Binaries as Base64 Strings

In version 2.0, the module has no dependencies anymore and no longer ships separate DLLs. It consists of plain text files only. The DLL file is incorporated into PowerShell files as string:

# loading binaries from string
$content = 'TVqQAAMAAAAEAAAA//8AALgAAAAA...

The binaries are restored from this string as byte array. The byte array represents exactly what previously was loaded from the external DLL file.

Loading Base64 into Memory

While Add-Type does not support loading byte arrays directly and always requires an external DLL file to load, [System.Reflection.Assembly]::Load() can load byte arrays, so this one-liner loads the Base64 string into memory:

$null = [System.Reflection.Assembly]::Load([System.Convert]::FromBase64String($content))

How to Convert Binaries to Base64

If you’d like to turn your own binary files (DLLs, pictures, etc.) into Base64-encoded strings, it’s very simple. These are the steps I have taken to turn a DLL into a string:

$binary = "C:\Github\Modules.QRCodeGenerator\QRCodeGenerator\2.0\binaries\QRCoder.dll"
$content = [System.IO.File]::ReadAllBytes($binary)
$string = [System.Convert]::ToBase64String($content)

Why Shipping Binaries as Text?

Which raises the question: why would you want to ship binary files as text in the first place? Well, my primary reason was “because I can!”, but there are more important reasons, too: binary files may be blocked in your environment, and more importantly, they get locked while in use:

I often ran into issues when I wanted to move or rename my module and couldn’t because files inside of it were “in use”. By loading binaries via byte array, there are no file locks whatsoever.

Using Free GeoCode API

New-PSOneQRCodeGeoLocation can take any address and return a QR code that points you to that address. That’s pretty cool but there needs to be some magic that turns an address into the geographical latitude and longitude.

In the initial version I used the free Google GeoCoding APIs. Then suddenly Google changed their terms and required an API key. API keys are evil because you can neither share them in public modules, nor can you ask users to create their own before using a module, so in essence, API keys are dead meat for public modules.

geocode.xyz to the Rescue

Fortunately, there are other services that remain free. Here is how I implemented the address-to-latlong-conversion:

$Address = 'Hannover Congress Centrum'
$AddressEncoded = [System.Net.WebUtility]::UrlEncode($Address)
        
$null = Invoke-RestMethod -SessionVariable session -Uri "https://geocode.xyz"
$data = Invoke-RestMethod -WebSession $session -Uri "https://geocode.xyz/${AddressEncoded}?json=1"

if ($data.error -ne $null)
{
     throw "Address not found. $($data.Error.Description)"
}

[PSCustomObject]@{
     Latitude = $data.latt
     Longitude = $data.longt
}

Coincidentally, this chunk of code returns the latitude and longitude of the Hannover Congress Center, home of the renown PowerShell Conference EU, so you can already make yourself familiar with getting there. Delegate registration is open. Get your seat while they last!

Rest API Tricks

There are a few tricks you should know when you work with public Rest APIs like the one from geocode.xyz. In order for them to not get overwhelmed with free requests, when you run Invoke-RestMethod on them, they simply return an exception.

The trick is to first and politely visit their homepage and get some cookies from there, just as if you were a human visitor. Then, when you query the geoinformation, you submit the same cookie information which identifies you as a legit user:

# visit the homepage and get cookies, returned in $session
$null = Invoke-RestMethod -SessionVariable session -Uri "https://geocode.xyz"
# make your actual call and submit the cookies from your first visit:
$data = Invoke-RestMethod -WebSession $session -Uri