Preventing computer password expiry
If you work with non-persistent virtual machines on Windows domains, you will be familiar with your machines being disconnected from the domain every 30 days.When you try to log in, you get a message saying:-
“The trust relationship between this workstation and the primary domain failed.”
The problem is detailed in this KB Article. What happens is that every 30 days (by default) the client initiates a computer password change on the domain controller. This computer password is used to authenticate the computer as the computer object in AD, and is distinct from the user’s password. When the non-persistent machine resets, the passwords go out of synchronization and domain authentication fails.
This can be fixed, as per Microsoft’s KB article, by disabling the client-initiated computer password changes; this can be done using Local or Group Policy, by script, or by directly editing the registry.
Using local, or group policy
Set the key shown below to Disabled
Using REGEDIT
Set the below value to 1
Using Windows shell script
:: Set registry key to disable computer password expiry
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" /v DisablePasswordChange /t REG_DWORD /d 1 /f
If you’ve got access to the Domain Controller, you can also set a GPO so that Domain Controller: Refuse Machine Password Changes is Enabled. This is in Windows Settings à Securiy Settings à Local Policies à Security Options (the same location as the Domain Member: Disable Machine Account Password Changes).
Also, if you need to rejoin machines that have already fallen off the domain, you can miss the reboot after removing it from the domain, so:
- Shut the machine down
- Make the drives Persistent
- Start the machine and log in
- Remove the machine from the domain
- Add the machine to the domain
- Reboot
- Shut-down and make Non-Peristent
Skipping the middle reboot saves a couple of minutes (which adds up if you have a lot to do). The above processes can also be scripted through the use of PowerCLI with Invoke-VMCommand and either NETDOM (for XP/Vista) or PowerShell for Windows 7.
Changing drive letter assignments after deploying a virtual machine from a template
We’ve had an ongoing problem with “Sequencing” machines for Microsoft Application Virtualisation (formerly SoftGrid). The virtual machine template is correctly set up with a secondary drive set to Q:\ (the drive letter is integral to the sequencing process). However, when the machines are deployed from the template, the Sysprep part of the customization process results in the drive being “reset” to the lowest available – in this case D:\.
At first, we manually changed these assignments using the Disk Management MMC before setting the drives to non-persistent. Lately, I’ve been using a DISKPART script, which speeds up the process, but still requires logging into each machine.
I saw Arnim van Lieshout’s post on Invoke-VMScript yesterday, and realised that this could be used to run the DISKPART script on multiple machines. In order to get the TXT file used by DISKPART onto the machine, I’m also using the Copy-VMGuestFile command found in PowerCLI 4.0 Update 1.
# Change drive letter assignment from D to Q
# Gets the specific VMs we're after as an object
$objVMs = Get-Folder "Sequencers" | Get-VM | Sort-Object Name
# Assign the command line required for DISKPART to a variable
$strScript = "IF EXIST D:\ DISKPART /S C:\DiskPart_Change_C_To_Q.txt"
# Loop through the VMs
ForEach ($objVM in $objVMs){
# Let the user know
Write-Host Copying file to $objVM
Copy-VMGuestFile -Source "C:\Tools\DiskPart_Change_C_To_Q.txt" -Destination "c:\" -LocalToGuest -VM $objVM -HostUser root -HostPassword password -GuestUser Administrator -GuestPassword password
Write-Host Changing disk partitions on $objVM
Invoke-VMScript $strScript -vm $objVM -HostUser root -HostPassword password -GuestUser Administrator -GuestPassword password -ScriptType "bat"
}</pre>
The TXT file contained the following:-
<pre>SELECT VOLUME 2
ASSIGN LETTER=Q
This requires root credentials for the host, and administrator rights on the target machine, but, as Arnim notes, will work in the absence of client network connectivity.
This is a bit of a hack,: leaving the TXT file behind on the C drive; using root credentials rather than an account with the least effective permissions; and having the script contain the credentials in plain-text. However, I’m enthusiastic about using this solution in a more structured way in future. I’m already thinking about using it to defragment and SDelete our thick-provisioned virtual machines before converting them to Thin provisioned disks.
Linked Clones
We’ve started our first “proper” implemenation of Linked Clones in our vSphere 4 environment. While we’ve done some limited proof-of-concept work, this is the first project to be entirely deployed using Linked Clones. The objective is to reduce the space used by our training machines on our new environment.
Linked clones allow multiple machines to share a common read-only “base” VMDK file, with each machine generating their own delta (REDO). Under normal usage circumstances, the REDO would continue to grow throughout the life of the machine; however as our machines have non-persistent hard drives, they reset to a clean state when powered-down. This makes our environment ideally suited to taking advanatage of the functionality offered by Linked Clones. They can either be created manually (by moving and renaming files on the datastore), or via the APIs, you can get more information on them in this White Paper from VMware.
Our training machines are functionally identical to our production machines, and similarly consist of three types – Capture, Packaging and Verification. These are 11, 8, and 8 GB respectively. The usage patterns are slightly different, as – unlike “live” projects which have a steady stream of work, trainees tend to come in in large batches. This means that the training environment either needs to be continuously large, but mostly idle, or it needs to be regularly redeployed then stripped back.
The benefits achieved via the implementation of Linked Clones in this project resulted in roughly the same ratio of space saving as our proof-of-concepts, but as the number of machines involved was greater, the differences are more pronounced. Also this is the first time we’ve exceeded 8 machines sharing the same VMDK, which is a notable milestone as it is only possible if we limit the number of possible hosts that the machines can run on (there is a VMFS limitation of 8 hosts accessing a VMDK concurrently). As we have DRS enabled, this meant reducing the number of hosts in each cluster to 8 or less.
We deployed twenty-five machines each, of the three different builds used in a project. All were Windows XP virtual machines
The three machines being used as the parents had their slack space on the drives was cleaned using SDelete, then the machine was converted to Thin Provisioned using Storage vMotion. It was switched off, and a snapshot was created. This snapshot will form the base for the parent’s clones.
The machines were deployed using the a script similar to the one at the bottom of this post, and it took just over an hour to deploy and customize all 75 machines. This was considerably faster than the time it would have taken to deploy 75 machines using the normal “Deploy from template” method.
Here are the data:-
- Estimated space used if deployed traditionally: 675 GB
- Capture: 11 GB per machine
- Packaging: 8 GB per machine
- Verification: 8 GB per machine
- Estimated Space if Deployed as Thin Provisioned, but not Linked Clones: 238.75 GB
- Capture: 3.34 GB per machine
- Packaging: 3.72 GB per machine
- Verification: 2.49 GB per machine
- Space used in current configuration: 19.3 GB
- Capture 3.34 GB for parent, plus 0.13 GB per Linked Clone
- Packaging 3.72 GB for parent, plus 0.13 GB per Linked Clone
- Verification 2.49 GB for parent, plus 0.13 GB per Linked Clone
And in graph-format, for extra impact:-
All size estimates are based on the machines in a powered-down state. When powered on, a swap file (equal to the size of the assigned RAM) is created, and (assuming the machines are non-persistent) REDO files are created on all types of machines.
I’ve been on a few of the machines and they don’t appear to suffer from any noticeable performance degradation, although the true test won’t come until we get considerable concurrent use.
I’m tentatively declaring this a huge success. Rather than the training environment using 240 GB between training engagaments, it’s now down to a svelte 20GB, with no reduction in functionality.
Below is a script similar to the one I used to deploy the linked clones. The actual “meat”, which deploys the machines was based on Hal Rottenberg’s New-LinkedClone.ps1 script. As far as possible, I’ve tried to strip out stuff that’s specific to our environment (we use the Custom Attributes as an asset management database and to track which machines were deployed from which templates). There’s probably going to be stuff in there that doesn’t make much sense, but if you’ve got a bit of an understanding of PowerShell, you should be able to cut and keep the bits you want.
# Script to deploy linked clones
# List of custom attributes which you're wanting to copy from the template or parent to the newly created machine
# (Machines deployed from templates no longer inherit CAs in vSphere 4.0)
# These help us track provenance, and provide information to the user
$arrStrAttributesToCopy = @(
"AD Object Location",
"Customisation",
"Infrastructure Consultant",
"Logon Administrator Name",
"Logon Administrator Password",
"Logon User Name",
"Logon User Password",
"Mobilisation Consultant",
"Project",
"Role",
)
# Name of the Custom Attribute on the parent which contains the name of the customisation to use
$CustomFieldName = "Customisation"
Function DeployLinkedClone ($strSourceVM, $intToBeDeployed, $intStartDeployingAtNumber, $CustomFieldName){
# Bases the name of the machine on the second part of the string split by spaces. This assumes that the template follows the standard naming convention of "Tmpl [Name] x.x"
$strMachinePrefix = ($strSourceVM.split(' ')[1])
$objVM = Get-VM $strSourceVM
$viewVM = $objVM | Get-View
$objCustomization = Get-OSCustomizationSpec ($objVM.CustomFields.Item($CustomFieldName))
# Ensure that the machines does not have a non persistent HD
If ($objVM | Get-HardDisk | Where-Object {$_.Persistence -like "IndependentNonPersistent"}){
Write-Host $objTemplate has a non-persistent HD!
}
# If the customisation, as specified in the parent's custom attribute does not exist, then quit.
If (!$objCustomization){
Write-Host Customisation ($objVM.CustomFields.Item($CustomFieldName)) not found. Exiting.
Break
}
$i = 1
Do {
# Convert the single digit integer (i.e., "1") into a double digit (i.e., "01")
$strMachineNumber = ("{0:0#}" -f $intStartDeployingAtNumber)
# Concatenate the machine name prefix (from the template name) with the double-digit integer, which is incrememted on each loop
$strMachineBeingDeployed = $strMachinePrefix+$strMachineNumber
# Check that the machine doesn't already exist
If ((Get-VM -Name $strMachineBeingDeployed -ErrorAction SilentlyContinue)){
Write-Host "Machine $strMachineBeingDeployed already exists!"
Break
}
# Let the user know what's going on
Write-Host ""
Write-Host "Deploying new linked-clone " -NoNewline
Write-Host $strMachineBeingDeployed -ForegroundColor Blue -NoNewline
Write-Host ", from template " -NoNewline
Write-Host $strSourceVM -ForegroundColor Blue -NoNewline
Write-Host ", using customisation " -NoNewline
Write-Host $objCustomization -ForegroundColor Blue -NoNewline
Write-Host ", on the same Host as the parent" -NoNewline
Write-Host ""
# Create the new machine using all these variables
$objFolder = $viewVM.parent
$specClone = New-Object Vmware.Vim.VirtualMachineCloneSpec
# Get the most recent snapshot attached to the machine
$specClone.Snapshot = $viewVM.Snapshot.CurrentSnapshot
# Create an object to represent the location of the clone
$specClone.Location = New-Object Vmware.Vim.VirtualMachineRelocateSpec
# This is the move-type that specifies the new disk backing (which is the bit that makes a linked clone)
$specClone.Location.DiskMoveType = "createNewChildDiskBacking"
# Run the task with the specified parameters
$task = $viewVM.CloneVM_Task($objFolder, $strMachineBeingDeployed, $specClone)
Get-VIObjectByVIView $task | Wait-Task | Out-Null
# Get the object for the machine which was just deployed
$objTargetVM = Get-VM $strMachineBeingDeployed
# Apply the customisation specification to the newly created clone
Set-VM -VM $objTargetVM -OSCustomizationSpec $objCustomization -Confirm:$false
# Start the clone
Start-VM -VM $objTargetVM
# Get the view (needed for writing custom attributes)
$viewTarget = $objTargetVM | Get-View
# Loop through each of the custom attributes which are to be copied
ForEach ($arrStrAttributeToCopy in $arrStrAttributesToCopy){
# Read the attribute from the source template
$objAttribute = $objVM.CustomFields.Item($arrStrAttributeToCopy)
# Apply the attribute to the machine object
$viewTarget.setCustomValue($arrStrAttributeToCopy,$objAttribute)
}
# Set the "Template" custom attribute to the parent templates
$arrStrAttributeToCopy = "Template"
$viewTarget.setCustomValue($arrStrAttributeToCopy,$strSourceTemplate)
# Increment the number used for naming the machines
$intStartDeployingAtNumber ++
# Increment the number used to count the number of machines deployed
$i ++
}
# Continue to loop while the number of machines deployed is less than the number required
While ($i -le $intToBeDeployed)
}
# Get the current time (for timing how long the script took to run)
$dteStart = Get-Date
# Name of source VM, should be persistent, should have a snapshot and the customisation specified in the nominated custom attribute
$strSourceVM = "Tmpl Capture 1.0"
# Number to be deployed
$intToBeDeployed = 25
# Number to start deploying from
$intStartDeployingAtNumber = 1
DeployLinkedClone $strSourceVM $intToBeDeployed $intStartDeployingAtNumber $CustomFieldName
# Name of source VM, should be persistent, should have a snapshot and the customisation specified in the nominated custom attribute
$strSourceVM = "Tmpl Packaging 1.0"
# Number to be deployed
$intToBeDeployed = 25
# Number to start deploying from
$intStartDeployingAtNumber = 1
DeployLinkedClone $strSourceVM $intToBeDeployed $intStartDeployingAtNumber $CustomFieldName
# Name of source VM, should be persistent, should have a snapshot and the customisation specified in the nominated custom attribute
$strSourceVM = "Tmpl Verification 1.0"
# Number to be deployed
$intToBeDeployed = 25
# Number to start deploying from
$intStartDeployingAtNumber = 1
DeployLinkedClone $strSourceVM $intToBeDeployed $intStartDeployingAtNumber $CustomFieldName
$dteEnd = Get-Date
$dteDiff = New-TimeSpan $dteStart $dteEnd
$timeTaken = [math]::round($dteDiff.totalMinutes, 2)
Write-Host ""
Write-Host "It took" $timeTaken "minutes for these machines to deploy"
# End of script
Happy New Year
Happy New Year to everyone!
I passed the VCP on vSphere 4 just before Christmas with 463/500. At the time the deadline for taking the exam without having to the attend the What’s New was 31st December 2009, but that’s now been extended to the 31st January. It was nice to have it out of the way before Christmas though.
The exam seemed no more difficult than the VCP on VI 3; I think they even reused a few of the questions. I found the following useful:-
- Simon Long’s VCP vSphere 4 Practice Exams
- vSphere 4 Configuration Maximums
- Barry Coombs’ VMware vSphere cue-cards
Those sites also contain numerous links to other resources, so I’m sure you’ll find something which will suit your revision style.
Next on my to-do list is the Microsoft 70-431 Microsoft SQL Server 2005 – Implementation and Maintenance.


