Adobe’s C:\Program Files\Common Files\Adobe\Adobe PCD\cache\cache.db file contains important information including licensing. I’ll go through ways to view and modify this file.

Adobe in recent times have taken to keeping licenses and other information like EULA acceptances in a file called cache.db. This file is located in C:\Program Files\Common Files\Adobe\Adobe PCD\cache. Deleting this file and then letting the relevant programs re-create the file is a common method of dealing with issues with serial numbers, EULA, language information but this isn’t always ideal. If your product is legitimately licensed but you don’t have the key handy, then you’ll be back to trial mode. If you’re still getting EULA messages the information is in here. I’ll go through a few things I’ve found about how to investigate and modify this file.

Opening the cache.db file with notepad doesn’t show a lot, but it should start with SQLite format 3. This was enough to lead me to investigate SQLite and to find something else to view the file. SQLite Browser will enable you to open and view the cache.db file. Once you open it up then navigate to the cache.db file (maybe take a copy) you’ll see the database structure which is basically 2 tables: pcd_meta and domain_data. Choose the Browser Data tab, then select the Table domain_data.

You should see 4 columns, domain (which is always 1), subDomain, key and value. Most of the entries in the subDomain column will be one of three types: a GUID, a serial or a LEID.

The GUID entries are standard Microsoft 32 character GUIDs and these should match with an entry in the registry inside HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall.

For instance {A1BC7068-C1BA-410F-8B9A-DB807C803DE2} would correspond to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{A1BC7068-C1BA-410F-8B9A-DB807C803DE2} which would show you DisplayName = Adobe Creative Suite 5 Design Premium. So you’ll be able to see which product these relate to. For these entries if there is a key named EncryptedSerial, the value column would show you just that, the serial number that Adobe has encrypted.

In some cases these encrypted serials will also appear in the subDomain column and for these values you might see some keys called things like PPAID, PPCGO, PPAPP, PPSUITE and so on. In particular PPAPP might show something like Acrobat X Pro, so you could decuce that those entries would relate to Acrobat.

The third type of entry in the subDomain column is a LEID (licensing identifier). These will look like ElementsOrganizer-EMT11- Win-GM or AcrobatPro-AS1-Win-GM{|}ALL. The first part before {|} is the LEID and afterwards is the language. These entries were the ones I was most concerned with and they have entries in the key field like EULA_ACCEPTED, IsProductActivation, LineCU 2 or Acrobat_Base_10.0. The value fields for these rows will contain values relevant to that key.

From looking at this table you might be able to guess quite accurately if a EULA has been accepted, if a serial has been entered, which suites or applications are installed. Adobe’s installers seem to use the information here to detect if a product is already installed and other information about it.

So after that explanation, what can you do now that you know this? Well using SQLite Browser, you can modify the database directly. Change, remove or add the entries you like, then MAKE SURE you save the database. You can also compact the database from the File menu if you like.

If you’re like me and you administer large numbers of systems, you may be looking for ways you can manipulate this database in an automated way. There are a couple of main methods for this.

The Adobe Provisioning Toolkit provides an executable which can do plenty of things you may be interested in. Ultimately it modifies the cache.db file and if you use APTEE you could observer what it changes in cache.db. In my case this didn’t help because I wanted to accept EULAs and couldn’t work out what a DriverLEID was compared to a LEID.

Another option, which is what I went with is to use SQLite and to get the command-line shell. This gives you the option to complete SQL commands on the file and you can read up about SQLite. You can complete your typical database operations to select, modify, delete and all of that. For my purposes, I worked out the entries in cache.db I wanted to change (or create if they weren’t there) by comparing a before and after cache.db with SQLite Browser and created the list of commands I wanted. Then I used a command line with SQLite to run all of these.

So a SQLite commands file might look like:

insert or replace into domain_data values (1,”AcrobatPro-AS1-Win-GM”,”EULA_ACCEPTED”,0);

insert or replace into domain_data values (1,”ElementsOrganizer-EMT11-Win-GM”,”EULA_ACCEPTED”,0);


and the command to run this in a Windows command prompt would look like:

sqlite3.exe “path\to\cache.db” < mycommands.txt


In looking to use ISLockPermissions in InstallShield to add some permissions into a transform, I thought I was doing all the right things – selecting “Custom InstallShield handling”, adding my permissions as required, checking they were getting entered in the ISLockPermissions table and all looked good except I wasn’t getting the permissions set.

It turned out that the ISLockPermissionsInstall Custom Action wasn’t getting run at all until I changed the Schema level from the msi set level of 200 to 405. Happy days!

(Get-WmiObject Win32_ComputerSystem -computerName “ComputerName”).UserName

Running a program locally you can use the App Compat Toolkit to shim all sorts of compatibility settings. Running the program from a network drive, you’ve got far less:

It looks like there’s 3 things we can try:

  1. Add an entry in this key
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
    Something like: F:\Folder\App.exe=WIN98
  2. Add an entry in this key
    HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
    Something like: K:\Folder\App.exe=WIN98
  3.  Or create a batch file like so:
    set __COMPAT_LAYER=Win98

There’s some info about the batch file method here: http://support.microsoft.com/kb/286705

There’s a little bit about the reg key method here: http://msdn.microsoft.com/en-us/library/windows/desktop/bb756937.aspx

I’ve been looking for a little while to prevent that security bugbear of laptops bridging the corporate network by keeping the wifi or 3G connection running while connected to the domain. A neat product I’ve come across is Accessity 1Net. Easy to install, runs a lightweight service and it was pretty snappy at disabling the unwanted connection. It identified the domain straight off and prevented other unwanted connections while on the domain. I could still take a laptop home and connect via wifi.

You can set the configuration via Group Policy which is nice.

You can set some HP models in the BIOS to disable a wireless connection when a wired one is available, but I haven’t seen it from all manufacturers.In the 1NET install you can set the command line property

ALLOWWLANONDOMAIN=N if you want to disconnect the wireless when the ethernet is connected or

ALLOWWLANONDOMAIN=Y if you’re happy to allow both connections.

It worked very well for me, so take a look if you’re trying to prevent network bridging or to disable wireless while on the LAN.

Further to my recent SCCM report post to return All advertisements run in the last 24 hours, here’s a way to include if a program requires users logged on, or off, or either for a particular program.

1. Join the v_Program table to your query. In my query it’s included by join v_Program pgm on adv.PackageID=pgm.PackageID and adv.ProgramName=pgm.ProgramName

2. Select pgm.ProgramFlags. This will probably return you at least a 7 digit number that you’ll want to  look for some bit flags in. The values in question are documented on http://msdn.microsoft.com/en-us/library/cc144361 and of particular interest are 0x20000 and 0x4000

3. Rather than just selecting the pgm.ProgramFlags value, add a case statement to return something in words that people can understand. In this instance, if 0x20000 is set, it’s logged out only. If 0x4000 is set it’s logged on only. If neither is set, it’s either logged on or logged off. This is the part you’ll want in your select statement:

CASE WHEN (pgm.ProgramFlags & 0x20000 != 0) THEN ‘Logged out only’
WHEN (pgm.ProgramFlags & 0x4000 != 0) THEN ‘Logged on only’
WHEN (pgm.ProgramFlags & 0x4000 = 0 AND pgm.ProgramFlags & 0x20000 = 0) THEN ‘Logged on or off’
ELSE ‘Unknown’
END AS “Logged on or off”

With the help of the internet, I have created the greatest and most best SCCM Report ever. This report indicates how many advertisement executions have taken place in the last 24 hours. Its genesis lies in a report whose source eludes me that shows all advertisements created in the last X days. This is fabulous as it shows which long standing advertisements get any use. You could expand it to show advertisements run in the last year for instance.


The query is below and the most important items are in bold. The bold sections join the advertisement status table to the report and select only items with the status time in the last 24 hours. Note that my query uses @__timezoneoffset that you’ll need in order to make this report accurate unless you live in England. I also have the links tab set to link to another report and this is the Software Distribution – Advertisement Status – Status of a specific advertisement report. The prompts for this are set to Name=AdvertID, Prompt Text=Advertisement ID, Column = 12


select adv.AdvertisementName, pkg.Name as C001, pgm.ProgramName, coll.Name as C002,
adv.PresentTime as ‘Creation Time’,
count(*) as ‘Total’,
sum(case LastState when 13 then 1 else 0 end) as ‘Success’,
 sum(case LastAcceptanceState when 0 then 1 else 0 end) as ‘No Status’,
sum(case LastState when 8 then 1 else 0 end) as ‘Waiting’,
sum(case LastState when 11 then 1 else 0 end) as ‘Fail’,
sum(case LastAcceptanceState when 2 then 1 else 0 end) as ‘Reject’,
from v_Advertisement adv
join v_Package pkg on adv.PackageID=pkg.PackageID
join v_Program pgm on adv.PackageID=pgm.PackageID and adv.ProgramName=pgm.ProgramName
join v_Collection coll on adv.CollectionID=coll.CollectionID
join v_ClientAdvertisementStatus stat on adv.AdvertisementID=stat.AdvertisementID

where DATEDIFF(hour, DATEADD(ss,@__timezoneoffset,stat.LastStatusTime),GETDATE())<24

group by adv.AdvertisementID, adv.AdvertisementName, adv.PresentTime, adv.Comment,
       pkg.Name, pgm.ProgramName, adv.SourceSite, coll.Name, adv.IncludeSubCollection,
               (CASE WHEN adv.IncludeSubCollection!=0 then ‘*’ else ” END),
 CASE WHEN AssignedScheduleEnabled != 0 or
                                      (AdvertFlags & 0x720) != 0
  THEN ‘*’
  ELSE ”
       (case when (0x00001000&ProgramFlags)!=0 then ‘*’ else ‘ ‘ end)
order by adv.PresentTime DESC