<# Copyright 2021 VMware, Inc. SPDX-License-Identifier: BSD-2-Clause #> # Script Module : VMware.VMEncryption # Version : 1.2 # Copyright © 2016 VMware, Inc. All Rights Reserved. # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies # of the Software, and to permit persons to whom the Software is furnished to do # so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. New-VIProperty -Name AESNIStatus -ObjectType VMHost -Value { Param ($VMHost) $FeatureCap = $VMHost.ExtensionData.Config.FeatureCapability foreach ($Feature in $FeatureCap) { if ($Feature.FeatureName -eq "cpuid.AES") { ($Feature.Value -eq "1") } } } -BasedOnExtensionProperty 'Config.FeatureCapability' -Force | Out-Null New-VIProperty -Name CryptoSafeSupported -ObjectType VMHost -Value { Param ($VMHost) $VMHost.ExtensionData.Runtime.CryptoState -ne $null } -BasedOnExtensionProperty 'Runtime.CryptoState' -Force New-VIProperty -Name CryptoSafe -ObjectType VMHost -Value { Param ($VMHost) $VMHost.ExtensionData.Runtime.CryptoState -eq "safe" } -BasedOnExtensionProperty 'Runtime.CryptoState' -Force New-VIProperty -Name Encrypted -ObjectType VirtualMachine -Value { Param ($VM) $VM.ExtensionData.Config.KeyId -ne $null } -BasedOnExtensionProperty 'Config.KeyId' -Force | Out-Null New-VIProperty -Name EncryptionKeyId -ObjectType VirtualMachine -Value { Param ($VM) if ($VM.Encrypted) { $VM.ExtensionData.Config.KeyId } } -BasedOnExtensionProperty 'Config.KeyId' -Force | Out-Null New-VIProperty -Name Locked -ObjectType VirtualMachine -Value { Param ($VM) if ($vm.ExtensionData.Runtime.CryptoState) { $vm.ExtensionData.Runtime.CryptoState -eq "locked" } else { ($vm.extensiondata.Runtime.ConnectionState -eq "invalid") -and ($vm.extensiondata.Config.KeyId) } } -BasedOnExtensionProperty 'Runtime.CryptoState', 'Runtime.ConnectionState','Config.KeyId' -Force | Out-Null New-VIProperty -Name vMotionEncryption -ObjectType VirtualMachine -Value { Param ($VM) $VM.ExtensionData.Config.MigrateEncryption } -BasedOnExtensionProperty 'Config.MigrateEncryption' -Force | Out-Null New-VIProperty -Name KMSserver -ObjectType VirtualMachine -Value { Param ($VM) if ($VM.Encrypted) { $VM.EncryptionKeyId.ProviderId.Id } } -BasedOnExtensionProperty 'Config.KeyId' -Force | Out-Null New-VIProperty -Name Encrypted -ObjectType HardDisk -Value { Param ($hardDisk) $hardDisk.ExtensionData.Backing.KeyId -ne $null } -BasedOnExtensionProperty 'Backing.KeyId' -Force | Out-Null New-VIProperty -Name EncryptionKeyId -ObjectType HardDisk -Value { Param ($Disk) if ($Disk.Encrypted) { $Disk.ExtensionData.Backing.KeyId } } -BasedOnExtensionProperty 'Backing.KeyId' -Force | Out-Null New-VIProperty -Name KMSserver -ObjectType VMHost -Value { Param ($VMHost) if ($VMHost.CryptoSafe) { $VMHost.ExtensionData.Runtime.CryptoKeyId.ProviderId.Id } } -BasedOnExtensionProperty 'Runtime.CryptoKeyId.ProviderId.Id' -Force | Out-Null Function Enable-VMHostCryptoSafe { <# .SYNOPSIS This cmdlet enables the VMHost's CryptoSate to safe. .DESCRIPTION This cmdlet enables the VMHost's CryptoSate to safe. .PARAMETER VMHost Specifies the VMHost you want to enable. .PARAMETER KMSClusterId Specifies the KMS cluster ID which you want to use to generate the encrytion key. .EXAMPLE C:\PS>$VMHost = Get-VMHost -name $VMHostName C:\PS>Enable-VMHostCryptoSafe -VMHost $VMHost Enables the specified VMHost's CryptoSate to safe. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost] $VMHost, [Parameter(Mandatory=$False)] [String] $KMSClusterId ) Process { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter if (!$VMHost.CryptoSafeSupported) { Write-Error "The VMHost: $VMHost does not support CryptoSafe!`n" return } if ($VMHost.CryptoSafe) { Write-Error "The VMHost: $VMHost CryptoSafe already enabled!`n" return } # Generate key from the specified KMS cluster try { $KeyResult = NewEncryptionKey -KMSClusterId $KMSClusterId } catch { Throw "Key generation failed, make sure the KMS Cluster exists!`n" } $VMHostView = Get-View $VMHost $VMHostView.ConfigureCryptoKey($KeyResult.KeyId) } } Function Set-VMHostCryptoKey { <# .SYNOPSIS This cmdlet changes the VMHost CryptoKey. .DESCRIPTION This cmdlet changes the VMHost CryptoKey if VMHost is already in Crypto safe state. .PARAMETER VMHost Specifies the VMHost whose CryptoKey you want to update. .PARAMETER KMSClusterId Specifies the KMS cluster ID which you want to use to generate the encryption key. .EXAMPLE C:\PS>$VMHost = Get-VMHost -Name $VMHostName C:\PS>Set-VMHostCryptoKey -VMHost $VMHost Changes the VMHost CryptoKey to a new CryptoKey. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost] $VMHost, [Parameter(Mandatory=$False)] [String] $KMSClusterId ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { if (!$VMHost.CryptoSafeSupported) { Write-Error "The VMHost: $VMHost does not support CryptoSafe!`n" return } if (!$VMHost.CryptoSafe) { Write-Error "The VMHost: $VMHost has not enabled the CrytoSate to safe!" return } $VMHostView = Get-View $VMHost $OldKey = $VMHostView.Runtime.CryptoKeyId # Generate key from the specified KMSCluster try { $KeyResult = NewEncryptionKey -KMSClusterId $KMSClusterId } catch { Throw "Key generation failed, make sure the KMS Cluster exists!`n" } try { $VMHostView.ConfigureCryptoKey($KeyResult.KeyId) Write-Verbose "Change Crypto Key on VMHost: $VMHost succeeded!`n" } catch { Write-Error "Change Crypto Key on VMHost: $VMHost failed.$_!`n" return } # Remove the old host key only when connected to vSphere 6.5 to ensure any coredumps are recrypted with the new host key; # For vSphere 6.7 and above, the ConfigureCryptoKey() will automatically remove the old host key when successfully changed # the host key. # Adding below condition to avoid misunderstanding when running against vSphere 6.7 and above. $VCVersion = ($global:DefaultVIServer).Version $MajorVersion = $VCVersion.split('.')[0] $MinorVersion = $VCVersion.split('.')[1] if ($MajorVersion -eq 6 -And $MinorVersion -eq 5) { Write-Verbose "Removing the old hostKey: $($OldKey.KeyId) on $VMHost...`n" $VMHostCM = Get-View $VMHostView.ConfigManager.CryptoManager $VMHostCM.RemoveKeys($OldKey, $false) } } } Function Set-vMotionEncryptionConfig { <# .SYNOPSIS This cmdlet sets the vMotionEncryption property of a VM. .DESCRIPTION Use this function to set the vMotionEncryption settings for a VM. The 'Encryption' parameter is set up with Tab-Complete for the available options. .PARAMETER VM Specifies the VM you want to set the vMotionEncryption property. .PARAMETER Encryption Specifies the value you want to set to the vMotionEncryption property. The Encryption options are: disabled, opportunistic, and required. .EXAMPLE PS C:\> Get-VM | Set-vMotionEncryptionConfig -Encryption opportunistic Sets the vMotionEncryption of all the VMs .NOTES Author : Brian Graf, Carrie Yang. Author email : grafb@vmware.com, yangm@vmware.com #> [CmdLetBinding()] param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$VM, [Parameter(Mandatory=$True)] [ValidateSet("disabled", "opportunistic", "required")] [String]$Encryption ) process{ if ($VM.vMotionEncryption -eq $Encryption) { Write-Warning "The encrypted vMotion state is already $Encrypted, no need to change it." return } if ($VM.Encrypted) { Write-Error "Cannot change encrypted vMotion state for an encrypted VM." return } $VMView = $VM | get-view $Config = New-Object VMware.Vim.VirtualMachineConfigSpec $Config.MigrateEncryption = New-Object VMware.Vim.VirtualMachineConfigSpecEncryptedVMotionModes $Config.MigrateEncryption = $Encryption $VMView.ReconfigVM($config) $VM.ExtensionData.UpdateViewData() $VM.vMotionEncryption } } Function Enable-VMEncryption { <# .SYNOPSIS This cmdlet encrypts the specified VM. .DESCRIPTION This cmdlet encrypts the specified VM. .PARAMETER SkipHardDisks If specified, skips the encryption of the hard disks of the specified VM. .PARAMETER VM Specifies the VM you want to encrypt. .PARAMETER Policy Specifies the encryption policy you want to use. .PARAMETER KMSClusterId Specifies the KMS clusterId you want to use to generate new key for encryption. .EXAMPLE C:\PS>Get-VM -Name win2012|Enable-VMEncryption Encrypts the whole VM with default encryption policy. .EXAMPLE C:\PS>$SP = Get-SpbmStoragePolicy -name "EncryptionPol" C:\PS>Get-VM -Name win2012 |Enable-VMEncryption -Policy $SP -SkipHardDisks Encrypts the VM Home with the encryption policy 'EncryptionPol' and skips hard disks encryption. .NOTES This cmdlet assumes there already is KMS defined in vCenter Server. If VM Home is already encrypted, the cmdlet quits. If VM Home is not encrypted, encrypt VM Home if SkipHardDisks specified. Otherwise encrypt the VM Home and VM-attached disks. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$False)] [VMware.VimAutomation.Storage.Types.V1.Spbm.SpbmStoragePolicy] $Policy, [Parameter(Mandatory=$False,ValueFromPipeline=$False,ValueFromPipelinebyPropertyName=$False)] [String] $KMSClusterId, [Parameter(Mandatory=$False)] [switch]$SkipHardDisks=$False ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { # VM Home is already encrypted if ($VM.Encrypted) { $ErrMsg = "VM $VM is already encrypted, please use: "+ "Enable-VMDiskEncryption if you want to "+ "encrypt disks which not encrypted yet!`n" Write-Error $ErrMsg return } Write-Verbose "Checking if the VMHost supports CryptoSafe...`n" $VMhost = $VM|Get-VMHost if (!$VMHost.CryptoSafeSupported) { Write-Error "The VMHost: $VMHost does not support CryptoSafe.`n" return } Write-Verbose "Checking if $VM has no snapshots...`n" if ($VM|Get-Snapshot) { Write-Error "$VM has snapshots, please remove all snapshots and try again!`n" return } Write-Verbose "Checking if $VM powered off...`n" if ($VM.PowerState -ne "PoweredOff") { $ErrMsg = "The VM can only be encrypted when powered off, "+ "but the current power state of $VM is $($VM.PowerState)!`n" Write-Error $ErrMsg return } $PolicyToBeUsed = $null $BuiltInEncPolicy = Get-SpbmStoragePolicy -Name "VM Encryption Policy" if ($Policy) { # Known issue: If the provided policy is created/cloned from # the default "VM Encryption Policy", # Or When creating the policy you didn't select 'Custom', # there will be null-valued Exception. Write-Verbose "Checking if the provided policy: $Policy is an encryption policy`n" if (($Policy.Name -ne "VM Encryption Policy") -and !$Policy.CommonRule.Capability.Category.Contains("ENCRYPTION")) { Write-Error "The policy $Policy is not an encryption policy, exit!" return } $PolicyToBeUsed = $Policy } else { Write-Verbose "No storage policy specified, try to use the built-in policy.`n" if ($BuiltInEncPolicy) { $PolicyToBeUsed = $BuiltInEncPolicy } else { Throw "The built-in policy does not exist, please use: New-SpbmStoragePolicy to create one first!`n" } } # Encrypt the VM disks if SkipHardDisk not specified if (!$SkipHardDisks) { $Disks = $VM|Get-HardDisk } $VMView = Get-View $VM $ProfileSpec = New-Object VMware.Vim.VirtualMachineDefinedProfileSpec $ProfileSpec.ProfileId = $PolicyToBeUsed.Id $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $VMCfgSpec.VmProfile = $ProfileSpec if ($KMSClusterId) { # Generate a new key from KMS try { $KeyResult = NewEncryptionKey -KMSClusterId $KMSClusterId } catch { Throw "Key generation failed, make sure the specified KMS Cluster exists!`n" } $CryptoKeyId = $KeyResult.KeyId $CryptoSpec = New-Object VMware.Vim.CryptoSpecEncrypt $CryptoSpec.CryptoKeyId = $CryptoKeyId $VMCfgSpec.Crypto = $CryptoSpec } $DeviceChanges = @() foreach ($Disk in $Disks) { Write-Verbose "Attaching policy: $PolicyToBeUsed to $Disk`n" $DeviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $BackingSpec = New-Object VMware.Vim.VirtualDeviceConfigSpecBackingSpec $DeviceChange.operation = "edit" $DeviceChange.device = $Disk.extensiondata $DeviceChange.Profile = $ProfileSpec $BackingSpec.Crypto = $CryptoSpec $DeviceChange.Backing = $BackingSpec $DeviceChanges += $deviceChange } if ($Devicechanges) { $VMCfgSpec.deviceChange = $Devicechanges } return $VMView.ReconfigVM_Task($VMCfgSpec) } } Function Enable-VMDiskEncryption { <# .SYNOPSIS This cmdlet encrypts the specified hard disks. .DESCRIPTION This cmdlet encrypts the specified hard disks. .PARAMETER VM Specifies the VM whose hard disks you want to encrypt. .PARAMETER Policy Specifies the encryption policy you want to use. .PARAMETER HardDisk Specifies the hard disks you want to encrypt. .PARAMETER KMSClusterId Specifies the KMS clusterId you want to use to generate new key for encryption. .EXAMPLE C:\PS>$VM = Get-VM -Name win2012 C:\PS>$VMDisks= $VM|Get-Harddisk|Select -last 2 C:\PS>Enable-VMDiskEncryption -VM $VM -$HardDisk $VMDisks Encrypts the VM disks with the default encryption policy and use the VM encryption key. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.VirtualDevice.HardDisk[]] $HardDisk, [Parameter(Mandatory=$False)] [VMware.VimAutomation.Storage.Types.V1.Spbm.SpbmStoragePolicy] $Policy, [Parameter(Mandatory=$False)] [String] $KMSClusterId ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { Write-Verbose "Checking if $VM is encrypted..." if (!$VM.Encrypted) { Write-Error "$VM is not encrypted, please use:Enable-VMEncryption to encrypt the VM.`n" return } # Validate the hard disks Write-Verbose "Checking the hard disks...`n" ConfirmHardDiskIsValid -VM $VM -HardDisk $HardDisk Write-Verbose "Checking if $VM has no snapshots..." if ($VM|Get-Snapshot) { Write-Error "$VM has snapshots, please remove all snapshots!`n" return } Write-Verbose "Checking if $VM is powered off..." if ($VM.powerstate -ne "PoweredOff") { $ErrMsg = "The VM can only be ecrypted when powered off, "+ "but the current power state of $VM is $($VM.PowerState)!`n" Write-Error $ErrMsg return } $PolicyToBeUsed = $null if ($Policy) { # Known issue: If the provided policy is created/cloned from # the default "VM Encryption Policy", # Or When creating the policy you didn't select 'Custom', # there will be null-valued Exception. Write-Verbose "Checking if the provided policy: $Policy is an encryption policy`n" if (($Policy.Name -ne "VM Encryption Policy") -and !$Policy.CommonRule.Capability.Category.Contains("ENCRYPTION")) { Throw "The policy $Policy is not an encryption policy, exit!" } $PolicyToBeUsed = $Policy } else { Write-Verbose "No storage policy specified, try to use the VM Home policy.`n" $PolicyToBeUsed = (Get-SpbmEntityConfiguration -VM $VM).StoragePolicy if (!$PolicyToBeUsed) { Write-Warning "The VM Home policy is not available, try to use the built-in policy.`n" $BuiltInEncPolicy = Get-SpbmStoragePolicy -Name "VM Encryption Policy" if ($BuiltInEncPolicy) { $PolicyToBeUsed = $BuiltInEncPolicy } else { Throw "The built-in policy does not exist, please use: New-SpbmStoragePolicy to create one first!`n" } } } # Specify the key used to encrypt disk if ($KMSClusterId) { # Generate a new key from KMS try { $KeyResult = NewEncryptionKey -KMSClusterId $KMSClusterId } catch { Throw "Key generation failed, make sure the KMS Cluster exists!`n" } $CryptoKeyId = $KeyResult.KeyId $CryptoSpec = New-Object VMware.Vim.CryptoSpecEncrypt $CryptoSpec.CryptoKeyId = $CryptoKeyId } Write-Verbose "Encrypting the hard disks: $HardDisk...`n" $VMView = Get-View $VM $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $ProfileSpec = New-Object VMware.Vim.VirtualMachineDefinedProfileSpec $ProfileSpec.ProfileId = $PolicyToBeUsed.Id $DeviceChanges = @() foreach ($Disk in $HardDisk) { Write-Verbose "Attaching policy: $PolicyToBeUsed to $Disk`n" $DeviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $BackingSpec = New-Object VMware.Vim.VirtualDeviceConfigSpecBackingSpec $DeviceChange.operation = "edit" $DeviceChange.device = $Disk.extensiondata $DeviceChange.Profile = $ProfileSpec $BackingSpec.Crypto = $CryptoSpec $DeviceChange.Backing = $BackingSpec $DeviceChanges += $DeviceChange } if ($DeviceChanges) { $VMCfgSpec.deviceChange = $DeviceChanges } return $VMView.ReconfigVM_Task($VMCfgSpec) } } Function Disable-VMEncryption { <# .SYNOPSIS This cmdlet decrypts the specified VM. .DESCRIPTION This cmdlet decrypts the specified VM. .PARAMETER VM Specifies the VM you want to decrypt. .EXAMPLE C:\PS>Get-VM -Name win2012 | Disable-VMEncryption Decrypts the VM Home and all encrypted disks. .EXAMPLE C:\PS>$VM = Get-VM -Name win2012 C:\PS>Disable-VMEncryption -VM $VM Decrypts the whole VM, including the encrypted disks. .NOTES If the VM is not encrypted, the cmdlet quits. .NOTES Author : Carrie Yang. Author email : yangm@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { Write-Verbose "Checking if $VM is encrypted..." if (!$VM.Encrypted) { Write-Error "$VM is not encrypted.`n" return } Write-Verbose "Checking if $VM has no snapshots..." if ($VM|Get-Snapshot) { Write-Error "$VM has snapshots, it can not be decrypted!`n" return } Write-Verbose "Checking if $VM is powered off..." if ($VM.powerstate -ne "PoweredOff") { $ErrMsg = "The VM can only be decrypted when powered off, "+ "but the current power state of $VM is $($VM.PowerState)!`n" Write-Error $ErrMsg return } $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $Profile = New-Object VMware.Vim.VirtualMachineEmptyProfileSpec $DecryptCrypto = New-Object VMware.Vim.CryptoSpecDecrypt $DisksToDecrypt = $VM|Get-HardDisk|Where {$_.Encrypted} $VMCfgSpec.VmProfile = $Profile $VMCfgSpec.Crypto = $DecryptCrypto $DeviceChanges = @() foreach ($Disk in $DisksToDecrypt) { $DeviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $DeviceChange.operation = "edit" $DeviceChange.device = $Disk.extensiondata $DeviceChange.Profile = $Profile $DeviceChange.Backing = New-Object VMware.Vim.VirtualDeviceConfigSpecBackingSpec $DeviceChange.Backing.Crypto = $DecryptCrypto $DeviceChanges += $DeviceChange } if ($Devicechanges) { $VMCfgSpec.deviceChange = $Devicechanges } return (Get-View $VM).ReconfigVM_Task($VMCfgSpec) } } Function Disable-VMDiskEncryption { <# .SYNOPSIS This cmdlet decrypts the specified hard disks in a given VM. .DESCRIPTION This cmdlet decrypts the specified hard disks in a given VM. .PARAMETER VM Specifies the VM which the hard disks belong to. .PARAMETER HardDisk Specifies the hard disks you want to decrypt. .EXAMPLE C:\PS>$VM = Get-VM -Name win2012 C:\PS>$HardDisk = $VM|Get-HardDisk|select -last 1 C:\PS>Disable-VMDiskEncryption -VM $VM -HardDisk $HardDisk Decrypts the last hard disk in the VM. .NOTES If the VM is not encrypted, the cmdlet quits. .NOTES Author : Carrie Yang. Author email : yangm@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.VirtualDevice.HardDisk[]] $HardDisk ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { Write-Verbose "Checking if $VM is encrypted..." if (!$VM.Encrypted) { Write-Error "$VM is not encrypted.`n" return } # Validate the hard disks Write-Verbose "Checking the hard disks...`n" ConfirmHardDiskIsValid -VM $VM -HardDisk $HardDisk $DisksToDecrypt = $HardDisk |Where {$_.Encrypted} if ($DisksToDecrypt.Length -eq 0) { Write-Error "The provided disks are not encrypted.`n" return } Write-Verbose "Checking if $VM has no snapshots..." if ($VM|Get-Snapshot) { Write-Error "$VM has snapshots, it can not be decrypted!`n" return } Write-Verbose "Checking if $VM is powered off..." if ($VM.powerstate -ne "PoweredOff") { $ErrMsg = "The VM can only be decrypted when powered off, "+ "but the current power state of $VM is $($VM.PowerState)!`n" Write-Error $ErrMsg return } $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $Profile = New-Object VMware.Vim.VirtualMachineEmptyProfileSpec $DecryptCrypto = New-Object VMware.Vim.CryptoSpecDecrypt $DeviceChanges = @() foreach ($Disk in $DisksToDecrypt) { $DeviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $DeviceChange.operation = "edit" $DeviceChange.device = $Disk.extensiondata $DeviceChange.Profile = $Profile $DeviceChange.Backing = New-Object VMware.Vim.VirtualDeviceConfigSpecBackingSpec $DeviceChange.Backing.Crypto = $DecryptCrypto $DeviceChanges += $DeviceChange } $VMCfgSpec.deviceChange = $DeviceChanges return (Get-View $VM).ReconfigVM_Task($VMCfgSpec) } } Function Set-VMEncryptionKey { <# .SYNOPSIS This cmdlet sets the encryption key of VM or hard disks. .DESCRIPTION This cmdlet sets the encryption key of VM or hard disks. .PARAMETER VM Specifies the VM you want to rekey. .PARAMETER KMSClusterId Specifies the KMS clusterId you want to use for getting a new key for rekey operation. .PARAMETER Deep When it's specified, both the key encryption key (KEK) and the internal data encryption key (DEK) will be updated. This is implemented through a full copy; It's a slow operation that must be performed while the virtual machine is powered off. A shallow key change will only update the KEK and the operation can be performed while the virtual machine is running. .PARAMETER SkipHardDisks Skip updating the hard disk keys. .EXAMPLE C:\PS>Get-VM -Name win2012 | Set-VMEncryptionKey Rekeys the VM win2012 VM Home and all its disks. .EXAMPLE C:\PS>$VM = Get-VM -Name win2012 C:\PS>$VM|Set-VMEncryptionKey -SkipHardDisks Rekeys the VM Home only. .EXAMPLE C:\PS>$VM = Get-VM -Name win2012 C:\PS>$VM|Set-VMEncryptionKey -Deep Rekeys the VM Home and all its disks with Deep option. .EXAMPLE C:\PS>$KMSCluster = Get-KMSCluster | select -last 1 C:\PS>$VM = Get-VM -Name win2012 C:\PS>$VM|Set-VMEncryptionKey -KMSClusterId $KMSCluster.Id -Deep Deep rekeys the VM Home and all its disks using a new key. The key is generated from the KMS whose clusterId is $KMSCluster.Id. .NOTES This cmdlet assumes there is already a KMS in vCenter Server. If VM is not encrypted, the cmdlet quits. You should use Enable-VMEncryption cmdlet to encrypt the VM first. .NOTES Author : Carrie Yang. Author email : yangm@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, [Parameter(Mandatory=$False)] [String] $KMSClusterId, [Parameter(Mandatory=$False)] [switch]$Deep = $FALSE, [Parameter(Mandatory=$False)] [switch]$SkipHardDisks = $False ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { Write-Verbose "Checking if $VM is encrypted...`n" if (!$VM.Encrypted) { Write-Error "$VM is not encrypted." return } Write-Verbose "Checking if $VM has no snapshots...`n" if ($VM|Get-Snapshot) { Write-Error "$VM has snapshot, please remove all snapshots and try again!`n" return } if ($Deep) { Write-Verbose "Checking if $VM powered off...`n" if ($VM.powerstate -ne "PoweredOff") { $ErrMsg = "The VM can only be recrypted when powered off, "+ "but the current power state of $VM is $($VM.PowerState)!`n" Write-Error $ErrMsg return } } $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $ProfileSpec = New-Object VMware.Vim.VirtualMachineDefinedProfileSpec $CryptoSpec = New-Object VMware.Vim.CryptoSpecShallowRecrypt if ($Deep) { $CryptoSpec = New-Object VMware.Vim.CryptoSpecDeepRecrypt $VMPolicy = (Get-SpbmEntityConfiguration -VM $VM).StoragePolicy $ProfileSpec.ProfileId = $VMPolicy.Id $VMCfgSpec.VmProfile = $ProfileSpec } # Generate a key from KMS try { $KeyResult = NewEncryptionKey -KMSClusterId $KMSClusterId } catch { Throw "Key generation failed, make sure the KMS Cluster exists!`n" } $CryptoSpec.NewKeyId = $KeyResult.KeyId $VMCfgSpec.Crypto = $CryptoSpec if (!$SkipHardDisks) { $DisksToRecrypt = $VM|Get-HardDisk|Where {$_.Encrypted} $DeviceChanges = @() foreach ($disk in $DisksToRecrypt) { $DeviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $DeviceChange.operation = "edit" $DeviceChange.device = $Disk.extensiondata if ($Deep) { $DiskProfileSpec = New-Object VMware.Vim.VirtualMachineDefinedProfileSpec $DiskProfileSpec.ProfileId = ($Disk|Get-SpbmEntityConfiguration).StoragePolicy.Id $DeviceChange.Profile = $DiskProfileSpec } $DeviceChange.Backing = New-Object VMware.Vim.VirtualDeviceConfigSpecBackingSpec $DeviceChange.Backing.Crypto = $CryptoSpec $DeviceChanges += $DeviceChange } if ($DeviceChanges.Length -gt 0) { $VMCfgSpec.deviceChange = $DeviceChanges } } return (Get-View $VM).ReconfigVM_Task($VMCfgSpec) } } Function Set-VMDiskEncryptionKey { <# .SYNOPSIS This cmdlet sets the encryption key of the hard disks in the VM. .DESCRIPTION This cmdlet sets the encryption key of the hard disks in the VM. .PARAMETER VM Specifies the VM from which you want to rekey its disks. .PARAMETER HardDisk Specifies the hard disks you want to rekey. .PARAMETER KMSClusterId Specifies the KMS clusterId you want to use for getting a new key for rekey operation. .PARAMETER Deep When it's specified, both the key encryption key (KEK) and the internal data encryption key (DEK) will be updated. This is implemented through a full copy; It's a slow operation that must be performed while the virtual machine is powered off. A shallow key change will only update the KEK and the operation can be performed while the virtual machine is running. .EXAMPLE C:\PS>$VM = Get-VM -Name win2012 C:\PS>$HardDisk = $VM|Get-HardDisk|select -last 2 C:\PS>Set-VMDiskEncryptionKey -VM $VM -HardDisk $HardDisk Rekeys the last 2 hard disks in the VM. .EXAMPLE C:\PS>$VM=Get-VM -Name win2012 C:\PS>$HardDisk = get-vm $vm|Get-HardDisk|Select -last 2 C:\PS>Set-VMDiskEncryptionKey -VM $VM -HardDisk $HardDisk -Deep Deep rekeys the last 2 hard disks in the VM. .EXAMPLE C:\PS>$KMSCluster = Get-KMSCluster | select -last 1 C:\PS>$VM = Get-VM -Name win2012 C:\PS>$HardDisk = get-vm $vm|Get-HardDisk C:\PS>$HardDisk| Set-VMDiskEncryptionKey -VM $VM -KMSClusterId $KMSCluster.Id -Deep Deep rekeys all the disks of the $VM using a new key. The key is generated from the KMS whose clusterId is $KMSCluster.Id. .NOTES This cmdlet assumes there is already a KMS in vCenter Server. If VM is not encrypted, the cmdlet quits. You should use Enable-VMEncryption cmdlet to encrypt the VM first. .NOTES Author : Carrie Yang. Author email : yangm@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.VirtualDevice.HardDisk[]] $HardDisk, [Parameter(Mandatory=$False)] [String] $KMSClusterId, [Parameter(Mandatory=$False)] [switch]$Deep = $FALSE ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { Write-Verbose "Checking if $VM is encrypted...`n" if (!$VM.Encrypted) { Write-Error "$VM is not encrypted." return } # Valid the hard disks Write-Verbose "Checking the hard disks...`n" ConfirmHardDiskIsValid -VM $VM -HardDisk $HardDisk Write-Verbose "Checking if $VM has no snapshots...`n" if ($VM|Get-Snapshot) { Write-Error "$VM has snapshot, please remove all snapshots and try again!`n" return } if ($Deep) { Write-Verbose "Checking if $VM powered off...`n" if ($VM.powerstate -ne "PoweredOff") { $ErrMsg = "Deep rekey could be done only when VM powered off,"+ "but current VM power state is: $($VM.powerstate)!`n" Write-Error $ErrMsg return } } $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $CryptoSpec = New-Object VMware.Vim.CryptoSpecShallowRecrypt if ($Deep) { $CryptoSpec = New-Object VMware.Vim.CryptoSpecDeepRecrypt } # Generate a key from KMS try { $KeyResult = NewEncryptionKey -KMSClusterId $KMSClusterId } catch { Throw "Key generation failed, make sure the KMS Cluster exists!`n" } $CryptoSpec.NewKeyId = $KeyResult.KeyId $DeviceChanges = @() foreach ($disk in $HardDisk) { $DeviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $DeviceChange.operation = "edit" $DeviceChange.device = $Disk.extensiondata if ($Deep) { $ProfileSpec = New-Object VMware.Vim.VirtualMachineDefinedProfileSpec $ProfileSpec.ProfileId = ($Disk|Get-SpbmEntityConfiguration).StoragePolicy.Id $DeviceChange.Profile = $ProfileSpec } $DeviceChange.Backing = New-Object VMware.Vim.VirtualDeviceConfigSpecBackingSpec $DeviceChange.Backing.Crypto = $CryptoSpec $DeviceChanges += $DeviceChange } $VMCfgSpec.deviceChange = $DeviceChanges return (Get-View $VM).ReconfigVM_Task($VMCfgSpec) } } Function Get-VMEncryptionInfo { <# .SYNOPSIS This cmdlet gets the encryption information of VM and its disks. .DESCRIPTION This cmdlet gets the encryption information of VM and its disks. .PARAMETER VM Specifies the VM for which you want to retrieve the encryption information. .PARAMETER HardDisk Specifies the hard disks for which you want to retrieve the encryption information. .EXAMPLE C:\PS>Get-VM|Get-VMEncryptionInfo Retrieves all VM's encryption information. .EXAMPLE C:\PS>Get-VMEncryptionInfo -VM $vm -HardDisk $HardDisks Retrieves only disks' encryption information. .NOTES If $HardDisk is specified, then only the encryption information of the disks specified in $HardDisk is obtained. Otherwise, all disks' encryption information of the specified VM is returned. .NOTES Author : Carrie Yang. Author email : yangm@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.VirtualDevice.HardDisk[]] $HardDisk ) Process { $DisksInfo = @() if ($HardDisk) { # Validate the hard disks Write-Verbose "Checking the hard disks...`n" ConfirmHardDiskIsValid -VM $VM -HardDisk $HardDisk } foreach ($DK in $HardDisk) { $DKInfo = @{} $DKInfo.index = $DK.ExtensionData.Key $DKInfo.label = $DK.ExtensionData.DeviceInfo.Label $diskSize = $DK.ExtensionData.CapacityInKB $formattedSize = "{0:N0}" -f $diskSize $DKInfo.summary = "$formattedSize KB" $DKInfo.profile = ($DK|Get-SpbmEntityConfiguration).StoragePolicy $DKInfo.fileName = $DK.Filename $DKInfo.uuid = $DK.ExtensionData.Backing.Uuid $DKInfo.keyId = $DK.ExtensionData.Backing.KeyId $DKInfo.iofilter = $DK.ExtensionData.Iofilter $DisksInfo += $DKInfo } $VMInfo = @{} $VMInfo.name = $VM.Name $VMInfo.connectState = $VM.ExtensionData.Runtime.ConnectionState $VMInfo.profile = ($VM | Get-SpbmEntityConfiguration).StoragePolicy $VMInfo.keyId = $VM.ExtensionData.Config.KeyId $VMInfo.disks = $DisksInfo return $VMInfo } } Function Get-EntityByCryptoKey { <# .SYNOPSIS This cmdlet gets all the related objects in which it has the key associated. .DESCRIPTION This cmdlet gets all the related objects in which it has the key associated. .PARAMETER KeyId Specifies the KeyId string. .PARAMETER KMSClusterId Specifies the KMSClusterId string. .PARAMETER SearchVMHosts Specifies whether to search the VMHosts. .PARAMETER SearchVMs Specifies whether to search the VMs. .PARAMETER SearchDisks Specifies whether to search the HardDisks. .EXAMPLE C:\PS>Get-EntityByCryptoKeyId -SearchVMHosts -KeyId 'keyId' Gets the VMHosts whose CryptoKeyId's KeyId matches exactly the 'keyId'. .EXAMPLE C:\PS>Get-EntityByCryptoKeyId -SearchVMs -KMSClusterId 'clusterId' Gets the VMs whose CryptoKeyId's ProfileId.Id matches exactly the 'clusterId'. .EXAMPLE C:\PS>Get-EntityByCryptoKey -SearchVMHosts -SearchVMs -KMSClusterId 'clusterId' Gets VMHosts and VMs whose CryptoKeyId's ProviderId.Id matches the 'clusterId'. .NOTES At least one of the KeyId and KMSClusterId parameters is required. If the SearchVMHosts, SearchVMs and SearchDisks all not specified, the cmdlet return $null. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$false,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [String] $keyId, [Parameter(Mandatory=$false,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [String] $KMSClusterId, [Parameter(Mandatory=$False)] [switch] $SearchVMHosts, [Parameter(Mandatory=$False)] [switch] $SearchVMs, [Parameter(Mandatory=$False)] [switch] $SearchDisks ) if (!$KeyId -and !$KMSClusterId) { Throw "One of the keyId or KMSClusterId must be specified!`n" } # The returned Items $Entities = @{} # Find VMHosts $CryptoSafeVMHosts = Get-VMHost|Where {$_.CryptoSafe} # Quit if no VMHosts found. if (!$CryptoSafeVMHosts) { Throw "No VMHosts enabled the CrytoState to Safe!`n" } if ($SearchVMHosts) { Write-Verbose "Starting to search VMHosts...`n" $VMHostList = $CryptoSafeVMHosts| Where {$_.ExtensionData.Runtime.CryptoKeyId|MatchKeys -KeyId $KeyId -KMSClusterId $KMSClusterId} $Entities.VMHostList = $VMHostList } # Find the VMs which encrypted: Look for both VMHome and Disks $VMs = Get-VM|Where {$_.Encrypted} if ($SearchVMs) { Write-Verbose "Starting to search VMs...`n" $VMList = @() $Disks = $VMs|Get-HardDisk|Where {$_.Encrypted} $VMDiskList = $Disks|Where {$_.EncryptionKeyId|MatchKeys -KeyId $keyId -KMSClusterId $KMSClusterId} $VMList += $VMs|Where {$_.EncryptionKeyId|MatchKeys -KeyId $keyId -KMSClusterId $KMSClusterId} $VMList += $VMDiskList.Parent $VMList = $VMList|sort-object|Get-Unique $Entities.VMList = $VMList } # Find the Disks if ($SearchDisks) { Write-Verbose "Starting to search Disks...`n" if ($SearchVMs) { $DiskList = $VMDiskList } else { $Disks = $VMs|Get-HardDisk|Where {$_.Encrypted} $DiskList = $Disks|Where {$_.EncryptionKeyId|MatchKeys -KeyId $keyId -KMSClusterId $KMSClusterId} } $Entities.DiskList = $DiskList } return $Entities } Function New-KMServer { <# .SYNOPSIS This cmdlet adds a Key Management Server. .DESCRIPTION This cmdlet adds a Key Management Server to vCenter Server and verifies it. .PARAMETER KMServer Specifies the Key Management Server IP address or FQDN. .PARAMETER KMSClusterId Specifies the ID of the KMS cluster. KMSs with the same cluster ID are in one cluster and provide the same keys for redundancy. .PARAMETER UserName Specifies user name to authenticate to the KMS. .PARAMETER Password Specifies password to authenticate to the KMS. .PARAMETER Name Specifies the name of the KMS. .PARAMETER Port Specifies the port of the KMS. .PARAMETER ProxyServer Specifies the address of the proxy server. .PARAMETER ProxyPort Specifies the port of the proxy server. .PARAMETER Protocol Specifies the KMS library protocol handler, for example KMS1. .EXAMPLE C:\PS>New-KMServer -KMServer 1.1.1.1 -KMSClusterId clsName -UserName "YourKMSUserName" -Password '***' -Name "KMS1" Adds the Key Management Server 1.1.1.1 into vCenter with the cluster name 'clsname' and KMS name 'KMS1'. .NOTES This cmdlet only supports PyKMIP Server. For other KMS vendors, modify the script accordingly. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [String]$KMServer, [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [String]$KMSClusterId, [Parameter(Mandatory=$False)] [String] $UserName, [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [String] $Name, [Parameter(Mandatory=$False)] [String] $Password, [Parameter(Mandatory=$False)] [Int] $Port=5696, [Parameter(Mandatory=$False)] [String] $ProxyServer, [Parameter(Mandatory=$False)] [Int] $ProxyPort, [Parameter(Mandatory=$False)] [String] $Protocol ) Begin { write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Add-KeyManagementServer instead" # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager } Process { if ([string]::IsNullOrWhiteSpace($KMSClusterId)) { Write-Error "The KMSClusterId parameter is mandatory, please specify a valid value!`n" return } if ([string]::IsNullOrWhiteSpace($KMServer)) { Write-Error "The KMServer parameter is mandatory, please specify a valid value!`n" return } if ([string]::IsNullOrWhiteSpace($Name)) { Write-Error "The KMSName parameter is mandatory. Please specify a valid value!`n" return } Write-Verbose "Starting to add Key Management Server: $KMServer......`n" # Construct KMServerInfo and Spec $KMServerInfo = New-Object VMware.Vim.KmipServerInfo $KMServerSpec = New-Object VMware.Vim.KmipServerSpec $KMServerInfo.Address = $KMServer $KMServerInfo.Name = $Name if ($UserName) { $KMServerInfo.UserName = $UserName } if ($KMSPassword) { $KMServerSpec.Password = $Password } if ($Port) { $KMServerInfo.Port = $Port } if ($ProxyServer) { $KMServerInfo.ProxyAddress = $ProxyServer } if ($ProxyPort) { $KMServerInfo.ProxyPort = $ProxyPort } if ($Protocol) { $KMServerInfo.Protocol = $Protocol } $ProviderID = New-Object VMware.Vim.KeyProviderId $ProviderID.Id = $KMSClusterId $KMServerSpec.ClusterId = $ProviderID $KMServerSpec.Info = $KMServerInfo Write-Verbose "Registering $KMServer to vCenter Server....`n" try { $CM.RegisterKmipServer($KMServerSpec) } catch { Write-Error "Exception: $_ !" return } Write-Verbose "Establishing trust between vCenter Server and the Key Management Server: $KMServer`n" try { $KMServerCert = $CM.RetrieveKmipServerCert($providerID,$KMServerInfo) $CM.UploadKmipServerCert($providerID,$KMServerCert.Certificate) } catch { Write-Error "Error occurred while retrieveing and uploading certification!`n" return } $CM.updateviewdata() if (!(Get-DefaultKMSCluster) -and ($CM.KmipServers|foreach {$_.servers}|foreach {$_.Address}) -contains $KMServer) { Write-Verbose "No default Key Management Server yet. Marking $KMServer as default!`n" Set-DefaultKMSCluster -KMSClusterId $ProviderID.Id } Write-Verbose "Verifying KMS registration.....`n" $CM.updateviewdata() $KMServers = $CM.Kmipservers|where {($_.servers|foreach {$_.Address}) -contains $KMServer} if ($KMServers) { Write-Verbose "Key Management Server registered successfully!`n" $KMServers } else { Write-Error "Key Management Server registration failed!`n" } } } Function Remove-KMServer { <# .SYNOPSIS This cmdlet removes a Key Management Server. .DESCRIPTION This cmdlet removes a Key Management Server from vCenter Server. .PARAMETER Name Specifies the name or alias of the Key Management Server. .PARAMETER KMSClusterId Specifies the KMS cluster ID string to be used as Key Management Server cluster. .EXAMPLE C:\PS>Remove-KMServer -KMSClusterId "ClusterIdString" -KMSName "KMServerName" Removes the KMS from vCenter Server which has the KMS name and KMS cluster ID. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True)] [String]$KMSClusterId, [Parameter(Mandatory=$True)] [String]$Name ) Begin { write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Remove-KeyManagementServer instead" # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager } Process { if ([string]::IsNullOrWhiteSpace($Name) -Or [string]::IsNullOrWhiteSpace($KMSClusterId)) { $ErrMsg = "The KMSName and KMSClusterId parameters are mandatory "+ "and should not be null or empty!`n" Write-Error $ErrMsg return } $KMServers = $CM.KmipServers if (!$KMServers) { Write-Error "There are no Key Managerment Servers in vCenter Server!`n" return } if ($KMServers|Where { ($_.ClusterId.Id -eq $KMSClusterId) -and ($_.Servers|Where {$_.Name -eq $Name})}) { #Start to remove the specified Km Server try { $ProviderID = New-Object VMware.Vim.KeyProviderId $ProviderID.Id = $KMSClusterId $CM.RemoveKmipServer($providerID, $Name) } catch { Write-Error "Exception: $_!`n" return } } else { $KMSNotFounErrMsg = "Cannot find the KMS with Name:$Name and KMS ClusterId:$KMSClusterId,"+ "please make sure you specified correct parameters!`n" Write-Error $KMSNotFounErrMsg return } } } Function Get-KMSCluster { <# .SYNOPSIS This cmdlet retrieves all KMS clusters. .DESCRIPTION This cmdlet retrieves all KMS clusters. .EXAMPLE C:\PS>Get-KMSCluster Retrieves all KMS clusters. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Get-KmsCluster instead" # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager # Get all KMS Clusters return $CM.KmipServers.ClusterId } Function Get-KMSClusterInfo { <# .SYNOPSIS This cmdlet retrieves the KMS cluster information. .DESCRIPTION This cmdlet retrieves the KMS cluster Information by providing the KMS cluster ID string. .PARAMETER KMSClusterId Specifies the KMS cluster ID. .EXAMPLE C:\PS>Get-KMSClusterInfo Retrieves all KMS cluster information. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [String] $KMSClusterId ) Begin { write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Get-KmsCluster instead" # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager } Process { # Get all Km Clusters if no KMSClusterId specified if (!$KMSClusterId) { return $CM.KmipServers } return $CM.KmipServers|where {$_.ClusterId.Id -eq $KMSClusterId} } } Function Get-KMServerInfo { <# .SYNOPSIS This cmdlet retireves the Key Management Servers' information. .DESCRIPTION This cmdlet retireves the Key Management Servers' information by providing the KMS cluster ID string. .PARAMETER KMSClusterId Specifies the KMS cluster ID. .EXAMPLE C:\PS>Get-KMServerInfo Retrieves information about all Key Management Servers. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [String] $KMSClusterId ) Begin { write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Get-KeyManagementServer instead" # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager } Process { # Get all KMS Info if no clusterId specified if ($KMSClusterId) { $FindCluster = (Get-KMSCluster).Contains($KMSClusterId) if (!$FindCluster) { Write-Error "Cannot find the specified KMS ClusterId in vCenter Server!" return } $ClsInfo = Get-KMSClusterInfo -KMSClusterId $KMSClusterId return $ClsInfo.Servers } return $CM.KmipServers.Servers } } Function Get-KMServerStatus { <# .SYNOPSIS This cmdlet retrieves the KMS status. .DESCRIPTION This cmdlet retrieves the KMS status by providing the KMS cluster ID String .PARAMETER KMSClusterId Specifies the KMS cluster ID from which to retrieve the servers' status. .EXAMPLE C:\PS>Get-KMServerStatus -KMSClusterId 'ClusterIdString' Retrieves the specified KMS cluster 'ClusterIdString' server status. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [String] $KMSClusterId ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager } Process { $ClusterInfo = @() if ($KMSClusterId) { # Quit if the ClusterID cannot be found $FindCluster = (Get-KMSCluster).Contains($KMSClusterId) if (!$FindCluster) { Write-Error "Cannot find the specified KMS ClusterId in vCenter Server!" return } $ClsInfo = New-Object VMware.Vim.KmipClusterInfo $ProviderId = New-Object VMware.Vim.KeyProviderId $ProviderId.Id = $KMSClusterId $ClsInfo.ClusterId = $providerId $ClsInfo.Servers = (Get-KMSClusterInfo -KMSClusterId $KMSClusterId).Servers $ClusterInfo += $ClsInfo $KMSClsStatus = $CM.RetrieveKmipServersStatus($ClusterInfo) } else { $ClusterInfo = Get-KMSClusterInfo $KMSClsStatus = $CM.RetrieveKmipServersStatus($ClusterInfo) } if ($KMSClsStatus) { return $KMSClsStatus } else { Write-Error "Failed to get the KMS status`n" return $null } } } Function Get-DefaultKMSCluster { <# .SYNOPSIS This cmdlet retrieves the default KMS cluster. .DESCRIPTION This cmdlet retrieves the default KMS cluster. .EXAMPLE C:\PS>Get-DefaultKMSCluster Retrieves the default KMS cluster. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Get-KmsCluster instead" # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager return ($CM.KmipServers|where {$_.UseAsDefault}).ClusterId.Id } Function Set-DefaultKMSCluster { <# .SYNOPSIS This cmdlet sets the provided KMS cluster as the default KMS cluster. .DESCRIPTION This cmdlet sets the provided KMS cluster as the default KMS cluster. .PARAMETER KMSClusterId Specifies KMS cluster ID which will be used to mark as default KMS cluster. .EXAMPLE C:\PS>Set-DefaultKMSCluster -KMSClusterId 'ClusterIdString' Sets the KMS cluster whose cluster ID is 'ClusterIdString' as the default KMS cluster. .NOTES Author : Baoyin Qiao. Author email : bqiao@vmware.com #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True)] [String] $KMSClusterId ) write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Set-KmsCluster instead" # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager $ProviderId = New-Object VMware.Vim.KeyProviderId $ProviderId.Id = $KMSClusterId $CM.MarkDefault($ProviderId) } Function Set-VMCryptoUnlock { <# .SYNOPSIS This cmdlet unlocks a locked vm .DESCRIPTION This cmdlet unlocks a locked vm .PARAMETER VM Specifies the VM you want to unlock .EXAMPLE PS C:\> Get-VM |where {$_.locked}| Set-VMCryptoUnlock Unlock all locked vms .NOTES Author : Fangying Zhang Author email : fzhang@vmware.com #> [CmdLetBinding()] param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]]$VM ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { foreach ($thisvm in $vm) { if (!$thisvm.encrypted) { write-warning "$thisvm is not encrypted, will skip $thisvm" continue } if (!$thisvm.Locked) { write-warning "$thisvm may not be locked!" # $thisvm.locked could be false on old 6.5.0 build (bug 1931370), so do not skip $thisvm } write-verbose "try to CryptoUnlock $thisvm" $thisvm.ExtensionData.CryptoUnlock() } } } Function Add-Vtpm { <# .SYNOPSIS This cmdlet adds a Virtual TPM to the specified VM. .DESCRIPTION This cmdlet adds a Virtual TPM to the specified VM. .PARAMETER VM Specifies the VM you want to add Virtual TPM to. .EXAMPLE C:\PS>$vm1 = Get-VM -Name win2016 C:\PS>Add-Vtpm $vm1 Encrypts $vm1's VM home and adds Virtual TPM .NOTES If VM home is already encrypted, the cmdlet will add a Virtual TPM to the VM. If VM home is not encrypted, VM home will be encrypted and Virtual TPM will be added. .NOTES Author : Chong Yeo. Author email : cyeo@vmware.com #> [CmdLetBinding()] param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { $deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $deviceChange.operation = "add" $deviceChange.device = new-object VMware.Vim.VirtualTPM $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $VMCfgSpec.DeviceChange = $deviceChange return $VM.ExtensionData.ReconfigVM_task($VMCfgSpec) } } Function Remove-Vtpm { <# .SYNOPSIS This cmdlet removes a Virtual TPM from the specified VM. .DESCRIPTION This cmdlet removes a Virtual TPM from the specified VM. .PARAMETER VM Specifies the VM you want to remove Virtual TPM from. .EXAMPLE C:\PS>$vm1 = Get-VM -Name win2016 C:\PS>Remove-Vtpm $vm1 .EXAMPLE C:\PS>Get-VM -Name win2016 |Remove-Vtpm Remove Virtual TPM from VM named win2016 .NOTES Removing VirtualTPM will render all encrypted data on this VM unrecoverable. VM home encryption state will be returned to the original state before Virtual TPM is added .NOTES Author : Chong Yeo. Author email : cyeo@vmware.com #> [CmdLetBinding(SupportsShouldProcess=$true, ConfirmImpact = "High")] param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { $message = "Removing Virtual TPM will render all encrypted data on this VM unrecoverable" if ($PSCmdlet.ShouldProcess($message, $message + "`n Do you want to proceed", "WARNING")) { $deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $deviceChange.operation = "remove" $deviceChange.device = $vtpm $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $VMCfgSpec.DeviceChange = $deviceChange return $VM.ExtensionData.ReconfigVM_task($VMCfgSpec) } } } Function Get-VtpmCsr { <# .SYNOPSIS This cmdlet gets certficate signing requests(CSR) from Virtual TPM. .DESCRIPTION This cmdlet gets certficate signing requests(CSR) from Virtual TPM. The CSR is a ComObject X509enrollment.CX509CertificateRequestPkcs10 .PARAMETER VM Specifies the VM you want to get the CSRs Virtual TPM from. .PARAMETER KeyType [RSA | ECC] Specify that only get CSR with public key RSA algorithm. If none is specified, both CSR will get returned .EXAMPLE C:\PS>$vm1 = Get-VM -Name win2016 C:\PS>Get-VtpmCsr $vm1 -KeyType RSA .NOTES Both RSA and ECC CSRs objects will be returned. If ECC or RSA is specified, only the corresponding object will be returned .NOTES Author : Chong Yeo. Author email : cyeo@vmware.com #> [CmdLetBinding()] param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, [Parameter(Mandatory=$False)] [String]$KeyType ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } process { # Get vTPM from VM $vtpm = $VM.ExtensionData.Config.Hardware.Device |Where {$_ -is [VMware.Vim.VirtualTPM]} # Check if vTPM is already present if (!$vtpm) { Write-Error "$VM does not contains a Virtual TPM" return } $CSRs = @() foreach ($csrArray in $vtpm.EndorsementKeyCertificateSigningRequest) { $csrString = [System.Convert]::ToBase64String($csrArray) $csr = New-Object -ComObject X509enrollment.CX509CertificateRequestPkcs10 #decode a base64 string into a CSR object $csr.InitializeDecode($csrString,6) if ($keyType) { if ($csr.PublicKey.Algorithm.FriendlyName -eq $KeyType){ return $csr } } else { $CSRs += $csr } } return $CSRs } } Function Set-VtpmCert{ <# .SYNOPSIS This cmdlet replaces certificates of Virtual TPM in the specified VM. .DESCRIPTION This cmdlet replaces certificates to Virtual TPM in the specified VM. .PARAMETER VM Specifies the VM with Virtual TPM where you want to replace the certificates to. .PARAMETER Cert Specifies the certificate object (System.Security.Cryptography.X509Certificates.X509Certificate) .EXAMPLE C:\PS>$vm1 = Get-VM -Name win2016 C:\PS>Set-VtpmCert $vm1 $certObj .EXAMPLE C:\PS>Get-VM -Name win2016 | Set-VtpmCert $certObj Replace the appropriate certificate specified .NOTES Only RSA or ECC certs will be overwritten .NOTES Author : Chong Yeo. Author email : cyeo@vmware.com #> [CmdLetBinding()] param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$VM, [Parameter(Mandatory=$True)] [System.Security.Cryptography.X509Certificates.X509Certificate] $Cert ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } process { # Get vTPM from VM $vtpm = $VM.ExtensionData.Config.Hardware.Device |Where {$_ -is [VMware.Vim.VirtualTPM]} #check if vTPM is already present if (!$vtpm) { Write-Error "$VM does not contains a Virtual TPM" return } $certOid = New-Object System.Security.Cryptography.Oid($Cert.GetKeyAlgorithm()) # Check which certificate to overwrite $certLocation = GetKeyIndex $vtpm.EndorsementKeyCertificate $certOid.FriendlyName if ($certLocation -eq -1) { Write-Error "No Certificate with Matching Algorithm $($certOid.FriendlyName) found" return } $vtpm.EndorsementKeyCertificate[$certLocation] = $cert.GetRawCertData() $deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec $deviceChange.Operation = "edit" $deviceChange.Device = $vtpm $VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $VMCfgSpec.DeviceChange = $deviceChange return $VM.ExtensionData.ReconfigVM_task($VMCfgSpec) } } Function Get-VtpmCert{ <# .SYNOPSIS This cmdlet gets certificates of Virtual TPM in the specified VM. .DESCRIPTION This cmdlet gets certificates of Virtual TPM in the specified VM. .PARAMETER VM Specifies the VM with Virtual TPM where you want to get the certificate from .EXAMPLE C:\PS>$vm1 = Get-VM -Name win2016 C:\PS>$certs = Get-VtpmCert $vm1 .NOTES An array of certificate object (System.Security.Cryptography.X509Certificates.X509Certificate) will be returned .NOTES Author : Chong Yeo. Author email : cyeo@vmware.com #> [CmdLetBinding()] param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM ) Begin { # Confirm the connected VIServer is vCenter Server ConfirmIsVCenter } Process { # Get vTPM from VM $vtpm = $VM.ExtensionData.Config.Hardware.Device |Where {$_ -is [VMware.Vim.VirtualTPM]} # check if vTPM is already present if (!$vtpm) { Write-Error "$VM does not contain a Virtual TPM" return } $certs = @() $vtpm.EndorsementKeyCertificate|foreach { $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate $cert.Import($_) $certs += $cert } return $certs } } Function ConfirmIsVCenter{ <# .SYNOPSIS This function confirms the connected VI server is vCenter Server. .DESCRIPTION This function confirms the connected VI server is vCenter Server. .EXAMPLE C:\PS>ConfirmIsVCenter Throws exception if the connected VIServer is not vCenter Server. #> $SI = Get-View Serviceinstance $VIType = $SI.Content.About.ApiType if ($VIType -ne "VirtualCenter") { Throw "Operation requires vCenter Server!" } } Function ConfirmHardDiskIsValid { <# .SYNOPSIS This function confirms the hard disks is valid. .DESCRIPTION This function confirms the hard disks is valid. .PARAMETER VM Specifies the VM which you want to used to validate against. .PARAMETER HardDisk Specifies the hard disks which you want to use to validate. #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, [Parameter(Mandatory=$True)] [VMware.VimAutomation.ViCore.Types.V1.VirtualDevice.HardDisk[]] $HardDisk ) $NonVMHardDisks = $HardDisk|Where {$_.Parent -ne $VM} if ($NonVMHardDisks.Length -ge 1) { Throw "Some of the provided hard disks: $($NonVMHardDisks.FileName) do not belong to VM: $VM`n" } } Function MatchKeys { <# .SYNOPSIS This function checks whether the given keys matched or not. .DESCRIPTION This function checks whether the given keys matched or not with the provided KeyId or KMSClusterId. .PARAMETER KeyToMatch Specifies the CryptoKey to match for. .PARAMETER KeyId Specifies the keyId should be matched. .PARAMETER KMSClusterId Specifies the KMSClusterId should be matched. .NOTES Returns the true/false depends on the match result. One of keyId or KMSClusterId parameter must be specified. #> [CmdLetBinding()] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [VMware.Vim.CryptoKeyId] $KeyToMatch, [Parameter(Mandatory=$false)] [String] $KeyId, [Parameter(Mandatory=$false)] [String] $KMSClusterId ) Process { if (!$KeyId -and !$KMSClusterId) { Throw "One of the keyId or KMSClusterId must be specified!`n" } $Match = $True if ($KeyId -and ($KeyId -ne $KeyToMatch.KeyId)) { $Match = $false } if ($KMSClusterId) { if (!$KeyToMatch.ProviderId) { $Match = $false } if ($KMSClusterId -ne $KeyToMatch.ProviderId.Id) { $Match = $false } } return $Match } } Function NewEncryptionKey { <# .SYNOPSIS This function generates new encryption key from KMS. .DESCRIPTION This function generates new encryption from KMS, if no KMSClusterId specified the default KMS will be used. .PARAMETER KMSClusterId Specifies the KMS cluster id. .EXAMPLE C:\PS>NewEncryptionKey -KMSClusterId 'ClusterIdString' Generates a new encryption key from the specified KMS which cluster id is 'ClusterIdString'. #> Param ( [Parameter(Mandatory=$False)] [String]$KMSClusterId ) # Confirm the connected VIServer is vCenter ConfirmIsVCenter # Get the cryptoManager of vCenter Server $CM = GetCryptoManager $ProviderId = New-Object VMware.Vim.KeyProviderId Write-Verbose "Generate a CryptoKey.`n" if ($KMSClusterId) { $ProviderId.Id = $KMSClusterId } else { $ProviderId = $null } $KeyResult = $CM.GenerateKey($ProviderId) if (!$keyResult.Success) { Throw "Key generation failed, make sure the KMS Cluster exists!`n" } return $KeyResult } Function GetCryptoManager { <# .SYNOPSIS This function retrieves the cryptoManager according to the given type. .DESCRIPTION This function retrieves the cryptoManager according to the given type. .PARAMETER Type Specifies the type of CryptoManager instance to get, the default value is KMS. .EXAMPLE C:\PS>GetCryptoManager -Type "CryptoManagerKmip" Retrieves the 'CryptoManagerKmip' type CryptoManager. #> Param ( [Parameter(Mandatory=$false)] [String] $Type ) Process { $SI = Get-View Serviceinstance $CM = Get-View $SI.Content.CryptoManager $cryptoMgrType = $CM.GetType().Name if (!$Type) { # As the type is not cared, so return the CM directly return $CM } if ($cryptoMgrType -eq $Type) { return $CM } Throw "Failed to get CryptoManager instance of the required type {$Type}!" } } Function GetKeyIndex{ <# .SYNOPSIS This cmdlet returns the index to the key with a matching algorithm as the KeyType parameter .DESCRIPTION This cmdlet returns the index to the key with a matching algorithm as the KeyType parameter .PARAMETER Certs Specifies the list of certificats. Expected format is byte[][] .PARAMETER KeyType Specifies the keytype to search for .EXAMPLE C:\PS>$keyIndex = GetKeyIndex $Certs RSA C:\PS>$keyIndex = GetKeyIndex $Certs ECC .NOTES Author : Chong Yeo. Author email : cyeo@vmware.com #> [CmdLetBinding()] param ( [Parameter(Mandatory=$True)] [byte[][]] $Certs, [Parameter(Mandatory=$True)] [String] $KeyType ) process { for ($i=0;$i -lt $Certs.Length; $i++) { $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate $cert.Import($Certs.Get($i)) $certType = New-Object System.Security.Cryptography.Oid($cert.GetKeyAlgorithm()) if ( $certType.FriendlyName -eq $keyType) { return $i } } return -1 } } Export-ModuleMember *-*