Encoding sensitive information in CustomSettings.ini and Bootstrap.ini

One of the questions I received after presenting a session at TechEd Europe was about encoding any clear-text passwords that you might place into the Bootstrap.ini file, so that if someone looked at the file they wouldn’t be able to tell what value it represented.  I suggested that it would be fairly simple to write a script that would take an encoded value, decode it, and save the decoded value to the “real” task sequence variable.  That evening, a script was written and a blog post started.

As the MDT scripts already provide everything needed to do this, the resulting scripts are pretty simple, with more comments than lines of code.  For the already-typed up scripts, see the attachment below. 

First, let’s talk about the approach.  We need to have encoded values that we can decode.  It’s easy enough to save those encoded values in task sequence variables, set via CustomSettings.ini or Bootstrap.ini.  So imagine something like this:

[Settings]
Priority=Decode, Default
Properties=EncodedUserPassword

[Decode]
EncodedUserPassword=SGVsbG8=

There’s not much to that:  I have declared a new variable called EncodedUserPassword, and set the value of that variable to “SGVsbG8=”, which is the base64-encoded equivalent of the string “Hello”.

The next step then is to decode that encoded value.  The simplest way of doing this is to use a user exit script.  The logic for that needs to do the following:

  • Look for a list of “encoded” variable names.  Because MDT already has the concept of “sensitive” variables (passwords, product keys, etc.), we can use that same list of variables as a starting point (although you could obviously add your own list).  To build the name of the “encoded” variable, we just prepend the word “Encode” to the variable as an easy-to-remember (and easy-to-script) convention.
  • For each “encoded” variable name, see if we can find a value for it.  If so, we’ll decode it and store it in the non-encoded variable.  For example, we would take “EncodedUserPassword”, if not blank, and store it in “UserPassword”.

The basic logic:

For each sVar in Array("USERID", "USERPASSWORD", "USERDOMAIN", "DOMAINADMIN", "DOMAINADMINPASSWORD", "DOMAINADMINDOMAIN", _
"ADMINPASSWORD", "BDEPIN", "TPMOWNERPASSWORD", "ADDSUSERNAME", "ADDSPASSWORD", _
"SAFEMODEADMINPASSWORD", "USERNAME", "USERPASSWORD", "PRODUCTKEY")

    ' If the encoded value exists, decode it and save it to the proper task sequence variable

    If oEnvironment.Item("Encoded" & sVar) <> "" then
oLogging.CreateEntry "Decoding variable Encoded" & sVar & " for assignment to " & sVar, LogTypeInfo
oEnvironment.Item(sVar) = oStrings.Base64Decode(oEnvironment.Item("Encoded" & sVar))
End if
Next

(Don’t try to copy and paste this, as it’s not complete and it doesn’t wrap nicely in the blog posting.  Use the already typed-up version attached below.)  The only real “magic” in this code is to use the “oStrings.Base64Decode” function, which already exists in MDT’s ZTIUtility.vbs script (as MDT actually stores these variables base64-encoded – if you think about that, you realize that we’re taking an encoded value, decoding it, then telling MDT to save it back again encoded.  Kind of silly, yes, but it does mean you won’t ever see the value in clear text.)

To use this user exit script in CustomSettings.ini, you need to copy the “DecodeExit.vbs” script into your deployment share’s “Scripts” folder, then add a reference to it in CustomSettings.ini:

[Settings]
Priority=Decode, Default
Properties=EncodedUserPassword

[Decode]
EncodedUserPassword=SGVsbG8=
UserExit=DecodeExit.vbs

OK, great, you’re all set to go now right?  Well, not really.  Look again at my example:  It’s setting the “UserPassword” variable.  That’s the password used to make a connection to the deployment share.  It really wouldn’t do any good to set that one in CustomSettings.ini.  Instead, it needs to be set in Bootstrap.ini.  Simple enough, right?  Just copy and paste the same lines into Bootstrap.ini.  Well, almost, as there is one additional challenge:  You have to get MDT to include the user exit script in the boot image, so that it’s available when the boot image is generated.  There are two ways that you could do that:

    • Create a folder somewhere that is accessible via a UNC path, e.g. \\SERVER\ExtraFiles$.  Inside of that folder, create a “Deploy” folder, and inside that, a “Scripts” folder.  Place a copy of DecodeExit.vbs in that “Scripts” folder.  Then update the deployment share properties to specify that UNC path for the “Extra directory to add” path.
    • Find the “LiteTouchPE.xml” file that defines what files MDT adds into the boot image.  Edit the file to add a new entry for DecodeExit.vbs that looks something like this:

<Copy source="%DEPLOYROOT%\Scripts\DecodeExit.vbs" dest="Deploy\Scripts\DecodeExit.vbs" />

Either approach will work.  After you make either change, you’ll need to update the deployment share to generate new boot images (then import those to WDS, generate new boot CDs, etc.).  The advantage of the first is that it will survive MDT upgrades.  The advantage of the second is that it’s easier to do and will detect script changes (e.g. if you modify the script to include more variables and then want to update the boot image again).

So how do you come up with the encoded value in the first place?  Well, if you search the internet, you’ll find lots of “base64 encoder” web pages, so you can always do that.  Or you can use the second script that I’ve attached, Encode.wsf, which leverages the matching “oStrings.Base64Encode” function from ZTIUtility.vbs.  You would run the script like so:

cscript.exe Encode.wsf /Value:”Hello"

It will display the resulting encoded value on the console, so you can then copy-and-paste into CustomSettings.ini or Bootstrap.ini.

As usual, even the simplest setup requires a lot of explanation…

DecodeExit.zip