Security – Hardening – Part 1 – Virtual Machines

A couple of weeks ago Charu Chaubal published his draft vSphere 4.0 Security Hardening Guides in the Security & vShield Zones community. If you haven’t read them yet, you definitely have to put them on your To-do list.

A vSphere administrator often considers security as a necessary evil that he has to take care of at a point in time, preferably a few days before an audit is going to take place šŸ˜‰

Charu’s Guides can make this exercise a lot easier. And if we add to those guides some scripts to automate the hardening process, the vSphere administrator has no more excuses to tackle security on a regular basis (like it should be !).

Background information

Charu’s Guides are by far not the only security resources that are available to the vSphere administrator, but at this point in time they are in any case the most-up-to-date resources.

The security bible is of course Edward Haletky‘s book VMware vSphere and Virtual Infrastructure Security. A book every serious vSphere administrator should have on his bookshelf.

Some other noteworthy resources to consult:

Automating the hardening process

The first to publish an automated process based on Charu’s Hardening Guides was William Lam. His script produces a great report, where you can see immediately which hardening guidelines need your attention.

My idea was to automate not only the verification but also the correction, where possible.

Purely random, I have chosen the Virtual Machine Hardening Guide as my first attempt on automating the hardening process.

Preparing the script

If you read the Virtual Machine Guide you will notice that most of the guidelines are composed of conditions that can be easily automated.

My first challenge was to find a “structure” to store the guidelines. After some testing I came up with this structure.

Each recommendation is represented by such an object. And each of these objects is stored in a hash table with the vulnerability code as the key.

In these objects the following properties are present:

  • Level: indicates for which operational environment the recommendation is intended
  • Combination: a recommendation can have multiple components. This property indicates how they shall be combined
  • Keys: the parameters to check for. Is an array
  • Operation: an array with the operation to perform on the Key-Value combination
  • Values: the actual values the parameters are checked against

An example will hopefully make this a bit clearer. Let’s take recommendation VMX01.

This recommendation tells you to check two parameters (“” and ““) in the VMX file. Both parameters should have the value “TRUE”. This gives the following object, which is added to the hash table with the key “VMX01”.

The second problem to solve was the multitude of operators that are used in the recommendations. These range from “equal” over “not equal” to “exists” and “not present”, and some more. Thanks to PowerShell this was in the end not too difficult to solve. More on these operators later on in the script annotations.

The script


Line 4-9: This hash table contains the maxima, as described in Configuration Maximums, for specific virtual hardware.

Line 11: This is the hash table that will hold all recommendations. The key for each recommendation object is the Code from the Hardening Guide.

Line 12-161: All the recommendations that I was able to encode as an object.

Line 162-170: I’m not sure at this point in time if recommendation VMX55 can be automated. I couldn’t find any definition of the VMX parameter “”. I don’t know how many “filters” there can be. I left this recomendation out for now.

Line 173-180: Function to create a new VMX parameter if the script is run with the option to implement the recommendations.

Line 182-233: The Test-VMXDevPresence function check if specific devices are present in the VMX file.

Line 185: Some devices can be present more than once. That’s were the capital X is used for. Together with maximums in hash table $VmMax this allows the script to test all possible parameters for a specific device type.

Line 188: IDE devices have two numerical fields in their parameters. That’s why the capital Y appears in the condition for IDE devices.

Line 206, 209, 215, 218, 226, 229: Once the parameter is composed it’s rather straightforward to look up if the parameter exists by using the hash table $VMXtab.

Line 235-239: Function to test if there exists a portgroup with the name in $pgName on the ESX server that hosts the specific virtual machine.

Line 241-245: Function to test if there exists a dvSwitch with the name in $dvSwName on the ESX server that hosts the specific virtual machine.

Line 247-267: Driving function that checks if an object with a specific name exists on the ESX server that hosts the specific virtual machine.

Line 270: The Boolean variable $report defines if the script should produce a report.

Line 271: The Boolean variable $correct defines if the script should apply the recommendations

Line 272: The string variable $scope specifies to the script which recommendations should be investigated. Possible values are “Enterprise”, “DMZ”, “SSLF” or “All”.

Line 277-278: These lines select the virtual machines that will be checked and eventually hardened. These lines can be replaced by any other selection mechanism, as long as the $vms variable is populated by one or more VirtualMachineĀ  objects.

Line 289-292: These lines load all VMX parameters into a hash table. The key is the parameter name.

Line 295: This loop runs through all recommendations.

Line 303-325: This switch construction handles all Operation types.

Line 326-333: This switch construction handles all Combination options.

Line 346-348: If the corrective action was requested (the $correct variable) then all the parameter changes are added to the extraconfig property.

Line 355-357: When all recommendations are verified and when the corrective action was requested, this call to ReconfigVm will apply all changes required by the recommendations.

The report

If the reporting option is selected the script will produce a CSV file that shows what was found on each virtual machine for each of the recommendations.

In the report you see the following columns.

  • Code: The recommendation code.
  • Level: The recommendation level which was used.
  • Condition: The “keys” from the recommendation object above
  • Value: The value for the key that was found on the virtual machine
  • Desired: The value that is recommended
  • OperDesired: How the conditions for a specific recommendation were combined. The Combination property in the recommendation object.
  • Protected: Indicates if the virtual machine is protected against the vulnerability described in the recommendation


As I already mentioned above not all recommendations are implemented in this version of the script.

  • VMX55 uses the parameter but for now I don’t know the syntax and limits of this parameter
  • The removal of a portgroup and a dvSwitch as recommended in VMX50 and VMX53 is not implemented in the script as I feel this should belong in the Host Hardening Guide
  • VMX03 only mentions and but apparently there are also the parameters and I think they should be included in the recommendation as well. And it would be useful to know which of these takes precedence.

And as this is the first version of this script there will most probably be some “features” present in the script. I tested against a number of configurations but with the abundance of VMX parameters, it is nearly impossible to have a test scenario that includes all possible combinations.

If you encounter a bug or a problem please forward me the VMX file that caused the problem. And if you have any suggestions, feel free to forward them to me as well.

To close, a word of warning, before you use this to implement the recommendations in your production environment test, test and test again. And make sure you have a fall-back scenario if something goes wrong !



    Hi Luc,

    Been using this script for a long time but now vSphere 5 is out i’d like to use it still, should this script work with vSphere 5 ?? as in ESXi 5 VM’s.



    In the script, guest.command.enabled is tested in VMX30. VMware has a KB article 1010103
    seems to indicate the parameter name is guest.commands.enabled (with an ‘s’). Should the script be updated to guest.commands.enabled or are these two different parms?

    Thank you,




    VMX10 doesn’t work for me. All other changes work fine but VMX10.

    The error I get is:

    Exception calling “ReconfigVM” with “1” argument(s): “A specified parameter was not correct.

    At C:\4.VMhardening.ps1:302 char:17
    + $vm.ReconfigVM <<<< ($vmConfigSpec)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Any idea ?


    I used this script last year, and didn’t have a problem. I’ve built some new ESXi4.1 hosts, standalone not connected to vCenter, and am trying to run the script. I get the following message when I set (line 271) $correct = $true:

    Exception calling “ReconfigVM” with “1” argument(s): “fault.RestrictedVersion.summary”
    At C:\scripts\ESXi_hardening\report-harding-vm-guests.ps1:357 char:19
    + $vm.ReconfigVM <<<< ($vmConfigSpec)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    The only other change I made was on line 278: $rootNode = Get-VM | Get-View


      @Rob, it looks as if you are using a “free” ESXi installation (indicated by the restrictedversion fault).
      I’m afraid you only have read-only access to that type of server, no changes allowed.

    Serge Meeuwsen

    Hi Luc,
    Great script, I really like the way you set it up, it’s easily extensible.
    I have one issue tho I’m trying to figure out and hoping you have some ideas.
    Somehow in my lab environment, the $vm.config.extraconfig doesn’t contain all keys and values present in the VMX file. For instance I have a VM which does have floppy0.present = “TRUE” in its VMX file, but when I examine that VM’s .config.extra.config, it’s not present there.
    Hence the script cannot report correctly in this case.

    My Lab environment is as follows:
    ESXi 4.1.0 build 348841
    vCenter is version 4.1.0 345043
    PowerCLI version is 4.1 U1 build 332441



      @Serge, you are correct, the floppy drive presence is not visible in the ExtraConfig property in vSphere 4.x.
      It seems that we will have to use the Config.Hardware.Device table to determine if there is a connected virtual floppy present.
      This will require some fundamental re-writing of the script, I’m afraid.


    Hi LucD,

    Great script! I’ve looking for something to audit these isolation settings to ensure they are always applied or changed. Do you know of other scripts or other tools for that purpose?



      @PJT, thanks.
      There will a chapter in our upcoming book on hardening.
      There are some commercial tools on the market that do a security check of your environment.


    Disclaimer: That would only work if you were not using vmsafe.

    Also, I noticed that if you run the script with both the $report and $correct set to $true then the report wasn’t updated with the configurations that were changed.


    Here’s an example of how I correct it for VMX50:

    $VMThreats[“VMX51”] = (New-Object PSObject -Property @{
    Level = “Enterprise”
    Combination = “and”
    Keys = @(“vmsafe.enable”,
    Operation = @(“eq”,
    Values = @(“FALSE”,


      @Abe, that’s indeed a good solution.
      Thanks for sharing that.


    I found that the settings that had an operation of “ne” (as “vmsafe.enable” shown on lines 114-161) actually set the value to what was defined in “Values” when you ran the script with $correct = $true. I think this is due to the line:

    “$vmConfigSpec.extraconfig += (Set-VMXOption $ThreatParam.Keys[$i] $ThreatParam.Values[$i])”

    It does not have a parameter in the case that the operation is set to “ne”. I loved the script and it worked great otherwise.


      @Abe, you’re absolutely right.
      I’ll have to figure out how to correct these “ne” conditions in the script.
      I guess an “ne” requirement can be translated in an “eq” requirement. But that would mean the script needs to know all the possible values.
      Another alternative is to remove the key from the .VMX file. But that means I would need to make sure that the default are not conflicting with the requirement.

      I definitely have to do a bit of brainstorming on this one šŸ™‚


    Hi Luc… the script is awsome bt I am getting the following msg when running it.
    Index operation failed; the array index evaluated to null.
    At C:\Program Files\VMware\Infrastructure\vSphere PowerCLI\My-Scripts\Testing\Scan_VMX.ps1:291 char:11
    + $VMXtab[ <<<< $_.Key] = $_.Value
    + CategoryInfo : InvalidOperation: (System.Collections.Hashtable:Hashtable) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex


      @Rahul, thanks.
      It looks as if you have 1 or more guests with an empty VMX file.
      Can you execute the following line and check if there are any guests that have 0 (zero) in the Count column ?

      PowerCLI 4.1 version

      Get-VM | Select Name,@{N="Count";E={$_.Extensiondata.Config.ExtraConfig.Count}} | ft -AutoSize

      pre-PowerCLI 4.1 version

      Get-View -ViewType VirtualMachine | Select Name,@{N="Count";E={$_.Config.ExtraConfig.Count}} | ft -AutoSize

    Iben Rodriguez

    Great work both of you. Not sure why I am only just now finding this site but better late than never.

    There’s a new version of the hardening guide out since April and there are some updates needed still.

    Keep the feedback coming so we can improve it.

    As for the disk shrink issue – this is not even supported with VMware ESX so not sure why we recommend this setting. But we will improve as we go along.


    If I just want to get the values of “” and ” and “” for each VM. Could you help simplify the script? Thanks.


    very good script –> right on


      Thanks. I hope to post scripts for the other hardening parts in the near future.


    Excellent script. Not something thrown together, but planned out and well executed — as I would expect from the great LucD. Bravo and thank you for your efforts! :



      Thanks Doug


    it works now, i did not even have a profile.ps1 so i created it.

    i might recommend to group the output by vm instead. i can solve this for myself by adding a sort to the VMName column.

    thanks for this tool.


      Ken,you only have to change the order of the names on the Sort-Object -Property parameter in line 360.


    I’m also very inexperienced with powershell. I upgraded to v2 RTM and receive these errors:

    The term ‘Get-Folder’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or
    if a path was included, verify that the path is correct and try again.
    At D:\hardesx.ps1:277 char:23
    + $rootNode = Get-Folder <<<< -Name "VMXtest" | Get-View
    + CategoryInfo : ObjectNotFound: (Get-Folder:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    I did a bit of reading to try and narrow the problem down and made sure RemoteScripts was enabled and checked that the path was correct.


      Hi Ken, it looks as if the PowerCLI snapin is not loaded when you execute the script.
      You can try adding the following line to the top of the script:

      Add-PsSnapin VMware.VimAutomation.Core

      I don’t know how you start the script (PowerCLI prompt, PowerShell prompt or one of the GUIs) but ultimately it would be better to add the line above to one the profile.ps1 files.
      See Tobias’s paragraph called Profile: Autostart Scripts for more information.

    J. Kalf


    Very nice script. I’ve given it a test run. But I can’t seem to get it working right at the moment. I’m no vPowercli specialist, so that might be the issue at hand.

    But on running the script I get the following error message over and over again:

    New-Object : A parameter cannot be found that matches parameter name ‘Property’

    I’m running powershell 1.(latest) with vPowercli 4.0.1-208462



      Hi Jelle,
      That’s an oversight from me, I should have mentioned that the script requires PowerShell v2 RTM.
      The -Property parameter on the New-Object cmdlet is new in PS v2 RTM.
      Sorry about that,

    John Reeman

    Really good script, well done. I am one of the developers behind a tool called vminformer, it does what your script does and more in terms of showing you graphically where your issues are.

    Interesting you mention the and as there is also isolation.device.edit.disable which seems to be similar to and again not sure which one takes precedence.

    Don’t want this to sound like a sales plug but would appreciate some feedback, so if you do get a chance to take a look send me an email and let me know your thoughts.




      Hi John,
      Had a quick look at your site and the product looks very interesting. Just requested for a download of the Community Edition. I will definitely give it a spin and send you my impressions.
      PS: I liked the your Scoobydoo movie on YouTube. It’s a very good vSphere security risks overview.

Leave a Reply

Your email address will not be published.


This site uses Akismet to reduce spam. Learn how your comment data is processed.