SQL – How to Calculate Age in SQL Server

email me

A common requirement in SQL Server databases is to calculate the age of something in years.  There are several techniques for doing this depending on how accurate you want the final result to be.  This blog considers three techniques, saving the most complex, but most accurate, for last.

Using DATEDIFF to Calculate Age

Apparently, the quickest and easiest way to calculate the age of someone or something in years is to simply use the DATEDIFF function.

DATEDIFF to calculate age
A seemingly quick and obvious way to calculate age in years.

At first glance the DATEDIFF function seems to successfully calculate ages quickly and easily, but closer inspection reveals that it’s not quite as accurate as we’d like (and certainly not as accurate as Keanu Reeves would like!).  In fact, in the above list, only the last record is calculated correctly – the other three are being reported as one year older than they actually are.

The problem is that when the DATEDIFF function is told to look at years it ignores every other part of the dates involved, essentially performing the calculation shown below:

DATEDIFF with years
This is what DATEDIFF is really doing when you ask it to give you the difference between two dates in years.

 

Clearly, using DATEDIFF to calculate the difference between dates in years isn’t accurate enough for something as potentially sensitive as age.  In that case we need a different approach.

Calculating Age in Days and Dividing the Result

A more accurate, but not perfect, way to calculate age in years is to first work out the difference in days between two dates and then divide the result by the number of days in a year.  The method is shown in the example below:

Calculating age in days
Dividing the age in days by the number of days in a year gives a slightly more accurate result.  The .25 is to take into account leap years.

The last step in this type of calculation is to remove the decimal places to give the age in whole years.  To do this we can convert the answer to the INT data type.

Calculating whole years
Converting the result of the above calculation to the INT data type gives us the age in years.

Clearly this method is more accurate than using DATEDIFF with years, but we’re still not one hundred percent there.

Inaccurate age using DATEDIFF with days
Here the date range doesn’t include a leap year so we’re inaccurately reporting the age as a year younger than it should be.

 

The problem with this method is that smaller date ranges will give us a less accurate answer, as in the example shown above.  Fortunately, there’s one further method that we can use to calculate age in years correctly.

Using DATEDIFF and Correcting the Result

This is the most accurate way to calculate an age in years, but it’s also the most complex expression to write.  The starting point is to use the first calculation we demonstrated at the top of the page to calculate the difference in years between two dates:

The original DATEDIFF calculation
The original DATEDIFF calculation reports some dates as a year older than they actually are.

The next step is to incorporate the DATEADD function into the expression to add the calculated number of years to the original date:

Using DATEADD
This calculation tells us the date on which the event reaches the age shown in the third column.

The result of the above calculation is the date on which the person or thing reaches the age that the DATEDIFF function calculates.  The final step is to work out whether that date is after today’s date, and if so subtract 1 from the age that DATEDIFF calculates.  We can use the CASE statement to do this as follows:

Combining DATEDIFF and DATEADD

Restart IIS Web Services

email me

Simple script from me

Title Restart IIS Services
color 0b

@echo off
cls
echo Stopping Web Services…started
echo Starting Web Services…pending
ping -n 4 127.0.0.1>nul
net stop IISAdmin /y && EVENTCREATE /T INFORMATION /l Application /ID 777 /d “IISAdmin Services were stopped successfully” /SO EventCreate || EVENTCREATE /T INFORMATION /l Application /ID 777 /d “IISAdmin failed stop” /SO EventCreate
ping -n 4 127.0.0.1>nul
cls
echo Stopping Web Services…done
echo Starting Web Services…started
net start IISAdmin && EVENTCREATE /T INFORMATION /l Application /ID 777 /d “IISAdmin Services were started successfully” /SO EventCreate || EVENTCREATE /T INFORMATION /l Application /ID 777 /d “IISAdmin Services failed start” /SO EventCreate
ping -n 4 127.0.0.1>nul
cls
echo Stopping Web Services…done
echo Starting Web Services…done
echo exiting…
ping -n 4 127.0.0.1>nul
exit /b 0

 

More advanced script from Microsoft

@echo off
cls
echo RESTART – A restart utility for IIS web services.
echo June 1998, Microsoft Corporation.
echo ****************************************>>%SystemRoot%\restart.log
echo Stop Date/Time:>>%SystemRoot%\restart.log
echo. | date | find /i “current”>>%SystemRoot%\restart.log
echo. | time | find /i “current”>>%SystemRoot%\restart.log
echo.>>%SystemRoot%\restart.log
echo Stopping Web Services…
echo.

set MSFTPSVC=0
set NNTPSVC=0
set SMTPSVC=0
set W3SVC=0
set BROKSVC=0
set LDAPSVC=0
set MSGBLDSVC=0
set IISERROR=0

:MSFTPSVC
net start | find /i “FTP Publishing Service”>NUL
if errorlevel==1 goto NNTPSVC
set MSFTPSVC=1

:NNTPSVC
net start | find /i “Microsoft NNTP Service”>NUL
if errorlevel==1 goto SMTPSVC
set NNTPSVC=1

:SMTPSVC
net start | find /i “Microsoft SMTP Service”>NUL
if errorlevel==1 goto W3SVC
set SMTPSVC=1

:W3SVC
net start | find /i “World Wide Web Publishing Service”>NUL
if errorlevel==1 goto BROKSVC
set W3SVC=1

:BROKSVC
net start | find /i “Site Server Authentication Service”>NUL
if errorlevel==1 goto LDAPSVC
set BROKSVC=1

:LDAPSVC
net start | find /i “Site Server LDAP Service”>NUL
if errorlevel==1 goto MSGBLDSVC
set LDAPSVC=1

:MSGBLDSVC
net start | find /i “Site Server Message Builder Service”>NUL
if errorlevel==1 goto STOPIIS
set MSGBLDSVC=1

:STOPIIS
net stop iisadmin /y>>%SystemRoot%\restart.log
if errorlevel==1 goto STOPERROR
goto STOPPED

:STOPERROR
REM ********************
REM * Put any desired error-handling commands here.
REM * For example, if you have the NT Resource Kit,
REM * you could use the following command to stop
REM * IIS down the hard way:
REM * KILL.EXE INETINFO.EXE
REM ********************
set IISERROR=1

:STOPPED
REM ********************
REM * Put any desired commands to run while IIS is stopped here.
REM * For example, if you have the Windows NT Resource Kit,
REM * you could use the following command to pause
REM * the restart for one minute:
REM * SLEEP.EXE 60
REM ********************

:STARTIIS
echo ——————–>>%SystemRoot%\restart.log
echo Start Date/Time:>>%SystemRoot%\restart.log
echo. | date | find /i “current”>>%SystemRoot%\restart.log
echo. | time | find /i “current”>>%SystemRoot%\restart.log
echo.>>%SystemRoot%\restart.log
echo Starting web services…
echo.

if %W3SVC%==0 goto NOW3SVC
net start W3SVC>>%SystemRoot%\restart.log
if errorlevel==1 set IISERROR=1

:NOW3SVC
if %MSFTPSVC%==0 goto NOMSFTPSVC
net start MSFTPSVC>>%SystemRoot%\restart.log
if errorlevel==1 set IISERROR=1

:NOMSFTPSVC
if %NNTPSVC%==0 goto NONNTPSVC
net start NNTPSVC>>%SystemRoot%\restart.log
if errorlevel==1 set IISERROR=1

:NONNTPSVC
if %SMTPSVC%==0 goto NOSMTPSVC
net start SMTPSVC>>%SystemRoot%\restart.log
if errorlevel==1 set IISERROR=1

:NOSMTPSVC
if %BROKSVC%==0 goto NOBROKSVC
net start BROKSVC>>%SystemRoot%\restart.log
if errorlevel==1 set IISERROR=1

:NOBROKSVC
if %LDAPSVC%==0 goto NOLDAPSVC
net start LDAPSVC>>%SystemRoot%\restart.log
if errorlevel==1 set IISERROR=1

:NOLDAPSVC
if %LDAPSVC%==0 goto NOMSGBLDSVC
net start MSGBLDSVC>>%SystemRoot%\restart.log
if errorlevel==1 set IISERROR=1

:NOMSGBLDSVC
if %IISERROR%==0 goto EXIT

:ERROR
echo RESTART ERROR…>>%SystemRoot%\restart.log
echo One or more of the services could not be
restarted.>>%SystemRoot%\restart.log
echo Please check the Event Viewer logs for more
information.>>%SystemRoot%\restart.log

REM ********************
REM * Put any desired error-handling commands here.
REM * For example, if you have the Windows NT Resource Kit,
REM * you could use the following command to restart
REM * the server in two minutes:
REM * SHUTDOWN.EXE /L /R /T:120 /Y
REM ********************

:EXIT
set MSFTPSVC=
set NNTPSVC=
set SMTPSVC=
set W3SVC=
set BROKSVC=
set LDAPSVC=
set MSGBLDSVC=
set IISERROR=

AdobeReader.msi

email me

Version 11.0.7:

  1. Download AdbeRdr11007_*.exe
    and move it to an empty directory.
  2. Run AdbeRdr-Extract.bat
    (in the same directory).
  3. Run ApplyMSP.bat
    (in C:\AdobeReaderFiles)
  4. Typein ‘MSI‘ & press Enter.
  5. Copy contents of directory AIP.
  6. Goto section “Configure“.

Adobe offers MSI-files only for some versions, but not for all. For the other versions (the ones with minor version steps), they offer only MSP-files.

The easiest way to get the required files (MSI-file plus the required MSP-files if applicable) is to extract them from the installer file AdbeRdr*.exe.

However Adobe offers exe-installers only for the latest series (currently 11). In the series 10 they offer it for up to version 10.1.4, but not for later ones, because after that they started running series 11 in parallel.

Register

First you should register with Adobe, because otherwise you are not allowed to distribute Adobe Reader. Registration is free and takes only a few minutes. In return they will send you an URL where you can download the enterprise version (which does not try to talk you into using McAffee).

Extract from installer

Download the installer from the link that Adobe sent you after your registration, or from their ftp-server, because if you download from http://get.adobe.com/de/reader Adobe wants to include McAffee.

You might be tempted to do the extraction with 7zip, but you shouldn’t. 7zip cannot see the included MSP-files, so you’ll end up in most cases with an outdated MSI-file, and the MSP-file(s) required to do the update is/are missing.

The extraction must be done with a command like
AdbeRdr11002_en_US.exe -nos_oC:\AdobeReaderFiles -nos_ne
If you do not like typing complicated commands, you can instead copy the installer.exe to an empty directory, dowload my script AdbeRdr-Extract.bat and copy it into the same directory, then double-click the script. It will detect the filename of the installer.exe in the same directory, and then issue the above command with the correct filename.

The extracted files will be saved in the newly created directory C:\AdobeReaderFiles. It will contain one MSI-file, one file named data1.cab, plus in most cases one or more MSP-files, plus some other files like setup.exe that are not needed for deployment with GPO.

If there are MSP-files, then the included MSI-file and data1.cab are outdated, and you must apply the patches from the MSP-files to get the latest version. If you want to deploy using GPO, you must slipstream them, see below. In the example from above (version 11.0.2) you get two MSP-files: AdbeRdrUpd11001.msp and AdbeRdrSecUpd11002.msp. They must be applied one after the other, in the correct order, according to the version numbers in the filenames.

Or try to find the right downloads

Alternatively the available MSI-files can be downloaded from Adobes ftp-server, and for the MSP-files go to the web-page Downloads and scroll down to Updates, or look on the ftp-server in the directory that has the name ‘misc’ instead of the language code. If the FTP-server offers several MSP-files for the version that you want, each one is for a different group of languages. They are using codes in the filenames like TIER and MUI to specify that. That’s described for older versions here. The TIERs for Adobe Reader 10 are described here (redirects to here). For more info about their language codes they refer to their ‘Enterprise Administration Guide’, see below.

The regular quarterly MSP-files for Adobe Reader are cumulative, i.e. you need to apply only the latest one. But emergency patches are incremental. Thus if Adobe has published emergency patches after the last regular update, you must apply the latest cumulative update, and then all emergency updates that came after it. Thus for version 10.1.6 (an emergency update) you must apply AdbeRdrSecUpd1016.msp to the AIP of version 10.1.5. Version 10.1.5 was a regular update, so you only need the MSP-file for 10.1.5 and must apply it directly to the MSI-file of 10.1.0. The versions inbetween are not required. The link on Adobes download page leads to info which version is required to apply the patch. Also Adobe spells the rule out here for version 7 to 9 and separately for version 10. The release notes tell which update was planned, and which was not.

Slipstream MSP-files

The MSP-files cannot directly be deployed via GPO to patch already existing installations. Instead the MSI-file must be extracted to an AIP-directory, and then the MSP-file must slipstreamed into that, to get an updated AIP. This new AIP-directory can then be deployed like an MSI-file.

My MSP-description offers a script that automates the slipstreaming. Please note that the extraction from the installer.exe as described above is not an AIP, so you must typein MSI when my script asks its question. If there is more than one MSP-file to slipstream, make sure to always have only one of them in the directory when you call the script. Also only the first MSP is applied to the MSI, which creates an AIP. If there is more than one MSP to be applied, all others ones must all be applied to that AIP, one at a time. To do this, copy the script into the AIP directory, and typein AIP when the script asks its question.

Slipstreaming MSP-files of Adobe Reader does not always succeed. In my experience it only works reliably on a PC on which Adobe Reader is not installed, ideally a PC where it has never been installed. Also it requires admin rights, otherwise it aborts with strange error messages.

Configure

For most configuration changes you need the customization wizard. The wizard is version specific. For any Adobe Reader version 10.x.x you need the Wizard 10, for versions 11.x.x you need Wizard version 11.

There you can disable all updates. I also set the option “Display PDF in browser” to disabled, but it still displays PDFs in Firefox. Probably this option affects only Internet Explorer.

The wizard creates a MST-file that you can deploy as modification to the MSI-file or AIP. You can either tell the wizard to write an MST-file, or just quit and it will ask to save changes to the MSI. Even in this case it will also write an MST-file, it will be in the same directory as the MSI-file.

The Wizard version 11.0.0 has a bug (fixed in version 11.0.3): Every time you change anything, the property REMOVE_PREVIOUS changes by itself from YES to NO, even if you do not touch the corresponding Install-Option “Remove all versions of reader”. You can edit again, load the bad transform, and put the missing checkmark back into the box. Now it’s correct. But if you later make another change, the same error will happen again. So you must always edit twice: first for your desired changes, then to re-enable this option. Another possibility is to edit the MSI plus the MST in Orca and restore REMOVE_PREVIOUS to YES there.

Note that this uninstall-option is important, because when upgrading via GPO from version 10 to 11, the default install method autodetected by the server is update, not replace. Thus if you accept the default GPO-setting, and loose the MSI-property because of this bug, then the old version will remain installed.

Other options

In the MSI-file the options ARPNOREMOVE and ARPNOMODIFY are not set, ARPNOREPAIR is set to 1. I usually set ARPNOREMOVE and ARPNOMODIFY to 1. Repair can be triggered in the help menu of AdobeReader, even if it is disabled in the MSI-file and does not show up in appwiz.cpl.

GPO templates

Adobe announced that version 11 has “GPO Template for the most common enterprise settings”.

Details can be found here:
http://www.404techsupport.com/2012/10/adobe-reader-11-has-landed-with-gpo-adm-templates/
http://www.grouppolicy.biz/2012/10/how-to-configure-group-policy-for-adobe-reader-xi/

More info

Adobe used to offer PDF-Documents with descriptions how to deploy Adobe Reader. The document for version 9 is still available here. The document for version 10 used to be here (and they still link to that location on the bottom of their page Reader Development Center), but this now redirects to the new web-based Enterprise Administration Guide, which is part of the Enterprise Toolkit, but this seems to be only for version 11. A pdf-file for versions 9, 10, and 11 can be found here.

A lot more info is on http://www.grouppolicy.biz/tag/adobe-reader/

 

How to create a self-extracting archive or installer in Linux

While a typical archive file relies on a separate program (e.g., tar, gunzip) to extract content from the archive file, a self-extracting (SFX) archive is an executable itself, and can self-extract its content simply upon running. A self-extracting installer does the same thing, but it also copies the extracted content to appropriate directories.

In this tutorial, I will explain how to create a self-extracting archive or installer on Linux.

For this purpose, you can use a command-line utility called makeself. The makeself tool is a shell script which creates a compressed TAR archive out of input directories/files, and adds a small shell script stub at the beginning of the archive to initiate self-extraction, and guide installation of extracted files.

To install makeself on Linux, download the latest version in an archive format, and extract the downloaded archive as follows. Once the archive has extracted itself, it will create a new directory called makeself-2.1.5. Copy all the shell scripts in the directory to /usr/bin.

$ wget http://megastep.org/makeself/makeself-2.1.5.run
$ chmod 755 makeself-2.1.5.run
$ ./makeself-2.1.5.run
$ cd makeself-2.1.5
$ sudo cp *.sh /usr/bin

 

The basic usage of makeself.sh is as follows.

makeself.sh [options] [directory_to_package] [sfx_archive_filename] [label] [startup_script] [optional_script_args]

The “label” argument is the message to print while an SFX archive is uncompressed.

The “startup_script” argument specifies the script/command to launch after an SFX archive is successfully extracted. This is useful when you create a self-extracting installer. Typically a start-up script will copy/install the extracted content to appropriate target directories. The start-up script must be located inside the directory to package, so that the script is included in the SFX archive.

Here are some of available options for makeself.sh:

  • –gzip : Use gzip for compression (default option).
  • –bzip2 : Use bzip2 for compression.
  • –nocomp : Do not compress.
  • –notemp : Do not extract files into a temporary directory, but in a new sub-directory created in the current directory.
  • –follow : Follow all symbolic links, and archive files that are symbolic-linked.

Create a Self-Extracting Archive

To create a self-extracting archive which contains all files inside ./backup directory, do the following. Here the start-up routine does nothing more than printing “Extraction done”.

$ makeself.sh –notemp ./backup ./backup.run “SFX archive for backup” echo “Extraction done”
Header is 403 lines long

About to compress 1540 KB of data...
Adding files to archive named "./backup.run"...
./
./jpeg/
./jpeg/1.jpg
.
.
CRC: 2238411397
MD5: 0b0fd3a2ba08ffcec821b9cbaa11b70d

Self-extractible archive "./backup.run" successfully created.

To extract files from the archive, simply execute the archive:

$ ./backup.run
Creating directory backup
Verifying archive integrity... All good.
Uncompressing SFX archive for backup.............
Done

Create a Self-Extracting Installer

If you want to create a self-extracting installer, you need to prepare a separate start-up script which will do the installation upon file extraction. Here I assume that the program directory to package is located at ./program. So prepare a start-up script inside ./program directory.

$ vi ./program/install.sh
#!/bin/sh
   
if [ -d $HOME/bin ]
then
    cp myprogram $HOME/bin/
fi

Then make the start-up script executable.

$ chmod 755 ./program/install.sh

 

Go ahead and create a self-extracting installer, and package the start-up script along with it as follows.

$ makeself.sh ./program ./program.run “SFX installer for program” ./install.sh

email me

VBScript – Batch – SCCM – Loading User’s Registry Hive

email me

This is a code snippet for loading each user’s profile on a workstation. Note, objSubKey is the returned user SID and strUser is the returned username. This can be extremely useful if you have computers with multiple user profiles that need modifications made to their registry hives…in a scripted, enterprise deployment.

VBScript

'LOAD REGISTRY HIVE - THIS IS UNTESTED
objShell.Run "%comspec% /c REG.exe LOAD HKU\" & objSubkey & " " & "C:\Users\" & strUser & "\NTUSER.DAT",0,true

'ADD YOUR KEYS HERE
objShell.Run "%comspec% /c REG.exe DELETE " & chr(34) & "HKEY_USERS\" & objSubkey & "\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range1" & chr(34) & " /f",0,true

objShell.Run "%comspec% /c REG.exe DELETE " & chr(34) & "HKEY_USERS\" & objSubkey & "\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges" & chr(34) & " /f",0,true

'TIMING
WScript.Sleep 2000

'UNLOAD HIVE KEY
objShell.Run "%comspec% /c REG.exe UNLOAD HKU\" & objSubkey,0,true

 

This is how you would do something similar, but inside an SCCM Task Sequence. I load the Default user profile, add some reg keys, and then unload the profile.

Each command will be in a Run Command Line item.

Batch Commands for SCCM Task Sequence

cmd /c REG LOAD HKLM\DEFAULT c:\users\default\ntuser.dat

cmd /c REG ADD “HKLM\DEFAULT\SOFTWARE\Policies\Microsoft\Office\16.0\Common\General” /v “OptInDisable” /t REG_DWORD /d 1 /f /REG:64

cmd /c REG ADD “HKLM\DEFAULT\SOFTWARE\Policies\Microsoft\Office\16.0\Registration” /v “AcceptAllEulas” /t REG_DWORD /d 1 /f /REG:64

cmd /c REG ADD “HKLM\DEFAULT\Software\Citrix\Receiver” /v “HideAddAccountOnRestart” /t REG_DWORD /d 1 /f /REG:64

cmd /c REG ADD “HKLM\DEFAULT\Software\Microsoft\Windows NT\CurrentVersion\Windows” /v “LegacyDefaultPrinterMode” /t REG_DWORD /d 1 /f /REG:64

cmd /c REG UNLOAD HKLM\DEFAULT

Your account has expired. Please see your system administrator.

Your account has expired. Please see your system administrator.
* Note, this is the computer account.

The security database on the server does not have a computer account for this workstation trust relationship.

 
From Microsoft

Log on locally as a local administrator. In the Network tool of Control Panel, select Change and enter a Workgroup name, leaving the domain. Restart the computer and log on locally as a local administrator.There are two methods to rejoin the domain:

  • You can join the domain from the client if at the same time you can provide an administrator username and password on the domain.-or-
  • You can delete the existing computer account in Server Manager, recreate the computer account, synchronize the domain, and then on the client rejoin the domain.

 

These are the possible causes of the account expired

01 – Date/Time is set incorrectly
02 – Missing domain suffix – possibly from a failed GPO or DHCP server
03 – SPN may not be updating correctly
04 – Duplicate SPN on the DC – http://technet.microsoft.com/en-us/library/cc733945(WS.10).aspx
04 – Computer Account conflict/corrupted – disjoin/rejoin
05 – There is a user domainName\MachineName in the local administrators, remove it from the administrators group
06 – A Windows update failed

* Simplest fixes: check time and/or disjoin/rejoin machine to domain 

 

Try this out on the Domain Controller:

From a DC/AD server

ldifde -f C:\SPNs.txt -t 3268 -d dc=domain,dc=com -l serviceprincipalname -r (serviceprincipalname=*) -p subtree

In the above command, replace DC=domain,DC=com with the DN of the domain. To check if duplicate SPN is present.

The issue could be a duplicate HOST or entry for the server found in a service account

OR

A) Start > Run > ADSIEDIT.MSC

B) Go to Domain Partition and mark the affected computer

C) Rightclick and Properties.

D) Doubleclick ServicePrincipalName

E) Add new value: HOST/yourcomputername.yourdomain.xyz or whatever HOST is missing.

 

Reference

http://social.technet.microsoft.com/Forums/windows/en-US/31905c1a-5c25-4426-ac8d-677004c21f5d/the-security-database-on-the-server-does-not-have-a-computer-account-for-this-workstation-trust?forum=itprovistanetworking

http://technet.microsoft.com/en-us/library/cc957199.aspx

http://virtualcurtis.wordpress.com/2011/03/02/fix-the-security-database-on-the-server-does-not-have-a-computer-account-for-this-workstation-trust-relationship/

http://social.technet.microsoft.com/Forums/windowsserver/en-US/eb0b6761-d468-4dc1-a90a-451ae78d409b/the-security-database-on-the-server-does-not-have-a-computer-account-for-this-workstation-trust?forum=winserverDS

http://technet.microsoft.com/en-us/library/ee849847(v=ws.10).aspx

 

email me

10 Things you don’t want to know about BitLocker

I have an article here for you to review. It’s a guy who has had an overall negative experience with BitLocker, and…he lets us have it! 🙂

Many of this his complaints can be resolved with 5 minutes of proper training, and by managing the BitLocker keys through Active Directory.

One major flaw in his thinking is that he believes his “work” computer and “work-related” data belong to him; they do not.. Work machines and work-related data belong to the company you work for.

BitLocker is so easy, even a caveman can do it. Not to mention, it’s nearly free to implement, with a lower TCO than most other enterprise-based encryption software.

 

by Simon Hunt – August 28, 2009

So, with the forthcoming release of Windows 7, the ugly beast known as “Bitlocker” has reared its head again.

For those of you who were around during the original release of Bitlocker, or as it was known then “Secure Startup”, you’ll remember that it was meant to completely eliminate the necessity for third party security software. Yes, Bitlocker was going to secure our machines against all forms of attack and make sure we never lost data again.

What happened?

Bitlocker was/is actually pretty good – it’s nicely integrated into Vista, it does its job well, and is really simple to operate. As it was designed to “protect the integrity of the operating system”, most who use it implemented it in “TPM Mode”, where no user involvement is required to boot the machine..

And that’s where problems started.

Hands up how many people have a TPM chip on their laptop?

Everyone I bet – it’s a ubiquitous piece of hardware nowadays. Ok, another show of hands please for those who’ve enabled, and taken ownership of the chip? “Taken ownership?” – yes, you remember going through the personalization phase of the chip, enabling it in the BIOS etc? Remember, all TPM’s are shipped disabled and deactivated.

What? You didn’t go through that yet? You didn’t do that before you deployed your laptops? Oh well, Bitlocker’s going to be a bit of a struggle for you isn’t it?

Fact 1. To use Bitlocker without adding additional authentication, you need an enabled, owned TPM1.2+ hardware chip.

Ok, For those of you who did go through this I congratulate your foresight. The only problem of course is:

Fact 2. Bitlocker with TPM-Only protection is vulnerable to Cold Boot, Firewire and BIOS Keyboard Buffer attacks.

Damn! Sorry to tell you this but there are some pretty simple attacks on your TPM-only machines – Do a google search for “Bitlocker Firewire” or “Bitlocker Cold Boot” or”BIOS keyboard” and you’ll find lots of research, and even a few tools which will unlock your nice “protected” machine and recover the data.

To make a machine secure, and by that I mean give you protection against having to disclose loss of personal information to all your customers if the machine goes missing, you need to use some form of pre-windows authentication (with or without TPM as well – it makes no difference). Microsoft themselves recommend this mode of operation.

For Bitlocker, turning on authentication gives you a couple of choices, you can set a pin for the machine, and also if you want, you can use a USB storage device (a memory stick, NOT a smart card) as a token. Yes, I did say a pin, and I certainly did not say “your Windows user ID and password” In fact I didn’t mention users at all. Bitlocker officially supports ONE login, so if more than one person uses a machine, you’re going to have to share that with everyone.

I feel some facts coming on…

Fact 3. Bitlocker is only secure if you use a pin or USBstick for authentication

Fact 4. There’s no link between your Windows credentials and Bitlocker Credentials

Fact 5. Bitlocker does not support the concept of more than one user

Even Microsoft’s official advice tells you to use a 6+char pin, plus TPM for authentication – no using it in TPM only mode now!

Ok, so now your lucky Bitlocker users have pc’s protected, maybe with a TPM, but certainly with some form of authentication which is shared between the owner of the machine, and probably you (as administrator), and the system guys etc. Hey – you probably have an excel spreadsheet with everyone’s pin’s written down?

I hope so, because when those users start forgetting their pins, who’s at the end of the phone? The good news is the pin never changes – there’s no forced change or lifetime.

What do you mean, that doesn’t fit with your password policy? Did I mention yet that the PIN can only be made from the Fn keys, not the normal letter keys unless you configure a special “Enhanced Pin” mode which does not work on non-USA keyboards? Did I mention there’s no complexity or content rules apart from Length?

Fact 6. Bitlocker PIN’s are usually FN key based. Bitlocker does not support non-US Keyboards

Hands up again all of you who’ve implemented PKI smart cards, or bought laptops with fingerprint sensors, or who have tokens such as ActivIdentity, CAC, PIV, eToken Keys, DataKey cards, SafeNet cards etc? You’d like to be able to use them for authentication to your PC’s wouldn’t you?

Fact 7. Bitlocker only supports USB STORAGE devices and PINs – no integration with any other token

And of course, you want users to be able to reset these credentials when they forget them without calling you, or your overworked, understaffed helpdesk? Sorry. No can do.

Fact 8. There’s no built in self-service pin recovery for Bitlocker users

There are Active Directory based methods, the GPO settings will let you store the (fixed) recovery key in your AD. I’m not sure how you feel about that getting propagated to every controller in your forest, but I’m sure you know and trust EVERY AD administrator in your organization who (now) have access to those keys. I mean, if someone was to dump out those keys and then quit, what would you do? It’s not as if the key ever expires. I guess you could write a program and then run it on every machine to recreate the keys, or write the recovery key down and give it to the user to hold on to?

Going back a bit, let’s review why we are going through this effort in the first place. I know the flippant answer is “because we were told to secure our machines”, but what does that mean? Most likely your company falls under one of the 250+ global laws defining and mandating the protection of peoples personal data, social security numbers, health information, credit card numbers etc. Regulations such as PCI, HIPPA, HITECH, SOX etc. You’re wanting to use Bitlocker to encrypt your machines because then, WHEN they get lost or stolen, you won’t have to pay fines, or tell everyone you lost their data, because to be honest, you didn’t did you? You lost the machine sure, but as the data was encrypted, no one can get access to it.

To use this “get out of jail” card you need to be able to prove a couple of things:

  1. That the data was indeed protected at time of loss
  2. That the protection method was appropriate given the type of data.

So, applying those tests, a rule appears.

Fact 9. You need extra software to PROVE Bitlocker was enabled and protecting the drive at time of theft to claim protection from PII laws

Personally, I know how to set GPO’s etc to mandate the use of Bitlocker, but I also know how easy it is for a user to turn it off. I don’t know of anything in Active Directory which gives me a definitive answer as to the state of protection of a given machine. There’s even a command line tool which can be run to completely (un)configure it. We need something that reports on the state of protection of a lost machine – just saying “well,. the policy says it should be encrypted” is not enough. Perhaps a reader can help out?

Ok, let’s finally take a look at implementing this solution. Now, you do have a 100% Vista Ultimate / Windows7 Enterprise environment don’t you? What? You still have some XP and Vista Business out there? Are you going to leave those machines unprotected, or are you planning to run a mix of third party software and Bitlocker?

Fact 10. Bitlocker only supports Windows7 Ultimate/Enterprise and Vista Ultimate.

It may come across that I’m not a great fan of Bitlocker – that’s far from the truth. I would use it (personally), and would recommend it to my friends etc. I see it as REALLY good for technical, trustworthy end users. But, that’s not the market it’s being promoted for is it? Nothing fills me with dread more than an enterprise product which requires yet another password, require specific hardware which is not enabled by default, presents a black screen with white text to users (urgh! So archaic), does not conform to our recognized password/pin lifetime policies, does not work on non-USA machines, and does not have audit-friendly output for the main purpose it serves, i.e. tell me if this stolen machine is a liabiltiy or not. Come on now – it’s 2009! Don’t we deserve better?

I actually like it because of the following 10 reasons:

  1. Only 1 of the 3 machines I use has a USA keyboard, so I can use FN mode Pins
  2. It never forces me to change my Pin
  3. I can turn it on and off whenever I like without my corporate IT people knowing.
  4. I get to use the TPM chip, even though it took me a whole day to work out how to enable it
  5. I can write fancy scripts to turn it on and off (I’m a closet programmer)
  6. I get a nice dos-like screen when I turn my machine on, just like 20 years ago
  7. Bitlocker is mostly controlled through a command line script (manage-bde)
  8. My local IT team can’t come and use my machine, or see what’s stored on it without me knowing
  9. I know that no one will be able to recover my data if I leave McAfee
  10. I just like things to be done the hard way

email me

Dell BIOS Failed Upgrade – Computer Won’t Load – Bricked Machine

In the case the BIOS fails an upgrade process, here is how you perform a low-level restore/repair.

The Steps

00 – Download the previous BIOS version or known working BIOS version.

01 – Use a USB flash drive (Sandisk 4GB flash worked) and format it with FAT default.

02 – Copy a single E430026.hdr file to the USB flash drive. Extracted and renamed from Dell E4300A26.exe (the bios update) by Start->Run->CMD, type e4300a26.exe /writehdrfile

03 – Remove the battery pack and plug in the USB flash.

04 – Hold the END key while you plug in the AC adapter.

05 – The battery LED will show orange.

06 – Release the END key immediately upon seeing orange color.

07 – After a couple of seconds, PC will start reading flash.

08 – You will see the battery LED flashes orange and blue (never RED), for about a minute or two, then the machine will reboot.

You’re done!

 

Misc Info

Tools for BIOS

phoenixtool.exe

http://www.box.net/shared/9yif6rf96u – BIOS sections and extract modules & unpack modules

https://app.box.com/shared/0orjdypm0l – Uncompressor

https://app.box.com/shared/q9v0gt3c34  – recompressed to exact size of marker 2.0

 

Uncompression algorithm code samples

Code:
Code from d610_a06.hdr
; ds = in seg, si = 0
; es = out seg, di = 0
; dx = compressed size
000045C3: 6603D6                        6add         edx,esi
000045C6: 6633C9                        Dxor         ecx,ecx
000045C9: 663BF2                         cmp         esi,edx
000045CC: 736F                           jnc         00000463D --↓9
000045CE: 67AC                           lodsb
000045D0: A80F                           test        al,00F
000045D2: 752B                           jnz         0000045FF --↓A
000045D4: 3CE0                           cmp         al,0E0 ;'р'
000045D6: 7418                           jz          0000045F0 --↓B
000045D8: 3CF0                           cmp         al,0F0 ;'Ё'
000045DA: 740B                           jz          0000045E7 --↓C
000045DC: C0E804                         shr         al,4
000045DF: 8AC8                           mov         cl,al
000045E1: 41                             inc         cx
000045E2: F367A4                        Erep movsb
000045E5: EBDF                           jmps        0000045C6 --↑D
000045E7: 67AC                          Clodsb
000045E9: 8AC8                           mov         cl,al
000045EB: 83C10F                         add         cx,00F
000045EE: EBF2                           jmps        0000045E2 --↑E
000045F0: 67AC                          Blodsb
000045F2: 8AC8                           mov         cl,al
000045F4: 41                             inc         cx
000045F5: 26678A47FF                     mov         al,es:[edi][-1]
000045FA: F367AA                         rep stosb
000045FD: EBC7                           jmps        0000045C6 --↑D
000045FF: 8AC8                          Amov         cl,al
00004601: 80E10F                         and         cl,00F
00004604: 80F90F                         cmp         cl,00F
00004607: 7421                           jz          00000462A --↓7
00004609: FEC1                           inc         cl
0000460B: 2AE4                           sub         ah,ah
0000460D: C1E004                         shl         ax,4
00004610: 67AC                           lodsb
00004612: 668BDE                        Fmov         ebx,esi
00004615: 668BF7                         mov         esi,edi
00004618: 660FB7C0                       movzx       eax,ax
0000461C: 662BF0                         sub         esi,eax
0000461F: 664E                           dec         esi
00004621: F32667A4                       rep movsb
00004625: 668BF3                         mov         esi,ebx
00004628: EB9C                           jmps        0000045C6 --↑D
0000462A: 8AC8                          7mov         cl,al
0000462C: 67AD                           lodsw
0000462E: 8AEC                          8mov         ch,ah
00004630: C1E904                         shr         cx,4
00004633: 83E13F                         and         cx,03F ;'?'
00004636: 41                             inc         cx
00004637: 41                             inc         cx
00004638: C0EC02                         shr         ah,2
0000463B: EBD5                           jmps        000004612 --↑F
0000463D: C3                            9retn
Code:
And one more from D4600A12.hdr (quite older version)
; ds:si -> start of chain type A
; es:si -> where to store uncompressed module
; bl = module type to find and uncompress
0006C712: FC                             cld
0006C713: 8BC6                          5mov         ax,si
0006C715: C1E804                         shr         ax,4
0006C718: 8CDA                           mov         dx,ds
0006C71A: 03D0                           add         dx,ax
0006C71C: 8EDA                           mov         ds,dx
0006C71E: 83E60F                         and         si,00F
0006C721: AD                             lodsw
0006C722: 8BD0                           mov         dx,ax
0006C724: AC                             lodsb
0006C725: 3AC3                           cmp         al,bl
0006C727: 7404                           jz          00006C72D --↓4
0006C729: 03F2                           add         si,dx
0006C72B: EBE6                           jmps        00006C713 --↑5
0006C72D: 03D6                          4add         dx,si
0006C72F: 2AED                           sub         ch,ch
0006C731: 3BF2                          9cmp         si,dx
0006C733: 7356                           jnc         00006C78B --↓6
0006C735: AC                             lodsb
0006C736: A80F                           test        al,00F
0006C738: 7521                           jnz         00006C75B --↓7
0006C73A: 3CE0                           cmp         al,0E0 ;'р'
0006C73C: 730A                           jnc         00006C748 --↓8
0006C73E: C0E804                         shr         al,4
0006C741: 8AC8                           mov         cl,al
0006C743: 41                             inc         cx
0006C744: F3A4                          Brep movsb
0006C746: EBE9                           jmps        00006C731 --↑9
0006C748: AC                            8lodsb
0006C749: 8AC8                           mov         cl,al
0006C74B: 7405                           jz          00006C752 --↓A
0006C74D: 83C10F                         add         cx,00F
0006C750: EBF2                           jmps        00006C744 --↑B
0006C752: 41                            Ainc         cx
0006C753: 268A45FF                       mov         al

email me

7Zip with Password

This is how you add a password to any file(s) using 7Zip.

Can be used in a script or via the command line.

This would add all Microsoft Word docs to an archive named TestArchive.z with the password of SECRET

7z.exe a TestArchive.7z *.docx -pSECRET

email me

Return Installed Product with GUIDs

This script is pretty useful if you need to do things with product guids. I recommend using cscript script.vbs>text.txt to output list to a text file…and then read that text file.

email me

on error resume next

Const msiInstallStateNotUsed = -7
Const msiInstallStateBadConfig = -6
Const msiInstallStateIncomplete = -5
Const msiInstallStateSourceAbsent = -4
Const msiInstallStateInvalidArg = -2
Const msiInstallStateUnknown = -1
Const msiInstallStateBroken = 0
Const msiInstallStateAdvertised = 1
Const msiInstallStateRemoved = 1
Const msiInstallStateAbsent = 2
Const msiInstallStateLocal = 3
Const msiInstallStateSource = 4
Const msiInstallStateDefault = 5

‘ Connect to Windows Installer object
On Error Resume Next
Dim installer : Set installer = Nothing
Set installer = Wscript.CreateObject(“WindowsInstaller.Installer”) : CheckError

‘ If no arguments supplied, then list all installed or advertised products
Dim argCount:argCount = Wscript.Arguments.Count
If (argCount = 0) Then
Dim product, products, info, productList, version
On Error Resume Next
Set products = installer.Products : CheckError
For Each product In products
version = DecodeVersion(installer.ProductInfo(product, “Version”)) : CheckError
info = product & ” = ” & installer.ProductInfo(product, “ProductName”) & ” ” & version : CheckError
If productList <> Empty Then productList = productList & vbNewLine & info Else productList = info
Next
If productList = Empty Then productList = “No products installed or advertised”
Wscript.Echo productList
Set products = Nothing
Wscript.Quit 0
End If

‘ Check for ?, and show help message if found
Dim productName:productName = Wscript.Arguments(0)
If InStr(1, productName, “?”, vbTextCompare) > 0 Then
Wscript.Echo “Windows Installer utility to list registered products and product information” &_
vbNewLine & ” Lists all installed and advertised products if no arguments are specified” &_
vbNewLine & ” Else 1st argument is a product name (case-insensitive) or product ID (GUID)” &_
vbNewLine & ” If 2nd argument is missing or contains ‘p’, then product properties are listed” &_
vbNewLine & ” If 2nd argument contains ‘f’, features, parents, & installed states are listed” &_
vbNewLine & ” If 2nd argument contains ‘c’, installed components for that product are listed” &_
vbNewLine & ” If 2nd argument contains ‘d’, HKLM “”SharedDlls”” count for key files are listed” &_
vbNewLine &_
vbNewLine & “Copyright (C) Microsoft Corporation. All rights reserved.”
Wscript.Quit 1
End If

‘ If Product name supplied, need to search for product code
Dim productCode, property, value, message
If Left(productName, 1) = “{” And Right(productName, 1) = “}” Then
If installer.ProductState(productName) <> msiInstallStateUnknown Then productCode = UCase(productName)
Else
For Each productCode In installer.Products : CheckError
If LCase(installer.ProductInfo(productCode, “ProductName”)) = LCase(productName) Then Exit For
Next
End If
If IsEmpty(productCode) Then Wscript.Echo “Product is not registered: ” & productName : Wscript.Quit 2

‘ Check option argument for type of information to display, default is properties
Dim optionFlag : If argcount > 1 Then optionFlag = LCase(Wscript.Arguments(1)) Else optionFlag = “p”
If InStr(1, optionFlag, “*”, vbTextCompare) > 0 Then optionFlag = “pfcd”

If InStr(1, optionFlag, “p”, vbTextCompare) > 0 Then
message = “ProductCode = ” & productCode
For Each property In Array(_
“Language”,_
“ProductName”,_
“PackageCode”,_
“Transforms”,_
“AssignmentType”,_
“PackageName”,_
“InstalledProductName”,_
“VersionString”,_
“RegCompany”,_
“RegOwner”,_
“ProductID”,_
“ProductIcon”,_
“InstallLocation”,_
“InstallSource”,_
“InstallDate”,_
“Publisher”,_
“LocalPackage”,_
“HelpLink”,_
“HelpTelephone”,_
“URLInfoAbout”,_
“URLUpdateInfo”) : CheckError
value = installer.ProductInfo(productCode, property) ‘: CheckError
If Err <> 0 Then Err.Clear : value = Empty
If (property = “Version”) Then value = DecodeVersion(value)
If value <> Empty Then message = message & vbNewLine & property & ” = ” & value
Next
Wscript.Echo message
End If

If InStr(1, optionFlag, “f”, vbTextCompare) > 0 Then
Dim feature, features, parent, state, featureInfo
Set features = installer.Features(productCode)
message = “—Features in product ” & productCode & “—”
For Each feature In features
parent = installer.FeatureParent(productCode, feature) : CheckError
If Len(parent) Then parent = ” {” & parent & “}”
state = installer.FeatureState(productCode, feature)
Select Case(state)
Case msiInstallStateBadConfig: state = “Corrupt”
Case msiInstallStateIncomplete: state = “InProgress”
Case msiInstallStateSourceAbsent: state = “SourceAbsent”
Case msiInstallStateBroken: state = “Broken”
Case msiInstallStateAdvertised: state = “Advertised”
Case msiInstallStateAbsent: state = “Uninstalled”
Case msiInstallStateLocal: state = “Local”
Case msiInstallStateSource: state = “Source”
Case msiInstallStateDefault: state = “Default”
Case Else: state = “Unknown”
End Select
message = message & vbNewLine & feature & parent & ” = ” & state
Next
Set features = Nothing
Wscript.Echo message
End If

If InStr(1, optionFlag, “c”, vbTextCompare) > 0 Then
Dim component, components, client, clients, path
Set components = installer.Components : CheckError
message = “—Components in product ” & productCode & “—”
For Each component In components
Set clients = installer.ComponentClients(component) : CheckError
For Each client In Clients
If client = productCode Then
path = installer.ComponentPath(productCode, component) : CheckError
message = message & vbNewLine & component & ” = ” & path
Exit For
End If
Next
Set clients = Nothing
Next
Set components = Nothing
Wscript.Echo message
End If

If InStr(1, optionFlag, “d”, vbTextCompare) > 0 Then
Set components = installer.Components : CheckError
message = “—Shared DLL counts for key files of ” & productCode & “—”
For Each component In components
Set clients = installer.ComponentClients(component) : CheckError
For Each client In Clients
If client = productCode Then
path = installer.ComponentPath(productCode, component) : CheckError
If Len(path) = 0 Then path = “0”
If AscW(path) >= 65 Then ‘ ignore registry key paths
value = installer.RegistryValue(2, “SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDlls”, path)
If Err <> 0 Then value = 0 : Err.Clear
message = message & vbNewLine & value & ” = ” & path
End If
Exit For
End If
Next
Set clients = Nothing
Next
Set components = Nothing
Wscript.Echo message
End If

Function DecodeVersion(version)
version = CLng(version)
DecodeVersion = version\65536\256 & “.” & (version\65535 MOD 256) & “.” & (version Mod 65536)
End Function

Sub CheckError
Dim message, errRec
If Err = 0 Then Exit Sub
message = Err.Source & ” ” & Hex(Err) & “: ” & Err.Description
If Not installer Is Nothing Then
Set errRec = installer.LastErrorRecord
If Not errRec Is Nothing Then message = message & vbNewLine & errRec.FormatText
End If
Wscript.Echo message
Wscript.Quit 2
End Sub


Created by Eddie Jackson | 1994-2024