One of the customers I was engaged with ran into an issue where Citrix Studio was throwing out power commands towards Prism and Nutanix AHV but the VMs didn’t always respond properly. After some investigation it turned out we ran into the issue described here. Now obviously Citrix has best practices to disable screensavers on the VM side and optimize power managent but if you’re doing persistent desktops you might want a way to report which desktops aren’t optimized before taking any action, right? In my case I decided to write a short powershell script to get those VMs.
One of the issues I faced was that I had a lot more AD objects than actual VMs so to prevent loss of time I wanted to do a cross reference on the VMs I had running on my infrastructure vs the AD-objects.
My thoughts process here:
- Collect the VMs running on the virtual infrastructure.
- Collect the Client OS based AD Objects
- Cross reference those lists
- Turn on the VMs that are in both lists
- Check the settings for each of the VMs that exist in the final list.
- Report back if a connection could be made and what the actual settings where.
I’ve ran the script inside my environment and it got the job done, the goal of this blogpost/powershell script is to document the script and to show how you can save time by cross referencing multiple sources before actually going out and process a number of items that are irrelevant.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# kees@nutanix.com # @kbaggerman on Twitter # http://blog.myvirtualvision.com # Created on September, 2019 # Connect to HV first, get all powered on VMs, compare that to AD get-adcomputer and run this across that array # Full functioning script # Setting parameters for the connection [CmdletBinding(SupportsShouldProcess = $False, ConfirmImpact = "None") ] Param( # Nutanix cluster IP address [Parameter(Mandatory = $true)] [Alias('IP')] [string] $nxIP, # Nutanix cluster username [Parameter(Mandatory = $true)] [Alias('User')] [string] $nxUser, # Nutanix cluster password [Parameter(Mandatory = $true)] [Alias('Password')] [String] $nxPassword ) # Converting the password to a secure string which isn't accepted for our API connectivity $nxPasswordSec = ConvertTo-SecureString $nxPassword -AsPlainText -Force $nxPassword = $null Function write-log { <# .Synopsis Write logs for debugging purposes .Description This function writes logs based on the message including a time stamp for debugging purposes. #> param ( $message, $sev = "INFO" ) if ($sev -eq "INFO") { write-host "$(get-date -format "hh:mm:ss") | INFO | $message" } elseif ($sev -eq "WARN") { write-host "$(get-date -format "hh:mm:ss") | WARN | $message" } elseif ($sev -eq "ERROR") { write-host "$(get-date -format "hh:mm:ss") | ERROR | $message" } elseif ($sev -eq "CHAPTER") { write-host "`n`n### $message`n`n" } } # Adding PS cmdlets $loadedsnapins = (Get-PSSnapin -Registered | Select-Object name).name if (!($loadedsnapins.Contains("NutanixCmdletsPSSnapin"))) { Add-PSSnapin -Name NutanixCmdletsPSSnapin } if ($null -eq (Get-PSSnapin -Name NutanixCmdletsPSSnapin -ErrorAction SilentlyContinue)) { write-log -message "Nutanix CMDlets are not loaded, aborting the script" break } # Connecting to the Nutanix Cluster $nxServerObj = Connect-NTNXCluster -Server $nxIP -UserName $nxUser -Password $nxPasswordSec -AcceptInvalidSSLCerts -ForcedConnection write-log -Message "Connecting to cluster $nxIp" if ($null -eq (get-ntnxclusterinfo)) { write-log -message "Cluster connection isn't available, abborting the script" break } else { write-log -message "Connected to Nutanix cluster $nxIP" } # Fetching VMs running on AHV $VMs = get-ntnxvm | Where-Object { $_.controllerVm -Match "False" } write-log -message "Grabbing VM information and Client OS based Windows AD-objects" write-log -message "Currently grabbing information on $($VMs.count) VMs" # Check Windows Client OS-based AD Objects $Clients = Get-ADComputer -Filter { OperatingSystem -like '*7*' -or OperatingSystem -like '*10*' } -Property * write-log -message "Currently grabbing information on $($Clients.count) workstations" # Comparing the VM list with the Windows Client OS-based AD Objects write-log -message "Comparing the VM list with the AD object list" $ADVMs = $VMs.vmName | where-object { $clients.Name -contains $_ } write-log -message "The both lists have $($advms.count) machines in common" # Turning on the VMs that are in both lists write-log -message "Starting the VMs in the combined list that are turned off" foreach ($advm in $ADVMs) { $vminfo = Get-NTNXVM | Where-Object { $_.vmName -eq $advm } If ($vminfo.powerState -eq "Off") { # Get the VmID of the VM $vmId = ($vminfo.vmid.split(":"))[2] # Booting the VM Set-NTNXVMPowerOn -Vmid $VMid | out-null Write-log -message "Starting $ADVM" } } # Waiting a minute to start all the VMs in the previous action Start-Sleep 60 # Getting remote registry for each VM that also has a Windows Client OS-based AD object foreach ($vm in $ADVMs) { try { $RemoteRegistry = Get-CimInstance -Class Win32_Service -ComputerName $vm -Filter 'Name = "RemoteRegistry"' -ErrorAction Stop if ($RemoteRegistry.State -eq 'Running') { write-log -Message "$vm : Remote Registry is already Enabled" # Getting Screen saver configuration $result = Invoke-Command -Computername $VM { Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\7516b95f-f776-4464-8c53-06167f40cc99\8EC4B3A5-6868-48c2-BE75-4F3044BE88A7\' -Name 'Attributes' | select-object 'Attributes' } if ($result.Attributes -eq '1') { write-log -message "$VM : Screensaver set" # Collecting current power scheme and changing power options if needed $currentPowerScheme = Invoke-Command -Computername $VM { Powercfg -getactivescheme } $currentPowerScheme = $currentPowerScheme.split("()") Write-log -Message "$VM : Power Scheme set to $($currentPowerScheme[1])" $DisplaySettings = Invoke-Command -Computername $VM { powercfg -query SCHEME_CURRENT 7516b95f-f776-4464-8c53-06167f40cc99 3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e } $DisplaySettings = $DisplaySettings[10].Split(":")[-1] if ($DisplaySettings -like '*0x00000000') { Write-log -Message "$VM : Display Settings: Configured to Never turn off the display" } else { Write-log -Message "$VM : Display Settings: Not configured to Never turn off the display" } } } } catch { write-log -sev 'Error' -message "$vm : Looks like WinRM isn't enabled" } } # Disconnecting from the Nutanix Cluster Disconnect-NTNXCluster -Servers * write-log -message "Closing the connection to the Nutanix cluster $($nxIP)" |
Here’s how the script outputs to the console:
Next step would be to output this to a CSV or HTML file so you can go around showing the report and take action based on the report. As you’ve seen from previous scripts it should be simple to output this to HTML and set actions for the VMs that aren’t fully optimized.
Kees Baggerman
Latest posts by Kees Baggerman (see all)
- Nutanix AHV and Citrix MCS: Adding a persistent disk via Powershell – v2 - November 19, 2019
- Recovering a Protection Domain snapshot to a VM - September 13, 2019
- Checking power settings on VMs using powershell - September 11, 2019
- Updated: VM Reporting Script for Nutanix with Powershell - July 3, 2019
- Updated (again!): VM Reporting Script for Nutanix AHV/vSphere with Powershell - June 17, 2019