PowerCLI Powerhsell

From Michael's Information Zone
Jump to navigation Jump to search

Installation

2021

Clean install of Serve 2016

  • Enable TLS support[1]
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
  • Restart powershell and install[2]
Install-Module -Name VMware.PowerCLI
  • Install Horizon view helper moduals[3]

old

Allow powershell to run powercli cmdlets

Set-ExecutionPolicy RemoteSigned
Install-Module -Name VMware.PowerCLI -allowclobber

If you have not installed a valid certificate.[4]

Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false

Download modules and place them in the modules directory.

  • Download from github
  • Unzip, move modules to "C:\ProgramFiles\WindowsPowerShell\Modules"

Horizon

[5]It looks like vmware relies on the API to do most of the work with horizon. If you are not familiar with working with the API, like myself, this requires you to install additional scripts from github[6]. In my case I had to change the execution policy to unrestricted as the vmware.hv.helper module was not signed. Fun stuff.

Installation

After installing PowerShell 7.1.3 [7][8]

Install-Module -Name VMware.PowerCLI -AllowClobber

List of Commands

PS C:\Windows\system32> Get-Command | where {$_.name -match "get-hv"}

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Get-HvCommand                                      7.6.0.1... VMware.VimAutomation.HorizonView
Function        Get-HVEntitlement                                  1.1        VMware.Hv.Helper
Function        Get-HVEvent                                        1.1        VMware.Hv.Helper
Function        Get-HVEventDatabase                                1.1        VMware.Hv.Helper
Function        Get-HVFarm                                         1.1        VMware.Hv.Helper
Function        Get-HVFarmSummary                                  1.1        VMware.Hv.Helper
Function        Get-HVGlobalEntitlement                            1.1        VMware.Hv.Helper
Function        Get-HVGlobalSession                                1.1        VMware.Hv.Helper
Function        Get-HVGlobalSettings                               1.1        VMware.Hv.Helper
Function        get-hvhealth                                       1.1        VMware.Hv.Helper
Function        Get-HVHomeSite                                     1.1        VMware.Hv.Helper
Function        Get-HVInternalName                                 1.1        VMware.Hv.Helper
Function        Get-HVlicense                                      1.1        VMware.Hv.Helper
Function        get-HVlocalsession                                 1.1        VMware.Hv.Helper
Function        Get-HVMachine                                      1.1        VMware.Hv.Helper
Function        Get-HVMachineSummary                               1.1        VMware.Hv.Helper
Function        get-hvpodfederation                                1.1        VMware.Hv.Helper
Function        Get-HVPool                                         1.1        VMware.Hv.Helper
Function        Get-HVPoolSpec                                     1.1        VMware.Hv.Helper
Function        Get-HVPoolSummary                                  1.1        VMware.Hv.Helper
Function        Get-HVQueryFilter                                  1.1        VMware.Hv.Helper
Function        Get-HVQueryResult                                  1.1        VMware.Hv.Helper
Function        Get-HVResourceStructure                            1.1        VMware.Hv.Helper
Function        get-hvsite                                         1.1        VMware.Hv.Helper

Creating a list of machines and users

The problem

This is not as intuitive as other cmdlets. For example; you can run get-hvmachinesummary and get a list of machines.

PS C:\Windows\system32> Get-HVMachineSummary

Machine         DesktopPool  DNS Name     User     Host            Agent Datastore  Status
-------         -----------  --------     ----     ----            ----- ---------  ------
lxn-vdi-02      Test         lxn-vdi-0... csp.t... 172.16.5.50     7.7.0 {vdiswa... DISCONNECTED
lxn-vdi-03      Test         lxn-vdi-0... ad.my... 172.16.5.42     7.7.0 {vdiswa... AVAILABLE
lxn-vdi-04      Test         lxn-vdi-0... csp.t... 172.16.5.42     7.7.0 {vdiswa... DISCONNECTED
csp-vdi-70      Test         csp-vdi-7... ad.my... 172.16.5.42     7.4.0 {vdiswa... CONNECTED

But then you can't select the Machine and User fields.

PS C:\Windows\system32> Get-HVMachineSummary | select Machine,User

Machine User
------- ----

The fix

Ends up things are a little different[9]. Using get-member was useful to finding that there is a "base" property, then under this there was all the information I needed.

PS C:\Windows\system32> $machines=Get-HVMachineSummary
PS C:\Windows\system32> $machines | get-member


   TypeName: VMware.Hv.MachineNamesView

Name                    MemberType Definition
----                    ---------- ----------
Equals                  Method     bool Equals(System.Object obj)
GetHashCode             Method     int GetHashCode()
GetType                 Method     type GetType()
ToString                Method     string ToString()
Base                    Property   VMware.Hv.MachineBase Base {get;set;}
Id                      Property   VMware.Hv.MachineId Id {get;set;}
ManagedMachineNamesData Property   VMware.Hv.MachineManagedMachineNamesData ManagedMachineNamesData {get;set;}
MessageSecurityData     Property   VMware.Hv.MachineMessageSecurityData MessageSecurityData {get;set;}
NamesData               Property   VMware.Hv.MachineNamesData NamesData {get;set;}

PS C:\Windows\system32> $machines.base


Name                             : lxn-vdi-02
DnsName                          : lxn-vdi-02.domain
User                             : VMware.Hv.UserOrGroupId
AccessGroup                      : VMware.Hv.AccessGroupId
Desktop                          : VMware.Hv.DesktopId
DesktopName                      : Test
Session                          : VMware.Hv.SessionId
BasicState                       : DISCONNECTED
Type                             : MANAGED_VIRTUAL_MACHINE
OperatingSystem                  : Windows 10
OperatingSystemArchitecture      : 64_bit
AgentVersion                     : 7.7.0
AgentBuildNumber                 : 11054235
RemoteExperienceAgentVersion     :
RemoteExperienceAgentBuildNumber : 11054235

PS C:\Windows\system32> $machines.namesdata

DesktopName UserName
----------- --------
Test        domain.tld\user1

Then to pull it all together by creating an array[10] to hold the values.

##This will create a CSV of users and their assigned desktops.
##Then save the file to C:\list.csv.

##Grab credentials
$creds=Get-Credential -ErrorAction Stop

##Set execution policy, because vmware didn't sign their modules.
Set-ExecutionPolicy Unrestricted

##Connect to horizon connection server
Connect-HVServer -server localhost -Credential $creds -ErrorAction Stop
##Import needed modules
Import-Module VMware.Hv.Helper -ErrorAction stop
Import-Module VMware.VimAutomation.HorizonView -ErrorAction stop
Import-Module VMware.VimAutomation.Core -ErrorAction Stop
##Get list of machines
$machines=Get-HVMachineSummary
##Create empt array
$list=@()
##Generate list of users and their machines.
$machines | foreach {
    $test=$null
    $test=new-object system.object
    $test | Add-Member -Type NoteProperty -Name User -Value $_.namesdata.username
    Add-Member -InputObject $test -Type NoteProperty -Name Desktop -Value $_.base.name
    $list+= $test
    }
$list | Export-Csv -NoClobber -NoTypeInformation -Path C:\list.csv

Horizon API

These are just notes on what I was able to figure out.

Example: Maintenance MOde

1.Connect to the server and create the object to hold all the commands and junk.

$hvserver=connect-hvserver -server localhost -user user -password password -domain domain.tld
$services=$hvserver.extensiondata

2. Figure out the overload objects for the tasks you want to complete

PS C:\Windows\system32> $services.machine.machine_entermaintenancemode

OverloadDefinitions
-------------------
void Machine_EnterMaintenanceMode(VMware.Hv.MachineID id)

3. Create the object with the value you want.

[Vmware.Hv.machineid]$machine=(get-machine -machinename testmachine).id

4. Execute the task

$services.machine.machine_entermaintenancemode($machine)

Example: Refresh all VMs for Composer based images

$hvserver=connect-hvserver -server localhost -user user -password password -domain domain.tld
$services=$hvserver.extensiondata
$spechelper=New-Object VMware.Hv.DesktopService+DesktopRefreshSpecHelper
$specbase=New-Object VMware.Hv.DesktopRefreshSpec
(get-hvmachine).base.desktop | foreach {
 [Vmware.Hv.DesktopID]$deskid=$_
 $spec=$specbase
 $spec.logoffsetting=$spechelper.LOGOFF_SETTING_FORCE_LOGOFF
 $spec.machines=$deskid
 $services.desktop.desktop_refresh($deskid, $spec)
}

vcenter

Log into the server and start using commands

$cred=get-credential
connect-viserver -server localhost -credential $cred
get-vm

Add/Remove Hardware

CPUs

[11]

Network Interfaces

[12]The fun with this is that you can not remove a NIC from a running VM using powercli, or at least not in the way you would think. You actually need to rebuild the config with the changes you want then apply it back. Instead of doing this I decided to just disconnect the unwanted NIC and install the desired one. Thankfully this is in a DHCP environment so no modifications needed in the guest OS.

The reason for this change was due to Windows VMs losing connectivity to domain traffic using the emulated Intel NIC. According to our MS rep, we needed to change the NICs from e1000 to vmxnet3.

connect-viserver -server localhost
$list=get-vm
foreach ($i in $list){
$type=$i | Get-NetworkAdapter | select -ExpandProperty Type
if ($type -like "e1000"){
$i | get-networkadapter -name "Network adapter 1" | set-networkadapter -connected $false -startconnected $false -confirm $false
$i | new-networkadapter -networkname VDI -StartConnected -type vmxnet3}
}

RAM

Lets say you created a default config with 6GB of RAM because you were an ignorant moron, and now you need to increase this to a proper 8GB.[13] The fun part is that the -MemoryGB option does not autofill, so you would be hard pressed to find this option without the Google. Gotta love Linux man pages!

Get-Folder -Name <your folder>| get-vm | where {$_.MemoryGB -eq "6.00"} | Set-VM -MemoryGB 8 -confirm:$false

Clone VM

new-vm -name <new_machine_name> -vm <source_machine_name> -vmhost <ip or host name of the physical host, not the controller>

Sample Script : format is <scriptname>.ps1 <number of VMs to make>
ie clone_vm.ps1 3

#######################################################################
###08-14-2017
###Specified the datastore to use because vmware is stupid, and was
###putting the VMs in the swap volume. Idiots.
#######################################################################
$num1 = Read-Host -Prompt "How many VMs? "
#Athenticate
$cred=get-credential
connect-viserver -server localhost -credential $cred

#Check for enough space
$neededspace=([int]$num1 * '<space needed for each VM>')
$space12=(datastore -Name <datastore name> | Select-Object FreeSpaceGB | ForEach-Object { $_.FreeSpaceGB })
if ( $space12 -lt $neededspace ){
echo "Not enought space, $space12 is available and you need $neededspace"
exit
}
#The following assumes you are creating VMs with an incrementing name based on a [a-z]+-[a-z]+-[0-9]+ format.
#Get last VM created for incremental creation
get-folder -name <folder name> | get-vm | select name > C:\powercli\outtest
$vms=(Get-Content C:\powercli\outtest | %{"$($_.Split('-')[2])"})
$base=0
foreach($line in $vms){
if ([int]$line -gt [int]$base){
$base=$line
}
}
$base = [int]$base + 1
$num453=0
Do{
$usehost=(Get-VMHost | Get-Random)
new-vm -name vm-name-$base -vm clonefromthis -VMHost $usehost -Datastore <datastore to be used> -RunAsync -WhatIf
$num453=[int]$num453 + [int]1
}until ([int]$num453 -eq [int]$num1)

Delete VM

remote-vm -vm <namme_of_vm> -deletepermanently  -confirm:$false

Shutdown / Start VM

To shutdown and start VMs[14]

Get-Folder -Name pool02 | get-vm | where {$_.MemoryGB = "6.00"} | Shutdown-VM -Confirm:$false
Get-Folder -Name <your folder> | get-vm | Start-VM -Confirm:$false

Snapshot Management

This will create snapshots and remove any from a month ago.
TODO:Update to remove any older than a month. Also need email notification of failed attempts

#################################################
##For creating a snapshot every week, and
##removing snapshots older than a month.
#################################################
$newdate=date -Format MMddyyy
$olddate=date (date).addmonths(-1) -Format MMddyyy
$vsipass= echo 'password' | ConvertTo-SecureString -AsPlainText -force
$cred=New-Object System.Management.Automation.PSCredential -ArgumentList username,$vsipass
Connect-VIServer -server localhost -Credential $cred
##Create new snapshots
Get-VM | New-Snapshot -Name "vsi-$newdate" -RunAsync -whatif
##Delete old snapshots
$vsisnapshots=Get-VM | Get-Snapshot
if ($vsisnapshots.Name -like "vsi-$olddate"){$_.Name | remove-Snapshot -RunAsync -whatif}
Remove-Variable newdate
Remove-Variable olddate
exit 0
##Check logs
sleep -Seconds 3600
get-vmhost | Get-Log -Key vmkernel | select $_.Entries -ExpandProperty Entries | where {$_ -like '*Failed*snapshot*'}

Various Tasks

Modify VM hardware for Disconnected Desktops