«

»

Apr 05 2011

Automatic VLAN change in VMware View

Some of my colleagues over at VMware US, Scott Jobe (Sr. Systems Engineer) and Josh Spencer (Desktop Specialist), teamed up to address the need to automatically assign VM’s to a particular VLAN in VMware View during refresh or recompose cycles.

When the Parent VM is configured administrators need to assign a VLAN or Port Group. This VLAN will follow the cloned (full-clones or linked-clones) virtual desktops whenever they are created, refreshed or recomposed.

Administrators are able to manually move the desktops to various VLAN’s. It is also possible to automate VLAN change through PowerShell scripting after the desktop is created. However, none of these methods allow the newly assigned VLAN to survive a refresh or recompose operation.

As an example, when deploying a pool of linked clone virtual machines all VMs are created in a single VLAN. The administrator then manually or via scripting moves the VMs to a new Port Group. However, when a refresh or recompose operation is initiated, all of the work is discarded, as the VMs default back to the original VLAN, the same one configured in the Parent VM.

With Scott’s and Josh’s authorisation (Thanks’ guys) I will share here the step-by-step recipe to address this problem. From here onwards is with Scott and Josh.

>>

DISCLAIMER – The solution proposed below is a workaround and is offered without any support or warranties from me, VMware, Scott Jobe or Josh Spencer. It may not work in your environment for multiple different reasons. Only implement the solution if you feel conformable with the proposed setup and architecture, including scripting. Do not test the solution in production environment.

If you read the above disclaimer and are happy with that… read on.

>>

The solution leverage View post–?synchronization scripts. The primary advantage to this technique is that View will automatically invoke the scripts when:

  1. A new VM is created.
  2. A refresh operation is targeted at a pool or an individual VM.
  3. A recompose of a pool is performed.

Early on in testing we were making several modifications to the post–? synchronization script. Because it must live on the virtual hard disk of the master image (it cannot run from a UNC path) this quickly became tedious. In order to address this issue, a batch file was written with the intent that it would not need to change. Rather, the post–?synchronization script would call this file and it would do nothing more than go “fetch” and execute a PowerShell script from a network share. This simply became known as fetch.bat. Fetch.bat requires the use of a service account with nothing more than “read” rights to the share on which the PowerShell script resides. With this process in place, the PowerShell script that is fetched could now be modified and tested without modifying the master image and recomposing the pool. Because it would always be copied down to the VM and executed locally, it became runFromGuest.ps1.

RunFromGuest.ps1 gets the name of the guest VM, looks up the associated VLAN ID in a CSV file (data.csv in this case), and uses PsExec.exe to pass these variables to the VC server and execute postSync.ps1. Because this script requires a service account with permissions to the VC, it is deleted by fetch.bat upon execution. This will prevent end users from stumbling upon this information on their virtual hard disks. Finally, postSync.ps1 leverages PowerCLI to change the VLAN within VC and then reboots the guest VM. The entire process adds less than one minute and one reboot to the total time to build/refresh/recompose a VM.

Solution Configuration and Setup

 

Virtual Machine Template

Platform tested: Windows XP SP3

Configuration procedure:

Technically, the client–?side scripts could be written in another language such as VBScript. However, for maximum flexibility and to future–?proof this process, PowerShell was the language of choice.

  • Modify the PowerShell execution policy
  • This is a one–?time process to allow PowerShell scripts to run.
  • Open a PowerShell command window and enter the following command: Set–?ExecutionPolicy Unrestricted

In some scenarios, the unrestricted policy may not pass security standards. In this case, script signing will be required.

  • Create the following folder structure and file:
  • C:\installs\fetch.bat

While the path and file name can be changed, there are multiple locations throughout this project that need to be uniform.

 

Virtual Center Server

Platform tested:

  • Windows 2003 R2 SP2 –? x86
  • View Composer 2.5.0–?291081
  • View 4.6

Configuration procedure:

  • Ensure that PowerShell is installed.
  • Modify the PowerShell execution policy

This is a one–?time process to allow PowerShell scripts to run.

  • Open a PowerShell command window and enter the following command:
  • Set–?ExecutionPolicy Unrestricted

In some scenarios, the unrestricted policy may not pass security standards. In this case, script signing will be required.

  • Install VMware PowerCLI
  • Create the following folder structure: D:\postsync
  • Create the following file: D:\postsync\postsync.ps1

Populate postsync.ps1 with the code found in code block two.

  • Create the following file: D:\postsync\data.csv

Populate data.csv with the code found in code block three.

  • Create the following file: D:\postsync\runFromGuest.ps1

Populate runFromGuest.ps1 with the code found in code block four.

 

Code Block One
Name: fetch.bat
Location: C:\installs\fetch.bat
Purpose: By design, View Manager post–?synchronization scripts must reside on the virtual hard drive of the linked clone being refreshed or recomposed; UNC paths are not supported.

The challenge with this configuration is that each modification to the post–? sync script requires a recompose to take effect. This is an invasive process, especially in a healthcare or other 24×7 operations.

Fetch.bat is designed to be called from View Manager as the post–? synchronization script. It maps a network drive, copies a PowerShell script locally, and executes it. This grants the flexibility to make modifications to the post–?sync script, without having to recompose a pool.

REM –?–?–?–?–?–?–?–?–?–?–?–?–?– Begin Script –?–?–?–?–?–?–?–?–?–?–?–?–?–
REM Because posy–?synch script runs so early in the boot process,
REM we make sure key services for networking are ready
sc start w32time
REM This is a simple trick to pause the script for a few seconds
netsh diag ping loopback
sc start lanmanworkstation
netsh diag ping loopback
REM Map a drive using service account creds
net use \\server.dom.com\postsync /USER:domain\serviceaccount password
REM Copy PowerShell script down to the linked clone
copy /y \\server.dom.com\postsync\runfromguest.ps1
C:\installs\runfromguest.ps1
REM Disconnect network drive
net use /d \\server.dom.com\postsync
REM Start the PowerShell script
Call powershell.exe C:\installs\runfromguest.ps1
REM Delete the script we just copied for security purposes
del /f C:\installs\runfromguest.ps1
REM –?–?–?–?–?–?–?–?–?–?–?–?–?– End Script –?–?–?–?–?–?–?–?–?–?–?–?–?–

 

Code Block Two
Name: postsync.ps1
Location: \\vcserver\d$\postsync\postsync.ps1
Purpose:

# –?–?–?–?–?–?–?–?–?–?–?–?–?– Begin Script –?–?–?–?–?–?–?–?–?–?–?–?–?–
# Load the VIM API
Add–?PSSnapin VMware.VimAutomation.Core
# Connect to the VC
connect–?viserver servername
# RunFromGuest.ps1 passes the VMname and the VLAN info,then sets the VLAN accordingly
get–?vm $args[0] | get–?networkadapter | set–?networkadapter –?networkname $args[1] –?confirm:$false
# Because we just disconnected the NIC and changed the VLAN, reboot the VM
restart–?vmguest –?vm $args[0] –?confirm:$false exit
# –?–?–?–?–?–?–?–?–?–?–?–?–?– End Script –?–?–?–?–?–?–?–?–?–?–?–?–?–

 

Code Block Three
Name: Data.csv
Location: \\vcserver\d$\postsync\data.csv
Purpose: Data.csv is a simple, comma–?separated file that holds a list of virtual machines and the VLAN on which they should reside. In this case the CSV is populated manually based on the View pool naming convention and the associated VLAN. This could however be implemented using XML or a database, and be dynamically populated as pools are created.

VMname,VLANID
VMname–?1,VLAN10
VMname–?2,VLAN20
VMname–?3,VLAN30

 

Code Block Four
Name: runFromGuest.ps1
Location: \\vcserver\d$\postsync\runFronGuest.ps1
Purpose: This is the script that gets copied to the linked clone VM and executed by fetch.bat, during each refresh/recompose operation. The script can be modified offline, and will take effect without modifying the View template.

# –?–?–?–?–?–?–?–?–?–?–?–?–?– Begin Script –?–?–?–?–?–?–?–?–?–?–?–?–?–
start–?sleep –?seconds 15
# First we get the name of the VM and store it in the variable $vmName
$vmName = get–?content env:computername
# Next, we connect to our data source. In this case a simple CSV.
$obj = import–?csv
\\server\postsync\data.csv
# Finally, we’ll search the CSV for the VM name and find the associated VLAN ID
foreach ($item in $obj)
{
if ($vmName –?eq $item.vm)
{
# If we find a match, execute postsync.ps1 from the VC server
psexec –?accepteula –?d \\server.dom.com –?u domain\serviceaccount –?p password –?i C:\Windows\System32\WindowsPowershell\v1.0\Powershell.exe D:\PostSync\Postsync.ps1 $vmName $item.vlan
}
}
# –?–?–?–?–?–?–?–?–?–?–?–?–?– End Script –?–?–?–?–?–?–?–?–?–?–?–?–?–

Similar Posts:

Permanent link to this article: http://myvirtualcloud.net/?p=1838

14 comments

3 pings

Skip to comment form

  1. chadd

    Does anyone know if this will work with View 5?

  2. Andre Leibovici

    @chadd
    I haven’t tested with VMware View 5.0 andn vSphere 5.0 but it should work without major issues.

    Andre

  3. JCM

    This does not seem to work on Windows 7 Virtual Machines. The process requires that psexec be launched by the Post-synchronization script, which is run under the SYSTEM account. On Windows 7, the SYSTEM account gets an “Access is denied” error when trying to launch PSEXEC. Has anyone found a way of successfully automating VLAN assignment like this for Win7 VMs?

  4. Andre Leibovici

    @JCM
    If you find a better way to execute VLAN changes please let us know.

    Andre

  5. Joe C

    I am trying to implement this into a vSphere 5 environment. Along with the psexec “access is denied” message, I am running into other challenges with the Powershell script.
    I am running WinXP SP3 VMs only.

    Has anyone out there successfully applied this solution? Would love to hear some success stories.

    Thanks!

  6. JCM

    We have gotten this working in our View 5 environment with Windows 7. We are using Domain Group Policy Preferences to create a Scheduled Task that uses a Service account to launch the scripted VLAN assignment process. This resolved the issue we were experiencing where the SYSTEM account used by the PostSync process did not seem to have access to run PSEXEC on Windows 7. I have done tests so far recomposing 100-200 VMs using this process to automatically assign a VLAN to a subset of those VMs. We modified the PS script that runs on the VM so it looks at the first nine characters of the VM Name to determine its VLAN – that way the .csv does not need to include the exact name of every VM in the environment.

    Some caveats to be aware of with this approach:
    1. The account being used to connect to vCenter using PSEXEC to launch the SetVLAN PS script must have local Admin privileges on the vCenter server. PSEXEC must be able to connect to the Admin share on the remote computer to initiate the remote process.
    2. If locking down the account being used to launch the script on vCenter, it must have the following permissions in vCenter at a minimum in order to set the VLAN on VMs:
    Network – Assign Network
    Virtual Machine (Configuration) – Modify Device Settings
    Virtual Machine (Interaction) – Reset
    3. The PS script run on vCenter consumes a large amount of resources (or at least it is in our environment); you may need to allocate more CPU/RAM to your vCenter server to make sure it does not run out of resources when doing large Recompose operations after implementing the automated VLAN process.
    4. At least in our tests here, the process does not seem to work 100% of the time (out of 50 VMs 5 might not be properly reconfigured). If assigning the proper VLAN is critical to your operations, you would probably want to add some more logic to the scripts/process to verify that the appropriate VLAN has been assigned. In our environment, we’re just trying to segregate our VMs on different VLANs to reduce problems caused by broadcast storms, so if a small number of VMs are not on the “proper” VLAN it doesn’t cause any major issues for us.
    5. Our antivirus was blocking PSEXEC, so we had to Exclude it from On-Access Scans to allow the process to work. We only Exclude it if the .exe is in the Path we specify to try to minimize the potential for viruses exploiting it due to the Exclusion.

    I have found out that Unidesk can assign VLANs to VMs as it is creating them. If dynamically assigning the correct VLAN is critical, it may be worth looking at that product. It is a system that automates customizing VMs during the Provisioning process by “layering” applications/settings.

    Another topic that came up in a recent vShield presentation from VMWare is the concept of segregating VMs from each other using vShield App. With vShield App, you can control inter-VM communications without requiring separate VLANs at all. That is likely the approach we will try to take in the long-term once we’ve had more time to look into it.

    @Joe C

  7. Joe C

    @JCM

    Thanks for the response. I’ve checked out Unidesk and it seems like it has some decent features. We went with Profile Unity, so leveraging Unidesk isn’t an option. Most likely it’s my script that is the culprit here, as I am not great at Powershell or VB.
    I made some changes in the script. Is my criteria wrong here? In the fetch.bat I am copying the csv to the local machine:

    start-sleep -seconds 15
    # First get the name of the virtual machine and store it in the variable $vmName
    $vmName = get-content env:computername
    # Next, connect to the data source (in this case a simple CSV)
    $obj = import-csv C:\Windows\Installs\data.csv
    # Finally, search the CSV for the virtual machine name and find the associated VLAN ID
    foreach ($item in $obj)
    {
    if ($vmName -eq $item.VMName) <——-
    {
    # If we find a match, execute postsync.ps1 from the VirtualCenter server
    psexec -accepteula -d \\servername -u servername\administrator -p password -i C:\Windows\System32\WindowsPowershell\v1.0\Powershell.exe D:\PostSync\Postsync.ps1 $vmName $item.VLANID <——
    }
    }

    1. forbsy

      Why can’t you run ProfileUnity and Unidesk together?

      1. Andre Leibovici

        I guess you can do that if both solutions combined provide the required functionality. However, without disclosing too much, I would wait for the next VMware View release to see if there is any new functionality that will help you with that.

        Andre

  8. JCM

    @Joe C
    Make sure the first row of your .csv specifies the Headers used in the functions related to the csv, otherwise statements like “if ($vmName -eq $item.VMName)” will fail.

    I had to add the “-s” switch to the RunfromGuest.PS1 script to have the PostSync.ps1 run on vCenter as the SYSTEM account, and I had to add the “-file” switch to specify the path to the script. In your case, that would be:
    psexec -accepteula -d \\servername -u servername\administrator -p password -s -i C:\Windows\System32\WindowsPowershell\v1.0\Powershell.exe -file “D:\PostSync\Postsync.ps1″ $vmName $item.VLANID

    The important thing is to test each component individualy to make sure each script is working on its own before trying to put the whole process together, and then troubleshoot it as a whole once you know the individual parts are working.

  9. Joe C

    Finally got this working, thanks for your help. I had the VLANID $args wrong. One thing I noticed, it takes a while for it to complete.
    What I may do is only use the postsync.ps1 and modify it with wild cards for each pool. Then run a task after recomposition. It is so much faster when switching ports and rebooting than using the csv method.
    I hope that VMware incorportates something to handle this. I have an open ticket with them and filled out a “feature request”.
    Once again THANKS, this is a very cool method and great assistance on this site!

  10. Paul

    Hi – is it not possible to set the Master to one VLAN (say 999) and then give that VLAN access to the other VLANs (say 900-910). Use the Helper address for VLAN 999 to point to the DHCP Server and create scopes for the 900-910 VLANs?

  11. Vaibhav

    I got this working on windows 7 and vcenter on windows 2008 using the invoke command design
    Needed to set on vcenter for powershell memory & Shells allowed for on vcenter server

    set-item wsman:localhost\Shell\MaxMemoryPerShellMB 1024
    winrm set winrm/config/winrs ‘@{MaxShellsPerUser=”50″}’

    postsync script
    # ——————————– Begin Script ————————————
    # Load the VIM API
    Write-Host $args[0]
    Write-Host $args[1]
    Add-PSSnapin VMware.VimAutomation.Core
    # Connect to the VirtualCenter
    connect-viserver $vcenterservername -User $vcenteruserid -Password $vcenterpassword
    # RunFromGuest.ps1 passes the VMname and the VLAN information, then sets the VLAN accordingly
    get-vm $args[0] | get-networkadapter | set-networkadapter -networkname $args[1] -confirm:$false
    # Because we just disconnected the NIC and changed the VLAN, reboot the virtual machine
    Write-Host $args[0]
    restart-vmguest -vm $args[0] -confirm:$false
    exit
    # ——————————– End Script ————————————

    # ——————————– Begin Script ————————————
    start-sleep -seconds 15
    # First get the name of the virtual machine and store it in the variable $vmName
    $vmName = get-content env:computername
    # Next, connect to the data source (in this case a simple CSV)
    $obj = import-csv \\$vcenterserver\postsync\data.csv
    # Finally, search the CSV for the virtual machine name and find the associated VLAN ID
    foreach ($item in $obj)
    {
    if ($vmName -eq $item.vm)
    {
    # If we find a match, execute postsync.ps1 from the VirtualCenter server

    $VLAN=$item.vlan
    $pass = convertto-securestring “$vcenterpassword” -asplaintext -force
    $mycred = new-object -typename System.Management.Automation.PSCredential -argumentlist “$$vcenteruserid”,$pass
    Invoke-Command -computername $vcenterservername -Credential $mycred -scriptBlock {param($vmName,$VLAN) C:\postsync\postsync.ps1 $vmName $VLAN } -Argumentlist $vmName,$VLAN
    }
    }
    # ——————————– End Script ————————————

  12. Andre Leibovici

    @Vaibhav
    Thanks for sharing this with us. Vary useful!

    Andre

  1. - Cliff Davies

    […] solution created by few VMware colleagues to automatic change the desktop VLAN in VMware View (here). The solution works great and I have received comments from organizations that have successfully […]

  2. Automatic IP Assignment and VLAN change in VMware View « vResource.net

    […] solution created by few VMware colleagues to automatic change the desktop VLAN in VMware View (here). The solution works great and I have received comments from organizations that have successfully […]

  3. Automatic IP Assignment and VLAN change in VMware View » myvirtualcloud.net

    […] solution created by few VMware colleagues to automatic change the desktop VLAN in VMware View (here). The solution works great and I have received comments from organizations that have successfully […]

Leave a Reply