Use PowerShell to Work with the MDT CustomSettings.ini File

Use PowerShell to Work with the MDT CustomSettings.ini File

  • Comments 1
  • Likes

Summary: Microsoft PowerShell MVP, Sean Kearney, shows how to use Windows PowerShell to work with the MDT CustomSettings.ini file.

Microsoft Scripting Guy, Ed Wilson, is here. This week, Windows PowerShell MVP, Sean Kearney, is our guest blogger, and he is writing about Microsoft Development Kit Update 1 (MDT).

All throughout history, there have been great teams: Abbott and Costello, Sears and Roebuck, hotdogs and ketchup. Today, we continue with another great team: MDT and Windows PowerShell.

Yesterday, we showed you how to improve the stock cmdlet for making a new Deployment Share in MDT. We found that it was like some of the greatest symphonies—a little unfinished, but we polished it up. But I mentioned that there was another feature that is not echoed in our cmdlet or script. When you create a new Deployment Share, MDT asks you three questions…three questions that cause the greatest of philosophers to debate into the night the answer to life, the universe, and...everything.

(Pssst, it’s 42, and it works in Base 13.)

Now that I have angered several philosophers, and possibly put them out of work, let us step back to MDT…

MDT prompts us with the following key questions about the base ability of this share:

  • Ask if an image should be captured (selected by default)
  • Ask user to set the local Administrator Password (not selected by default)
  • Ask user for a product key (not selected by default)

When you are finished with the standard wizard, these are converted to three settings in a file called CustomSettings.ini, which is located under the Control subfolder in your newly created Deployment Share. By default this file will look like this (depending on the options you have selected):

[Settings]
Priority=Default
Properties=MyCustomProperty

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

We will be dealing with the last three lines and their settings. Fortunately, the actual variable matches exactly what it is doing. The answer is obvious too. In the GUI, all you have to know is if you didn’t select it, the answer for that option will be No; otherwise, it will be Yes.

That sounds like a very “Boolean” answer to me, so we could actually add some simple parameters to ask for a $True/$False as part of the script. When we build it, we’ll put in three Boolean parameters like this:

[Parameter (Mandatory=$false)]
[Boolean] $PromptPassword,
[Parameter (Mandatory=$false)]
[Boolean] $PromptKey,
[Parameter (Mandatory=$false)]
[Boolean] $CaptureImage

The next task, of course, is…well…how do we edit it? Because CustomSettings.ini is a text file, we can get away with building a simple “search and destroy.” This could be accomplished probably far better with regular expressions (Oh, Dr. ReGeX ! Wherefore art thou!), but we’ll try something simpler. Let us get the data, store it away in a Windows PowerShell variable, and pass that through Select-String.

Why, you wonder? We may have to edit three lines or no lines. We need the data in memory so we can work with it as many times as we need it. So because we’re going to build on our original script, we’ll use the following script:

$CustomSettingsINI=(GET-CONTENT “$Folder\Control\CustomSettings.ini”)

If you did not pick up…that’s a little trick that you can do with variables in Windows PowerShell. If you are assigning a value, if it’s within double quotation marks, and it contains a Windows PowerShell variable (for example, $Folder), Windows PowerShell will expand it to its actual value when assigning it.

Now we can use Select-String on one of the lines to find its location in the file as shown here:

$CustomSettingsINI | SELECT-STRING –pattern “SkipProductKey”

If you have played with Select-String, you know that one of the properties returned with that object is LineNumber, which is the row where it found your data within an array. So I can easily access the value of the variable $CustomSettingsINI by referencing the results of the first search.

$CustomSettingsINI[($CustomSettingsINI | SELECT-STRING –pattern “SkipProductKey”)]

But this would fail because an array always starts counting at 0, but the row count starts at 1. If Select-String finds your data, you must bump back the count by 1.

$CustomSettingsINI[(($CustomSettingsINI | SELECT-STRING –pattern “SkipProductKey”)-1)]

We’ve found the row with the value. How do we edit it? The choice is up to you. You can get really fancy or just do something dead simple. (Remember, you can always go back to your script and improve how you did it later.)

I am going to get a little bit fancy. Because the parameter is going to be a Boolean $True/$False only, we can build a tiny array of “Yes” and “No” for the values, and have it flip that value simply dependent on the Boolean value. To convert a Boolean $True/$False to a value like one or zero we simply do this:

[int]$SomeBooleanValue

Now for my array, I was not kidding…it is a tiny two-member array with the values of “Yes” or “No” to edit into the value depending on our parameter:

$YESNO=("NO","YES")

You will notice that it is backwards. In our case, if the box is selected ($True), we want to make sure the answer to the value is “Yes.” So a Boolean $False (0) will yield “No” and a Boolean $True (1) will yield “Yes.” I do that with this little bit of trickery:

$CustomSettingsANSWER=$YESNO[([int]$SkipProductKey)]

Now the rest the answer is up to you. I will be honest. I cheated. I sat down and wrote an “If” statement for the three Boolean tests. That feels like a cheat to me because I am repeating a procedure. But then again, as I have said before, this may well get me my answer in the short term. I can always go back and improve on the script with the time that I have saved by not sitting in the GUI all day.

So let us pull the pieces together and turn all of this into a new advanced function called NEW-MDTDeploymentShare.

function global:NEW-MDTDeploymentShare()

{

[CmdletBinding()]
param(
[Parameter (Mandatory=$true)]
[String] $Folder,
[Parameter (Mandatory=$true)]
[String] $Description,
[Parameter (Mandatory=$true)]
[String] $Share,
[Parameter (Mandatory=$false)]
[Boolean] $PromptPassword,
[Parameter (Mandatory=$false)]
[Boolean] $PromptKey,
[Parameter (Mandatory=$false)]
[Boolean] $CaptureImage
)

Process
{
Add-PSSnapIn Microsoft.BDD.PSSnapIn

$ListOfShares=GET-MDTPersistentDrive
Do {
$DSNAME="DS"+((GET-RANDOM 999999999).tostring().trim())
} Until ( ! ( $ListOfShares | Select-string -Pattern $DSNAME))

# Get NETBIOS name of computer
$ComputerName=$ENV:Computername

# Create Folder for Deployment Share
new-item -type Directory -path $Location

# Create Network Share for Deployment Share
$UNC=”\\$Computername\$Sharename"
([wmiclass]"Win32_share").Create($Location,$Sharename,0)

# Create Deployment Point within MDT
new-PSDrive -Name $DSNAME -PSProvider "MDTProvider" –Root $Location –Description $Description –NetworkPath $UNC -Verbose | add-MDTPersistentDrive –Verbose

# Based upon Supplied parameters, Customize the Custom.ini
# Contained with the specific Deployment point
$YESNO=("NO","YES")
$CustomINI=(GET-CONTENT "$Location\Control\CustomSettings.INI")
IF ($PromptPassword)
{
$AnswerValue=$YESNO[([int] $PromptPassword)]
$CustomINI[(($CustomINI | SELECT-STRING -Pattern "SkipAdminPassword").LineNumber)-1]="SkipAdminPassword=$AnswerValue"
}
IF ($PromptKey)
{
$AnswerValue=$YESNO[([int] $PromptKey)]
$CustomINI[(($CustomINI | SELECT-STRING -Pattern "SkipProductKey").LineNumber)-1]="SkipProductKey=$AnswerValue"
}
IF ($CaptureImage)
{
$AnswerValue=$YESNO[([int] $CaptureImage)]
$CustomINI[(($CustomINI | SELECT-STRING -Pattern "SkipCapture").LineNumber)-1]="SkipCapture=$AnswerValue"
}
$CustomINI | SET-CONTENT -path "$Location\Control\CustomSettings.ini"
}
}

There are obviously many ways that we can build on and improve on this—error checking, adding some Help, perhaps even rewriting how I prompted for the settings in CustomSettings.ini.

But what this does give us is a way to fully automate the creation of Deployment Shares. It shows us that we can also improve existing tools that are provided to us if they do not meet our needs.

So with this added to my profile or a module, I can now do something as simple as this:

NEW-MDTDeploymentShare –Folder ‘C:\MyShare’ –Description ‘Another MDT Share’ –Share ‘ThisShare’

MDT will do all the work, or I can have a CSV file with configurations for a lab environment and simply execute the script to rebuild it as I need.

Tomorrow we will dive into the real power of MDT—bringing in data to make that image useful, and utilizing Windows PowerShell to repeat those tasks easily.

~Sean

Thanks, Sean!

Join us tomorrow for Part 3.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Sean,

    as I don't have MDT here (and I suppose, that I really won't need it personally) I can't follow the MDT specific part of your series.

    But I can tell you, that I won't prefer the Select-String method to get at the line numbers of the ini file and change the values using the $yesno array! In fact I was a little bit confused and it took me some time to verify that your results are correct!

    A simpler way ( YES! I'm using a tiny little bit of an RegExp! ) is the following:

    1. I'd like to use a hashtable instead of an array here:

      $NoYes=@{$false='NO';$true='YES'}

    2. I'd use the simple -replace operator to change the content of the INI file, e.g.

      IF ($CaptureImage)

      {

         $CustomSettingsINI -replace 'SkipCapture=.*', "SkipCapture=$($NoYes[$CaptureImage])"

      }

    I made the regExp as simple as possible, in fact it acts more or less like a wildcard!

    We search for 'SkipCapture=' followed by anything and replace it with the same ( I could have used a matching group here and '$1' on the other side ... ) expression, followed by the value resolved from the hash $NoYes' using $CaptureImage as key to the hash.

    To me this approach is more straight forward ...

    Klaus.