Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Hosted-services / Azure

How to Install Fonts into an Azure Worker Role Instance using a Startup Task

4.50/5 (2 votes)
5 Nov 2013CPOL6 min read 19.2K  
How to install fonts into an Azure Worker Role instance using a startup task

Currently, I am working on an Azure project to automate SVG templating in a Worker Role. The project is called The Azure Badge Generator.

Everything was fine so far, except for the problem, that when I generate an image out of an SVG, I need the same fonts available on my Worker Role, like the fonts installed on the machine where I created the SVG. Otherwise, those fonts are replaced by available system fonts. And that can look really ugly.

Looking for a Solution

After about 2 hours of searching Bing, Google and (of course) StackOverflow, I was not very pleased with the solutions. Some of them suggested to run VBS scripts (I really don’t like them). Other solutions just suggested to run a piece of .NET code using P\Invoke calls like on this thread on MSDN. That’s fine – but those API calls install a font, but I would have an additional project to maintain.

Coming Closer to a Solution – Cloud Cover Episode 31

Because I am a big fan of the Cloud Cover show, I started to browse all episodes, and found an episode from 2010 Cloud Cover Episode 31 – Startup Tasks, Elevated Privileges, and classic ASP. Luckily, I watched the whole show and at the end, John Ryan said something like this (don’t remember the exact wording):

“Running a startup task in elevated mode means that it runs with the rights of the system account. Everything else, like installing software and such, needs administrative privileges”

Yay! Why didn’t I try that before? And why could I not find it in the official Azure online documentation?

Some years ago, I earned my MCP (Microsoft Certified Professional) certificate. At this time, Bill Gates was still CEO at Microsoft. This knowledge came in very handy to solve this problem. Certification pays off – it really does!

Adding and Removing Users with Elevated Privileges

To add or remove a user and to add the specific user to the Administrators group, net user can be used. You can read more about this command on TechNet: Net User

Because the Worker Role is executed with elevated privileges, it runs under the System account. You can set this option within your ServiceDefinintion.csdef file. This file is located directly in the root tree of your cloud project. It is a simple XML file, that can be edited from within Visual Studio.

XML
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="AzureBadgeGenerator" 
 xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" 
 schemaVersion="2013-10.2.2">
  <WorkerRole name="BadgeService" vmsize="Small">
    <Runtime executionContext="elevated" />
    <Imports>
      <Import moduleName="RemoteAccess" />
      <Import moduleName="RemoteForwarder" />
    </Imports>
    <Endpoints>
      <InputEndpoint name="Http" 
      protocol="http" port="80" localPort="80" />
    </Endpoints>
    <ConfigurationSettings>
      <Setting name="SqlConnection" />
    </ConfigurationSettings>
    <Startup>
      <Task commandLine="startup.cmd" 
      executionContext="elevated" taskType="simple" />
    </Startup>
  </WorkerRole>
</ServiceDefinition>

As you can see in line four of the file, executionContext is set to elevated. This setting allows the Azure Worker Role to be executed with the privileges of the System account.

Back to Net User. These three lines executed in a command prompt will add a user and set the password (1), add the user to a group (2) or remove the user from the system (3):

  1. net user username password /add
  2. net localgroup Administrators username /add
  3. net user username /delete

To achieve my goal, I need to add some user, give him administrative rights and execute the font installation impersonated as this user.

Avoiding Run As – psexec to the Rescue!

To impersonate as a different user, and to run a process with his privileges, people usually call runas. This command is fine to be run when you sit in front of the machine and you want to wait for runas to ask you for your password. This disqualifies runas to be run from within a startup task on Azure.

Mark Russinovich still maintains the Sysinternals comand-line tools on Technet (thanks Mark), which psexec.exe is part of. You can download it here: psexec.

This neat little helper allows you to execute a process with the rights of any user located on a specific PC, within a specific domain and more. The best thing about it is that it can be used in a command-line script and that it accepts the password in clear-text. There is another important option, that should be used when you execute psexec for the first time: –accepteula. It avoids opening a dialog where you have to accept the EULA.

Knowing all that, you can execute a specific command, impersonated as user x very easily:

psexec -accepteula -u username -p password  commandtoexecute

The Last Player in the Game – FontReg.exe

FontReg.exe allows you to install fonts from within a folder, where the fonts and FontReg.exe are located. You simply copy it to a folder where you have downloaded/saved all the fonts to be installed to and execute it. It has two options:

  • /copy
  • /move

The first option copies the files to the font directory and registers them. The second variant moves those files to the font folder. This means that the files in the source folder are deleted.

If you execute FontReg.exe without any parameters, it will clean-up and fix your font-related registry entries.

You can download FontReg.exe here: FontRegWindows Font Registration & Installation Utility

Very handy little tool and works flawlessly.

How to Put All of This Together

After you downloaded all the required files, open your Azure Worker Role project and create a special kind of folder called Role Content Folder. These type of folders have been introduced with Azure SDK 1.7. RCFs allow you to create folders inside the app-root folder. This folder contains all the binaries that are required to run your Worker Role, specifically all of your project assemblies.

Here is a very good article about the Windows Azure Role Architecture by Kevin Williamson, where you can learn a lot about the startup cycle, to really understand what is happening.

RoleContentFolder

Simply right click the newly created folder, and add all the font files you want to install as well as psexec.exe and FontReg.exe to this folder, by choosing add=>existing item…

This folder will be created inside the AppRoot-folder, which is created inside the RoleRoot folder after a successful deployment of your Worker Role. I have added a video at the end of this blog-post. There I explain in detail, how to create these folders, and where the folders are located inside the VM running your Worker Role.

Time to Create the Startup Task

To execute a specific task when the role starts, it is necessary to create an ANSI encoded batch-file and not an UTF encoded file. Azure will not execute UTF encoded files, because a special header byte sequence is needed! You can do this by creating a file with Notepad and save it ANSI encoded:

Notepad

After you have done this, add the text-file to your Worker Role assembly and rename it to startup.cmd. Add the following code:

REM installing the font files from within the role root folder fonts
REM put your fonts there

net user fontinstaller InstFont3tC00$ /add

net localgroup Administrators fontinstaller /add

cd "%ROLEROOT%\approot\fonts"

echo running psexec ... >> test.txt

start /w psexec -accepteula -u fontinstaller -p InstFont3tC00$  fontreg.exe /copy 

net user  fontinstaller /delete

exit /b 0

These few lines of code will install your font files now on each start of the worker role. FontReg.exe will take care of fonts already installed and more.

Please see this video explaining some things more in detail, and demonstrating the installation of the fonts:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)