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

Comments (30)
  1. Anonymous says:

    Powershelly! Some of this is copy pasted from others including Michael 🙂 :

    #function borrowed from
    gallery.technet.microsoft.com/…/Powershell-script-to-33887eb2

    function ConvertFrom-Base64($stringfrom) {

      $bytesfrom  = [System.Convert]::FromBase64String($stringfrom);

      $decodedfrom = [System.Text.Encoding]::UTF8.GetString($bytesfrom);

       return $decodedfrom  

    }

    # Grab the variables from the Task Sequence

    $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment

    $tsenv.GetVariables() | % { Set-Variable -Name "$_" -Value "$($tsenv.Value($_))" }

    #Set Credentials to Task Sequence variable values

    $ClearID = ConvertFrom-Base64 -stringfrom "$UserID"

    $ClearDomain = ConvertFrom-Base64 -stringfrom "$UserDomain"

    $ClearPW = ConvertFrom-Base64 -stringfrom "$UserPassword"

    $User = "$ClearDomain$ClearID"

    $Password = ConvertTo-SecureString -String "$ClearPW" -AsPlainText -Force

    $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Password

  2. Anonymous says:

    The problem with certs is that they secure the data, but who secures the cert?  Regardless, you can use the same type of user exit to implement any type of encoding or encrypting.  I just used a simple base64 encoding (which we always refer to as "obfuscation", not "encryption" or security of any kind) because it's simple and doesn't trick you into thinking this is somehow secure.

  3. DHLao says:

    My mistake. I should modify the "LiteTouchPE.xml" inside "C:Program FilesMicrosoft Deployment ToolkitTemplates" instead of the 1 inside "DeploymentShareBoot"
    It works.

  4. DHLao says:

    I don’t understand how to "include the user exit script in the boot image".
    First, I don’t know how to use method 1
    Second, method 2 say need to modify "LiteTouchPE.xml". But the problem is this file will regenerate every time I update the deployment share. The new add line will not exist anymore.

  5. Mike W. says:

    Great post!

  6. Alexey Semibratov says:

    Good job, but still – it's security through obscurity… We could get real encryption with certs implemented…

  7. YPae says:

    Thanks Michael, you finally came up with the solution. It will be even better if you include it as part of MDT 2012 Update 1!

    To me, even though it is not 100% secured solution but it is way better than clear-text value for sure!

  8. GL says:

    Nice job..it would be better if it is part of the GUI.

  9. Andrés Villalobos says:

    Hi Michael, great job.

    Tested with MDT 2012 U1 and works perfectly.

  10. Kuli says:

    Thanks for the above.  I have followed the process and updated my customsettings.ini file – but please can someone advise what expression i need to use to call the encoded password?

    I have used the DomainAdminPassword=$EncodedUserPassword to join to the domain but it fails….. i'm not sure if i'm using the correct expression statement – pls can someone help

  11. kor says:

    @OP, same question as Kulie. This "guide" is lacking a LOT of information needed to fully implement this solution.

    Also, this script doesn't seem to work in MDT 2013. I've tried to use it following your steps and during WinPE it hangs at "Processing Rule: DECODE"

  12. See the note above starting with "You have to get MDT to include the user exit script in the boot image" – that explains the "hang" in Windows PE.  (The script actually fails when you skip this step.  The progress dialog is waiting forever for a script that failed in the background.)

  13. And the sample above shows pretty much exactly what you would need to add to CustomSettings.ini.  Since everyone's file is different though, you might need to adjust it some, but the concept doesn't change.

  14. kor says:

    @Michael, thank you for the quick response. I've made sure to follow your directions about creating a new directory and including that directory in the "extra directory" path. I did not however make it a UNC patch because I've confirmed that the VBS script is in fact making it into the boot image via this method.

    I've also read another technet article that says you must but UserExit scripts inside the same directory that contains the customsettings.ini file which would be inside the "control" folder.

    I've tried both methods and still hangs.

    Also, I am hoping you can address Kuli's question. Do you do a variable declaration similar to his question (IE, DomainAdminPassword=$EncodedUserPassword) or do you just not include a DomainAdminPassword statement in the customettings and rather ONLY have an EncodedDomainAdminPassword statement?

  15. User exit scripts should be placed into the "Scripts" folder where ZTIGather.wsf can find them, and where they will automatically be copied into media folders when they are updated.  That also results in the correct placement in the boot image when you use one of the methods above.  I usually modify LiteTouchPE.xml, but the extra files method will work fine too.

    The user exit script knows to look for "sensitive" variables, including DomainAdminPassword, so no explicit logic is needed for that – the exit will set it automatically.

  16. kor says:

    If userexit scripts should be placed in the script directory with all the other wsf files, why is it recommended then to also setup an "extra directory" and put the vbs file in that as well?

    So to be 100% clear, if we follow your method above and use an "EncodedDomainAdminPassword" variable in the [Decode] section a "DomainAdminPassword" variable is not needed anywhere else in the customsettings.ini correct?

  17. kor says:

    I've given up. Your Decode hangs during bootsrap no matter what I do. I've tried the extra directory, copying the files into the script DIR, and editing the LiteTouchPE xml file. Nothing works and I need to move on.

    Your thing might work in theory, but I can't get it working.

  18. Dhalse says:

    I think I may be able to shed some light (I Hope) on how to set this up in the cs and boot ini for the example that is set on this page. IF you have ANY of the entries from the "sVar in Array" section stated in the DecodeExit script,
    1) Add the corresponding entry with "Encoded" in front of it.
    Example: In the BootStrap.ini you have the UserID and UserDomain and well as UserPassword under

    the [DEFAULT] section. Add the following:
    [Settings]
    Priority=Decode, Default
    Properties=EncodedUserPassword, EncodedUserID, EncodedUserDomain

    2) In the [DECODE] section add:
    EncodedUserPassword=
    EncodedUserID=
    EncodedUserDomain=
    UserExit=DecodeExit.vbs

    Note: Each line needs to have its own unique base64 hash corresponding to what the original answers for the entries were.

    3) Remove the UserPassword, UserID, UserDomain entries under the [Default] section.

    If there are similar entries in the CustomSettings.ini just do the same thing.
    Mind you, I followed the first option of creating the extra shared folder and adding the DecodeExit.vbs in the UNC path specified AE:\Some_FolderDeployScripts
    I added permissions for this folder using "Advanced Sharing…"
    I also deleted the *.wim, *.iso, *.xml under the "Boot" folder.
    Rebuild those files by updating the Deployment Share
    Then finally deleting and updating the Boot PE image in the WDS server that I am using.
    I hope this this information helps.

  19. Seth L says:

    One point of clarity I would like to point out, the password example used in the above includes quotes. I was getting my encoded password by entering, as per the example, cscript.exe Encode.wsf /Value:”mypasswordhere” but my actual password did not have leading or closing quotes.

    For reference to others who may come along and try this my setup is MDT 2013 and am using this for deploying Windows 8.1 with update 1. I did not do the portions to add this to the boot disk, for that I require a login. Mostly because I am joining to a test domain while pulling files from a server in my production domain (and there is no trust from the production to the test domain) and because I have implemented a multi-MDT server boot disk (the MDT boot disk asks you what server, from a drop down, you want to connect to).

    Also, now that I was able to start using the built-in ability of MDT to join a domain, I had to remove the sections from UNATTEND.XML that does a domain join as I must have my joining done at the end of the task sequence due to GPO restrictions that prevent LITETOUCH.WSF from running, most notably via GPO we rename the admin account an change the password. For that same reason I also modified ZTIDomainJoin.wsf to remove the auto-reboot upon success as that would prevent the final stages of the TS form completing. I do my “Recover from Domain” as the last steps of the build and have enabled “finishaction=reboot” so the system will reboot when the summary screen has been acknowledged.

  20. Anonymous says:

    As we were going through our TechEd North America deployment pre-conference today, we showed a lot of

  21. Anonymous says:

    Pingback from Material de apoyo usado en la preconferencia de TechED NA 2014 (deployment??s) + links de interes – Freelance-IT Ags, Mex.

  22. Anonymous says:

    Pingback from Michael Niehaus Notes from TechEd North America | What have I learnt today?

  23. Maksym says:

    Thanks, Michael. Great article.
    As I understand, MDT transfers all sensitive information previously obfuscated? For example, when enter manually domainusernamepassword to access deployment share, this information transfers obfuscated with base64 encoding? Moreover, bootstrap.ini and Decode.wsf
    injected in boot image, and it’s easy to extract passwords from boot CD, if you have one. Can you tell, if to implement strong encryption type and store boot images in WDS, not boot CD’s, is it enough secure? Can sensitive information be sniffed such a way?

    Thanks. Have a nice day.

  24. yaro137 says:

    Just testing this and indeed it looks like it’s the LiteTouchPE.xml in Templates folder that needs modifying as it will overwrite the one in Boot on deployment share update. Yet when I remove my UserPassword from Default in bootstrap.ini it doesn’t get
    inserted during deployment.

  25. Peter says:

    Hello, I followed the instructions but I have a situation. machine is not able to get to the share. Password is missing. Could you hep me how to define?
    UserPassword: …………

  26. Peter says:

    Hello, I followed the instructions but I have a situation. machine is not able to get to the share. Password is missing. Could you hep me how to define?
    UserPassword: …………

  27. showbox says:

    Thanks for the great info. I really loved this. I would like to apprentice at the same time as you amend your web site, how could i subscribe for a blog site?
    For more info on showbox please refer below sites:
    http://showboxandroids.com/showbox-apk/
    http://showboxappandroid.com/
    Latest version of Showbox App download for all android smart phones and tablets.
    http://movieboxappdownloads.com/ – It’s just 2 MB file you can easily get it on your android device without much trouble. Showbox app was well designed application for android to watch movies and TV shows, Cartoons and many more such things on your smartphone.
    For showbox on iOS (iPhone/iPad), please read below articles:
    http://showboxappk.com/showbox-for-ipad-download/
    http://showboxappk.com/showbox-for-iphone/
    Showbox for PC articles:
    http://showboxandroids.com/showbox-for-pc/
    http://showboxappandroid.com/showbox-for-pc-download/
    http://showboxforpcs.com/
    There are countless for PC clients as it is essentially easy to understand, simple to introduce, gives continuous administration, effectively reasonable. it is accessible at completely free of expense i.e., there will be no establishment charges and after establishment
    it doesn’t charge cash for watching films and recordings. Not simply watching, it likewise offers alternative to download recordings and motion pictures. The accompanying are the strides that are to be taken after to introduce Showbox application on Android.
    The above all else thing to be done is, go to the Security Settings on your Android telephone, Scroll down and tap on ‘Obscure sources’.

  28. aw says:

    hai, I just want to tell you that I am just very new to blogs and seriously loved this website. More than likely I’m planning to bookmark your blog post .
    You amazingly come with really good posts. Thanks a lot for sharing your blog Microsoft.

    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Komunikasi
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Listrik
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Management%20Trainee
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Manajemen
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Marketing
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Mekanik
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Mesin
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Metro%20TV
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Negeri
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Online
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Online%20Terbaru
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Oto
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Otomotif
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Pegawai%20Negeri
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Pendidikan
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Penerbangan
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Perawat
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Perikanan
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Perkapalan
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Perpustakaan
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Persero
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Pertamina
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Pertanian
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Peternakan
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Polisi
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Polwan
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Pramugari
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Programmer
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Psikologi
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20PTN
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20PTS
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Reporter
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20S1
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20S2
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Sales
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Sastra
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Sekretaris
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Semua%20Jurusan
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Serang
    http://www.lokerjobindo.com/search/label/Lowongan%20Kerja%20Serpong

  29. GJ says:

    I’m having issues with this script despite following the instructions. Here is what I’ve done:

    This is my customsettings.ini script:

    [Settings]
    Priority=Decode, Default
    Properties=MyCustomProperty
    Properties=EncodedDomainAdmin, EncodedDomainAdminPassword

    [Decode]
    EncodedDomainAdmin=QWRtaW5pc3RyYXRvcg==
    EncodedDomainAdminPassword=SGVsbG8=
    UserExit=DecodeExit.vbs

    [Default]
    OSInstall=Y
    SkipAppsOnUpgrade=YES
    SkipCapture=YES
    SkipAdminPassword=YES
    SkipProductKey=YES

    SkipBuild=YES
    TaskSequenceID=001

    SkipApplications=YES
    SkipAppsOnUpgrade=YES

    Applications001={e65205e8-931e-444e-acee-c580ad436150}
    Applications002={c46f2ac7-0d1e-4ffe-b618-add1095da16b}
    Applications003={e776ed9c-8beb-4056-b3d9-986d7ab4f7c6}
    Applications004={94edd96f-2805-4f5f-a211-f6e7e350d226}
    Applications005={b529cbab-8cdd-42d5-9bc3-6855add32da5}

    SkipDomainMembership=YES
    JoinDomain=MDT-TEST.com
    EncodedDomainAdmin=QWRtaW5pc3RyYXRvcg==
    EncodedDomainAdminPassword=SGVsbG8=

    SkipLocaleSelection=YES
    UILanguage=en-GB
    UserLocale=en-GB
    KeyboardLocale=0809:00000809

    SkipUserData=YES
    SkipComputerBackup=YES

    SkipTimeZone=YES
    TimeZoneName=GMT Standard Time

    SkipSummary=YES
    SkipFinalSummary-YES

    I have put the script in the Scripts folder, added the necessary line to the LiteTouchPE file, rebuilt the boot image. I don’t know what else to try – my deployment works without this script, but it’s something I need to implement.

    Any help would be greatly appreciated.

  30. Great scripts and instructions Michael. Works a treat!

    To add to this here is a good article to secure the deployment shares: http://www.ingmarverheij.com/mdt-secure-deployment-share/

    Cheers,
    Jeremy

Comments are closed.