Archives for May 2013

Awarded VMware vExpert 2013 Status

It’s that time of year again when VMware vExpert 2013 awards are handed out. Last year I was very surprised and honored that my blogging efforts got such recognition and that I made the 2012 list. Since then I’ve tried to do even more community work, and spent countless hours doing the vSphere 5.1 install guide series. And for 2013 I’m honored to again be selected as a VMware vExpert. You can find the full VMware blog post with all 579 of us here. I look forward to continuing to participate in the community, and expand my audience reach. My last name got fat fingered in the list, so hopefully they can fix that up in short order.

VMware Releases vCenter 5.1 U1a

5-22-2013 8-40-53 PMTonight VMware released vCenter 5.1.0 U1a, which is a bugfix re-release of U1. A day or two after vSphere 5.1 U1 was out there was a warning regarding multi-domain authentication when a user was in a lot of groups. You can check out important information about the 5.1 U1a release here. It describes the multi-domain scenarios that didn’t work, and which ones do work in Update 1a.

5-22-2013 9-04-28 PM

Some errors that you could have seen with vSphere 5.1 U1 were:

The vSphere Client could not connect to "<vCenter Server name>". You do not have permission to login to the server: <servername>

In the vpxd.log, you see permissions errors similar

2012-10-31T13:18:27.665-07:00 [02756 info 'Default' opID=DD905A5F-00000004-7] [Auth]: User DOMAIN

2012-10-31T13:18:27.681-07:00 [02756 info 'commonvpxLro' opID=DD905A5F-00000004-7] [VpxLRO] -- FINISH task-internal-671700 -- -- vim.SessionManager.login --
2012-10-31T13:18:27.681-07:00 [02756 info 'Default' opID=DD905A5F-00000004-7] [VpxLRO] -- ERROR task-internal-671700 -- -- vim.SessionManager.login: vim.fault.NoPermission:
--> Result:
--> (vim.fault.NoPermission) {
--> dynamicType = <unset>,
--> faultCause = (vmodl.MethodFault) null,
--> object = 'vim.Folder:group-d1',
--> privilegeId = "System.View",
--> msg = "",
--> }
--> Args:

Given the frequent patch updates to vSphere 5.1, I would strongly urge extremely thorough testing in a lab environment before putting it into production.

Import IIS SSL Certificate to Citrix NetScaler

5-18-2013 10-03-29 PMFor a recent project I’ve been configuring a Citrix NetScaler (which are wickedly cool) for load balancing of a web service over SSL. The web service is hosted on a Windows server using IIS, so I wanted to re-use the SSL certificate on the NetScaler. The steps to import IIS SSL certificate to NetScaler are actually fairly easy. I found various blog articles and Citrix KB articles on the process, but they were a bit convoluted and I thought there had to an easier process than using OpenSSL and WinSCP/NotePad to manipulate the certificate files.

The first thing you need to do is look in the server’s computer certificate personal store for your IIS certificate. In my case I’m looking for the certificate. Since I knew I’d be exporting the whole certificate (including the private key), I made sure when I was requesting the certificate to allow the private key to be exported. You can request certificates from your MS CA a variety of ways, so I’ll assume you can find the option to allow private key export.

5-18-2013 8-52-39 PM

Exporting the Certificate

1. Right click on the certificate select All Tasks then select Export. You should be presented with the option to export the private key. If not, then your certificate’s private key is “stuck” in the computer’s store and you can’t get it out. Issue a new certificate with the private key export option.

5-18-2013 8-58-01 PM

2. Assuming you can export the private key you are now given some options for the PKCS#12 certificate file. You shouldn’t need to select any of the options.

5-18-2013 8-59-29 PM

3. Select a strong password to protect the file with. Remember it.

4. Chose an appropriate filename for the certificate. I strongly suggest using the FQDN of the certificate, because the NetScaler will store the files with the name you choose. So don’t do something like “cert.pfx” since you will have no clue what site it is for. In my case I chose

5. Run through the same export wizard again, but this time select No, do not export the private key.

5-18-2013 9-04-19 PM

6. Select Base-64 encoding for your certificate.

5-18-2013 9-05-03 PM

7. Again, I suggest using the FQDN of the certificate for the filename (e.g. Make sure the file ends in “.cer”.

8. At this point you should have two certificate files, both with the FQDN, and one ending in .PFX and the other in .cer.

5-18-2013 9-06-50 PM

Importing Certificates into NetScaler

1. Logon to your Citrix NetScaler and open the root SSL page. Under Tools click Import PKCS#12.

import iis ssl netscaler

2. In the import window click on Browse next to the PKCS12 filename (NOT the output file name). Browse to your pfx file. Type in the password you entered during the certificate export process. Enter a new password to protect the private key on the Netscaler (PEM passphrase). In the Output File Name use the FQDN of the certificate and add a .key suffix. Change the encoding format to DES3. The NetScaler will automatically extract the private key from the PFX file and put it into the .key file.

5-18-2013 9-12-17 PM

3. Click on Manage Certificates / Keys / CSRs. Upload your .cer file. You should now see three certificate files with your certificate’s FQDN.

5-18-2013 9-17-12 PM

4. At this point you can delete the .pfx file if you wish, since we no longer need it. I suggest you do remove it, to reduce clutter on your NetScaler.

5. In the left pane under SSL click on Certificates then in the middle pane click on Install.

5-18-2013 9-18-41 PM

6. Enter the FQDN of your certificate in the Certificate-Key Pair Name. For the Certificate FIle Name select the .cer file you uploaded. For the Private Key File Name select your .key file. Enter the password you entered back in step 2.

5-18-2013 9-20-59 PM

7. If all goes well you will now have a new certificate from IIS installed on your NetScaler with no command line effort or manual modification of certificate files.

import iis ssl to netscaler

Automate Sysprep on vSphere w/o Custom Specs

I’m a huge fan of using vCenter customization specifications to automate the sysprep process for deploying new Microsoft VMs. The sysprep process ensures a unique Windows SID, sets the VM’s hostname, and can even join a VM to the domain, among other things. However, the customization specifications can only be triggered when you clone a VM. While that may be good for a vast majority of use cases, I recently ran across a scenario where that was not possible since my VMs already existed.

For a VDI project I am looking at a software storage appliance to offload a lot of the IOPS from our back end storage system, to increase performance and reduce costs. One feature the our particular solution has is called “fast clone”, which allows the storage appliance to create a VM clone in just a few seconds, instead of several minutes using the vCenter clone method. Internally it adjusts some pointers to the VMDK, and de-dupes, so it doesn’t have to copy every block when you create a new VM. In fact, very few blocks are copied during the cloning process.

However the “fast clone” process literally cloned the master VM and did not have any method to trigger vCenter customization specs. As a result all the Windows hostnames were the same as were the SIDs. I certainly did not want to run sysprep manually on hundreds of VMs. The vendor workaround was far too complex and cumbersome to consider. So I developed the script below which automates the major tasks which the vCenter customization specifications perform and easier (IMHO) than what the vendor suggested.

Script Features

  • Copies an existing sysprep unattend XML file to the VM via the VMware tools VIX interface
  • Each unattended XML file is automatically customized with the VM’s name as it appears in vCenter, so sysprep will change the Windows hostname appropriately
  • Deletes the residual unattended XML files which may contain sensitive passwords or product keys
  • Auto-joins the VM to the domain assuming an appropriately configured unattend XML file and DHCP is available
  • Accepts a command line argument for easy testing against one VM, but it will also read a CSV file for mass processing

It’s up to you to supply an appropriately configured Windows sysprep unattended XML file for the operating system in question. If you include domain join parameters then it will join the VM to the domain as well, all without prompting for a username or password. To delete the residual XML files, the script will upload a setupcomplete.cmd file to c:\windows\setup\scripts. It will not over-write any existing file, so make sure it doesn’t exist. Windows knows to automatically run that script after the sysprep process.

In order to customize the unattended XML file with the VM’s hostname, the script does a simple replace on a string called “CHANGEHOSTNAME”. When you create your XML file be sure to use this name for the machine name, so the search and replace will work properly. Otherwise all the VMs will have the same hostname!

5-18-2013 6-35-18 PM

Using the Script

When you want to run the script against several machines, use the csv option. The csv file must have the vCenter VM name, one VM per line, without any header or empty lines at the end. There’s limited error checking, so I would urge you to take a snapshot of your target VM so you can revert back until you work out the kinks with your unattend file. In the vCenter console you will see some authentication errors when sysprep kicks off and invoke-script can no longer connect to the VM , but those are harmless messages.

In the example below I executed the script on the vCenter server using a PowerCLI console. I had configured the CSV input file with two hostnames. First I entered my password (for my current user account), then the administrator credentials for the guest VM. The script assumes all VMs have the same credentials as you will only be prompted once.

vsphere sysprep windows

If you watch the vCenter console you will see a bunch of entries. As I mentioned earlier, once sysprep kicks off vCenter is unable to connect to the guest so some authentication errors appear.

vsphere sysprep windows

After minute or so the VM rebooted and the sysprep process kicked off. A few minutes later my VM was joined to the domain with its new name and ready for use. Depending on the complexity of your unattended sysprep file you do could a lot of customization within the guest, install software, etc. the sky is really the limit. This script just gives you an easy way to run sysprep against dozens or hundreds of existing VMs if you can’t use vCenter customization specifications.

5-18-2013 6-52-35 PM

# This script will copy a sysprep unattend XML file to the guest VM and execute it,
# using the VM's vCenter name. Input can be a single arguement on the command line,
# or a csv file. The CSV must have one VM name per line and no blank lines or header.
# The setupcomplete.cmd deletes the two copies of the unattend XML file, which may
# contain sensitive passwords or product keys.
# Derek Seaman

# Your vcenter server name
$vCenter = ""

# Your master sysprep unattended file. It will not be modified.
$MasterSysprep = "d:\sysprep-master.xml"

# Optional CSV input file. Only called if no VM argument is provided.
# One vCenter VM name per line with no header
$CSV_File = "D:\vms.csv"

# "Hostname" in the master unattended sysprep file that will be replaced for each VM

# Resulting sysprep file with the custom hostname, overwritten for each VM. Do not change.
$CustomSysprep = "D:\sysprep.xml"

# Don't change anything below here

#Validates VMware PowerCLI snap-ins are loaded

$xPsCheck = Get-PSSnapin | Select Name | Where {$_.Name -Like "*VMware*"}
If ($xPsCheck -eq $Null) {Add-PsSnapin VMware.VimAutomation.Core}
if ($args[0] -eq $null ) {$list = import-csv $CSV_File -header name} else { $list = $args[0] }

# Function to mask password input
function Read-HostMasked([string]$prompt="Password") {
$password = Read-Host -AsSecureString $prompt;
$BSTR = [System.Runtime.InteropServices.marshal]::SecureStringToBSTR($password);
$password = [System.Runtime.InteropServices.marshal]::PtrToStringAuto($BSTR);
return $password;

} # function Read-HostMasked([string]$prompt="Password")

# Connects to vCenter
$currentUser = ([System.Security.Principal.WindowsIdentity]::GetCurrent()).Name
$currentUsePassword = Read-HostMasked "Enter the password for the current user"
Connect-VIServer -Server $vCenter -User $currentUser -Password $currentUsePassword | out-null

# Guest OS administrator credential input
$guestuser = read-host "Enter guest administrator username"
$guestpassword = read-HostMasked "Enter guest administrator password"

Foreach ($vm in $list) {

# Cleans up prior local sysprep output file and replaces hostname in sysprep.xml
remove-item $CustomSysprep -ErrorAction SilentlyContinue

$content = Get-Content $MasterSysprep
$content | foreach { $_.Replace($ReplaceHost, $ } | Set-Content $CustomSysprep
write-host $ Custom sysprep file created

# Creates setupcomplete.cmd file to delete sysprep XML files post-sysprep. File must not already exist.
$Script1 = "echo `"del /F /Q c:\windows\panther\unattend.xml c:\windows\system32\sysprep\sysprep.xml`" | out-file -encoding ASCII c:\windows\setup\scripts\setupcomplete.cmd"
invoke-vmscript -scripttext $script1 -VM $ -guestuser $guestuser -GuestPassword $GuestPassword | out-null
write-host $ setupcomplete.cmd uploaded

# Copies sysprep.xml to guest and executes asynchronously
$script2 = "c:\windows\system32\sysprep\sysprep.exe /generalize /oobe /unattend:c:\windows\system32\sysprep\sysprep.xml /reboot"
copy-vmguestfile -source $CustomSysprep -destination c:\windows\system32\sysprep -VM $ -localtoguest -guestuser $guestuser -guestpassword $guestpassword
invoke-vmscript -scripttext $script2 -VM $ -guestuser $guestuser -GuestPassword $GuestPassword -scripttype bat -runasync | out-null
write-host $ Sysprep executed