Scheduled View VM refresh

Posted by: hbr in vmwareviewvdischedulerefreshdesktop virtualization on Print 

If you use non persistent desktops with VMware View, there are two options to reset the machine to its default state. One is immediately after a user logs off, the other is manually by a View Administrator. Currently, there is no way to schedule a VM reset at, say, 2PM. 

A VM reset generates a lot of IOPS. So doing this in a production environment that's strained for IOPS is a performance risk (read http://virtuall.eu/download-document/vdi-storage-deep-impact!). But having administrators do this every day when everybody's logged off is not a real option either. 

Luckily, there is a way to schedule VM resets. The View Connection server has a local LDAP database (Microsoft's ADAM) that contains all information and tasks for the VDI desktops. What needs to be done is to change a couple of properties for VM objects in this database: 

  • pae-SVIVmPendingOperation: refresh
  • pae-SVIVmPendingOperationPolicy: immediate
  • pae-SVIVmOperationId: [Unique GUID!]
  • pae-SVIVmOperationStartTime: YYYYMMDDHHmmSS.0Z
  • pae-SVIVmOperationStatus: scheduled
  • pae-SVIVmOperationProgress: 0
If you change those for all VMs from a View pool, the VM reset will be executed at the given time.
To script this, first you need to find all VMs from a pool. One way of doing this, is to use ldifde against the connection server with a domain context of vdi.vmware.int:
  •  ldifde -f output.ldf -s 127.0.0.1 -d "ou=servers,DC=vdi,DC=vmware,DC=int"
And because we don't need everything else, we filter on the poolname and objectclass pae-VM and request only 2 properties back:
  •  ldifde -f output.ldf -s 127.0.0.1 -d "ou=servers,DC=vdi,DC=vmware,DC=int" -r "(&(objectclass=pae-vm)(pae-MemberDNOf=cn=VDI_POOL_NAME,ou=server groups,dc=vdi,dc=vmware,dc=int))" -l dn,pae-displayname 
We can now create a loop that generates a ldif change file and import that back into the ADAM database: 
  • ldifde -i -f import.ldf -z -k -s 127.0.0.1 
Using the ldifde from the C:\windows\ADAM directory allows the -z and -k options to ignore any messages on properties that already exist so use that one. 
After this import, the VMs will reset at the given time (or thereabout). Schedule this script with windows scheduler on a Connection server and you're set. 
 
Instead of building your own script you can use mine. It has some additional options and error checking that should make life even easier. Copy and paste this in a Schedule.cmd file or download it from http://virtuall.eu/download-document/schedule-vdi-view-vm-refresh
 
@echo off

setlocal & pushd %~dp0

:: set DBG to ECHO to get more verbose output or to REM for quiet operation
set DBG=ECHO
set LDIF=C:\windows\adam\ldifde.exe
set OUT="%TEMP%\out.ldf"
set LOG="%TEMP%\ldf.log"
set ERR="%TEMP%\ldf.err"
set IMP="%TEMP%\import.ldf"
set GUID="%TEMP%\genGuid.js"

type nul:>%OUT%
type nul:>%IMP%

if not exist %LDIF% goto :ERR1
if not exist %OUT% goto :ERR2

echo WScript.Echo ( new ActiveXObject("Scriptlet.TypeLib").GUID.substr(1,36)); > %GUID%

set sDate=
set sTime=
set Pool=
set execute=

:args
if "%1" == "" goto :argsDone

if not "%~1" == "-l" goto :argExec
  %LDIF% -f %OUT% -s 127.0.0.1 -d "ou=applications,dc=vdi,dc=vmware,dc=int" -r "(objectClass=pae-App)" -l cn -j "%TEMP%" > %LOG% 2> %ERR%
  if errorlevel 1 goto :ERR3
  for /f "tokens=*" %%i in ('type %OUT%') do call :list "%%i"
  goto :end
:argExec

if not "%~1" == "-f" goto :argPool
  set execute=1
  shift 
  goto :args
:argPool

if not "%~1" == "-p" goto :argDate
  set Pool=%~2
  shift 
  shift
  goto :args
:argDate

if defined sDate goto :argTime
  set sDate=%~1
  set sDate=%sDate:~-10%
  if not "%sDate%" == "%~1" set sDate=
  set sDate=%sDate:-=%
  shift
  goto :args
:argTime

if defined sTime goto :argsDone
  set sTime=%~1
  set sTime=%stime:~-5%
  if not "%sTime%" == "%~1" set sTime=
  set sTime=%sTime::=%
  shift
  goto :args
:argsDone

if "%sDate%" == "" goto :syntax
if "%sTime%" == "" goto :syntax
if "%Pool%" == "" (
  set Filter=(pae-MemberDNOf=*) 
) else (
  set Filter=(pae-MemberDNOf=cn=%Pool%,ou=server groups,dc=vdi,dc=vmware,dc=int)
)

%LDIF% -f %OUT% -s 127.0.0.1 -d "ou=servers,DC=vdi,DC=vmware,DC=int" -r "(&(objectclass=pae-vm)%FILTER%)" -l dn,pae-displayname -j "%TEMP%" > %LOG% 2> %ERR%
if errorlevel 1 goto :ERR3

set count=0
for /f "tokens=*" %%i in ('type %OUT%') do call :proc "%%i"

echo %count% entries updated
if not defined execute goto :END
%LDIF% -i -f %IMP% -z -k -s 127.0.0.1 -j "%TEMP%" > %LOG% 2> %ERR%
if errorlevel 1 goto :ERR3
goto :END

:list
set l=%~1
if not "%l:~0,3%" == "cn:" goto :EOF
echo %l:~4%
goto :EOF

:proc
set dn=%~1
if "%dn:~0,3%" == "dn:" goto :showDN
if "%dn:~0,3%" == "pae" goto :showCN
goto :EOF
:showCN
%DBG% %count%: Setting reset time for %dn:~17% to %sDate%, %sTime%
goto :EOF
:showDN
set /a count=count+1
for /f %%i in ('C:\windows\system32\cscript.exe //nologo %GUID%') do set SID=%%i
echo %dn%>>%IMP%
echo changetype: modify>>%IMP%
echo replace: pae-SVIVmPendingOperation>>%IMP%
echo pae-SVIVmPendingOperation: refresh>>%IMP%
echo ->>%IMP%
echo replace: pae-SVIVmPendingOperationPolicy>>%IMP%
echo pae-SVIVmPendingOperationPolicy: immediate>>%IMP%
echo ->>%IMP%
echo replace: pae-SVIVmOperationId>>%IMP%
echo pae-SVIVmOperationId: %SID% >>%IMP%
echo ->>%IMP%
echo replace: pae-SVIVmOperationStartTime>>%IMP%
echo pae-SVIVmOperationStartTime: %sDate%%sTime%00.0Z>>%IMP%
echo ->>%IMP%
echo replace: pae-SVIVmOperationStatus>>%IMP%
echo pae-SVIVmOperationStatus: scheduled>>%IMP%
echo ->>%IMP%
echo replace: pae-SVIVmOperationProgress>>%IMP%
echo pae-SVIVmOperationProgress: ^0>>%IMP%
echo ->>%IMP%
echo replace: pae-SVIVmOperationFlags>>%IMP%
echo pae-SVIVmOperationFlags: onError=StopOnError>>%IMP%
echo ->>%IMP%
echo.>>%IMP%
goto :EOF

:syntax
echo.
echo   %~n0 [-l] [-f] [-p POOLNAME] YYYY-MM-DD HH:mm
echo.
echo   -l  :  list available VDI pools.
echo   -f  :  force execution of changes. without this no changes will be made!
echo   -p  :  only update machines from this specific pool. without this option, 
echo            all machines will be updated!
echo.
pause > NUL:
goto :EOF
:ERR1
echo This is not an ADAM capable server (probably not a View Connection server). 
pause > NUL:
goto :END

:ERR2
echo Could not create tempfile in %TEMP%.
pause > NUL:
goto :END

:ERR3
type "%TEMP%\ldif.err" 2> NUL
pause > NUL:
goto :END

:END
endlocal & popd

 

Comments (0)Add Comment

Write comment
You must be logged in to post a comment. Please register if you do not have an account yet.

busy