PowerShell Script: Change Advanced Settings of Hyper-V Virtual Machines

 

Each Hyper-V virtual machine sports a number of settings that can be changed, but not by any sanctioned GUI tools. If you’re familiar with WMI, these properties are part of the Msvm_VirtualSystemSettingData class. Whether you’re familiar with WMI or not, these properties are not simple to change. I previously created a script that modifies the BIOS GUID setting, but that left out all the other available fields. So, I took that script back into the workshop and rewired it to increase its reach.

If you’re fairly new to using PowerShell as a scripting language and use other people’s scripts to learn, there are some additional notes after the script contents that you might be interested in.

What this Script Does

This script can be used to modify the following properties of a Hyper-V virtual machine:

  • BIOS GUID: The BIOS of every modern computer should contain a Universally Unique Identifier (UUID). Microsoft’s implementation of the standard UUID is called a Globally Unique Identifier (GUID).  You can see it on any Windows computer with gwmi Win32_ComputerSystem | select UUID. On physical machines, I don’t believe that it’s possible to change the UUID. On virtual machines, it is possible and even necessary at times. You can provide your own GUID or specify a new one.
  • Baseboard serial number.
  • BIOS serial number.
  • Chassis asset tag.
  • Chassis serial number.

There are other modifiable fields on this particular WMI class, but these are the only fields that I’m certain have no effect on the way that Hyper-V handles the virtual machine.

Warning 1: Changes to these fields are irreversible without restoring from backup. Modification of the BIOS GUID field is likely to trigger software activation events. Other side effects, potentially damaging, may occur. Any of these fields may be tracked and used by software inside the virtual machine. Any of these fields may be tracked and used by third-party software that manipulates the virtual machine. Use this script at your own risk.

Warning 2: These settings cannot be modified while the virtual machine is on. It must be in an Off state (not Saved or Paused). This script will turn off a running virtual machine (you are prompted first). It will not change anything on saved or paused VMs.

Warning 3: Only the active virtual machine is impacted. If the virtual machine has any checkpoints, they are left as-is. That means that if you delete the checkpoints, the new settings will be retained. If you apply or revert to a checkpoint, the old settings will be restored. I made the assumption that this behavior would be expected.

The following safety measures are in place:

  • The script is marked as High impact, which means that it will prompt before doing anything unless you supply the -Force parameter or have your confirmation preference set to a dangerous level. It will prompt up to two times: once if the virtual machine is running (because the VM must be off before the change can occur) and when performing the change.
  • The script will only accept a single virtual machine at a time. Of course, it can operate within a foreach block so this barrier can be overcome. The intent was to prevent accidents.
  • If a running virtual machine does not shut down within the allotted time, the script exits. The default wait time is 5 minutes, overridable by specifying the Timeout parameter. The timeout is measured in seconds. If the virtual machine’s guest shutdown process was properly triggered, it will continue to attempt to shut down and this script will not try to turn it back on.
  • If a guest’s shutdown integration service does not respond (which includes guests that don’t have a shutdown integration service) the script will exit without making changes. If you’re really intent on making changes no matter what, I’d use the built-in Stop-VM cmdlet first.

Script Requirements

The script is designed to operate via WMI, so the Hyper-V PowerShell module is not required. However, it can accept output from Get-VM for its own VM parameter.

You must have administrative access on the target Hyper-V host. The script does not check for this status because you might be targeting a remote computer. I did not test the script with membership in “Hyper-V Administrators”. That group does not always behave as expected, but it might work.

Set-VMAdvancedSettings

Copy/paste the contents of the code block to a text editor on your system and save the file as Set-VMAdvancedSettings.ps1. As-is, you call the script directly. If you uncomment the first two lines and the last line, you will convert the script to an advanced function that can be dot-sourced or added to your profile.

#function Set-VMAdvancedSettings # uncomment this line, the second line, and the last line to use as a profile or dot-sourced function
#{ # uncomment this line, the first line, and the last line to use as a profile or dot-sourced function
	<#
	.SYNOPSIS
		Changes the settings for Hyper-V guests that are not available through GUI tools.
		If you do not specify any parameters to be changed, the script will re-apply the settings that the virtual machine already has.
	.DESCRIPTION
		Changes the settings for Hyper-V guests that are not available through GUI tools.
		If you do not specify any parameters to be changed, the script will re-apply the settings that the virtual machine already has.
		If the virtual machine is running, this script will attempt to shut it down prior to the operation. Once the replacement is complete, the virtual machine will be turned back on.
	.PARAMETER VM
		The name or virtual machine object of the virtual machine whose BIOSGUID is to be changed. Will accept a string, output from Get-VM, or a WMI instance of class Msvm_ComputerSystem.
	.PARAMETER ComputerName
		The name of the Hyper-V host that owns the target VM. Only used if VM is a string.
	.PARAMETER NewBIOSGUID
		The new GUID to assign to the virtual machine. Cannot be used with AutoGenBIOSGUID.
	 .PARAMETER AutoGenBIOSGUID
		  Automatically generate a new BIOS GUID for the VM. Cannot be used with NewBIOSGUID.
	 .PARAMETER BaseboardSerialNumber
		  New value for the VM's baseboard serial number.
	 .PARAMETER BIOSSerialNumber
		  New value for the VM's BIOS serial number.
	 .PARAMETER ChassisAssetTag
		  New value for the VM's chassis asset tag.
	 .PARAMETER ChassisSerialNumber
		  New value for the VM's chassis serial number.
	.PARAMETER ComputerName
		The Hyper-V host that owns the virtual machine to be modified.
	.PARAMETER Timeout
		Number of seconds to wait when shutting down the guest before assuming the shutdown failed and ending the script.
		Default is 300 (5 minutes).
		If the virtual machine is off, this parameter has no effect.
	.PARAMETER Force
		Suppresses prompts. If this parameter is not used, you will be prompted to shut down the virtual machine if it is running and you will be prompted to replace the BIOSGUID.
		Force can shut down a running virtual machine. It cannot affect a virtual machine that is saved or paused.
	.PARAMETER WhatIf
		Performs normal WhatIf operations by displaying the change that would be made. However, the new BIOSGUID is automatically generated on each run. The one that WhatIf displays will not be used.
	.NOTES
		Version 1.2
		July 25th, 2018
		Author: Eric Siron

		Version 1.2:
		* Multiple non-impacting infrastructure improvements
		* Fixed operating against remote systems
		* Fixed "Force" behavior

		Version 1.1: Fixed incorrect verbose outputs. No functionality changes.
	.EXAMPLE
		Set-VMAdvancedSettings -VM svtest -AutoGenBIOSGUID
		
		Replaces the BIOS GUID on the virtual machine named svtest with an automatically-generated ID.

	.EXAMPLE
		Set-VMAdvancedSettings svtest -AutoGenBIOSGUID

		Exactly the same as example 1; uses positional parameter for the virtual machine.

	.EXAMPLE
		Get-VM svtest | Set-VMAdvancedSettings -AutoGenBIOSGUID

		Exactly the same as example 1 and 2; uses the pipeline.

	.EXAMPLE
		Set-VMAdvancedSettings -AutoGenBIOSGUID -Force

		Exactly the same as examples 1, 2, and 3; prompts suppressed.

	.EXAMPLE
		Set-VMAdvancedSettings -VM svtest -NewBIOSGUID $Guid

		Replaces the BIOS GUID of svtest with the supplied ID. These IDs can be generated with [System.Guid]::NewGuid(). You can also supply any value that can be parsed to a GUID (ex: C0AB8999-A69A-44B7-B6D6-81457E6EC66A }.

	.EXAMPLE
		Set-VMAdvancedSettings -VM svtest -NewBIOSGUID $Guid -BaseBoardSerialNumber '42' -BIOSSerialNumber '42' -ChassisAssetTag '42' -ChassisSerialNumber '42'

		Modifies all settings that this function can affect.
	
	.EXAMPLE
		Set-VMAdvancedSettings -VM svtest -AutoGenBIOSGUID -WhatIf

		Shows HOW the BIOS GUID will be changed, but the displayed GUID will NOT be recycled if you run it again without WhatIf. TIP: Use this to view the current BIOS GUID without changing it.
	
	.EXAMPLE
		Set-VMAdvancedSettings -VM svtest -NewBIOSGUID $Guid -BaseBoardSerialNumber '42' -BIOSSerialNumber '42' -ChassisAssetTag '42' -ChassisSerialNumber '42' -WhatIf

		Shows what would be changed without making any changes. TIP: Use this to view the current settings without changing them.
	#>
	#requires -Version 4

	[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High', DefaultParameterSetName='ManualBIOSGUID')]
	param
	(
		[Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=1)][PSObject]$VM,
		[Parameter()][String]$ComputerName = $env:COMPUTERNAME,
		[Parameter(ParameterSetName='ManualBIOSGUID')][Object]$NewBIOSGUID,
		[Parameter(ParameterSetName='AutoBIOSGUID')][Switch]$AutoGenBIOSGUID,
		[Parameter()][String]$BaseBoardSerialNumber,
		[Parameter()][String]$BIOSSerialNumber,
		[Parameter()][String]$ChassisAssetTag,
		[Parameter()][String]$ChassisSerialNumber,
		[Parameter()][UInt32]$Timeout = 300,
		[Parameter()][Switch]$Force
	)

	begin
	{
		  function Change-VMSetting
		  {
				param
				(
					 [Parameter(Mandatory=$true)][System.Management.ManagementObject]$VMSettings,
					 [Parameter(Mandatory=$true)][String]$PropertyName,
					 [Parameter(Mandatory=$true)][String]$NewPropertyValue,
					 [Parameter(Mandatory=$true)][String]$PropertyDisplayName,
					 [Parameter(Mandatory=$true)][System.Text.StringBuilder]$ConfirmText
				)
				$Message = 'Set "{0}" from {1} to {2}' -f $PropertyName, $VMSettings[($PropertyName)], $NewPropertyValue
				Write-Verbose -Message $Message
				$OutNull = $ConfirmText.AppendLine($Message)
				$CurrentSettingsData[($PropertyName)] = $NewPropertyValue
				$OriginalValue = $CurrentSettingsData[($PropertyName)]
		  }

		<# adapted from http://blogs.msdn.com/b/taylorb/archive/2008/06/18/hyper-v-wmi-rich-error-messages-for-non-zero-returnvalue-no-more-32773-32768-32700.aspx #>
		function Process-WMIJob
		{
			param
			(
				[Parameter(ValueFromPipeline=$true)][System.Management.ManagementBaseObject]$WmiResponse,
				[Parameter()][String]$WmiClassPath = $null,
				[Parameter()][String]$MethodName = $null,
				[Parameter()][String]$VMName,
				[Parameter()][String]$ComputerName
			)
	
			process
			{
				$ErrorCode = 0
 
				if($WmiResponse.ReturnValue -eq 4096)
				{
					$Job = [WMI]$WmiResponse.Job
 
					while ($Job.JobState -eq 4)
					{
						Write-Progress -Activity ('Modifying virtual machine {0} on host {1}' -f $VMName, $ComputerName) -Status ('{0}% Complete' -f $Job.PercentComplete) -PercentComplete $Job.PercentComplete
						Start-Sleep -Milliseconds 100
						$Job.PSBase.Get()
					}
 
					if($Job.JobState -ne 7)
					{
						if ($Job.ErrorDescription -ne "")
						{
							Write-Error -Message $Job.ErrorDescription
							exit 1
						}
						else
						{
							$ErrorCode = $Job.ErrorCode
						}
						Write-Progress $Job.Caption "Completed" -Completed $true
					}
				}
				elseif ($WmiResponse.ReturnValue -ne 0)
				{
					$ErrorCode = $WmiResponse.ReturnValue
				}
 
				if($ErrorCode -ne 0)
				{
					if($WmiClassPath -and $MethodName)
					{
						$PSWmiClass = [WmiClass]$WmiClassPath
						$PSWmiClass.PSBase.Options.UseAmendedQualifiers = $true
						$MethodQualifiers = $PSWmiClass.PSBase.Methods[$MethodName].Qualifiers
						$IndexOfError = [System.Array]::IndexOf($MethodQualifiers["ValueMap"].Value, [String]$ErrorCode)
						if($IndexOfError -ne "-1")
						{
							Write-Error -Message ('Error Code: {0}, Method: {1}, Error: {2}' -f $ErrorCode, $MethodName, $MethodQualifiers["Values"].Value[$IndexOfError])
							exit 1
						}
						else
						{
							Write-Error -Message ('Error Code: {0}, Method: {1}, Error: Message Not Found' -f $ErrorCode, $MethodName)
							exit 1
						}
					}
				}
			}
		}
	}
	process
	{
		$ConfirmText = New-Object System.Text.StringBuilder
		$VMObject = $null
		Write-Verbose -Message 'Validating input...'
		$VMName = ''
		$InputType = $VM.GetType()
		if($InputType.FullName -eq 'System.String')
		{
			$VMName = $VM
		}
		elseif($InputType.FullName -eq 'Microsoft.HyperV.PowerShell.VirtualMachine')
		{
			$VMName = $VM.Name
			$ComputerName = $VM.ComputerName
		}
		elseif($InputType.FullName -eq 'System.Management.ManagementObject')
		{
			$VMObject = $VM
		}
		else
		{
			Write-Error -Message 'You must supply a virtual machine name, a virtual machine object from the Hyper-V module, or an Msvm_ComputerSystem WMI object.'
			exit 1
		}

		if($NewBIOSGUID -ne $null)
		{
			try
			{
				$NewBIOSGUID = [System.Guid]::Parse($NewBIOSGUID)
			}
			catch
			{
				Write-Error -Message 'Provided GUID cannot be parsed. Supply a valid GUID or use the AutoGenBIOSGUID parameter to allow an ID to be automatically generated.'
				exit 1
			}
		}

		Write-Verbose -Message ('Establishing WMI connection to Virtual Machine Management Service on {0}...' -f $ComputerName)
		$VMMS = Get-WmiObject -ComputerName $ComputerName -Namespace 'rootvirtualizationv2' -Class 'Msvm_VirtualSystemManagementService' -ErrorAction Stop
		Write-Verbose -Message 'Acquiring an empty parameter object for the ModifySystemSettings function...'
		$ModifySystemSettingsParams = $VMMS.GetMethodParameters('ModifySystemSettings')
		Write-Verbose -Message ('Establishing WMI connection to virtual machine {0}' -f $VMName)
		if($VMObject -eq $null)
		{
			$VMObject = Get-WmiObject -ComputerName $ComputerName -Namespace 'rootvirtualizationv2' -Class 'Msvm_ComputerSystem' -Filter ('ElementName = "{0}"' -f $VMName) -ErrorAction Stop
		}
		if($VMObject -eq $null)
		{
			Write-Error -Message ('Virtual machine {0} not found on computer {1}' -f $VMName, $ComputerName)
			exit 1
		}
		Write-Verbose -Message ('Verifying that {0} is off...' -f $VMName)
		$OriginalState = $VMObject.EnabledState
		if($OriginalState -ne 3)
		{
			if($OriginalState -eq 2 -and ($Force.ToBool() -or $PSCmdlet.ShouldProcess($VMName, 'Shut down')))
			{
				$ShutdownComponent = $VMObject.GetRelated('Msvm_ShutdownComponent')
				Write-Verbose -Message 'Initiating shutdown...'
				Process-WMIJob -WmiResponse $ShutdownComponent.InitiateShutdown($true, 'Change BIOSGUID') -WmiClassPath $ShutdownComponent.ClassPath -MethodName 'InitiateShutdown' -VMName $VMName -ComputerName $ComputerName -ErrorAction Stop
				# the InitiateShutdown function completes as soon as the guest's integration services respond; it does not wait for the power state change to complete
				Write-Verbose -Message ('Waiting for virtual machine {0} to shut down...' -f $VMName)
				$TimeoutCounterStarted = [datetime]::Now
				$TimeoutExpiration = [datetime]::Now + [timespan]::FromSeconds($Timeout)
				while($VMObject.EnabledState -ne 3)
				{
					$ElapsedPercent = [UInt32]((([datetime]::Now - $TimeoutCounterStarted).TotalSeconds / $Timeout) * 100)
					if($ElapsedPercent -ge 100)
					{
						Write-Error -Message ('Timeout waiting for virtual machine {0} to shut down' -f $VMName)
						exit 1
					}
					else
					{
						Write-Progress -Activity ('Waiting for virtual machine {0} on {1} to stop' -f $VMName, $ComputerName) -Status ('{0}% timeout expiration' -f ($ElapsedPercent)) -PercentComplete $ElapsedPercent
						Start-Sleep -Milliseconds 250
						$VMObject.Get()
					}
				}
			}
			elseif($OriginalState -ne 2)
			{
				Write-Error -Message ('Virtual machine must be turned off to change advanced settings. It is not in a state this script can work with.' -f $VMName)
				exit 1
			}
		}
		Write-Verbose -Message ('Retrieving all current settings for virtual machine {0}' -f $VMName)
		$CurrentSettingsDataCollection = $VMObject.GetRelated('Msvm_VirtualSystemSettingData')
		Write-Verbose -Message 'Extracting the settings data object from the settings data collection object...'
		$CurrentSettingsData = $null
		foreach($SettingsObject in $CurrentSettingsDataCollection)
		{
			if($VMObject.Name -eq $SettingsObject.ConfigurationID)
			{
				$CurrentSettingsData = [System.Management.ManagementObject]($SettingsObject)
			}
		}

		if($AutoGenBIOSGUID -or $NewBIOSGUID)
		{
			if($AutoGenBIOSGUID)
			{
				$NewBIOSGUID = [System.Guid]::NewGuid().ToString()
			}
			Change-VMSetting -VMSettings $CurrentSettingsData -PropertyName 'BIOSGUID' -NewPropertyValue (('{{{0}}}' -f $NewBIOSGUID).ToUpper()) -PropertyDisplayName 'BIOSGUID' -ConfirmText $ConfirmText
		}
		if($BaseBoardSerialNumber)
		{
			Change-VMSetting -VMSettings $CurrentSettingsData -PropertyName 'BaseboardSerialNumber' -NewPropertyValue $BaseBoardSerialNumber -PropertyDisplayName 'baseboard serial number' -ConfirmText $ConfirmText
		}
		if($BIOSSerialNumber)
		{
			Change-VMSetting -VMSettings $CurrentSettingsData -PropertyName 'BIOSSerialNumber' -NewPropertyValue $BIOSSerialNumber -PropertyDisplayName 'BIOS serial number' -ConfirmText $ConfirmText
		}
		if($ChassisAssetTag)
		{
			Change-VMSetting -VMSettings $CurrentSettingsData -PropertyName 'ChassisAssetTag' -NewPropertyValue $ChassisAssetTag -PropertyDisplayName 'chassis asset tag' -ConfirmText $ConfirmText
		}
		if($ChassisSerialNumber)
		{
			Change-VMSetting -VMSettings $CurrentSettingsData -PropertyName 'ChassisSerialNumber' -NewPropertyValue $ChassisSerialNumber -PropertyDisplayName 'chassis serial number' -ConfirmText $ConfirmText
		}

		Write-Verbose -Message 'Assigning modified data object as parameter for ModifySystemSettings function...'
		$ModifySystemSettingsParams['SystemSettings'] = $CurrentSettingsData.GetText([System.Management.TextFormat]::CimDtd20)
		if($Force.ToBool() -or $PSCmdlet.ShouldProcess($VMName, $ConfirmText.ToString()))
		{
			Write-Verbose -Message ('Instructing Virtual Machine Management Service to modify settings for virtual machine {0}' -f $VMName)
			Process-WMIJob -WmiResponse ($VMMS.InvokeMethod('ModifySystemSettings', $ModifySystemSettingsParams, $null)) -WmiClassPath $VMMS.ClassPath -MethodName 'ModifySystemSettings' -VMName $VMName -ComputerName $ComputerName
		}
		$VMObject.Get()
		if($OriginalState -ne $VMObject.EnabledState)
		{
			Write-Verbose -Message ('Returning {0} to its prior running state.' -f $VMName)
			Process-WMIJob -WmiResponse $VMObject.RequestStateChange($OriginalState) -WmiClassPath $VMObject.ClassPath -MethodName 'RequestStateChange' -VMName $VMName -ComputerName $ComputerName -ErrorAction Stop
		}
	}
#}  # uncomment this line and the first two lines to use as a profile or dot-sourced function

Script Notes for Other Scripters

I hope that at least some of you are using my scripts to advance your own PowerShell knowledge. This script shows two internal functions used for two separate purposes.

Code/Script Reusability

Sometimes, you’ll find yourself needing the same functionality in multiple scripts. You could rewrite that functionality each time, but I’m sure you don’t need me to tell you what’s wrong with that. You could put that functionality into another script and dot-source it into each of the others that rely on it. That’s a perfectly viable approach, but I don’t use it in my public scripts because I can’t guarantee what scripts will be on readers’ systems and I want to provide one-stop wherever possible. That leads to the third option, which is reusability.

Find the line that says function Process-WmiJob. As the comments say, I have adapted that from someone else’s work. I commonly need to use its functionality in many of my WMI-based scripts. So, I modularized it to use a universal set of parameters. Now I just copy/paste it into any other script that uses WMI jobs.

Making your code/script reusable can save you a great deal of time. Reused blocks have predictable results. The more you use them, the more likely you are to work out long-standing bugs and fine-tune them.

The problem with reused blocks is that they become disjointed. If I fix a problem that I find in the function within this script, I might or might not go back and update it everywhere else that I use it. In your own local scripting, you can address that problem by having a single copy of a script dot-sourced into all of your others. However, if each script file has its own copy of the function, it’s easier to customize it when necessary.

There’s no “right” answer or approach when it comes to code/script reusability. The overall goal is to reduce duplication of work, not to make reusable blocks. Never be so bound up in making a block reusable that you end up doing more overall work.

Don’t Repeat Yourself

A lofty goal related to code/script reusability is the Don’t Repeat Yourself principle (DRY). As I was reworking the original version of this script, I found that I was essentially taking the script block for the previous virtual machine property, copy/pasting it, and then updating the property and variable names. There was a tiny bit of customization on a few of them, but overall the blocks were syntactically identical. The script worked, and it was easy to follow along, but that’s not really an efficient way to write a script. Computers are quite skilled at repeating tasks. Humans, on the contrary, quickly tire of repetition. Therefore, it only makes sense to let the computer do whatever you’d rather skip.

DRY also addresses the issue of tiny mistakes. Let’s say that I duplicated the script for changing the ChassisSerialNumber, but left in the property name for the ChassisAssetTag. That would mean that your update would result in the ChassisAssetTag that you specified being applied to the ChassisAssetTag field and the ChassisSerialNumber. These types of errors are extremely common when you copy/paste/modify blocks.

Look at the line that says Change-VMSetting. That contains a fairly short bit of script that changes the properties of an object. I won’t dive too deeply into the details; the important part is that this particular function might be called up to five times during each iteration of the script. It’s only typed once, though. If I (or you) find a bug in it, there’s only place that I need to make corrections.

Internal Functions in Your Own Scripts

Notice that I put my functions into a begin {} block. If this script is on the right side of a pipe, then its process {} block might be called multiple times. The functions only need to be defined once. Leaving them in the begin block provides a minor performance boost because that part of the script won’t need to be parsed on each pass.

I also chose to use non-standard verbs “Process” and “Change” for the functions. That’s because I can never be entirely certain about function names that might already be in the global namespace or that might be in other scripts that include mine. Programming languages tend to implement namespaces to avoid such naming collisions, but PowerShell does not have that level of namespace support just yet. Keep that problem in mind when writing your own internal functions.

Altaro Hyper-V Backup
Share this post

Not a DOJO Member yet?

Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!

73 thoughts on "PowerShell Script: Change Advanced Settings of Hyper-V Virtual Machines"

  • Juri says:

    Eric,

    I struggle to find any practical use case for your advanced script.
    Would you be able to name a few examples when that came in handy?

    Thanks for all those very helpful blog posts 😉

    Cheers Juri

    • Eric Siron says:

      These fields are all duplicated when a virtual machine is cloned or deployed from some templating systems. BIOS GUID affects PXE boot. Some organizations use the other fields for inventory purposes.

  • Valeriy says:

    Hallo!

    String number 145:
    ‘Modifying virtual machine {0}’ -f $VMName, $ComputerName

    Missing parameter {1} in message for $ComputerName

    I think it should be something like this:
    ‘Modifying virtual machine {0} on {1}’ -f $VMName, $ComputerName

  • Ricky says:

    Hi Eric,

    Thanks for the advanced script. Do you know if there’s any way to modify the Manufacturer and Model that’s reported with gwmi win32_computersystem and the Name, Vendor and Version for gwmi win32_computersystemproduct in a Hyper-V Guest OS? I would assume it’s also a modification of one of the wmi classes on the Host, but don’t know which one or how to find out (and don’t know if it’s modifiable even if I find it).

    Thanks!

    • Eric Siron says:

      Not in any way that I know of. These fields are not exposed in the API. I believe that they are a hardcoded product of the hypervisor’s internal functions.

  • Eric says:

    Thank you for the script.

    I did find a typo in it.
    On lines 229 & 235, “rootvirtualizationv2” should be “rootvirtualizationv2”

    • Eric Siron says:

      There was a blog UI update a bit ago and some of the scripts in the articles were damaged. We haven’t gotten around to fixing all of them yet. Thanks for pointing this one out!

  • Keir Cooke says:

    I cannot for the life of me get this script to run on a remote computer. I’m executing it as a domain admin, but no matter how I feed it targets it simply returns the ‘VM {0} not found on computer {1}’ error.
    Even if I feed in the results straight from a Get-vm, I still get the exact same error. Any idea what the issue might be?

    • Eric Siron says:

      I’ll look into it when I get some time. It should work, especially from Get-VM.

    • Eric Siron says:

      I apologize for the extremely long delay on this, but I’ve fixed the problem. You’ll find the listing for version 1.2 above.

  • Christoph says:

    I have tried the script but it´s not working.

    I copy the script into the Editor and save as Set-VMAdvancedSettings.ps1 an call it with .Set-VMAdvancedSettings. It asks me about the VM and then after I´ve entert the the VM the script ends after it asks about to confirm.

    Did I something wrong or misssed something? I haven´t so much experience with PowerShell. I’ve allways used CMD. Please forgive my bad english.

    • Eric Siron says:

      When it works, it won’t tell you anything. It only writes output when an error occurs. Needless output from a script can break automation. If you want to visually see that it is doing work, include the -Verbose parameter.
      That said, you didn’t mention anything about giving it a task. You have to tell it what you want it to do. You can run Get-Help .Set-VMAdvancedSettings.ps1 -Examples to see example usage or look at the .EXAMPLE lines in the listing.

  • Ivan Mckenzie says:

    Hi, did not work for me. Running on a Windows 2016 Hyper-V cluster node with admin user. No errors, when I ran the script. Guest machine is Windows 2012 R2. The guest machine was on the node from which I was running the script. You can see th output of the script.

    Thanks a lot for your time and effort,

    Ivan

    PS C:UsersinDesktop> .Set-VMAdvancedSettings.ps1 -Verbose

    cmdlet Set-VMAdvancedSettings.ps1 at command pipeline position 1
    Supply values for the following parameters:
    VM: srv-sql
    VERBOSE: Validating input…
    VERBOSE: Establishing WMI connection to Virtual Machine Management Service on SRV-HV
    VERBOSE: Acquiring an empty parameter object for the ModifySystemSettings function…
    VERBOSE: Establishing WMI connection to virtual machine srv-sql
    VERBOSE: Verifying that srv-sql is off…
    VERBOSE: Retrieving all current settings for virtual machine srv-sql
    VERBOSE: Extracting the settings data object from the settings data collection object…
    VERBOSE: Assigning modified data object as parameter for ModifySystemSettings function…

    Confirm
    Are you sure you want to perform this action?
    Performing the operation “” on target “srv-sql”.
    [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is “Y”): y
    VERBOSE: Instructing Virtual Machine Management Service to modify settings for virtual machine srv-sql
    PS C:UsersinDesktop>

  • Thomas says:

    I’m really glad I found this script and you took the effort to create it!! Worked without any problems on my local hyper-v installation.

    Just FYI: I tried to use Advanced VM Settings Editor before, but this didn’t work. It says it can not communicate with the selected host.

    But nevertheless, THANK YOU once again!

Leave a comment or ask a question

Your email address will not be published. Required fields are marked *

Your email address will not be published.

Notify me of follow-up replies via email

Yes, I would like to receive new blog posts by email

What is the color of grass?

Please note: If you’re not already a member on the Dojo Forums you will create a new account and receive an activation email.

cyber security roundtable