Printing à la carte!
A customer printer deployment challenge that rolled in recently, that nicely backs up our key proposition, that with FastTrack Automation, you are not simply buying a product that executes set functionality, you are in fact buying into an open-ended subscription of problem resolution.
The FastTrack customer in question runs a large chain of small retail outlets, which for security and practicality reasons are not domain joined or have a reliable enough Internet connection for a VDI solution to work.
Every store is essentially an island, and there are around 80 of these for the IT department to look after, all over the country.
A crucial part of the outlets business is the visiting customer facing consultant, who (to keep operating costs down), is tasked with sharing his/her time between any number of multiple stores. On a typical week, it’s possible this consultant might visit a different store every day.
Core to our consultant’s role, is the ability to print, lots and lots of reports for the customers that visit in store.
Due to the number of stores, legacy IT procurement and perhaps the odd acquisition, each store has a single workhorse network printer (IP based), however this printer could be any one of three different brands.
Every store has a different network subnet, so no two printers have the same IP address.
However, a silver lining is that thankfully the IT department, when setting up each stores printer originally, ensured that each printer had the same last octet IP address.
To spice things up a bit, in just a matter of days, there is a hardware refresh, and all 30 consultants are going to receive a new Windows 10 laptop. No one thought about the printer chaos that would ensue.
A tall order…
Build a bullet proof, single file, multi-vendor print solution that will ensure that any of the 30 consultants can visit any of the 80 stores and print to any brand of in store IP printer.
Could this be done with an existing subscription of FastTrack Automation Studio Enterprise?
A recipe for success, is a good spec.
The first thing to do was to work with the customer to clearly understand the business needs and challenges. So we needed to come up with tight specification for the application:
- Ensure the application only runs on Windows 10 PCs with x64 architecture. The customer only has new Windows 10 x64 laptops in the stores, and we want to prevent the application from launching on any non-supported PC, which might cause trouble for the IT help-desk.
- Make the solution fully ‘portable’, so single EXE needs to contain our app, plus all driver and setup files needed for printer installation.
- Remove any printer mappings created by our printer setup application, (old connection from visit to previous days store) – but not to touch any printer(s) not setup by our application (ie home printers).
- Enable the consultant to choose the brand of printer via a simple three choice menu.
- Once chosen, dynamically determine the printer IP address for the store by detecting the currently active subnet.
- Install the printer driver completely unattended, based on the user’s menu selection.
- After installation, automatically set this printer as the default printer.
- The entire process should require a single click to start the app, a second click to choose the printer, and that is all.
Time to cook up a tasty FastTrack mini app!
Developers here at FastTrack will unanimously agree – I am no software developer, so their jobs are well and truly safe! My background is more system administration. This is the great thing about FastTrack Script is that someone like me can use a bit of my own ‘cleverness’ to quickly build a similarly clever application with a few lines of FastTrack Script.
So let’s look at my menu driven printer deployment program in more detail, line by line…
To kick things off, we are going to need to be local admin to install printers, and if we are not using technology found in our Admin By Request privilege management solution, the least we can do is to force our program to run ‘as administrator’. Doing this removes the requirement for the user to have to ‘right click, run as administrator’ so putting this command in first will force the users to enter a local admin password if they do not already have local admin rights. If they do have local admin rights, then they just need to click an OK button:
These next two lines are really me just showing off, by branding the application with the customers own name and logo. Cute!
SetUserDefaultCompanyName MyCompany SetUserDefaultCompanyLogo LOGO\MyCompany.png
Here’s the first real opening salvo of my application. The ‘DisconnectNonConnectedPrinters’ allows me to disconnect (remove) all printers that had been previously configured by the application, but not any other printers. So a consultant that had visited a different store on the previous day, would have that printer removed, making it impossible to print to the wrong one or being selected by mistake. The ‘DisconnectNonConnectedPrinters’ command ensures that the consultant only ever has a single store printer, and that’s just the one for the store they happen to be working in:
Next we use the IPAddressPart command – the ‘slam dunk’ for my program. We know that every store has a unique subnet, but the workhorse printer always has the same last octet IP. With this command, FastTrack detects the first three octets of the subnet which I then save to a variable called ‘subnet’ which will be my rabbit of the hat later on:
Set Subnet = [IPAddressPart 3]
We are now going to build our printer selection menu, but before we do this we are going to set the default printer to the last that was used, because it’s likely consultants will visit the same store more frequently than others, so a ‘last used’ default might help:
SetMenuDefault [RegistryValue HKCU\Software\FastTrack Software\CurrentPrinters]
We are setting our variable ‘Printers’ from the result of a menu selection. The menu asks the user for the brand of printer that is in that store, and they have three choices, RICOH, HP or OKI:
Set Printers=[Menu What is the make of your store printer?,Printer|RICOH,Printer|HP,Printer|OKI]
Next we need to check to see if there is a pre-set variable ‘Printers’, and if not, we write it to our registry which enables the ‘default’ functionality mentioned previously.
If Not VarIsEmpty Printers Then WriteRegistry HKCU\Software\FastTrack Software\CurrentPrinters,[Var Printers]
Here we are just showing the user some messages, in which we are dropping variables, so the user can see what printer is about to be installed. We had to keep the application very simple due to time constraints so there was not enough time to write in a check to see if the printer was online or not. When the printer is offline, the driver install would take longer, hence we put the extra message in:
SmallSplash Please wait whilst printer STORE-[$Printers] is set up.... Sleep 5 SmallSplash ...if this takes longer than usual please check the [$Printers] printer is switched on Sleep 3
This next line starts of our ‘switch block’ where we route to one of three different ‘cases’ dependant on the previously selected printer from the user’s menu selection.
Switch [Var Printers]
The Case line means if the user selected ‘RICOH’ from the menu, this subsequent code block will be run.
InstallPrinterDriver is exactly that, we use the printer driver name and point to an inf file that will load drivers that we rolled up in our single EXE.
InstallPrinterDriver RICOH PCL6 V4 UniversalDriver V2.8, RICOH\r4600.inf
So this next bit is the line where we take our detected subnet variable (minus the last octet) and then we append to this variable the last octet IP which we know is always set to .191. So this line installs a printer, to the right IP, based on whatever subnet that has been detected. Gloriously simple!
ConnectIPPrinterAsDefault [$Subnet].191, STORE-RICOH, RICOH PCL6 V4 UniversalDriver V2.8
We then have the other two CASE blocks for the other two printers:
Case HP InstallPrinterDriver HP LaserJet Pro M402-M403 PCL 6, HP\hpdo542a_x64.inf ConnectIPPrinterAsDefault [$Subnet].191, STORE-HP, HP LaserJet Pro M402-M403 PCL 6 SetPrinterDefault STORE-HP Case OKI InstallPrinterDriver OKI Universal PCL 5, OKI\okw3c03z.inf ConnectIPPrinterAsDefault [$Subnet].191, STORE-OKI, OKI Universal PCL 5 SetPrinterDefault STORE-OKI End Switch
(The ‘End Switch’ command ends our switch block)
We show a splash message that the printer in question (shown as variable) has been installed OK. Splash screens are nice because they don’t require a button to click ‘OK’ – they just go by themselves. If you have them at the end of your code, they will instantly appear and then vanish, so you need to put a little ‘sleep’ command in to make them hang around…
SmallSplash Printer STORE-[$Printers] successfully installed and set as default printer
Show this final splash screen for 4 seconds:
Room for improvement?
With so little time (just a few days from the initial request to understand the customers requirement, the business case, build a specification and then build the application), it was important we followed to KIS mantra (Keep It Simple). There is some manual user intervention required, the consultant must choose the correct brand of printer (not difficult) and, we are not checking to see if the printer is online.
With a little more work, we could have written in a little extra code that would have fired off a quick SNMP request which both check online status and fetch the make of the printer for us. So if we didn’t get any SNMP response back, we could ask the user to check the printer was switched on. Then we could have looked in the SNMP response for the brand name and use this to select the case, rather than requiring a manual user interaction:
Set MySNMPValueVar = [SNMPValue [$subnet].191, 126.96.36.199.188.8.131.52.0] If Contains [$MySNMPValueVar], OKI Then ShowMessage OKI printer found!
The above snippet checks an SNMP OID that contains the manufacturer name, and if it matches what we want, shows a message.
If SNMP was not possible, we could also attempt something similar using an HTTP request to the printer’s web admin (if enabled).
A simple ‘online http checker’ test could be performed using something like the following:
ResumeOnError 10 SmallSplash Checking if device is online... Set MyHttpRequestVar = run [HttpRequest http://hostname-to-check] Set MyLastHttpStatusVar = [LastHttpStatus] If StartsWith [LastHttpStatus], 4 Or StartsWith [LastHttpStatus], 5 Then If Ask No response from device, do you want to try again? Then Restart End If
If we knew a bit more about the exact composition of the web interface, then it’s also possible we could look at the response that comes back from the printer (similar how we did with SNMP) and use this to help us work out what make of printer this is.
This is a riskier method, because it’s possible that a future printer firmware upgrade could adjust the web interface and render our check useless. In the case of this customer, the application had to be ‘fire and forget’ so we had to keep it as simple and manual as possible to eliminate any possibility of a problem.
We were initially sent a very long spreadsheet from the customer, which contained data for each store, that stores subnet, a unique identifier for the store, and the make of printer in that store. The approach would involve us taking the data in this sheet, converting it to XML and then building an application that would read it. Our FastTrack application would then match the subnet with the store ID and from this determine the make of printer.
But this approach soon hit issues, because if one day the printer in a store broke down (as happens) and was changed, then everything would break. We could have put our XML online, and referenced that, but then that opens other issues (need to manage XML file, human error when editing it etc).
In the end, it was agreed to follow the much simpler specification – let the user in the store choose the make of printer and generate the IP of the printer from the detected subnet was chosen.
After checking back with this customer a few weeks into the roll out – our solution was a complete success!
Voilà! Your dynamic print menu solution, is served!
Here we have it, without comments, this entire application is just 26 lines short. This project makes for a truly excellent example of how a simple IT sysadmin can whip up some powerful functionality.
/*********************************************************************/ /* Menu Driven Dynamic Printer Mapping Tool */ /*********************************************************************/ ElevateUser SetUserDefaultCompanyName MyCompany SetUserDefaultCompanyLogo LOGO\specsavers.png DisconnectNonConnectedPrinters Set IPAddress = [IPAddress ] Set Subnet = [IPAddressPart 3] '' ShowMessage You are on subet [$subnet] and your printer IP address is [$Subnet].191 ''==== SHOW MENU ==== SetMenuDefault [RegistryValue HKCU\Software\FastTrack Software\CurrentPrinters] Set Printers=[Menu What is the make of your store printer?,Printer|RICOH,Printer|HP,Printer|OKI] ''==== REMEMBER SELECTION ==== If Not VarIsEmpty Printers Then WriteRegistry HKCU\Software\FastTrack Software\CurrentPrinters,[Var Printers] ''==== EXECUTE CONNECTION ==== SmallSplash Please wait whilst printer [$Printers] is set up.... Sleep 5 SmallSplash ...if this takes longer than usual please check the [$Printers] printer is switched on Sleep 3 Switch [Var Printers] Case RICOH InstallPrinterDriver RICOH PCL6 V4 UniversalDriver V2.8, RICOH\r4600.inf ConnectIPPrinterAsDefault [$Subnet].191, RICOH, RICOH PCL6 V4 UniversalDriver V2.8 Case HP InstallPrinterDriver HP LaserJet Pro M402-M403 PCL 6, HP\hpdo542a_x64.inf ConnectIPPrinterAsDefault [$Subnet].191, HP, HP LaserJet Pro M402-M403 PCL 6 Case OKI InstallPrinterDriver OKI Universal PCL 5, OKI\okw3c03z.inf ConnectIPPrinterAsDefault [$Subnet].191, HP, OKI Universal PCL 5 End Switch SmallSplash Printer [$Printers] successfully installed and set as default printer Sleep 4