VDI optimization script (part 2)
In my previous article I wrote about a VDI optimization script from Microsoft for Windows 8 and Windows 7. This article focuses on the features and services you could disable or adjust to increase the performance of your VDI desktops. There are a lot of changes that can be made and you might want to decide which change you do or do not use within your own infrastructure. Running the script in it’s default form could very well not be the way that you want it to be.
In this article I will try to explain the script in such a way that you should be able to read it and take out the parts that you want to use. Maybe after looking at the script you decide that you don’t want to use the script in itself, but it at least will show you where you can make the changes and choose your own way of applying it. So lets get started…
At several places in the script you can find lines that start with aThe text following after those marks are considered only text and don’t contain any script that is going to be executed. These lines are mostly used to provide information on what is happening.
Within this article there are several command-line tools mentioned that are used by the script. Some you probably already know about, but for a quick reference I added links to sites for each tool at the bottom.
Setting the variables
At the beginning of the script there are several variables that are set. The lines that start with “Const” are variables that are created and filled with a default response but can change by arguments that the administrator can pass along the execution of the script.
The “Set” command is used to give variables a certain role within the script that won’t change and help in making the script more readable and save hours of typing the same commands.
Determining the arguments
In the next part of the script it is determined if the administrator has passed along any of the “named” arguments (see link a bottom of article) with the execution of the script. An example of passing a named argument in this case might be: script.vbs /Aero:True
Within the script there are IF THEN statements that look like this:
If colNamedArguments.Exists(“Aero”) Then
strAero = colNamedArguments.Item(“Aero”)
strAero = Disable_Aero
This statement determines if the argument “Aero” has been passed along. If it is then the value of the variable “strAero” is set to the value that was entered when starting the script. In the case of our example this would mean the value is changed to “True”. When the argument Aero is not given the strAero will receive the value “Disable_Aero”.
Enable RDP Connections
To enable RDP connections there are two services that need a change, this being the RDP services itself and the firewall service. Both can be changed by using a command-line tool, one tool for each service.
First the RDP services is changed by using WMIC:
WMIC rdtoggle where AllowTSConnections=0 call SetAllowTSConnections 1,1
The firewall service needs a existing rule to be enabled and this is done with the netsh command:
netsh advfirewall firewall set rule group=” & Chr(34) & “remote desktop” & Chr(34) & ” new enable=Yes
In the script you will see that there is a command in front of those lines called “RunWait”. This command is actually a function which is placed further down in the script which I will explain later on in the document.
The script will disable a lot of services and for some it will also adjust other settings. There are a few different sets of commands used in this part of the script and I will try to explain the ones used.
Most commonly used in the script is the sc config command which is a command-line tool for editing services. This command is pretty straight forward, simply type the service name behind the command and define what you want to happen. An example of this is: sc config BITS start= disabled
At the beginning of the script we had a few named arguments that where defined. Depending on what the administrator used as arguments, these will now be used to determine if a service is disabled or not with lines like these:
If strAero = True Then
‘ Disable Themes Service
RunWait “sc config Themes start= disabled”
If an argument was passed along at the beginning of the script then the value of “strAero” has become “True” and thus will it execute the sc config command. If the strAero has any other value then true the script will going along with the next part and leave the service as it is.
Then there are a few services that also make use of scheduled tasks that need to be changed or disabled. Again there is a command-line tool available that is used within the script, this one is called schtasks: schtasks /change /tn “”microsoft\windows\defrag\ScheduledDefrag”” /disable
The “/change” indicates that you want to change the task that is named after the “/tn” into the disable state.
Finally there are lines in which the registry is being changed. An example line of this: oShell.RegWrite “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Dfrg\BootOptimizeFunction\Enable”, “N”, “REG_SZ”
In the beginning of the script there was a command setting “oShell”. This made it so that oShell can be used (amongst other things) to manipulate the registry. With the addition of “Regwrite” it indicates that you want to write/change something to the registry. The values entered are pretty self exploratory.
Most of the machine settings that are changed use one of the methods described earlier in the article. There are however a few additions that I will describe shortly, for more information on these command-line tools please refer to the links I applied at the bottom of the article.
There are some power management settings that will be changed and this is done through the powercfg command. The ones that might be a bit confusing are those that contain GUID numbers for the setting that needs to be changed: POWERCFG /SETACVALUEINDEX 381b4222-f694-41f0-9685-ff5bb260df2e 0012ee47-9041-4b5d-9b77-535fba8b1442 6738e2c4-e8a5-4a42-b16a-e040e769756e 0
Each set of numbers is separated with a space:
- First set specifies the power schema
- Second set specifies the subgroup of the selected schema
- Third set specifies the actual power setting you want to change
- Fourth number is the setting option as it is numbered in the list of options for the selected setting
In the linked article below you can find the switches that can be used to trace the GUID numbers used.
Known by most people is the fsutil command. The script only uses it once, in which it disables the “last access timestamps”.
There are changes made to the bootlog and the boot animation. These are made with the command Bcdedit.
This part of the script only does changes to the regisrty and the oShell.Regwrite was explained earlier. This leaves little to explain about this part of the script, but I did want to highlight the next line: RegBinWrite “HKEY_CURRENT_USER\Control Panel\Desktop”, “UserPreferencesMask”, “90,12,01,80”
With “RegBinWrite” the script is calling a part of the script that is called a “sub” which is defined further down the script. This call also passes along three values:
- HKEY_CURRENT_USER\Control Panel\Desktop
The sub in this case is used to create a registry file in a temporary directory. That file is then imported in the regisrty after which the file is removed. As of why this registry edit is being done trough another methode compared to the rest I have yet to figure out.
There are parts within the script that make repeated use of the same functionalities. To save time in typing these parts over and over again it is possible to make use of so called “functions”. One example of these functions is “Runwait” which we have seen multiple times throughout the script.
RunWait = oShell.Run(sFile, 1, True)
As mentioned earlier I will explain the purpose of this function with the help of an example:
RunWait “sc config Themes start= disabled”
To make a function work you will want to give along some data for it to work with. In this case we are sending along the data that is written down between the double quotes “sc config Themes start= disabled”.
The function Runwait starts with putting the data in a variable called “sFile” as defined between the () on the first line of the function.
Next the function will execute the oShell.run command with the use of three arguments:
- First value = sFile, which is the actual program you want to run
- Second value = 1, which means that the program is visible while running
- Third value = True, which means that the script will wait for the command to finish before continuing with the rest
The helper function section has a few more functions and one sub that I will list:
- Run, this runs visibly but does not wait for the command to finish
- RunWaitHidden, runs invisible and waits for the commond to finish
- IsServer, checks if the operating system is that of a server or desktop
- RegbinWrite (sub), explained this one in more detail with the user settings
- GetTEMPDir, is used by the RegbinWrite sub to get the temp directory
Of this list the first three I haven’t seen being used in the script. I guess the developers of the script wanted to provide the option at forehand for those that wanted to use them.
WMIC (WMI command-line): http://msdn.microsoft.com/en-us/library/windows/desktop/aa394531(v=vs.85).aspx
Named arguments: http://technet.microsoft.com/en-us/library/ee156618.aspx
WshShell (oshell.run): http://msdn.microsoft.com/en-us/library/d5fk67ky(v=vs.84).aspx
Hopefully this explanation of the script will give you some insight in what is going on or at least helps you get further in understanding it.