├── AddDiskToVm.ps1 ├── CreateSnapshotTimingReport.ps1 ├── EvacuateVMsFromUSV.ps1 ├── Get-AdvancedSettingsNotDefault.ps1 ├── Get-Empty-LUNs.ps1 ├── Get-Orphaned-Files.ps1 ├── Get-Wrong-DisplayNames.ps1 ├── HASettings.ps1 ├── Move-VMsIntoResoucePoolsBasedOnTag.ps1 ├── README.md ├── Set-ResourcePoolGranular.ps1 ├── Set-VMTagFromNotes.ps1 ├── Set-Zerto-VPGLimit.ps1 ├── SetHAAdmissionControl.ps1 ├── Test-HostNetworkingWindowsVM.ps1 ├── Update_VMs.ps1 ├── VmAutomatedDeployment.ps1 ├── bkp_rst_vcsa.sh ├── get_percentage_cluster_usage.ps1 └── testHostNetworking.ps1 /AddDiskToVm.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Attach a new disk to a existing controller or create a new one 4 | .DESCRIPTION 5 | This function will add a disk of a given Size to either a new controller 6 | of a given type, attach it to a specific controller number or just choose 7 | the last available scsi controller already attached to the VM. 8 | .NOTES 9 | Author: Dario Dörflinger aka. virtualFrog 10 | .PARAMETER vCenter 11 | The vCenter to connect to 12 | .PARAMETER vMName 13 | The VM to which the disk (and controller) will be attached to 14 | .PARAMETER diskGB 15 | The size of the disk (in GB) to add 16 | .PARAMETER controllerNumber 17 | The number of the controller you want to add the disk to (SCSI Controller 0 = 1, SCSI Controller 1 = 2) 18 | .PARAMETER addController 19 | Boolean to determine wether or not to add a new controller 20 | .PARAMETER controllerType 21 | If addController is true, this will determine the type of controller 22 | .EXAMPLE 23 | PS> Add-DiskToVm.ps1 -vMName reg-belairi81 -vCenter vcenter.virtualfrog.ch -diskGB 10 24 | 25 | This will attach a 10 GB disk to the VM on the last of its scsi controllers 26 | .EXAMPLE 27 | PS> Add-DiskToVm.ps1 -vCenter vcenter.virtualfrog.ch -vMName reg-belairi81 -diskGB 10 -addController:$true -controllerType paravirtual 28 | 29 | This will attach a 10 GB disk to the VM and attach it to a new scsi controller of type paravirtual 30 | .EXAMPLE 31 | PS> Add-DiskToVm.ps1 -vCenter vcenter.virtualfrog.ch -vMName reg-belairi81 -diskGB 10 -controllerNumber 2 32 | 33 | This will attach a 10 GB disk to the VM and attach it to the second controller on the VM 34 | #> 35 | 36 | ################################################################################## 37 | # Script: Add-DiskToVm.ps1 38 | # Datum: 04.10.2017 39 | # Author: Dario Doerflinger aka. virtualFrog (c) 2017 40 | # Version: 1.0 41 | # History: Check VMs current set of SCSI Controllers when adding Disks 42 | ################################################################################## 43 | 44 | [CmdletBinding(SupportsShouldProcess=$true)] 45 | Param( 46 | [parameter()] 47 | [string]$vCenter = "virtualfrogvc.virtual.frog", 48 | # Change to default VM for testing 49 | [string]$vMName = "reg-belairi82", 50 | # Change default Disk Size 51 | [decimal]$diskGB = 2.5, 52 | # Hardcode the SCSI Controller # (like 3 for the third controller) 53 | [int]$controllerNumber = 2000, 54 | # Add new SCSI Controller while you're at it 55 | [boolean]$addController = $false, 56 | # Type of SCSI Controller to add (paravirtual|VirtualLsiLogicSAS) 57 | [string]$controllerType = "paravirtual" 58 | 59 | ) 60 | function get-scsiCount ($vm) 61 | { 62 | try { 63 | return ($vm | get-scsicontroller -ErrorAction Stop).count 64 | } 65 | catch { 66 | Write-Host "Could not count Scsi Controller of $vm" 67 | exit 68 | } 69 | } 70 | 71 | function get-scsiID ($vm, $number) 72 | { 73 | try { 74 | return ($vm |get-scsicontroller |select -skip ($number-1) -first 1).ID 75 | } 76 | catch { 77 | Write-Host "Could not get scsi controller number $number from $vm" 78 | exit 79 | } 80 | } 81 | 82 | function get-scsiType ($vm, $id) 83 | { 84 | try { 85 | return ($vm |get-scsicontroller -ID $id -ErrorAction Stop).Type 86 | } 87 | catch { 88 | Write-Host "Could not determine type of SCSI Controller on vm ($vm)" 89 | exit 90 | } 91 | } 92 | 93 | function add-DiskToVmOnController ($vm, $controller) 94 | { 95 | try { 96 | New-Harddisk -Controller $controller -CapacityGB $diskGB -VM $vm -Whatif -ErrorAction Stop 97 | } catch { 98 | Write-Host "Could not add disk to VM ($vm)" 99 | exit 100 | } 101 | } 102 | 103 | function shutDownVm ($vm) 104 | { 105 | try { 106 | Stop-VMGuest -VM $vm -confirm:$false -ErrorAction Stop 107 | Write-Host "Successfully send the shutdown command over VMware Tools" 108 | } 109 | catch { 110 | Write-Host -Foregroundcolor:red "The VM did not respond to a VMware tools shutdown command" 111 | $switch = Read-Host -Prompt "Would you like to Power off the VM $vm ? (yes/no)" 112 | if ($switch -match "yes") { 113 | Stop-VM -VM $vm -confirm:$false 114 | } else { 115 | Write-Host "You chose not to power off the VM. Stopping the script.." 116 | exit 117 | } 118 | } 119 | 120 | while ((get-vm $vMName).PowerState -notmatch "PoweredOff") 121 | { 122 | Write-Host "Waiting for $vm to shut down..." 123 | sleep -s 5 124 | } 125 | $vmHasShutDown = $true 126 | } 127 | 128 | 129 | 130 | ####### Main Program ###### 131 | try { 132 | Import-Module -Name VMware.VimAutomation.Core -ErrorAction Stop | Out-Null 133 | } catch { 134 | Write-Host "Could not add VMware PowerCLI Modules" 135 | exit 136 | } 137 | 138 | try { 139 | Connect-VIServer $vCenter -WarningAction SilentlyContinue -ErrorAction Stop | Out-Null 140 | } 141 | catch { 142 | Write-Host "Could not connect to vCenter $vCenter" 143 | exit 144 | } 145 | 146 | Write-Host "Connected to $vCenter. Starting script" 147 | 148 | try { 149 | $vm = Get-VM $vMName -ErrorAction Stop 150 | } catch { 151 | Write-Host "Could not find VM with Name $vMName in vCenter $vCenter" 152 | exit 153 | } 154 | if ($addController) { 155 | if ($vm.PowerState -match "PoweredOn") { 156 | Write-Host -Foregroundcolor:red "The VM is still powered On." 157 | $switch = Read-Host -Prompt "Would you like to shut down the VM ($vm)? (yes/no)" 158 | if ($switch -match "yes") { 159 | shutDownVm $vm 160 | 161 | } else { 162 | Write-Host "You chose not to shutdown the VM ($vm). Stopping the script now" 163 | exit 164 | } 165 | } 166 | try { 167 | $vm |New-Harddisk -CapacityGB $diskGB |new-scsicontroller -type $controllerType -ErrorAction Stop 168 | if ($vmHasShutDown) { 169 | $switch = Read-Host -Prompt "The VM was shut down for this operation. Power it back on? (yes/no)" 170 | if ($switch -match "yes") { 171 | Start-VM $vm -confirm:$false 172 | } 173 | } 174 | } catch { 175 | Write-Host "could not add scsi controller with new disk to $vm" 176 | exit 177 | } 178 | } elseif ($controllerNumber -ne 2000) { 179 | $numberOfControllers = get-scsiCount $vm 180 | if ($numberOfControllers -gt $controllerNumber) { 181 | Write-Host "You specified controller number $controllerNumber but the VM ($vm) only has $numberOfControllers controllers" 182 | exit 183 | } else { 184 | $scsiID = get-scsiID $vm $controllerNumber 185 | Write-Host "The VM ($vm) has $numberOfControllers SCSI Controller(s) attached. You chose to attach a new disk to the $controllerNumber. adapter" 186 | 187 | Write-Host "The VM ($vm) has a "(get-scsiType $vm $scsiID)" Controller for the number you provided" 188 | add-DiskToVmOnController $vm ($vm | get-scsicontroller -ID $scsiID) 189 | Write-Host "Added a disk of $diskGB GB to $vm on controller "($vm | get-scsicontroller -ID $scsiID).Name 190 | } 191 | } 192 | else { 193 | $numberOfControllers = get-scsiCount $vm 194 | $scsiID = get-scsiID $vm $numberOfControllers 195 | Write-Host "The VM ($vm) has $numberOfControllers SCSI Controller(s) attached" 196 | 197 | Write-Host "The VM ($vm) has a "(get-scsiType $vm $scsiID)" Controller as the last one" 198 | add-DiskToVmOnController $vm ($vm | get-scsicontroller -ID $scsiID) 199 | Write-Host "Added a disk of $diskGB GB to $vm on controller "($vm | get-scsicontroller -ID $scsiID).Name 200 | } 201 | -------------------------------------------------------------------------------- /CreateSnapshotTimingReport.ps1: -------------------------------------------------------------------------------- 1 | # import vmware related modules, get the credentials and connect to the vCenter server 2 | Import-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue | Out-Null 3 | #$creds = Get-VICredentialStoreItem -file "D:\Scripts\CreateSnapshotCreationOverview\login.creds" 4 | #Connect-VIServer -Server $creds.Host -User $creds.User -Password $creds.Password 5 | connect-viserver vCenter.virtualfrog.lab 6 | 7 | function Get-TaskPlus { 8 | 9 | <# 10 | .SYNOPSIS Returns vSphere Task information 11 | .DESCRIPTION The function will return vSphere task info. The 12 | available parameters allow server-side filtering of the 13 | results 14 | .NOTES Author: Luc Dekens 15 | .PARAMETER Alarm 16 | When specified the function returns tasks triggered by 17 | specified alarm 18 | .PARAMETER Entity 19 | When specified the function returns tasks for the 20 | specific vSphere entity 21 | .PARAMETER Recurse 22 | Is used with the Entity. The function returns tasks 23 | for the Entity and all it's children 24 | .PARAMETER State 25 | Specify the State of the tasks to be returned. Valid 26 | values are: error, queued, running and success 27 | .PARAMETER Start 28 | The start date of the tasks to retrieve 29 | .PARAMETER Finish 30 | The end date of the tasks to retrieve. 31 | .PARAMETER UserName 32 | Only return tasks that were started by a specific user 33 | .PARAMETER MaxSamples 34 | Specify the maximum number of tasks to return 35 | .PARAMETER Reverse 36 | When true, the tasks are returned newest to oldest. The 37 | default is oldest to newest 38 | .PARAMETER Server 39 | The vCenter instance(s) for which the tasks should 40 | be returned 41 | .PARAMETER Realtime 42 | A switch, when true the most recent tasks are also returned. 43 | .PARAMETER Details 44 | A switch, when true more task details are returned 45 | .PARAMETER Keys 46 | A switch, when true all the keys are returned 47 | .EXAMPLE 48 | PS> Get-TaskPlus -Start (Get-Date).AddDays(-1) 49 | .EXAMPLE 50 | PS> Get-TaskPlus -Alarm $alarm -Details 51 | #> 52 | 53 | param( 54 | [CmdletBinding()] 55 | [VMware.VimAutomation.ViCore.Impl.V1.Alarm.AlarmDefinitionImpl]$Alarm, 56 | [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]$Entity, 57 | [switch]$Recurse = $false, 58 | [VMware.Vim.TaskInfoState[]]$State, 59 | [DateTime]$Start, 60 | [DateTime]$Finish, 61 | [string]$UserName, 62 | [int]$MaxSamples = 100, 63 | [switch]$Reverse = $true, 64 | [VMware.VimAutomation.ViCore.Impl.V1.VIServerImpl[]]$Server = $global:DefaultVIServer, 65 | [switch]$Realtime, 66 | [switch]$Details, 67 | [switch]$Keys, 68 | [int]$WindowSize = 100 69 | ) 70 | 71 | begin { 72 | function Get-TaskDetails { 73 | param( 74 | [VMware.Vim.TaskInfo[]]$Tasks 75 | ) 76 | begin{ 77 | $psV3 = $PSversionTable.PSVersion.Major -ge 3 78 | } 79 | 80 | process{ 81 | $tasks | %{ 82 | if($psV3){ 83 | $object = [ordered]@{} 84 | } 85 | else { 86 | $object = @{} 87 | } 88 | $object.Add("Name",$_.Name) 89 | $object.Add("Description",$_.Description.Message) 90 | if($Details){$object.Add("DescriptionId",$_.DescriptionId)} 91 | if($Details){$object.Add("Task Created",$_.QueueTime.tolocaltime())} 92 | $object.Add("Task Started",$_.StartTime.tolocaltime()) 93 | if($Details){$object.Add("Task Ended",$_.CompleteTime.tolocaltime())} 94 | $object.Add("State",$_.State) 95 | $object.Add("Result",$_.Result) 96 | $object.Add("Entity",$_.EntityName) 97 | $object.Add("VIServer",$VIObject.Name) 98 | $object.Add("Error",$_.Error.ocalizedMessage) 99 | if($Details){ 100 | $object.Add("Cancelled",(&{if($_.Cancelled){"Y"}else{"N"}})) 101 | $object.Add("Reason",$_.Reason.GetType().Name.Replace("TaskReason","")) 102 | $object.Add("AlarmName",$_.Reason.AlarmName) 103 | $object.Add("AlarmEntity",$_.Reason.EntityName) 104 | $object.Add("ScheduleName",$_.Reason.Name) 105 | $object.Add("User",$_.Reason.UserName) 106 | } 107 | if($keys){ 108 | $object.Add("Key",$_.Key) 109 | $object.Add("ParentKey",$_.ParentTaskKey) 110 | $object.Add("RootKey",$_.RootTaskKey) 111 | } 112 | 113 | New-Object PSObject -Property $object 114 | } 115 | } 116 | } 117 | 118 | $filter = New-Object VMware.Vim.TaskFilterSpec 119 | if($Alarm){ 120 | $filter.Alarm = $Alarm.ExtensionData.MoRef 121 | } 122 | if($Entity){ 123 | $filter.Entity = New-Object VMware.Vim.TaskFilterSpecByEntity 124 | $filter.Entity.entity = $Entity.ExtensionData.MoRef 125 | if($Recurse){ 126 | $filter.Entity.Recursion = [VMware.Vim.TaskFilterSpecRecursionOption]::all 127 | } 128 | else{ 129 | $filter.Entity.Recursion = [VMware.Vim.TaskFilterSpecRecursionOption]::self 130 | } 131 | } 132 | if($State){ 133 | $filter.State = $State 134 | } 135 | if($Start -or $Finish){ 136 | $filter.Time = New-Object VMware.Vim.TaskFilterSpecByTime 137 | $filter.Time.beginTime = $Start 138 | $filter.Time.endTime = $Finish 139 | $filter.Time.timeType = [vmware.vim.taskfilterspectimeoption]::startedTime 140 | } 141 | if($UserName){ 142 | $userNameFilterSpec = New-Object VMware.Vim.TaskFilterSpecByUserName 143 | $userNameFilterSpec.UserList = $UserName 144 | $filter.UserName = $userNameFilterSpec 145 | } 146 | $nrTasks = 0 147 | } 148 | 149 | process { 150 | foreach($viObject in $Server){ 151 | $si = Get-View ServiceInstance -Server $viObject 152 | $tskMgr = Get-View $si.Content.TaskManager -Server $viObject 153 | 154 | if($Realtime -and $tskMgr.recentTask){ 155 | $tasks = Get-View $tskMgr.recentTask 156 | $selectNr = [Math]::Min($tasks.Count,$MaxSamples-$nrTasks) 157 | Get-TaskDetails -Tasks[0..($selectNr-1)] 158 | $nrTasks += $selectNr 159 | } 160 | 161 | try { 162 | $tCollector = Get-View ($tskMgr.CreateCollectorForTasks($filter)) 163 | 164 | if($Reverse){ 165 | $tCollector.ResetCollector() 166 | $taskReadOp = $tCollector.ReadPreviousTasks 167 | } 168 | else{ 169 | $taskReadOp = $tCollector.ReadNextTasks 170 | } 171 | do{ 172 | $tasks = $taskReadOp.Invoke($WindowSize) 173 | if(!$tasks){return} 174 | $selectNr = [Math]::Min($tasks.Count,$MaxSamples-$nrTasks) 175 | Get-TaskDetails -Tasks $tasks[0..($selectNr-1)] 176 | $nrTasks += $selectNr 177 | }while($nrTasks -lt $MaxSamples) 178 | } 179 | catch { 180 | Write-Host "A error occured in the collector" 181 | } 182 | } 183 | try { 184 | $tCollector.DestroyCollector() 185 | } 186 | catch { 187 | Write-Host "The error not letting us destroy the collector" 188 | } 189 | } 190 | } 191 | $start = (Get-Date).AddDays(-30) 192 | $finish = (Get-Date) 193 | $output = Get-TaskPlus -Details -MaxSamples 20000000 -Start $start -Finish $finish | ? {$_.Name -match "CreateSnapshot_Task" -or $_.Name -match "RemoveSnapshot_Task"} |select Entity, "Task Created", "Task Started", "Task Ended", User, State, Name, @{Name="Duration in Seconds"; Expression = {(New-TimeSpan -start $_."Task Started" -End $_."Task Ended").TotalSeconds}} 194 | # create a CSV file with all snapshot related results 195 | $output | Export-Csv -Path "c:\temp\snapshot_create_and_remove_times_last_month.csv" -NoTypeInformation 196 | 197 | # cleanup and removal of loaded VMware modules 198 | #Disconnect-VIServer -Server $creds.Host -Confirm:$false 199 | disconnect-viserver vCenter.virtualfrog.lab -confirm:$false 200 | Remove-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue | Out-Null 201 | -------------------------------------------------------------------------------- /EvacuateVMsFromUSV.ps1: -------------------------------------------------------------------------------- 1 | ############################################################################################ 2 | # Script name: EvacuateVMsFromUSV.ps1 3 | # Description: Evacuate all VMs from one site in a active-active cluster and shut down the Hosts 4 | # Version: 1.0 5 | # Date: 20.07.2017 6 | # Author: Dario Doerflinger (https://soultec.ch/blog) 7 | # History: 20.07.2017 - First tested release 8 | ############################################################################################ 9 | 10 | # Example: # e.g.: .\EvacuateVMsFromUSV.ps1 -SiteToShutdown Allschwil 11 | 12 | param ( 13 | [string]$SiteToShutdown # Identifier of site 14 | ) 15 | $vCenter_server = "randomName.randomdomain.com" 16 | # clear global ERROR variable 17 | $Error.Clear() 18 | 19 | # import vmware related modules, get the credentials and connect to the vCenter server 20 | Import-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue | Out-Null 21 | Import-Module -Name VMware.VimAutomation.Vds -ErrorAction SilentlyContinue |Out-Null 22 | $creds = Get-VICredentialStoreItem -file "C:\Users\Administrator\Desktop\login.creds" 23 | Connect-VIServer -Server $vCenter_server -User $creds.User -Password $creds.Password |Out-Null 24 | 25 | # define global variables 26 | 27 | $current_date = $(Get-Date -format "dd.MM.yyyy HH:mm:ss") 28 | $log_file = "C:\Users\Administrator\Desktop\\log_$(Get-Date -format "yyyyMMdd").txt" 29 | 30 | 31 | Function SetDRStoAutomatic ($cluster) 32 | { 33 | try { 34 | $cluster | Set-Cluster -DrsEnabled:$true -DrsAutomationLevel FullyAutomated -Confirm:$false |Out-Null 35 | } catch { 36 | Write-Host -Foregroundcolor:red "Could not set DRS Mode to automatic" 37 | } 38 | } 39 | 40 | Function RemoveRemovableMediaFromVMs($esxhost) 41 | { 42 | try { 43 | $esxhost | Get-VM | Where-Object {$_.PowerState –eq “PoweredOn”} | Get-CDDrive | Set-CDDrive -NoMedia -Confirm:$False |Out-Null 44 | 45 | } catch { 46 | Write-Host -Foregroundcolor:red "Could not get the vm objects from host." 47 | } 48 | } 49 | 50 | Function EvacuateVMsFromHost($esxhost) 51 | { 52 | try { 53 | $esxhost | Set-VMHost -State Maintenance -Evacuate:$true -Confirm:$false |Out-Null 54 | } catch { 55 | Write-Host -Foregroundcolor:red "Could not put host into maintenance mode" 56 | } 57 | } 58 | 59 | Function ShutDownHost($esxhost) 60 | { 61 | try { 62 | $esxhost | Stop-VMhost -Confirm:$false -Whatif 63 | } catch { 64 | Write-Host -Foregroundcolor:red "Could not shut down host" 65 | } 66 | } 67 | 68 | 69 | ###### Main Program ###### 70 | if ($SiteToShutdown -eq "Allschwil") { 71 | $hosts = @("bezhesx40.bechtlezh.ch") 72 | 73 | } elseif ($SiteToShutdown -eq "Pratteln") 74 | { 75 | $hosts = @("bezhesx41.bechtlezh.ch") 76 | } 77 | 78 | foreach ($esxhost in $hosts) 79 | { 80 | $cluster = (get-vmhost $esxhost).Parent 81 | SetDRStoAutomatic($cluster) 82 | 83 | $esxihost = Get-VMhost $esxhost 84 | RemoveRemovableMediaFromVMs($esxihost) 85 | EvacuateVMsFromHost($esxihost) 86 | ShutDownHost($esxihost) 87 | } 88 | 89 | 90 | # cleanup and removal of loaded VMware modules 91 | Disconnect-VIServer -Server $vCenter_server -Confirm:$false |Out-Null 92 | Remove-Module -Name VMware.VimAutomation.Vds -ErrorAction SilentlyContinue | Out-Null 93 | Remove-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue | Out-Null 94 | 95 | 96 | # write all error messages to the log file 97 | Add-Content -Path $log_file -Value $Error 98 | -------------------------------------------------------------------------------- /Get-AdvancedSettingsNotDefault.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will output all Advanced Settings from a esxi host that differ from the default 4 | .DESCRIPTION 5 | The script will get all advanced settings that are not at default value from a given esxi host 6 | .NOTES 7 | Author : Dario Dörflinger - virtualfrog.wordpress.com 8 | .LINK 9 | http://virtualfrog.wordpress.com 10 | .PARAMETER hostName 11 | Name of the host used for source compare (optional) 12 | .PARAMETER delta 13 | Switch to decide if only values that differ from the default value should get processes 14 | .EXAMPLE 15 | C:\foo> .\Get-AdvancedSettingsNotDefault.ps1 -hostName esx01.virtualfrog.lab -delta:$true 16 | 17 | Description 18 | ----------- 19 | Gets All settings that are not at default value from given host 20 | .EXAMPLE 21 | C:\foo> .\Get-AdvancedSettingsNotDefault.ps1 -delta:$true 22 | 23 | Description 24 | ----------- 25 | Gets All settings from all hosts that are not at default value 26 | .EXAMPLE 27 | C:\foo> .\Get-AdvancedSettingsNotDefault.ps1 -delta:$false 28 | 29 | Description 30 | ----------- 31 | Gets All settings from all hosts 32 | #> 33 | 34 | param ( 35 | [Parameter(Mandatory=$False)] 36 | [string]$hostName="none", 37 | [Parameter(Mandatory=$False)] 38 | [boolean]$delta=$false 39 | ) 40 | 41 | $excludedSettings = "/Migrate/Vmknic|/UserVars/ProductLockerLocation|/UserVars/SuppressShellWarning" 42 | $AdvancedSettings = @() 43 | $AdvancedSettingsFiltered = @() 44 | 45 | # Checking if host exists 46 | if ($hostName -ne "none") { 47 | try { 48 | $vmhost = Get-VMHost $hostName -ErrorAction Stop 49 | } catch { 50 | Write-Host -ForegroundColor Red "There is no host available with name" $hostName 51 | exit 52 | } 53 | 54 | # Retrieving advanced settings 55 | $esxcli = $vmhost | get-esxcli -V2 56 | $AdvancedSettings = $esxcli.system.settings.advanced.list.Invoke(@{delta = $delta}) |select @{Name="Hostname"; Expression = {$vmhost}},Path,DefaultIntValue,IntValue,DefaultStringValue,StringValue,Description 57 | 58 | # Displaying results 59 | #$AdvancedSettings 60 | 61 | } else { 62 | $vmhosts = get-vmhost 63 | foreach ($vmhost in $vmhosts) { 64 | $esxcli = $vmhost | get-esxcli -V2 65 | $AdvancedSettings += $esxcli.system.settings.advanced.list.Invoke(@{delta = $delta}) |select @{Name="Hostname"; Expression = {$vmhost}},Path,DefaultIntValue,IntValue,DefaultStringValue,StringValue,Description 66 | } 67 | #$AdvancedSettings 68 | } 69 | 70 | # Browsing advanced settings and check for mismatch 71 | ForEach ($advancedSetting in $AdvancedSettings.GetEnumerator()) { 72 | if ( ($AdvancedSetting.Path -notmatch $excludedSettings) -And (($AdvancedSetting.IntValue -ne $AdvancedSetting.DefaultIntValue) -Or ($AdvancedSetting.StringValue -notmatch $AdvancedSetting.DefaultStringValue) ) ){ 73 | $line = "" | Select Hostname,Path,DefaultIntValue,IntValue,DefaultStringValue,StringValue,Description 74 | $line.Hostname = $advancedSetting.Hostname 75 | $line.Path = $advancedSetting.Path 76 | $line.DefaultIntValue = $advancedSetting.DefaultIntValue 77 | $line.IntValue = $advancedSetting.IntValue 78 | $line.DefaultStringValue = $advancedSetting.DefaultStringValue 79 | $line.StringValue = $advancedSetting.StringValue 80 | $line.Description = $advancedSetting.Description 81 | $AdvancedSettingsFiltered += $line 82 | } 83 | } 84 | $AdvancedSettingsFiltered -------------------------------------------------------------------------------- /Get-Empty-LUNs.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################## 2 | # Script: Get-Empty-LUNs.ps1 3 | # Datum: 07.10.2016 4 | # Author: Dario Doerflinger (c) 2016 5 | # Version: 1.0 6 | # History: Initial Script 7 | ################################################################################## 8 | 9 | # vCenter Credentials koennen mit folgendem Command vorgaengig einmalig konfiguriert und hinterlegt werden 10 | # New-VICredentialStoreItem $vCenter 11 | # Default Parameter in erster "Param" Sektion anpassen, ansonnsten werden die hinterlegten Default Werte verwendet 12 | 13 | 14 | [CmdletBinding(SupportsShouldProcess=$true)] 15 | Param( 16 | [parameter()] 17 | [Array]$vCenter = @("vcenter1","vcenter2"), 18 | # Change to a SMTP server in your environment 19 | [string]$SmtpHost = "mail.virtualfrog.ch", 20 | # Change to default email address you want emails to be coming from 21 | [string]$From = "admin@virtualfrog.ch", 22 | # Change to default email address you would like to receive emails 23 | [Array]$To = @("email1@mail.com","email2@mail.com","email3@mail.com"), 24 | # Change to default Report Filename you like 25 | [string]$Attachment = "$env:temp\Empty-LUN-Report-"+(Get-Date �f "yyyy-MM-dd")+".csv" 26 | ) 27 | 28 | 29 | 30 | Add-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue | out-null 31 | "C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\Scripts\Initialize-PowerCliEnvironment.ps1" 32 | Connect-VIServer $vCenter -WarningAction SilentlyContinue | Out-Null 33 | Write-Host "Connected to $vCenter. Starting script" 34 | #foreach ( $cluster in Get-Cluster) {Get-Datastore -RelatedObject $cluster |? {($_ |Get-VM).Count -eq 0 -and $_ -notlike "*rest*" -and $_ -notlike "*_local" -and $_ -notlike "*snapshot*" -and $_ -notlike "*placeholder*"}|select Name, FreeSpaceGB, CapacityGB, @{N="NumVM";E={@($_ |Get-VM).Count}}, @{N="LUN";E={($_.ExtensionData.Info.Vmfs.Extent[0]).DiskName}}, @{N="Cluster";E={@($cluster.Name)}} |Sort Name | Export-CSV $Attachment -Append -NoTypeInformation} 35 | 36 | $bodyh = (Get-Date �f "yyyy-MM-dd HH:mm:ss") + " - the following Datastores were found to be empty. `n" 37 | $body = foreach ( $cluster in Get-Cluster) {Get-Datastore -RelatedObject $cluster |Where-Object {($_ |Get-VM).Count -eq 0 -and $_ -notlike "*rest*" -and $_ -notlike "*_local" -and $_ -notlike "*snapshot*" -and $_ -notlike "*placeholder*"}|select Name, FreeSpaceGB, CapacityGB, @{N="NumVM";E={@($_ |Get-VM).Count}}, @{N="LUN";E={($_.ExtensionData.Info.Vmfs.Extent[0]).DiskName}}, @{N="Cluster";E={@($cluster.Name)}} |Sort Name } 38 | $body | Export-Csv "$Attachment" -NoTypeInformation -UseCulture 39 | $body = $bodyh + ($body | Out-String) 40 | $subject = "Report - Emtpy Datastores" 41 | send-mailmessage -from "$from" -to $to -subject "$subject" -body "$body" -Attachment "$Attachment" -smtpServer $SmtpHost 42 | Disconnect-VIServer -Server $vCenter -Force:$true -Confirm:$false 43 | -------------------------------------------------------------------------------- /Get-Orphaned-Files.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################## 2 | # Script: Get-Orphaned-Files.ps1 3 | # Datum: 12.07.2018 4 | # Author: Dario Doerflinger (c) 2013 - 2018 5 | # Version: 2.1 6 | # History: Added Comments 7 | # Replaced Add-PSSnapin with Module Command 8 | # Replaced Get-VmwOrphan Function 9 | ################################################################################## 10 | 11 | [CmdletBinding(SupportsShouldProcess=$true)] 12 | Param( 13 | [parameter()] 14 | [String]$vCenter = "virtualfrogvc.virtual.frog", 15 | # Change to a SMTP server in your environment 16 | [string]$SmtpHost = "mail.virtual.frog", 17 | # Change to default email address you want emails to be coming from 18 | [string]$From = "virtualFrog@virtual.frog", 19 | # Change to default email address you would like to receive emails 20 | [Array]$To = @("email@email.com","email2@email.com"), 21 | # Change to default Report Filename you like 22 | [string]$Attachment = "$env:temp\OrphanedFileReport-"+(Get-Date �f "yyyy-MM-dd")+".csv" 23 | ) 24 | 25 | function Get-VmwOrphan{ 26 | <# 27 | .SYNOPSIS 28 | Find orphaned files on a datastore 29 | .DESCRIPTION 30 | This function will scan the complete content of a datastore. 31 | It will then verify all registered VMs and Templates on that 32 | datastore, and compare those files with the datastore list. 33 | Files that are not present in a VM or Template are considered 34 | orphaned 35 | .NOTES 36 | Author: Luc Dekens 37 | .PARAMETER Datastore 38 | The datastore that needs to be scanned 39 | .EXAMPLE 40 | PS> Get-VmwOrphaned -Datastore DS1 41 | .EXAMPLE 42 | PS> Get-Datastore -Name DS* | Get-VmwOrphaned 43 | #> 44 | 45 | [CmdletBinding()] 46 | param( 47 | [parameter(Mandatory=$true,ValueFromPipeline=$true)] 48 | [PSObject[]]$Datastore 49 | ) 50 | 51 | Begin{ 52 | $flags = New-Object VMware.Vim.FileQueryFlags 53 | $flags.FileOwner = $true 54 | $flags.FileSize = $true 55 | $flags.FileType = $true 56 | $flags.Modification = $true 57 | 58 | $qFloppy = New-Object VMware.Vim.FloppyImageFileQuery 59 | $qFolder = New-Object VMware.Vim.FolderFileQuery 60 | $qISO = New-Object VMware.Vim.IsoImageFileQuery 61 | $qConfig = New-Object VMware.Vim.VmConfigFileQuery 62 | $qConfig.Details = New-Object VMware.Vim.VmConfigFileQueryFlags 63 | $qConfig.Details.ConfigVersion = $true 64 | $qTemplate = New-Object VMware.Vim.TemplateConfigFileQuery 65 | $qTemplate.Details = New-Object VMware.Vim.VmConfigFileQueryFlags 66 | $qTemplate.Details.ConfigVersion = $true 67 | $qDisk = New-Object VMware.Vim.VmDiskFileQuery 68 | $qDisk.Details = New-Object VMware.Vim.VmDiskFileQueryFlags 69 | $qDisk.Details.CapacityKB = $true 70 | $qDisk.Details.DiskExtents = $true 71 | $qDisk.Details.DiskType = $true 72 | $qDisk.Details.HardwareVersion = $true 73 | $qDisk.Details.Thin = $true 74 | $qLog = New-Object VMware.Vim.VmLogFileQuery 75 | $qRAM = New-Object VMware.Vim.VmNvramFileQuery 76 | $qSnap = New-Object VMware.Vim.VmSnapshotFileQuery 77 | 78 | $searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec 79 | $searchSpec.details = $flags 80 | $searchSpec.Query = $qFloppy,$qFolder,$qISO,$qConfig,$qTemplate,$qDisk,$qLog,$qRAM,$qSnap 81 | $searchSpec.sortFoldersFirst = $true 82 | } 83 | 84 | Process{ 85 | foreach($ds in $Datastore){ 86 | if($ds.GetType().Name -eq "String"){ 87 | $ds = Get-Datastore -Name $ds 88 | Write-Host "Checking Datastore $ds" 89 | } 90 | 91 | # Only shared VMFS datastore 92 | if($ds.Type -eq "VMFS" -and $ds.ExtensionData.Summary.MultipleHostAccess){ 93 | Write-Verbose -Message "$(Get-Date)`t$((Get-PSCallStack)[0].Command)`tLooking at $($ds.Name)" 94 | 95 | # Define file DB 96 | $fileTab = @{} 97 | 98 | # Get datastore files 99 | $dsBrowser = Get-View -Id $ds.ExtensionData.browser 100 | $rootPath = "[" + $ds.Name + "]" 101 | $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec) | Sort-Object -Property {$_.FolderPath.Length} 102 | foreach($folder in $searchResult){ 103 | foreach ($file in $folder.File){ 104 | $key = "$($folder.FolderPath)$(if($folder.FolderPath[-1] -eq ']'){' '})$($file.Path)" 105 | $fileTab.Add($key,$file) 106 | 107 | $folderKey = "$($folder.FolderPath.TrimEnd('/'))" 108 | if($fileTab.ContainsKey($folderKey)){ 109 | $fileTab.Remove($folderKey) 110 | } 111 | } 112 | } 113 | 114 | # Get VM inventory 115 | Get-VM -Datastore $ds | %{ 116 | $_.ExtensionData.LayoutEx.File | %{ 117 | if($fileTab.ContainsKey($_.Name)){ 118 | $fileTab.Remove($_.Name) 119 | } 120 | } 121 | } 122 | 123 | # Get Template inventory 124 | Get-Template | where {$_.DatastoreIdList -contains $ds.Id} | %{ 125 | $_.ExtensionData.LayoutEx.File | %{ 126 | if($fileTab.ContainsKey($_.Name)){ 127 | $fileTab.Remove($_.Name) 128 | } 129 | } 130 | } 131 | 132 | # Remove system files & folders from list 133 | $systemFiles = $fileTab.Keys | where{$_ -match "] \.|vmkdump"} 134 | $systemFiles | %{ 135 | $fileTab.Remove($_) 136 | } 137 | 138 | # Organise remaining files 139 | if($fileTab.Count){ 140 | $fileTab.GetEnumerator() | %{ 141 | $obj = [ordered]@{ 142 | Name = $_.Value.Path 143 | Folder = $_.Name 144 | Size = $_.Value.FileSize 145 | CapacityKB = $_.Value.CapacityKb 146 | Modification = $_.Value.Modification 147 | Owner = $_.Value.Owner 148 | Thin = $_.Value.Thin 149 | Extents = $_.Value.DiskExtents -join ',' 150 | DiskType = $_.Value.DiskType 151 | HWVersion = $_.Value.HardwareVersion 152 | } 153 | New-Object PSObject -Property $obj 154 | } 155 | Write-Verbose -Message "$(Get-Date)`t$((Get-PSCallStack)[0].Command)`tFound orphaned files on $($ds.Name)!" 156 | } 157 | else{ 158 | Write-Verbose -Message "$(Get-Date)`t$((Get-PSCallStack)[0].Command)`tNo orphaned files found on $($ds.Name)." 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | 166 | Import-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue | Out-Null 167 | Connect-VIServer $vCenter -WarningAction SilentlyContinue | Out-Null 168 | Write-Host "Connected to $vCenter. Starting script" 169 | 170 | 171 | $bodyh = (Get-Date �f "yyyy-MM-dd HH:mm:ss") + " - the following orphaned files were found on Datastores. `n" 172 | $body = Get-Datastore | Get-VmwOrphan 173 | $body | Export-Csv "$Attachment" -NoTypeInformation -UseCulture 174 | $body = $bodyh + ($body | Out-String) 175 | $subject = "Report - orphaned Files on Datastores for $vCenter" 176 | send-mailmessage -from "$from" -to $to -subject "$subject" -body "$body" -Attachment "$Attachment" -smtpServer $SmtpHost 177 | Disconnect-VIServer -Server $vCenter -Force:$true -Confirm:$false -------------------------------------------------------------------------------- /Get-Wrong-DisplayNames.ps1: -------------------------------------------------------------------------------- 1 | $OutArray = @() 2 | 3 | $vms = Get-VM 4 | foreach ($vm in $vms) 5 | { 6 | $myobj = "" | Select "VM", "DNSname", "Status" 7 | $guest = Get-VMGuest -VM $vm 8 | $pat = "." 9 | $vmname = $guest.VmName 10 | $hostname = $guest.HostName 11 | $myobj.VM = $vmname 12 | $myobj.DNSname = $hostname 13 | if ( $hostname -ne $null) 14 | { 15 | $pos = $hostname.IndexOf(".") 16 | if ( $pos -ne "-1") 17 | { 18 | $hostname = $hostname.Substring(0, $pos) 19 | } 20 | if ( $hostname -ne $vmname ) 21 | { 22 | Write-Host -ForegroundColor Red "---> The VM: $vm has different DNS and Display-Name!" 23 | Write-Host -ForegroundColor Red "---->Hostname: " $hostname 24 | Write-Host -ForegroundColor Red "---->VmName: "$vmname 25 | $myobj.Status = "Not OK!" 26 | } 27 | Else 28 | { 29 | Write-Host -ForegroundColor Green "---> The VM: $vm has identical Names." 30 | $myobj.Status = "OK!" 31 | } 32 | } 33 | Else 34 | { 35 | Write-Host -ForegroundColor Yellow "---> The VM: $vm is not powered-on. Hostname cannot be found in this state!" 36 | $myobj.Status = "N/A" 37 | } 38 | Clear-variable -Name hostname 39 | Clear-variable -Name vmname 40 | $OutArray += $myobj 41 | } 42 | $OutArray | Export-Csv "c:\tmp\name_vs_dns_$vcenter.csv" -------------------------------------------------------------------------------- /HASettings.ps1: -------------------------------------------------------------------------------- 1 | # Parameters 2 | $VMServer = ‘vCenterFQDN’ 3 | $OutFile = ‘C:\Path\To\File.csv’ 4 | 5 | # Connect to vCenter and get HA settings for every cluster 6 | Connect-VIServer -Server $VMServer -ErrorAction Stop | Out-Null 7 | Get-Cluster | Select-Object Name, HAAdmissionControlEnabled, 8 | @{N = 'Host failures cluster tolerates'; E = {$_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.FailOverLevel}}, 9 | @{N = 'Define host failover capacity by'; E = { 10 | switch ($_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.GetTYpe().Name) { 11 | 'ClusterFailoverHostAdmissionControlPolicy' {'Dedicated Failover Hosts (H)'} 12 | 'ClusterFailoverResourcesAdmissionControlPolicy' {'Cluster Resource Percentage (R)'} 13 | 'ClusterFailoverLevelAdmissionControlPolicy' {'Slot Policy (s)'} 14 | }} 15 | }, 16 | @{N = '(H) Failover Hosts '; E = {(Get-View -Id $_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.FailOverHosts -Property Name).Name -join '|'}}, 17 | @{N = '(R) Override calculated failover capacity'; E = { 18 | if ($_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.AutoComputePercentages) {'True'} 19 | else {'False (R-O)'}} 20 | }, 21 | @{N = '(R-O) CPU %'; E = {$_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.CpuFailoverResourcesPercent}}, 22 | @{N = '(R-O) Memory %'; E = {$_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.MemoryFailoverResourcesPercent}}, 23 | @{N = '(S) Slot Policy '; E = { 24 | if ($_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.SlotPolicy) {'Fixed Slot Size (S-F)'} 25 | else {'Cover all powered-on VM'} 26 | } 27 | }, 28 | @{N = '(S-F) CPU MhZ'; E = {$_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.SlotPolicy.Cpu}}, 29 | @{N = '(S-F) Memory MB'; E = {$_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.SlotPolicy.Memory}}, 30 | @{N = 'HA Admission Policy ResourceReductionToToleratePercent'; E = {$_.ExtensionData.Configuration.DasConfig.AdmissionControlPolicy.ResourceReductionToToleratePercent}}, 31 | @{N = 'Hearthbeat Datastore Policy'; E = { 32 | switch ($_.ExtensionData.Configuration.DasConfig.HBDatastoreCandidatePolicy) { 33 | 'allFeasibleDs' {'Automatically select datastores accessible from the host'} 34 | 'allFeasibleDsWithUserPreference' {'Use datastores from the specified list and complement automatically (L)'} 35 | 'userSelectedDs' {'Use datastores only from the specified list (L)'} 36 | } 37 | } 38 | }, 39 | @{N = '(L) Hearthbeat Datastore'; E = {(Get-View -Id $_.ExtensionData.Configuration.DasConfig.HeartbeatDatastore -property Name).Name -join '|'}}, 40 | @{N = 'Host Monitoring'; E = {$_.ExtensionData.Configuration.DasConfig.HostMonitoring}}, 41 | @{N = 'Host Failure Response'; E = { 42 | if ($_.ExtensionData.Configuration.DasConfig.DefaultVmSettings.RestartPriority -eq 'disabled') {'Disabled'} 43 | else {'Restart VMs'}} 44 | }, 45 | @{N = 'Host Isolation Response'; E = {$_.ExtensionData.Configuration.DasConfig.DefaultVmSettings.IsolationResponse}}, 46 | @{N = 'Datastore with PDL'; E = {$_.ExtensionData.Configuration.DasConfig.DefaultVmSettings.VmComponentProtectionSettings.VmStorageProtectionForPDL}}, 47 | @{N = 'Datastore with APD'; E = {$_.ExtensionData.Configuration.DasConfig.DefaultVmSettings.VmComponentProtectionSettings.VmStorageProtectionForAPD}}, 48 | @{N = 'VM Monitoring'; E = {$_.ExtensionData.Configuration.DasConfig.VmMonitoring}} | Export-Csv -NoTypeInformation -Path $OutFile 49 | Disconnect-VIServer -Server $VMServer -Confirm:$false -ErrorAction Stop | Out-Null 50 | -------------------------------------------------------------------------------- /Move-VMsIntoResoucePoolsBasedOnTag.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will help you automate the placement/movement of VMs in resource pools based on a tag. 4 | .DESCRIPTION 5 | By reading out the assigned resource pool tags the VMs are placed into resource pools with the same name 6 | .NOTES 7 | Version: 1.0 8 | Author: Dario Doerflinger (@virtual_frog) 9 | Creation Date: 04.04.2019 10 | Purpose/Change: Initial script development 11 | 12 | The original implementation uses the tag category "ResourcePool". The tags in this category can only be applied to Virtual Machine objects and must be unique (One tag per object). If you need to use another Tag feel free to change the category variable 13 | To use this script automatically please use the following code to produce a file with the password: 14 | New-VICredentialStoreItem -User $user_name -Password $user_password_decrypted -Host "Somethingsomething" -File "$file_location\login.creds" 15 | .LINK 16 | https://virtualfrog.wordpress.com 17 | .PARAMETER vCenter 18 | The vCenter to connect to 19 | .PARAMETER DefaultTag 20 | Parameter to tag VMs that have no tags assigned 21 | Default: $null 22 | .INPUTS 23 | None 24 | .OUTPUTS 25 | The script log file stored in /Move-VMsIntoResoucePoolsBasedOnTag.log 26 | .EXAMPLE 27 | ./Move-VMsIntoResoucePoolsBasedOnTag.ps1 -vCenter yourvcenter.yourdomain.com 28 | Will iterate through each cluster and move VMs into resource pools 29 | .EXAMPLE 30 | ./Move-VMsIntoResoucePoolsBasedOnTag.ps1 -vCenter yourvcenter.yourdomain.com -DefaultTag "2_Normal" 31 | Will first check if there are VMs without assigned Tags from the "ResourcePool" Category and assign the "2_Normal" Tag (will be created if it does not exist) 32 | Will iterate through each cluster and move VMs into resource pools 33 | 34 | #> 35 | 36 | #---------------------------------------------------------[Script Parameters]------------------------------------------------------ 37 | 38 | Param ( 39 | #Script parameters 40 | [Parameter(Mandatory = $true)][string]$vCenter, 41 | [Parameter(Mandatory = $false)][string]$defaultTag = $null 42 | ) 43 | 44 | #---------------------------------------------------------[Initialisations]-------------------------------------------------------- 45 | 46 | #Set Error Action to Stop 47 | $ErrorActionPreference = 'Stop' 48 | 49 | #Import Module for Logging 50 | Import-Module PSLogging 51 | 52 | #----------------------------------------------------------[Declarations]---------------------------------------------------------- 53 | 54 | #Script Version 55 | $sScriptVersion = '1.0' 56 | 57 | #Log File Info 58 | $sLogPath = $PSScriptRoot 59 | $sLogName = "Move-VMsIntoResoucePoolsBasedOnTag.log" 60 | $sLogFile = Join-Path -Path $sLogPath -ChildPath $sLogName 61 | 62 | #Default Tag Category name 63 | $defaultTagCategoryName = "ResourcePool" 64 | 65 | #-----------------------------------------------------------[Functions]------------------------------------------------------------ 66 | Function Connect-VMwareServer { 67 | Param ([Parameter(Mandatory = $true)][string]$VMServer) 68 | 69 | Begin { 70 | Write-LogInfo -LogPath $sLogFile -Message "Connecting to vCenter Server [$VMServer]..." 71 | } 72 | 73 | Process { 74 | Try { 75 | $oCred = Get-Credential -Message 'Enter credentials to connect to vCenter Server' 76 | Connect-VIServer -Server $VMServer -Credential $oCred -ErrorAction Stop | Out-Null 77 | 78 | #Use the below to automate the login with a VI Credential File 79 | #$oCred = Get-VICredentialStoreItem -File "c:\Set-Resourcepool\login.creds" 80 | #Connect-VIServer -Server $VMServer -User $oCred.User -Password $oCred.password -ErrorAction Stop | Out-Null 81 | } 82 | 83 | Catch { 84 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 85 | Break 86 | } 87 | } 88 | 89 | End { 90 | If ($?) { 91 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Connect-VMwareServer Successfully.' 92 | Write-LogInfo -LogPath $sLogFile -Message ' ' 93 | } 94 | } 95 | } 96 | 97 | Function Disconnect-VMwareServer { 98 | Param ([Parameter(Mandatory = $true)][string]$VMServer) 99 | 100 | Begin { 101 | Write-LogInfo -LogPath $sLogFile -Message "Disonnecting from vCenter Server [$VMServer]..." 102 | } 103 | 104 | Process { 105 | Try { 106 | Disconnect-VIServer -Server $VMServer -Confirm:$false| Out-Null 107 | } 108 | 109 | Catch { 110 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 111 | Break 112 | } 113 | } 114 | 115 | End { 116 | If ($?) { 117 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Disconnect-VMwareServer Successfully.' 118 | Write-LogInfo -LogPath $sLogFile -Message ' ' 119 | } 120 | } 121 | } 122 | 123 | Function Test-TagCategory { 124 | Param ([Parameter(Mandatory = $true)][string]$CategoryToCheck) 125 | 126 | Begin { 127 | Write-LogInfo -LogPath $sLogFile -Message "Checking if Tag Category [$CategoryToCheck] exists..." 128 | } 129 | 130 | Process { 131 | Try { 132 | Get-TagCategory -Name $CategoryToCheck | Out-Null 133 | } 134 | 135 | Catch { 136 | Write-LogInfo -LogPath $sLogFile -Message "Tag Category [$CategoryToCheck] did not exist. Creating it now..." 137 | New-TagCategory -Name $CategoryToCheck -Cardinality "Single" -Description "Category for resource pool assignment" -Confirm:$false | Out-Null 138 | } 139 | } 140 | 141 | End { 142 | If ($?) { 143 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Test-TagCategory Successfully.' 144 | Write-LogInfo -LogPath $sLogFile -Message ' ' 145 | } 146 | } 147 | } 148 | 149 | Function Test-Tag { 150 | Param ([Parameter(Mandatory = $true)][string]$TagToCheck) 151 | 152 | Begin { 153 | Write-LogInfo -LogPath $sLogFile -Message "Checking if Tag [$TagToCheck] exists..." 154 | } 155 | 156 | Process { 157 | Try { 158 | $returningThis = Get-Tag -Name $TagToCheck 159 | 160 | } 161 | 162 | Catch { 163 | Write-LogInfo -LogPath $sLogFile -Message "Tag [$TagToCheck] did not exist. Creating it now..." 164 | $returningThis = New-Tag -Name $TagToCheck -Category $defaultTagCategoryName -Description "Tag for VMs to move into corresponding Resource pool" -Confirm:$false 165 | } 166 | } 167 | 168 | End { 169 | If ($?) { 170 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Test-Tag Successfully.' 171 | Write-LogInfo -LogPath $sLogFile -Message ' ' 172 | return $returningThis 173 | } 174 | } 175 | } 176 | 177 | Function Test-ResourcePool { 178 | Param ([Parameter(Mandatory = $true)][string]$ResourcePoolToCheck, 179 | [Parameter(Mandatory = $true)][VMware.VimAutomation.ViCore.Impl.V1.Inventory.ComputeResourceImpl]$ClusterObject) 180 | 181 | Begin { 182 | Write-LogInfo -LogPath $sLogFile -Message "Checking if resource pool [$ResourcePoolToCheck] exists in cluster [$ClusterObject]..." 183 | } 184 | 185 | Process { 186 | Try { 187 | Get-ResourcePool -Name $ResourcePoolToCheck -Location $ClusterObject | Out-Null 188 | } 189 | 190 | Catch { 191 | Write-LogInfo -LogPath $sLogFile -Message "Resource pool [$ResourcePoolToCheck] did not exist in cluster [$ClusterObject]. Creating it now..." 192 | New-ResourcePool -Name $ResourcePoolToCheck -Location $ClusterObject -Confirm:$false | Out-Null 193 | } 194 | } 195 | 196 | End { 197 | If ($?) { 198 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Test-ResourcePool Successfully.' 199 | Write-LogInfo -LogPath $sLogFile -Message ' ' 200 | } 201 | } 202 | } 203 | 204 | Function Set-DefaultTag { 205 | Param ([Parameter(Mandatory = $true)][string]$defaultTag) 206 | 207 | Begin { 208 | Write-LogInfo -LogPath $sLogFile -Message "Checking if all VMs have a resource pool tag and if one does not then attach the tag [$defaultTag] to it ..." 209 | } 210 | 211 | Process { 212 | $tag = Test-Tag $defaultTag 213 | foreach ($currentVM in Get-VM) { 214 | if ($null -eq (Get-TagAssignment -Category $defaultTagCategoryName -Entity $currentVM)) { 215 | Write-LogInfo -LogPath $sLogFile -Message "VM [$currentVM] did not have a resource pool tag. Tagging it with [$defaultTag]..." 216 | New-TagAssignment -Entity $currentVM -Tag $tag -Confirm:$false | Out-Null 217 | If ($?) { 218 | Write-LogInfo -LogPath $sLogFile -Message "VM [$currentVM] succesfully tagged with [$defaultTag]." 219 | Write-LogInfo -LogPath $sLogFile -Message ' ' 220 | } 221 | } 222 | } 223 | 224 | } 225 | 226 | End { 227 | If ($?) { 228 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Set-DefaultTag Successfully.' 229 | Write-LogInfo -LogPath $sLogFile -Message ' ' 230 | } 231 | } 232 | } 233 | 234 | 235 | 236 | Function Move-VMsIntoResoucePoolsBasedOnTag { 237 | Param () 238 | 239 | Begin { 240 | Write-LogInfo -LogPath $sLogFile -Message 'Moving VMs into resource pools...' 241 | } 242 | 243 | Process { 244 | 245 | Test-TagCategory $defaultTagCategoryName 246 | if ($null -ne $defaultTag) { 247 | Set-DefaultTag $defaultTag 248 | } 249 | 250 | $i = 0 251 | $allClusters = Get-Cluster 252 | foreach ($currentCluster in $allClusters) { 253 | Write-Progress -Activity "Moving VMs into Resource Pools" -Status ("Cluster: {0}" -f $currentCluster.Name) -PercentComplete ((100 * $i) / ($allClusters.length)) -Id 1 -ParentId 0 254 | $currentCluster | Get-VM | Get-TagAssignment -Category $defaultTagCategoryName | ForEach-Object { 255 | Test-ResourcePool $_.Tag.Name $currentCluster 256 | Write-LogInfo -LogPath $sLogFile -Message "Moving VM $($_.Entity.Name) into resource pool $($_.Tag.Name) in Cluster $($currentCluster)..." 257 | (Get-ResourcePool -Name $_.Tag.Name -Location $currentCluster).ExtensionData.MoveIntoResourcePool((get-vm -Name $_.Entity.Name).ExtensionData.MoRef) 258 | If ($?) { 259 | Write-LogInfo -LogPath $sLogFile -Message "Completed moving VM $($_.Entity.Name) into resource pool $($_.Tag.Name) in Cluster $($currentCluster) Successfully." 260 | Write-LogInfo -LogPath $sLogFile -Message ' ' 261 | } 262 | } 263 | $i++ 264 | } 265 | } 266 | 267 | End { 268 | If ($?) { 269 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Move-VMsIntoResoucePoolsBasedOnTag Successfully.' 270 | Write-LogInfo -LogPath $sLogFile -Message ' ' 271 | } 272 | } 273 | 274 | } 275 | 276 | #-----------------------------------------------------------[Execution]------------------------------------------------------------ 277 | #Some housekeeping 278 | Set-PowerCLIConfiguration -Scope User -ParticipateInCEIP $false -InvalidCertificateAction Ignore -Confirm:$false | Out-Null 279 | 280 | Start-Log -LogPath $sLogPath -LogName $sLogName -ScriptVersion $sScriptVersion 281 | Connect-VMwareServer $vCenter 282 | Move-VMsIntoResoucePoolsBasedOnTag 283 | Disconnect-VMwareServer $vCenter 284 | Stop-Log -LogPath $sLogFile -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerCLI-Scripts 2 | Here are all the scripts that I have published on my blog https://soultec.ch/blog. Feel free to use, share, improve or print if you feel like it. 3 | -------------------------------------------------------------------------------- /Set-ResourcePoolGranular.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script balances resource pools by couting the VMs inside of them 4 | 5 | To use this script automatically please use the following code to produce a file with the password: 6 | 7 | New-VICredentialStoreItem -User $user_name -Password $user_password_decrypted -File "$file_location\login.creds" 8 | 9 | 10 | .DESCRIPTION 11 | By counting the VMs inside a resource pool this script can effectively balance resource pools according to their requirements 12 | 13 | .PARAMETER vCenter 14 | The vCenter to connect to 15 | 16 | .PARAMETER Cluster 17 | The Cluster in which the resource pools reside 18 | 19 | .INPUTS 20 | None 21 | 22 | .OUTPUTS Log File 23 | The script log file stored in /Set-ResourcePoolsGranular.log 24 | 25 | .NOTES 26 | Version: 1.2 27 | Author: Dario Dörflinger 28 | Creation Date: 22.10.2018 29 | Purpose/Change: Initial script development 30 | Added VICredentialStoreItems for automation of this script 31 | Added granularity to account for number of vCPUs and GBs of memory instead of VMs 32 | 33 | .EXAMPLE 34 | ./Set-ResourcePoolsGranular.ps1 -vCenter yourvcenter.yourdomain.com -Cluster yourClusterName 35 | 36 | That is it. 37 | #> 38 | 39 | #---------------------------------------------------------[Script Parameters]------------------------------------------------------ 40 | 41 | Param ( 42 | #Script parameters 43 | [Parameter(Mandatory=$true)][string]$vCenter, 44 | [Parameter(Mandatory=$true)][string]$Cluster 45 | ) 46 | 47 | #---------------------------------------------------------[Initialisations]-------------------------------------------------------- 48 | 49 | #Set Error Action to Silently Continue 50 | $ErrorActionPreference = 'Stop' 51 | 52 | #Import Modules & Snap-ins 53 | Import-Module PSLogging 54 | 55 | #----------------------------------------------------------[Declarations]---------------------------------------------------------- 56 | 57 | #Script Version 58 | $sScriptVersion = '1.2' 59 | 60 | #Log File Info 61 | $sLogPath = $PSScriptRoot 62 | $sLogName = "Set-ResourcePoolsGranular.log" 63 | $sLogFile = Join-Path -Path $sLogPath -ChildPath $sLogName 64 | 65 | $myResourcePools=@( 66 | [pscustomobject]@{name="1_veryhigh";factor=8}, 67 | [pscustomobject]@{name="2_high";factor=4}, 68 | [pscustomobject]@{name="3_normal";factor=2}, 69 | [pscustomobject]@{name="4_low";factor=1} 70 | ) 71 | 72 | 73 | #-----------------------------------------------------------[Functions]------------------------------------------------------------ 74 | Function Connect-VMwareServer { 75 | Param ([Parameter(Mandatory = $true)][string]$VMServer) 76 | 77 | Begin { 78 | Write-LogInfo -LogPath $sLogFile -Message "Connecting to vCenter Server [$VMServer]..." 79 | } 80 | 81 | Process { 82 | Try { 83 | $oCred = Get-Credential -Message 'Enter credentials to connect to vCenter Server' 84 | #$oCred = Get-VICredentialStoreItem -File 85 | Connect-VIServer -Server $VMServer -Credential $oCred -ErrorAction Stop | Out-Null 86 | } 87 | 88 | Catch { 89 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 90 | Break 91 | } 92 | } 93 | 94 | End { 95 | If ($?) { 96 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 97 | Write-LogInfo -LogPath $sLogFile -Message ' ' 98 | } 99 | } 100 | } 101 | Function OptimizeResourcePools { 102 | Param () 103 | 104 | Begin { 105 | Write-LogInfo -LogPath $sLogFile -Message 'Getting all Resource Pools from Cluster...' 106 | } 107 | 108 | Process { 109 | Try { 110 | [array]$rPools = Get-ResourcePool -Location (Get-Cluster $Cluster) -ErrorAction Stop 111 | foreach ($rPool in $rPools) { 112 | #Do nothing for root resource pool 113 | if ($rPool.name -ne "Resources") { 114 | #Loop through the custom objects 115 | foreach ($myPool in $myResourcePools) { 116 | #if custom name matches with existing resource pool 117 | if ($myPool.name -eq $rPool.name) { 118 | $vCPU = Get-VM -Location $rpool | where-object { $_.ExtensionData.Config.ManagedBy.Type -ne "placeholderVm" } | Measure-Object -Property NumCpu -Sum | Select-Object -ExpandProperty Sum 119 | $vMem = Get-VM -Location $rpool | where-object { $_.ExtensionData.Config.ManagedBy.Type -ne "placeholderVm" } | Measure-Object -Property MemoryMB -Sum | Select-Object -ExpandProperty Sum 120 | $vMemGB = [System.Math]::Round($vMem / 1024) 121 | $totalvms = $rpool.ExtensionData.Vm.count 122 | 123 | Write-LogInfo -LogPath $sLogFile -Message "Total VMs in $($myPool.name): $totalvms" 124 | Write-LogInfo -LogPath $sLogFile -Message "Total vCPUs in $($myPool.name): $vCPU" 125 | Write-LogInfo -LogPath $sLogFile -Message "Total Memory in $($myPool.name): $vMemGB" 126 | 127 | $rpsharesC = $myPool.factor * $vCPU 128 | $rpsharesM = $myPool.factor * $vMemGB 129 | 130 | # maximum value for share is 4000000 131 | if ($rpsharesC -lt 4000000 -and $rpsharesM -lt 4000000) 132 | { 133 | Write-LogInfo -LogPath $sLogFile -Message "Setting CPU Shares to $rpsharesC in $($myPool.name)" 134 | Write-LogInfo -LogPath $sLogFile -Message "Setting Memory Shares to $rpsharesM in $($myPool.name)" 135 | 136 | #set values 137 | Set-ResourcePool -ResourcePool $rpool.Name -CpuSharesLevel:Custom -NumCpuShares $rpsharesC -MemSharesLevel:Custom -NumMemShares $rpsharesM -Confirm:$False -ErrorAction Stop | Out-Null 138 | 139 | #for testing purposes: 140 | #Set-ResourcePool -ResourcePool $rpool.Name -CpuSharesLevel:Custom -NumCpuShares $rpsharesC -MemSharesLevel:Custom -NumMemShares $rpsharesM -Confirm:$False -ErrorAction Stop -WhatIf | Out-Null 141 | } 142 | else 143 | { 144 | Write-LogError -LogPath $sLogFile -Message "Value too high (above 4000000)" 145 | } 146 | } 147 | 148 | } 149 | } 150 | 151 | } 152 | 153 | } 154 | 155 | Catch { 156 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 157 | Break 158 | } 159 | } 160 | 161 | End { 162 | If ($?) { 163 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 164 | Write-LogInfo -LogPath $sLogFile -Message ' ' 165 | } 166 | } 167 | } 168 | 169 | #-----------------------------------------------------------[Execution]------------------------------------------------------------ 170 | 171 | Start-Log -LogPath $sLogPath -LogName $sLogName -ScriptVersion $sScriptVersion 172 | Connect-VMwareServer $vCenter 173 | OptimizeResourcePools 174 | Stop-Log -LogPath $sLogFile -------------------------------------------------------------------------------- /Set-VMTagFromNotes.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script takes the notes of each VM and creates a tag from it 4 | 5 | To use this script automatically please use the following code to produce a file with the password: 6 | 7 | New-VICredentialStoreItem -User $user_name -Password $user_password_decrypted -Host "Somethingsomething" -File "$file_location\login.creds" 8 | 9 | .DESCRIPTION 10 | By taking the notes of each VM and attaching them to the VM as a tag those values will be available to search in html5 client once more 11 | 12 | .PARAMETER vCenter 13 | The vCenter to connect to 14 | 15 | .PARAMETER tagCategory 16 | The tagCategory to check attach the tags to (default: "Notes") 17 | 18 | .INPUTS 19 | None 20 | 21 | .OUTPUTS Log File 22 | The script log file stored in /Set-VMTagFromNotes.log 23 | 24 | .NOTES 25 | Version: 1.2 26 | Author: Dario Doerflinger (@virtual_frog) 27 | Creation Date: 19.02.2019 28 | Purpose/Change: Initial script development 29 | (1.1)Added function to check tag category existance 30 | (a) Bugfix in Connect-VMwareServer Function 31 | (1.2) Bugfixes and Log improvements 32 | 33 | 34 | .EXAMPLE 35 | ./Set-VMTagFromNotes.ps1 -vCenter yourvcenter.yourdomain.com 36 | Uses the default Tag Category "Notes" 37 | 38 | .EXAMPLE 39 | ./Set-VMTagFromNotes.ps1 -vCenter yourvcenter.yourdomain.com -tagCategory Test 40 | Overwrites the default TagCategory 41 | #> 42 | 43 | #---------------------------------------------------------[Script Parameters]------------------------------------------------------ 44 | 45 | Param ( 46 | #Script parameters 47 | [Parameter(Mandatory = $true)][string]$vCenter, 48 | [Parameter(Mandatory = $false)][string]$tagCategory = "Notes" 49 | ) 50 | 51 | #---------------------------------------------------------[Initialisations]-------------------------------------------------------- 52 | 53 | #Set Error Action to Silently Continue 54 | $ErrorActionPreference = 'Stop' 55 | 56 | #Import Modules & Snap-ins 57 | Import-Module PSLogging 58 | 59 | #----------------------------------------------------------[Declarations]---------------------------------------------------------- 60 | 61 | #Script Version 62 | $sScriptVersion = '1.2' 63 | 64 | #Log File Info 65 | $sLogPath = $PSScriptRoot 66 | $sLogName = "Set-VMTagFromNotes.log" 67 | $sLogFile = Join-Path -Path $sLogPath -ChildPath $sLogName 68 | 69 | #-----------------------------------------------------------[Functions]------------------------------------------------------------ 70 | Function Connect-VMwareServer { 71 | Param ([Parameter(Mandatory = $true)][string]$VMServer) 72 | 73 | Begin { 74 | Write-LogInfo -LogPath $sLogFile -Message "Connecting to vCenter Server [$VMServer]..." 75 | } 76 | 77 | Process { 78 | Try { 79 | $oCred = Get-Credential -Message 'Enter credentials to connect to vCenter Server' 80 | Connect-VIServer -Server $VMServer -Credential $oCred -ErrorAction Stop | Out-Null 81 | 82 | #Use the below to automate the login with a VI Credential File 83 | #$oCred = Get-VICredentialStoreItem -File "c:\Set-Resourcepool\login.creds" 84 | #Connect-VIServer -Server $VMServer -User $oCred.User -Password $oCred.password -ErrorAction Stop | Out-Null 85 | } 86 | 87 | Catch { 88 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 89 | Break 90 | } 91 | } 92 | 93 | End { 94 | If ($?) { 95 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 96 | Write-LogInfo -LogPath $sLogFile -Message ' ' 97 | } 98 | } 99 | } 100 | 101 | Function Disconnect-VMwareServer { 102 | Param ([Parameter(Mandatory = $true)][string]$VMServer) 103 | 104 | Begin { 105 | Write-LogInfo -LogPath $sLogFile -Message "Disonnecting from vCenter Server [$VMServer]..." 106 | } 107 | 108 | Process { 109 | Try { 110 | Disconnect-VIServer -Server $VMServer -Confirm:$false| Out-Null 111 | } 112 | 113 | Catch { 114 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 115 | Break 116 | } 117 | } 118 | 119 | End { 120 | If ($?) { 121 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 122 | Write-LogInfo -LogPath $sLogFile -Message ' ' 123 | } 124 | } 125 | } 126 | 127 | Function Test-TagCategory { 128 | Param ([Parameter(Mandatory = $true)][string]$CategoryToCheck) 129 | 130 | Begin { 131 | Write-LogInfo -LogPath $sLogFile -Message "Checking if Tag Category [$CategoryToCheck] exists..." 132 | } 133 | 134 | Process { 135 | Try { 136 | Get-TagCategory -Name $CategoryToCheck | Out-Null 137 | } 138 | 139 | Catch { 140 | Write-LogInfo -LogPath $sLogFile -Message "Tag Category [$CategoryToCheck] did not exist. Creating it now..." 141 | New-TagCategory -Name $CategoryToCheck -Cardinality "Multiple" -Description "Category for all converted VM Notes tags" -Confirm:$false | Out-Null 142 | } 143 | } 144 | 145 | End { 146 | If ($?) { 147 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 148 | Write-LogInfo -LogPath $sLogFile -Message ' ' 149 | } 150 | } 151 | } 152 | 153 | 154 | Function New-TagsFromVMNotes { 155 | Param () 156 | 157 | Begin { 158 | Write-LogInfo -LogPath $sLogFile -Message 'Tagging VMs...' 159 | } 160 | 161 | Process { 162 | 163 | $i = 0 164 | $vms = get-vm 165 | foreach ($currentVm in $vms) { 166 | Write-Progress -Activity "Converting VM Notes to Tags" -Status ("VM: {0}" -f $currentVm.Name) -PercentComplete ((100 * $i) / ($vms.length - 1)) -Id 1 -ParentId 0 167 | $notesInfo = $currentVm.Notes 168 | 169 | if (($notesInfo -eq "") -or ($null -eq $notesInfo)) { 170 | Write-LogInfo -LogPath $sLogFile -Message "VM [$currentVM] does not have any Notes..." 171 | Write-Host -ForegroundColor yellow "$($currentVM) does not have any notes" 172 | } 173 | else { 174 | try { 175 | $tagToSet = get-tag -Name $notesInfo -ErrorAction Stop 176 | } 177 | catch { 178 | $tagToSet = New-Tag -Name $notesInfo -Category $tagCategory -Confirm:$false | Out-Null 179 | } 180 | finally { 181 | Write-LogInfo -LogPath $sLogFile -Message "Assigning Tag $($tagToSet) to VM $($currentVM)." 182 | Write-Host -ForegroundColor green "Assigning Tag $($tagToSet) to VM $($currentVM)." 183 | New-TagAssignment -Tag $tagToSet -Entity $currentVm -Confirm:$false | Out-Null 184 | } 185 | } 186 | $i++ 187 | } 188 | } 189 | 190 | End { 191 | If ($?) { 192 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 193 | Write-LogInfo -LogPath $sLogFile -Message ' ' 194 | } 195 | } 196 | 197 | } 198 | 199 | #-----------------------------------------------------------[Execution]------------------------------------------------------------ 200 | Set-PowerCLIConfiguration -Scope User -ParticipateInCEIP $false -Confirm:$false | Out-Null 201 | Start-Log -LogPath $sLogPath -LogName $sLogName -ScriptVersion $sScriptVersion 202 | Connect-VMwareServer $vCenter 203 | Test-TagCategory $tagCategory 204 | New-TagsFromVMNotes 205 | Disconnect-VMwareServer $vCenter 206 | Stop-Log -LogPath $sLogFile -------------------------------------------------------------------------------- /Set-Zerto-VPGLimit.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory = $true)][string]$zvm = "zvm.virtualfrog.wordpress.com", 3 | [Parameter(Mandatory = $true)][string]$vpgName = "Test", 4 | [Parameter(Mandatory = $true)][Int32]$LimitValueInGB = 300, 5 | [Parameter(Mandatory = $true)][Int32]$ThresholdValueInGB = 250 6 | ) 7 | 8 | #----------------------------------------------------------[Declarations]---------------------------------------------------------- 9 | 10 | # Build Base URL -> for all RestMethods 11 | $baseURL = "https://" + $zvm + ":443/v1/" 12 | 13 | # New Limit Value in MB 14 | $LimitValueInMB = $LimitValueInGB * 1024 15 | 16 | # New Warning Threshold in MB 17 | $ThresholdValueInMB = $ThresholdValueInGB * 1024 18 | 19 | # Responsetype 20 | $TypeJSON = "application/json" 21 | 22 | #-----------------------------------------------------------[Functions]------------------------------------------------------------ 23 | 24 | Function Get-ZertoSession ($ZertoUser, $ZertoPassword) { 25 | # Authenticating with Zerto APIs 26 | $xZertoSessionURL = $baseURL + "session/add" 27 | $authInfo = ("{0}:{1}" -f $ZertoUser, $ZertoPassword) 28 | $authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo) 29 | $authInfo = [System.Convert]::ToBase64String($authInfo) 30 | $headers = @{Authorization = ("Basic {0}" -f $authInfo)} 31 | $sessionBody = '{"AuthenticationMethod": "1"}' 32 | 33 | # Get Zerto Session Response 34 | $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON 35 | 36 | # Extracting x-zerto-session from the response 37 | $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") 38 | 39 | # Return Zerto Session Header 40 | return @{"Accept" = "application/json"; "x-zerto-session" = $xZertoSession} 41 | } 42 | 43 | #-----------------------------------------------------------[Execution]------------------------------------------------------------ 44 | 45 | # Get Zerto Session 46 | $zertoSessionHeader = Get-ZertoSession -ZertoUser "virtualFrog" -ZertoPassword "Password" 47 | 48 | # Get VPG 49 | $vpgListUrl = $baseURL + "vpgs" 50 | $vpg = Invoke-RestMethod -Uri $vpgListUrl -Headers $zertoSessionHeader -ContentType $TypeJSON 51 | 52 | #Filter the one from the paramater 53 | $vpgToEdit = $vpg |Where-Object {$_.VpgName -eq "$vpgName"} 54 | Write-Host "Changing Journal Limit and Threshold Settings of: "($vpgToEdit.VpgName) 55 | 56 | #Get the identifier of this VPG 57 | $VPGidentifier = $vpgToEdit.VpgIdentifier 58 | $VPGidentifierJSON = '{"VpgIdentifier":"' + $VPGidentifier + '"}' 59 | #$VPGidentifier 60 | 61 | # Get VPG Settings Identifier 62 | $VPGSettingsIDURL = $baseURL + "vpgSettings" 63 | $VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $VPGSettingsIDURL -Body $VPGidentifierJSON -ContentType $TypeJSON -Headers $zertoSessionHeader 64 | 65 | # Set VPG Settings URL 66 | $VPGSettingsURL = $baseURL + "vpgSettings/" + $VPGSettingsIdentifier 67 | $VPGSettingsBasicURL = $VPGSettingsURL + "/basic" 68 | $VPGSettingsJournalURL = $VPGSettingsURL + "/journal" 69 | $VPGSettingsCommitURL = $VPGSettingsURL + "/commit" 70 | $VPGSettingsVMsJournalURL = $VPGSettingsURL + "/vms" 71 | 72 | # Get the actual VPG Settings 73 | $VPGSettings = Invoke-RestMethod -Uri $VPGSettingsURL -Headers $zertoSessionHeader -ContentType $TypeJSON 74 | 75 | $HardLimitGB = $VPGSettings.Journal.Limitation.HardLimitInMB / 1024 76 | $WarningThresholdGB = $VPGSettings.Journal.Limitation.WarningThresholdInMB / 1024 77 | #Write-Host "Hard Limit of this VPG in GB: " $HardLimitGB 78 | #Write-Host "Warning Threshold of this VPG in GB: " $WarningThresholdGB 79 | 80 | #Change Setting of VPG 81 | $VPGSettings.Journal.Limitation.HardLimitInMB = $LimitValueInMB 82 | $VPGSettings.Journal.Limitation.WarningThresholdInMB = $ThresholdValueInMB 83 | 84 | $data = @{Limitation = @{ 85 | HardLimitInMB = $LimitValueInMB 86 | WarningThresholdInMB = $ThresholdValueInMB 87 | } 88 | } 89 | $json = $data | ConvertTo-Json 90 | 91 | $vmdata = @{Journal = @{ 92 | Limitation = @{ 93 | HardLimitInMB = $LimitValueInMB 94 | WarningThresholdInMB = $ThresholdValueInMB 95 | } 96 | } 97 | } 98 | $vmjson = $vmdata |ConvertTo-Json 99 | #Write Change to Zerto 100 | $ChangedVPG = Invoke-RestMethod -Uri $VPGSettingsJournalURL -Method Put -Body $json -Headers $zertoSessionHeader -ContentType $TypeJSON 101 | 102 | foreach ($vm in $VPGSettings.VMs) { 103 | $vmIdentifier = $vm.VmIdentifier 104 | $VPGSettingsVMsJournalURL = $VPGSettingsURL + "/vms/" + $vmIdentifier 105 | $VMHardLimitGB = $vm.Journal.Limitation.HardLimitInMB / 1024 106 | $VMWarningThreshold = $vm.Journal.Limitation.WarningThresholdInMB / 1024 107 | 108 | #Write-Host "VM ("$vm.VmIdentifier") has Limit of "$VMHardLimitGB " GB and Warning of " $VMWarningThreshold "GB" 109 | $ChangedVPG = Invoke-RestMethod -Uri $VPGSettingsVMsJournalURL -Method Put -Body $vmjson -Headers $zertoSessionHeader -ContentType $TypeJSON 110 | 111 | } 112 | 113 | $VPGCommit = Invoke-RestMethod -Method Post -Uri $VPGSettingsCommitURL -ContentType $TypeJSON -Headers $zertoSessionHeader 114 | Write-Host -ForegroundColor Green "Changed the valued successfully!" -------------------------------------------------------------------------------- /SetHAAdmissionControl.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script sets the HA admission control to the percentage setting taking into account the number of hosts the user wnats to tolerate 4 | 5 | .DESCRIPTION 6 | as a parameter you provide the number of hosts failures you want to tolerate, the name of the cluster and the name of the vCenter server 7 | the script will then set the admission control to the percentage value according to the number of hosts in the cluster 8 | the script will detect if there is a uneven set of resources in the cluster per host and display a warning. it will then base the calculations on the biggest host in the cluster. 9 | 10 | Important: this script is intended to for vSphere prior to 6.5. Starting with vSphere 6.5 this functionality is built in 11 | 12 | .PARAMETER vCenter 13 | vCenter Server to connect to (example: bezhvcs03.bechtlezh.ch) 14 | 15 | .PARAMETER cluster 16 | Name of the cluster on which this setting will be applied (example: CLTEST) 17 | 18 | .PARAMETER failuresToTolerate 19 | Number of host failures to tolerate (example: 1) 20 | 21 | .INPUTS 22 | Parameters above 23 | 24 | .OUTPUTS 25 | Log file stored in $sLogPath\$sLogName 26 | 27 | .NOTES 28 | Version: 1.0 29 | Author: Dario Dörflinger (aka. virtualFrog) 30 | Creation Date: 08.05.2018 31 | Purpose/Change: Script requested to frequently update the HA Admission setting if the number of hosts in a cluster changes 32 | 33 | .EXAMPLE 34 | SetHAAdmissionControl.ps1 -vCenter bezhvcs03.bechtlezh.ch -cluster CLTEST -failuresToTolerate 1 35 | Sets the correct percentages for 1 failure on cluster CLTEST in vCenter bezhvcs03.bechtlzh.ch 36 | #> 37 | 38 | #---------------------------------------------------------[Script Parameters]------------------------------------------------------ 39 | 40 | Param ( 41 | #Script parameters go here 42 | [Parameter(Mandatory = $true)][string]$vCenter, 43 | [Parameter(Mandatory = $true)][string]$cluster, 44 | [Parameter(Mandatory = $true)][string]$failuresToTolerate 45 | ) 46 | 47 | #---------------------------------------------------------[Initialisations]-------------------------------------------------------- 48 | 49 | #Set Error Action to Silently Continue 50 | $ErrorActionPreference = 'SilentlyContinue' 51 | 52 | #Import Modules & Snap-ins 53 | Import-Module PSLogging 54 | 55 | #----------------------------------------------------------[Declarations]---------------------------------------------------------- 56 | 57 | #Script Version 58 | $sScriptVersion = '1.0' 59 | 60 | #Log File Info 61 | $sLogPath = 'C:\Temp' 62 | $sLogName = 'HA_AdmissionControlLog.log' 63 | $sLogFile = Join-Path -Path $sLogPath -ChildPath $sLogName 64 | 65 | #-----------------------------------------------------------[Functions]------------------------------------------------------------ 66 | 67 | Function Connect-VMwareServer { 68 | Param ([Parameter(Mandatory = $true)][string]$VMServer) 69 | 70 | Begin { 71 | Write-LogInfo -LogPath $sLogFile -Message "Connecting to vCenter Server [$VMServer]..." 72 | } 73 | 74 | Process { 75 | Try { 76 | $oCred = Get-Credential -Message 'Enter credentials to connect to vCenter Server' 77 | Connect-VIServer -Server $VMServer -Credential $oCred -ErrorAction Stop 78 | } 79 | 80 | Catch { 81 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 82 | Break 83 | } 84 | } 85 | 86 | End { 87 | If ($?) { 88 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 89 | Write-LogInfo -LogPath $sLogFile -Message ' ' 90 | } 91 | } 92 | } 93 | 94 | 95 | Function checkRAMCompliance { 96 | Param ([Parameter(Mandatory = $true)][string]$clusterName) 97 | Begin { 98 | Write-LogInfo -LogPath $sLogFile -Message "Checking if all hosts in cluster [$clusterName] have the same amount of RAM..." 99 | $myHostsRAM = @() 100 | } 101 | Process { 102 | Try { 103 | $clusterObject = Get-Cluster -Name $clusterName -ErrorAction Stop 104 | $hostObjects = $clusterObject | Get-VMHost -ErrorAction Stop 105 | 106 | foreach ($hostObject in $hostObjects) { 107 | 108 | $HostInfoMEM = "" | Select-Object MEM 109 | 110 | $HostInfoMEM.MEM = $hostObject.MemoryTotalGB 111 | 112 | $myHostsRAM += $HostInfoMEM 113 | } 114 | #Check if all values are correct: return true, otherwise return false 115 | if (@($myHostsRAM | Select-Object -Unique).Count -eq 1) { 116 | #CPU are the same 117 | Write-LogInfo -LogPath $sLogFile -Message "RAM in the cluster is the same" 118 | return $true 119 | } 120 | else { 121 | Write-LogInfo -LogPath $sLogFile -Message "RAM in the cluster is NOT the same" 122 | return $false 123 | } 124 | 125 | } 126 | Catch { 127 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 128 | Break 129 | } 130 | } 131 | End { 132 | If ($?) { 133 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 134 | Write-LogInfo -LogPath $sLogFile -Message ' ' 135 | } 136 | } 137 | } 138 | 139 | 140 | Function checkCPUCompliance { 141 | Param ([Parameter(Mandatory = $true)][string]$clusterName) 142 | Begin { 143 | Write-LogInfo -LogPath $sLogFile -Message "Checking if all hosts in cluster [$clusterName] have the same CPU..." 144 | $myHostsCPU = @() 145 | } 146 | Process { 147 | Try { 148 | $clusterObject = Get-Cluster -Name $clusterName -ErrorAction Stop 149 | $hostObjects = $clusterObject | Get-VMHost -ErrorAction Stop 150 | 151 | foreach ($hostObject in $hostObjects) { 152 | $HostInfoCPU = "" | Select-Object CPU 153 | 154 | $HostInfoCPU.CPU = $hostObject.CpuTotalMhz 155 | 156 | $myHostsCPU += $HostInfoCPU 157 | } 158 | #Check if all values are correct: return true, otherwise return false 159 | 160 | if (@($myHostsCPU | Select-Object -Unique).Count -eq 1) { 161 | Write-LogInfo -LogPath $sLogFile -Message "CPU in the cluster is the same" 162 | return $true 163 | } 164 | else { 165 | Write-LogInfo -LogPath $sLogFile -Message "CPU in the cluster is NOT the same" 166 | return $false 167 | } 168 | 169 | } 170 | Catch { 171 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 172 | Break 173 | } 174 | } 175 | End { 176 | If ($?) { 177 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 178 | Write-LogInfo -LogPath $sLogFile -Message ' ' 179 | } 180 | } 181 | } 182 | 183 | Function getBiggestCPUInCluster { 184 | Param ([Parameter(Mandatory=$true)][string]$clusterName) 185 | Begin { 186 | Write-LogInfo -LogPath $sLogFile -Message "Trying to get the biggest CPU resource in cluster [$clusterName]..." 187 | } 188 | Process { 189 | Try { 190 | $clusterObject = Get-Cluster $clusterName -ErrorAction Stop 191 | $hostObjects = $clusterObject | Get-VMHost -ErrorAction Stop 192 | $cpuResources = @() 193 | foreach ($hostObject in $hostObjects) { 194 | $cpuInfo = "" | Select-Object CPU 195 | $cpuInfo.CPU = $hostObject.CpuTotalMhz 196 | 197 | $cpuResources += $cpuInfo 198 | } 199 | return ($cpuResources | Measure-Object -Maximum) 200 | 201 | } 202 | Catch { 203 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 204 | Break 205 | } 206 | } 207 | End { 208 | If ($?) { 209 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 210 | Write-LogInfo -LogPath $sLogFile -Message ' ' 211 | } 212 | } 213 | } 214 | 215 | Function getBiggestRAMInCluster { 216 | Param ([Parameter(Mandatory=$true)][string]$clusterName) 217 | Begin { 218 | Write-LogInfo -LogPath $sLogFile -Message "Trying to get the biggest RAM resource in cluster [$clusterName]..." 219 | } 220 | Process { 221 | Try { 222 | $clusterObject = Get-Cluster $clusterName -ErrorAction Stop 223 | $hostObjects = $clusterObject | Get-VMHost -ErrorAction Stop 224 | $ramResources = @() 225 | foreach ($hostObject in $hostObjects) { 226 | $ramInfo = "" | Select-Object RAM 227 | $ramInfo.RAM = $hostObject.MemoryTotalGB 228 | 229 | $ramResources += $ramInfo 230 | } 231 | return ($ramResources | Measure-Object -Maximum) 232 | 233 | } 234 | Catch { 235 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 236 | Break 237 | } 238 | } 239 | End { 240 | If ($?) { 241 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 242 | Write-LogInfo -LogPath $sLogFile -Message ' ' 243 | } 244 | } 245 | } 246 | 247 | Function SetAdmissionControl { 248 | Param ([Parameter(Mandatory = $true)][string]$clusterName) 249 | Begin { 250 | Write-LogInfo -LogPath $sLogFile -Message "Setting the admission policy on cluster [$clusterName].." 251 | } 252 | Process { 253 | Try { 254 | $RAMCompliance = checkRAMCompliance $clusterName 255 | $CPUCompliance = checkCPUCompliance $clusterName 256 | $totalAmountofHostsInCluster = (Get-Cluster -Name $clusterName -ErrorAction Stop | Get-VMHost -ErrorAction Stop).Count 257 | if (($RAMCompliance -eq $true) -and ($CPUCompliance -eq $true)) { 258 | #Same hardware. calculation very simple 259 | [int]$ramPercentageToReserve = [math]::Round((100 / ($totalAmountofHostsInCluster) * ($failuresToTolerate)), 0) 260 | [int]$cpuPercentageToReserve = [math]::Round((100 / ($totalAmountofHostsInCluster) * ($failuresToTolerate)), 0) 261 | 262 | } 263 | if ($CPUCompliance -eq $false) { 264 | #calculate with different CPU resources but same RAM resources 265 | #get biggest CPU amount, total amount and number of hosts in cluster 266 | $biggestCPUValue = getBiggestCPUInCluster $clusterName 267 | $totalCPUMhz = (Get-Cluster $clusterName).ExtensionData.Summary.TotalCPU 268 | 269 | [int]$cpuPercentageToReserve = [math]::Round(((($biggestCPUValue) * 100) / ($totalCPUMhz)*($failuresToTolerate)),0) 270 | } 271 | if ($RAMCompliance -eq $false) { 272 | #in this case RAM is the decisive factor 273 | #get biggest RAM amount, total amount and number of hosts in cluster 274 | $biggestMemoryValue = getBiggestRAMInCluster $clusterName 275 | $totalMemoryGB = [math]::Round(((Get-Cluster $clusterName).ExtensionData.Summary.TotalMemory /1024 /1024 /1024),0) 276 | 277 | [int]$ramPercentageToReserve = [math]::Round(((($biggestMemoryValue) * 100) / ($totalMemoryGB)*($failuresToTolerate)),0) 278 | } 279 | 280 | Write-LogInfo -LogPath $sLogFile -Message "CPU Value calculated: [$cpuPercentageToReserve].." 281 | Write-LogInfo -LogPath $sLogFile -Message "RAM Value calculated: [$ramPercentageToReserve].." 282 | 283 | $spec = New-Object VMware.Vim.ClusterConfigSpecEx 284 | $spec.dasConfig = New-Object VMware.Vim.ClusterDasConfigInfo 285 | $spec.dasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy 286 | $spec.dasConfig.AdmissionControlEnabled = $true 287 | $spec.dasConfig.AdmissionControlPolicy.cpuFailoverResourcesPercent = $cpuPercentageToReserve 288 | $spec.dasConfig.AdmissionControlPolicy.memoryFailoverResourcesPercent = $ramPercentageToReserve 289 | 290 | $clusterObject = Get-Cluster $clusterName 291 | $clusterView = Get-View $clusterObject 292 | $clusterView.ReconfigureComputeResource_Task($spec, $true) 293 | 294 | } 295 | Catch { 296 | Write-LogError -LogPath $sLogFile -Message $_.Exception -ExitGracefully 297 | Break 298 | } 299 | } 300 | End { 301 | If ($?) { 302 | Write-LogInfo -LogPath $sLogFile -Message 'Completed Successfully.' 303 | Write-LogInfo -LogPath $sLogFile -Message ' ' 304 | } 305 | } 306 | } 307 | 308 | #-----------------------------------------------------------[Execution]------------------------------------------------------------ 309 | 310 | Start-Log -LogPath $sLogPath -LogName $sLogName -ScriptVersion $sScriptVersion 311 | Connect-VMwareServer -VMServer $vCenter 312 | SetAdmissionControl -clusterName $cluster 313 | Stop-Log -LogPath $sLogFile -------------------------------------------------------------------------------- /Test-HostNetworkingWindowsVM.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Run various networking tests on all hosts in a cluster, using a test VM. 4 | Can be run on a dvSwitch or a Standard Switch 5 | .DESCRIPTION 6 | Using a Microsoft Windows test VM, iterate through a list of port groups and 7 | subnets (specified in the CSV input file) and run tests. 8 | Testing method involves assigning the test VM to a specific port group or VLAN ID, 9 | assigning IP information and running a test ping. 10 | 11 | Currently, performs the following tests: 12 | Test connectivity with VM on each port group 13 | Test connectivity for each VLAN ID on each uplink on each host in the cluster. 14 | 15 | Requirements: 16 | UAC disabled on Windows testVM 17 | PowerCLI 6.5 or higher 18 | testVM language must be english or the ping command outputs cannot be parsed correctly 19 | .PARAMETER clusterName 20 | Input - Clustername you want to test 21 | .PARAMETER dvsName 22 | Input - Name of the vSwitch/DVS you want to test. 23 | E.g.: vSwitch0 or dvs-01 24 | .PARAMETER isStandard 25 | Input - is it a standardswitch? 26 | E.g.: -isStandard:$false for a dvSwitch 27 | - isStandard:$true for a standard switch 28 | .PARAMETER resultfile 29 | Input - Path to the CSV that will save the output of the script 30 | .PARAMETER csvFile 31 | Input - CSV file containing IP info to test. Must contain the following columns. 32 | Port Group - a valid port group name available on the specified DVS 33 | Source IP - IP to assign to the test VM for this port group 34 | Gateway IP - Gateway to assign to the test VM 35 | SubnetMask - Subnet mask to assign to test VM 36 | Test IP - IP address to target for ping test 37 | 38 | This is example data: 39 | PortGroup,SourceIP,GatewayIP,SubnetMask,TestIP 40 | PG_NET1,10.10.101.55,10.10.101.1,255.255.255.0,10.0.0.1 41 | PG_NET2,10.10.102.55,10.10.102.1,255.255.255.0,10.0.0.1 42 | .PARAMETER creds 43 | The username and password for the guest OS of the test VM. 44 | .PARAMETER vmName 45 | A powered on Windows OS virtual machine with UAC disabled and VMware tools running. 46 | Note this VM will be vMotioned, network reassigned, and IP address changed by this script! 47 | .EXAMPLE 48 | ./virtualFrogNetworkTester.ps1 -clusterName VirtualFrog1 -dvsName vSwitch1 -isStandard:$true -vmName networktestingFrogVM -csvFile c:\temp\map.csv -resultFile c:\temp\virtualFrogRocks.csv 49 | .NOTES 50 | Author: Jeff Green; Dario Doerflinger 51 | Date: July 10, 2015; July 25, 2017 52 | Original script from https://virtualdatacave.com/2015/07/test-host-networking-for-many-hosts-and-port-groups-vlans/ 53 | Port to Standard Switch requested by VMware Code Community 54 | Port Author: Dario Doerflinger 55 | Ported Script published at: https://virtualfrog.wordpress.com/2017/07/26/powercli-testing-your-networks/ 56 | #> 57 | 58 | param 59 | ( 60 | [Parameter(Mandatory=$true)] 61 | [string]$clusterName, 62 | [Parameter(Mandatory=$true)] 63 | [string]$dvsName, 64 | [Parameter(Mandatory=$true)] 65 | [boolean]$isStandard, 66 | [Parameter(Mandatory=$true)] 67 | [pscredential]$creds, 68 | [Parameter(Mandatory=$true)] 69 | [string]$vmName, 70 | [Parameter(Mandatory=$true)] 71 | [string]$csvFile, 72 | [int]$timesToPing = 2, 73 | [int]$pingReplyCountThreshold = 2, 74 | [Parameter(Mandatory=$true)] 75 | [string]$resultFile 76 | ) 77 | 78 | #Setup 79 | 80 | # Configure internal variables 81 | $trustVMInvokeable = $false #this is to speed development only. Set to false. 82 | $testResults = @() 83 | $testPortGroupName = "VirtualFrog" 84 | $data = import-csv $csvFile 85 | $cluster = get-cluster $clusterName 86 | $vm = get-vm $vmName 87 | 88 | if ($isStandard -eq $false) { 89 | $dvs = get-vdswitch $dvsName 90 | $originalVMPortGroup = ($vm | get-Networkadapter)[0].networkname 91 | if ($originalVMPortGroup -eq "") { 92 | $originalVMPortGroup = ($vm | get-virtualswitch -name $dvsName |get-virtualportgroup)[0] 93 | write-host -Foregroundcolor:red "Adding a fantasy Name to $originalVMPortGroup" 94 | } 95 | } else { 96 | $originalVMPortGroup = ($vm | get-Networkadapter)[0].networkname 97 | $temporaryVar = ($vm |get-networkadapter)[0].NetworkName 98 | if ($originalVMPortGroup -eq "") { 99 | $originalVMPortGroup = ($vm |get-vmhost |get-virtualswitch -name $dvsName |get-virtualportgroup -Standard:$true)[0] 100 | write-host -Foregroundcolor:red "Adding a fantasy Name to $originalVMPortGroup" 101 | } 102 | } 103 | #We'll use this later to reset the VM back to its original network location if it's empty for some reason wel'll populate it with the first portgroup 104 | 105 | 106 | 107 | 108 | 109 | 110 | #Test if Invoke-VMScript works 111 | if(-not $trustVMInvokeable) { 112 | if (-not (Invoke-VMScript -ScriptText "echo test" -VM $vm -GuestCredential $creds).ScriptOutput -eq "test") { 113 | write-output "Unable to run scripts on test VM guest OS!" 114 | return 1 115 | } 116 | } 117 | 118 | #Define Test Functions 119 | function TestPing($ip, $count, $mtuTest) { 120 | if($mtuTest) { 121 | $count = 4 #Less pings for MTU test 122 | $pingReplyCountThreshold = 3 #Require 3 responses for success on MTU test. Note this scope is local to function and will not impact variable for future run. 123 | $script = "ping -f -l 8972 -n $count $ip" 124 | } else { 125 | $script = "ping -n $count $ip" 126 | } 127 | 128 | write-host -ForegroundColor yellow "Script to run: $script" 129 | $result = Invoke-VMScript -ScriptText $script -VM $vm -GuestCredential $creds 130 | 131 | #parse the output for the "received packets" number 132 | $rxcount = (( $result.ScriptOutput | Where-Object { $_.indexof("Packets") -gt -1 } ).Split(',') | Where-Object { $_.indexof("Received") -gt -1 }).split('=')[1].trim() 133 | 134 | #if we received enough ping replies, consider this a success 135 | $success = ([int]$rxcount -ge $pingReplyCountThreshold) 136 | 137 | #however there is one condition where this will be a false positive... gateway reachable but destination not responding 138 | if ( $result.ScriptOutput | Where-Object { $_.indexof("host unreach") -gt -1 } ) { 139 | $success = $false 140 | $rxcount = 0; 141 | } 142 | 143 | write-host "Full results of ping test..." 144 | write-host -ForegroundColor green $result.ScriptOutput 145 | 146 | return @($success, $count, $rxcount); 147 | } 148 | 149 | function SetGuestIP($ip, $subnet, $gw) { 150 | $script = @" 151 | function Elevate-Process { 152 | param ([string]`$exe = `$(Throw 'Pleave provide the name and path of an executable'),[string]`$arguments) 153 | `$startinfo = new-object System.Diagnostics.ProcessStartInfo 154 | `$startinfo.FileName = `$exe 155 | `$startinfo.Arguments = `$arguments 156 | `$startinfo.verb = 'RunAs' 157 | `$process = [System.Diagnostics.Process]::Start(`$startinfo) 158 | } 159 | 160 | Elevate-Process -Exe C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Arguments "-noninteractive -command netsh interface ip set address name=((gwmi win32_networkadapter -filter 'netconnectionstatus = 2' | select -First 1).interfaceindex) static $ip $subnet $gw 161 | netsh interface ipv4 set subinterface ((gwmi win32_networkadapter -filter 'netconnectionstatus = 2' | select -First 1).interfaceindex) mtu=1500 store=active" 162 | "@ 163 | Start-Sleep -Seconds 2 164 | write-host -ForegroundColor Yellow "Script to run: " $script 165 | return (Invoke-VMScript -ScriptType Powershell -ScriptText $script -VM $vm -GuestCredential $creds) 166 | } 167 | 168 | #Tests 169 | # Per Port Group Tests (Test each port group) 170 | 171 | $vmhost = $vm.vmhost 172 | if ($isStandard -eq $false) 173 | { 174 | foreach($item in $data) { 175 | if($testPortGroup = $dvs | get-vdportgroup -name $item.PortGroup) { 176 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup $testPortGroup -confirm:$false 177 | if( SetGuestIP $item.SourceIP $item.SubnetMask $item.GatewayIP ) { 178 | Write-Output ("Set Guest IP to " + $item.SourceIP) 179 | 180 | #Run normal ping test 181 | $pingTestResult = TestPing $item.TestIP $timesToPing $false 182 | #Add to results 183 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 184 | $thisTest["Host"] = $vmhost.name 185 | $thisTest["PortGroupName"] = $testPortGroup.name 186 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 187 | $thisTest["SourceIP"] = $item.SourceIP 188 | $thisTest["DestinationIP"] = $item.TestIP 189 | $thisTest["Result"] = $pingTestResult[0].tostring() 190 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 191 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 192 | $thisTest["JumboFramesTest"] = "" 193 | $thisTest["Uplink"] = $thisUplink 194 | 195 | $testResults += new-object -typename psobject -Property $thisTest 196 | 197 | #DISABLED JUMBO FRAMES TEST! 198 | if($false) { 199 | #Run jumbo frames test 200 | $pingTestResult = TestPing $item.TestIP $timesToPing $true 201 | #Add to results 202 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 203 | $thisTest["Host"] = $vmhost.name 204 | $thisTest["PortGroupName"] = $testPortGroup.name 205 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 206 | $thisTest["SourceIP"] = $item.SourceIP 207 | $thisTest["DestinationIP"] = $item.TestIP 208 | $thisTest["Result"] = $pingTestResult[0].tostring() 209 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 210 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 211 | $thisTest["JumboFramesTest"] = "" 212 | $thisTest["Uplink"] = $thisUplink 213 | 214 | $testResults += new-object -typename psobject -Property $thisTest 215 | } 216 | 217 | 218 | } else { 219 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 220 | $thisTest["PortGroupName"] = $testPortGroup.name 221 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 222 | $thisTest["SourceIP"] = $item.SourceIP 223 | $thisTest["DestinationIP"] = $item.GatewayIP 224 | $thisTest["Result"] = "false - error setting guest IP" 225 | $testResults += new-object -typename psobject -Property $thisTest 226 | } 227 | } else { 228 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 229 | $thisTest["PortGroupName"] = $item.PortGroup 230 | $thisTest["Result"] = "false - could not find port group" 231 | $testResults += new-object -typename psobject -Property $thisTest 232 | } 233 | } 234 | } 235 | else { 236 | #This is for a Standard Switch 237 | foreach($item in $data) { 238 | $dvs = $vm |get-vmhost | get-virtualswitch -name $dvsName 239 | if($testPortGroup = $dvs | get-virtualportgroup -name $item.PortGroup) { 240 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup $testPortGroup -confirm:$false 241 | if( SetGuestIP $item.SourceIP $item.SubnetMask $item.GatewayIP ) { 242 | Write-Output ("Set Guest IP to " + $item.SourceIP) 243 | 244 | #Run normal ping test 245 | $pingTestResult = TestPing $item.TestIP $timesToPing $false 246 | #Add to results 247 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 248 | $thisTest["Host"] = $vmhost.name 249 | $thisTest["PortGroupName"] = $testPortGroup.name 250 | $thisTest["VlanID"] = $testPortGroup.vlanid 251 | $thisTest["SourceIP"] = $item.SourceIP 252 | $thisTest["DestinationIP"] = $item.TestIP 253 | $thisTest["Result"] = $pingTestResult[0].tostring() 254 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 255 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 256 | $thisTest["JumboFramesTest"] = "" 257 | $thisTest["Uplink"] = $thisUplink 258 | 259 | $testResults += new-object -typename psobject -Property $thisTest 260 | 261 | #DISABLED JUMBO FRAMES TEST! 262 | if($false) { 263 | #Run jumbo frames test 264 | $pingTestResult = TestPing $item.TestIP $timesToPing $true 265 | #Add to results 266 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 267 | $thisTest["Host"] = $vmhost.name 268 | $thisTest["PortGroupName"] = $testPortGroup.name 269 | $thisTest["VlanID"] = $testPortGroup.vlanid 270 | $thisTest["SourceIP"] = $item.SourceIP 271 | $thisTest["DestinationIP"] = $item.TestIP 272 | $thisTest["Result"] = $pingTestResult[0].tostring() 273 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 274 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 275 | $thisTest["JumboFramesTest"] = "" 276 | $thisTest["Uplink"] = $thisUplink 277 | 278 | $testResults += new-object -typename psobject -Property $thisTest 279 | } 280 | 281 | 282 | } else { 283 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 284 | $thisTest["PortGroupName"] = $testPortGroup.name 285 | $thisTest["VlanID"] = $testPortGroup.vlanid 286 | $thisTest["SourceIP"] = $item.SourceIP 287 | $thisTest["DestinationIP"] = $item.GatewayIP 288 | $thisTest["Result"] = "false - error setting guest IP" 289 | $testResults += new-object -typename psobject -Property $thisTest 290 | } 291 | } else { 292 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 293 | $thisTest["PortGroupName"] = $item.PortGroup 294 | $thisTest["Result"] = "false - could not find port group" 295 | $testResults += new-object -typename psobject -Property $thisTest 296 | } 297 | } 298 | } 299 | 300 | 301 | # Per Host Tests (Test Each Link for Each VLAN ID on each host) 302 | $testPortGroup = $null 303 | 304 | if ($isStandard -eq $false) 305 | { 306 | 307 | ($testPortGroup = new-vdportgroup $dvs -Name $testPortGroupName -ErrorAction silentlyContinue) -or ($testPortGroup = $dvs | get-vdportgroup -Name $testPortGroupName) 308 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup $testPortGroup -confirm:$false 309 | 310 | $cluster | get-vmhost | Where-Object {$_.ConnectionState -match "connected" } | ForEach-Object { 311 | $vmhost = $_ 312 | #Migrate VM to new host 313 | if(Move-VM -VM $vm -Destination $vmhost) { 314 | 315 | foreach($item in $data) { 316 | #Configure test port group VLAN ID for this particular VLAN test, or clear VLAN ID if none exists 317 | $myVlanId = $null 318 | $myVlanId = (get-vdportgroup -name $item.PortGroup).VlanConfiguration.Vlanid 319 | if($myVlanId) { 320 | $testPortGroup = $testPortGroup | Set-VDVlanConfiguration -Vlanid $myVlanId 321 | } else { 322 | $testPortGroup = $testPortGroup | Set-VDVlanConfiguration -DisableVlan 323 | } 324 | 325 | 326 | if( SetGuestIP $item.SourceIP $item.SubnetMask $item.GatewayIP ) { 327 | Write-Output ("Set Guest IP to " + $item.SourceIP) 328 | 329 | #Run test on each uplink individually 330 | $uplinkset = ( ($testPortGroup | Get-VDUplinkTeamingPolicy).ActiveUplinkPort + ($testPortGroup | Get-VDUplinkTeamingPolicy).StandbyUplinkPort ) | sort 331 | foreach($thisUplink in $uplinkset) { 332 | #Disable all uplinks from the test portgroup 333 | $testPortGroup | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -UnusedUplinkPort $uplinkset 334 | #Enable only this uplink for the test portgroup 335 | $testPortGroup | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -ActiveUplinkPort $thisUplink 336 | 337 | #Run normal ping test 338 | $pingTestResult = TestPing $item.TestIP $timesToPing $false 339 | #Add to results 340 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 341 | $thisTest["Host"] = $vmhost.name 342 | $thisTest["PortGroupName"] = $testPortGroup.name 343 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 344 | $thisTest["SourceIP"] = $item.SourceIP 345 | $thisTest["DestinationIP"] = $item.TestIP 346 | $thisTest["Result"] = $pingTestResult[0].tostring() 347 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 348 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 349 | $thisTest["JumboFramesTest"] = "" 350 | $thisTest["Uplink"] = $thisUplink 351 | 352 | $testResults += new-object -typename psobject -Property $thisTest 353 | 354 | #DISABLED JUMBO FRAMES TEST! 355 | if($false) { 356 | #Run jumbo frames test 357 | $pingTestResult = TestPing $item.TestIP $timesToPing $true 358 | #Add to results 359 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 360 | $thisTest["Host"] = $vmhost.name 361 | $thisTest["PortGroupName"] = $testPortGroup.name 362 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 363 | $thisTest["SourceIP"] = $item.SourceIP 364 | $thisTest["DestinationIP"] = $item.TestIP 365 | $thisTest["Result"] = $pingTestResult[0].tostring() 366 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 367 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 368 | $thisTest["JumboFramesTest"] = "" 369 | $thisTest["Uplink"] = $thisUplink 370 | 371 | $testResults += new-object -typename psobject -Property $thisTest 372 | } 373 | } 374 | 375 | $testPortGroup | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -ActiveUplinkPort ($uplinkset | sort) 376 | 377 | } else { 378 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 379 | $thisTest["PortGroupName"] = $testPortGroup.name 380 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 381 | $thisTest["SourceIP"] = $item.SourceIP 382 | $thisTest["DestinationIP"] = $item.GatewayIP 383 | $thisTest["Result"] = "false - error setting guest IP" 384 | $testResults += new-object -typename psobject -Property $thisTest 385 | } 386 | } 387 | } else { 388 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 389 | $thisTest["Result"] = "false - unable to vMotion VM to this host" 390 | $testResults += new-object -typename psobject -Property $thisTest 391 | } 392 | } 393 | } 394 | else { 395 | #This is for a standard Switch 396 | $vmhost = $null 397 | 398 | #adding the testPortGroup on all hosts in the cluster 399 | $cluster | get-vmhost | Where-Object {$_.ConnectionState -match "connected" } | sort | ForEach-Object { 400 | $dvs = get-virtualswitch -Name $dvsName -VMhost $_ 401 | $dvs | new-virtualportgroup -Name $testPortGroupName -ErrorAction silentlyContinue 402 | } 403 | 404 | $vmhost = $null 405 | $cluster | get-vmhost | Where-Object {$_.ConnectionState -match "connected" } | sort | ForEach-Object { 406 | $vmhost = $_ 407 | $dvs = get-virtualswitch -Name $dvsName -VMhost $vmhost 408 | $testPortGroup = $dvs |get-virtualportgroup -Name $testPortGroupName -VMhost $vmhost -ErrorAction silentlyContinue 409 | 410 | 411 | #Migrate VM to new host 412 | if(Move-VM -VM $vm -Destination $vmhost) { 413 | write-host -Foregroundcolor:red "Sleeping 5 seconds..." 414 | start-sleep -seconds 5 415 | if (($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup ($dvs |get-virtualportgroup -Name $testPortGroupName -VMhost $vmhost) -confirm:$false -ErrorAction stop) 416 | { 417 | write-host -Foregroundcolor:green "Adapter Change successful" 418 | }else { 419 | write-host -Foregroundcolor:red "Cannot change adapter!" 420 | #$esxihost = $vm |get-vmhost 421 | #$newPortgroup = $esxihost | get-virtualportgroup -Name testPortGroupName -ErrorAction silentlyContinue 422 | #if (($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup ($newPortgroup) -confirm:$false -ErrorAction stop) { 423 | # write-host -Foregroundcolor:green "Adapter Change successful (2nd attempt)" 424 | #} else { 425 | # write-host -Foregroundcolor:red "Cannot change Adapter even on 2nd attempt. Exiting script" 426 | # exit 1 427 | #} 428 | } 429 | 430 | 431 | 432 | foreach($item in $data) { 433 | #Configure test port group VLAN ID for this particular VLAN test, or clear VLAN ID if none exists 434 | $myVlanId = $null 435 | $myVlanId = [int32](get-virtualportgroup -VMhost $vmhost -Standard:$true -name $item.PortGroup).Vlanid 436 | if($myVlanId) { 437 | $testPortGroup = $testPortGroup | Set-VirtualPortGroup -Vlanid $myVlanId 438 | } else { 439 | $testPortGroup = $testPortGroup | Set-VirtualPortGroup -VlanId 0 440 | } 441 | 442 | 443 | if( SetGuestIP $item.SourceIP $item.SubnetMask $item.GatewayIP ) { 444 | Write-Output ("Set Guest IP to " + $item.SourceIP) 445 | 446 | #Run test on each uplink individually 447 | $uplinkset = ( ($testPortGroup | Get-NicTeamingPolicy).ActiveNic + ($testPortGroup |Get-NicTeamingPolicy).StandbyNic ) |sort 448 | foreach($thisUplink in $uplinkset) { 449 | #Disable all uplinks from the test portgroup 450 | $testPortGroup | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicUnused $uplinkset 451 | #Enable only this uplink for the test portgroup 452 | $testPortGroup | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive $thisUplink 453 | 454 | #Run normal ping test 455 | $pingTestResult = TestPing $item.TestIP $timesToPing $false 456 | #Add to results 457 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 458 | $thisTest["Host"] = $vmhost.name 459 | $thisTest["PortGroupName"] = $testPortGroup.name 460 | $thisTest["VlanID"] = $testPortGroup.vlanid 461 | $thisTest["SourceIP"] = $item.SourceIP 462 | $thisTest["DestinationIP"] = $item.TestIP 463 | $thisTest["Result"] = $pingTestResult[0].tostring() 464 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 465 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 466 | $thisTest["JumboFramesTest"] = "" 467 | $thisTest["Uplink"] = $thisUplink 468 | 469 | $testResults += new-object -typename psobject -Property $thisTest 470 | 471 | #DISABLED JUMBO FRAMES TEST! 472 | if($false) { 473 | #Run jumbo frames test 474 | $pingTestResult = TestPing $item.TestIP $timesToPing $true 475 | #Add to results 476 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 477 | $thisTest["Host"] = $vmhost.name 478 | $thisTest["PortGroupName"] = $testPortGroup.name 479 | $thisTest["VlanID"] = $testPortGroup.vlanid 480 | $thisTest["SourceIP"] = $item.SourceIP 481 | $thisTest["DestinationIP"] = $item.TestIP 482 | $thisTest["Result"] = $pingTestResult[0].tostring() 483 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 484 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 485 | $thisTest["JumboFramesTest"] = "" 486 | $thisTest["Uplink"] = $thisUplink 487 | 488 | $testResults += new-object -typename psobject -Property $thisTest 489 | } 490 | } 491 | 492 | $testPortGroup | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive ($uplinkset | sort) 493 | 494 | } else { 495 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 496 | $thisTest["PortGroupName"] = $testPortGroup.name 497 | $thisTest["VlanID"] = $testPortGroup.vlanid 498 | $thisTest["SourceIP"] = $item.SourceIP 499 | $thisTest["DestinationIP"] = $item.GatewayIP 500 | $thisTest["Result"] = "false - error setting guest IP" 501 | $testResults += new-object -typename psobject -Property $thisTest 502 | } 503 | } 504 | } else { 505 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 506 | $thisTest["Result"] = "false - unable to vMotion VM to this host" 507 | $testResults += new-object -typename psobject -Property $thisTest 508 | } 509 | } 510 | } 511 | 512 | #Clean up 513 | if ($isStandard -eq $false) 514 | { 515 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup (get-vdportgroup $originalVMPortGroup) -confirm:$false 516 | Remove-VDPortGroup -VDPortGroup $testPortGroup -confirm:$false 517 | 518 | } else { 519 | $tempvm = get-vm $vmName 520 | $temphost = $tempvm |get-VMhost 521 | $portGroupToRevertTo = $temphost |get-virtualportgroup -name $temporaryVar -Standard:$true 522 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup $portGroupToRevertTo -confirm:$false 523 | write-host -Foregroundcolor:green "Waiting 5 seconds for $vm to revert back to $temporaryVar" 524 | start-sleep -seconds 5 525 | $cluster | get-vmhost | Where-Object {$_.ConnectionState -match "connected" } | ForEach-Object { 526 | $vmhost = $_ 527 | $dvs = $vmhost | get-virtualswitch -Name $dvsName 528 | $testPortGroup = $dvs | get-virtualportgroup -name $testPortGroupName -Standard:$true -VMhost $vmhost 529 | remove-virtualportgroup -virtualportgroup $testPortGroup -confirm:$false 530 | } 531 | } 532 | 533 | #Future Test Ideas 534 | #Query driver/firmware for each host's network adapters ? 535 | 536 | #Show Results 537 | $testResults | Format-Table 538 | $testResults | Export-CSV -notypeinformation $resultFile 539 | -------------------------------------------------------------------------------- /Update_VMs.ps1: -------------------------------------------------------------------------------- 1 | ##################################################################################################################### 2 | # Author: Dario Doerflinger (c) 2015-2018 3 | # Skript: Update_VMs_1.0.5.ps1 4 | # Datum: 11.10.2017 5 | # Version: 1.0.5 6 | # Original Author: AFokkema: http://ict-freak.nl/2009/07/15/powercli-upgrading-vhardware-to-vsphere-part-2-vms/ 7 | # Changelog: 8 | # - Added Support for "noreboot" on VMware Tools install 9 | # - Improved Readability and added a general variables section 10 | # - Addedd functionality to upgrade VM Version 7 VMs 11 | # - Added Snapshot Mechanism to enable Linux Tools Upgrade 12 | # - Added functionality to upgrade VM Versions to 11 13 | # - Added functionality to upgrade VM Versions to 13 (12 is only for Desktop products) 14 | # - Changed Add-Snapin to Import Module (not relevant for PowerCLI 6.5.1) 15 | # 16 | # Summary: This script will upgrade the VMWare Tools level and the hardware level from VMs 17 | ##################################################################################################################### 18 | clear 19 | Write-Host " " 20 | Write-Host " " 21 | Write-Host "######################## Update_VMs_1.0.5.ps1 ##########################" 22 | Write-Host " " 23 | Write-Host " this script updates VMware Tools und hardware." 24 | Write-Host " " 25 | Write-Host "######################################################################" 26 | Write-Host " " 27 | 28 | 29 | Import-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue | Out-Null 30 | # This script adds some helper functions and sets the appearance. 31 | #"C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\Scripts\Initialize-PowerCliEnvironment.ps1" 32 | 33 | 34 | # Variables 35 | $vCenter = Read-Host "Enter your vCenter servername" 36 | #$Folder = Read-Host "Enter the name of the folder where the VMs are stored" 37 | $timestamp = Get-Date -format "yyyyMMdd-HH.mm" 38 | # Note: enter the csv file without extension: 39 | $csvfile = "c:\tmp\$timestamp-vminfo.csv" 40 | $logFile = "c:\tmp\vm-update.log" 41 | 42 | 43 | #Rotate the Logfile 44 | if (Test-Path $logFile) 45 | { 46 | if (Test-Path c:\tmp\old_vm-update.log) 47 | { 48 | Remove-Item -Path c:\tmp\old_vm-update.log -Force -Confirm:$false 49 | } 50 | Rename-Item -Path $logfile -NewName old_vm-update.log -Force -Confirm:$false 51 | } 52 | 53 | #LogFunction: Standard at Coop! 54 | function LogWrite 55 | { 56 | #Aufruf: LogWrite "Tobi ist doof" "INFO" "1" 57 | Param([string]$logString, [string]$logLevel, [string]$priority) 58 | $nowDate = Get-Date -Format dd.MM.yyyy 59 | $nowTime = Get-Date -Format HH:mm:ss 60 | 61 | if ($logLevel -eq "EMPTY") 62 | { 63 | Add-Content $logFile -value "$logstring" 64 | Write-Host $logString 65 | } else { 66 | Add-Content $logFile -value "[$logLevel][Prio: $priority][$nowDate][$nowTime] - $logString" 67 | Write-Host "[$logLevel][Prio: $priority][$nowDate][$nowTime] - $logString" 68 | 69 | } 70 | 71 | } 72 | 73 | ################################################################ 74 | # Einlesen der Cred fuer vCenter und ESXi Server # 75 | ################################################################ 76 | #$vcCred = C:\vm-scripts\Get-myCredential.ps1 butob C:\vm-scripts\credentials 77 | #$esxCred = C:\vm-scripts\Get-myCredential.ps1 root C:\vm-scripts\host-credential 78 | 79 | ############################################################### 80 | # Prompt for Credentials # 81 | ################################################################ 82 | $vcCred = $host.ui.PromptForCredential("VCENTER LOGIN", "Provide VCENTER credentials (administrator privileges)", "", "") 83 | #$esxCred = $host.ui.PromptForCredential("ESX HOST LOGIN", "Provide ESX host credentials (probably root)", "root", "") 84 | 85 | 86 | Function Make-Snapshot($vm) 87 | { 88 | $snapshot = New-Snapshot -VM $vm -Name "BeforeUpgradeVMware" -Description "Snapshot taken before Tools and Hardware was updated" -Confirm:$false 89 | 90 | } 91 | 92 | Function Delete-Snap() 93 | { 94 | get-vm | get-snapshot -Name "BeforeUpgradeVMware" | Remove-Snapshot -Confirm:$false 95 | # $snapshot = Get-Snapshot -Name "BeforeUpgradeVMware" -VM $vm 96 | # Remove-Snapshot -Snapshot $snapshot -Confirm:$false 97 | } 98 | 99 | 100 | 101 | Function VM-Selection 102 | { 103 | $sourcetype = Read-Host "Do you want to upgrade AllVMs, a VM, Folder, ResourcePool or from a VMfile?" 104 | if($sourcetype -eq "AllVMs") 105 | { 106 | $abort = Read-Host "You've chosen $sourcetype, this is your last chance to abort by pressing +C. Press to continue selecting old hardware VMs" 107 | #$vms = Get-VM | Get-View | Where-Object {-not $_.config.template -and $_.Config.Version -eq "vmx-08" } | Select Name 108 | $vms = Get-VM | Get-View | Where-Object {-not $_.config.template} | Select Name 109 | } 110 | else 111 | { 112 | $sourcename = Read-Host "Give the name of the object or inputfile (full path) you want to upgrade" 113 | if($sourcetype -eq "VM") 114 | { 115 | $abort = Read-Host "You've chosen $sourcetype, this is your last chance to abort by pressing +C. Press to continue selecting old hardware VMs" 116 | #$vms = Get-VM $sourcename | Get-View | Where-Object {-not $_.config.template -and $_.Config.Version -eq "vmx-08" } | Select Name 117 | $vms = Get-VM $sourcename | Get-View | Where-Object {-not $_.config.template} | Select Name 118 | } 119 | elseif($sourcetype -eq "Folder") 120 | { 121 | $abort = Read-Host "You've chosen $sourcetype, this is your last chance to abort by pressing +C. Press to continue selecting old hardware VMs" 122 | #$vms = Get-Folder $sourcename | Get-VM | Get-View | Where-Object {-not $_.config.template -and $_.Config.Version -eq "vmx-08" } | Select Name 123 | $vms = Get-Folder $sourcename | Get-VM | Get-View | Where-Object {-not $_.config.template} | Select Name 124 | } 125 | elseif($sourcetype -eq "ResourcePool") 126 | { 127 | $abort = Read-Host "You've chosen $sourcetype, this is your last chance to abort by pressing +C. Press to continue selecting old hardware VMs" 128 | #$vms = Get-ResourcePool $sourcename | Get-VM | Get-View | Where-Object {-not $_.config.template -and $_.Config.Version -eq "vmx-08" } | Select Name 129 | $vms = Get-ResourcePool $sourcename | Get-VM | Get-View | Where-Object {-not $_.config.template} | Select Name 130 | } 131 | elseif(($sourcetype -eq "VMfile") -and ((Test-Path -path $sourcename) -eq $True)) 132 | { 133 | $abort = Read-Host "You've chosen $sourcetype with this file: $sourcename, this is your last chance to abort by pressing +C. Press to continue selecting old hardware VMs" 134 | #$list = Get-Content $sourcename | Foreach-Object {Get-VM $_ | Get-View | Where-Object {-not $_.config.template -and $_.Config.Version -eq "vmx-08" } | Select Name } 135 | $list = Get-Content $sourcename | Foreach-Object {Get-VM $_ | Get-View | Where-Object {-not $_.config.template} | Select Name } 136 | $vms = $list 137 | } 138 | else 139 | { 140 | Write-Host "$sourcetype is not an exact match of AllVMs, VM, Folder, ResourcePool or VMfile, or the VMfile does not exist. Exit the script by pressing +C and try again." 141 | } 142 | } 143 | return $vms 144 | } 145 | 146 | Function PowerOn-VM($vm) 147 | { 148 | Start-VM -VM $vm -Confirm:$false -RunAsync | Out-Null 149 | Write-Host "$vm is starting!" -ForegroundColor Yellow 150 | sleep 10 151 | 152 | do 153 | { 154 | $vmview = get-VM $vm | Get-View 155 | $getvm = Get-VM $vm 156 | $powerstate = $getvm.PowerState 157 | $toolsstatus = $vmview.Guest.ToolsStatus 158 | 159 | Write-Host "$vm is starting, powerstate is $powerstate and toolsstatus is $toolsstatus!" -ForegroundColor Yellow 160 | sleep 5 161 | #NOTE that if the tools in the VM get the state toolsNotRunning this loop will never end. There needs to be a timekeeper variable to make sure the loop ends 162 | 163 | }until(($powerstate -match "PoweredOn") -and (($toolsstatus -match "toolsOld") -or ($toolsstatus -match "toolsOk") -or ($toolsstatus -match "toolsNotInstalled"))) 164 | 165 | if (($toolsstatus -match "toolsOk") -or ($toolsstatus -match "toolsOld")) 166 | { 167 | $Startup = "OK" 168 | Write-Host "$vm is started and has ToolsStatus $toolsstatus" 169 | } 170 | else 171 | { 172 | $Startup = "ERROR" 173 | [console]::ForegroundColor = "Red" 174 | Read-Host "The ToolsStatus of $vm is $toolsstatus. This is unusual. Press +C to quit the script or press to continue" 175 | LogWrite "PowerOn Error detected on $vm" "ERROR" "1" 176 | [console]::ResetColor() 177 | } 178 | return $Startup 179 | } 180 | 181 | Function PowerOff-VM($vm) 182 | { 183 | Shutdown-VMGuest -VM $vm -Confirm:$false | Out-Null 184 | Write-Host "$vm is stopping!" -ForegroundColor Yellow 185 | sleep 10 186 | 187 | do 188 | { 189 | $vmview = Get-VM $vm | Get-View 190 | $getvm = Get-VM $vm 191 | $powerstate = $getvm.PowerState 192 | $toolsstatus = $vmview.Guest.ToolsStatus 193 | 194 | Write-Host "$vm is stopping with powerstate $powerstate and toolsStatus $toolsstatus!" -ForegroundColor Yellow 195 | sleep 5 196 | 197 | }until($powerstate -match "PoweredOff") 198 | 199 | if (($powerstate -match "PoweredOff") -and (($toolsstatus -match "toolsNotRunning") -or ($toolsstatus -match "toolsNotInstalled"))) 200 | { 201 | $Shutdown = "OK" 202 | Write-Host "$vm is powered-off" 203 | } 204 | else 205 | { 206 | $Shutdown = "ERROR" 207 | [console]::ForegroundColor = "Red" 208 | Read-Host "The ToolsStatus of $vm is $toolsstatus. This is unusual. Press +C to quit the script or press to continue" 209 | LogWrite "PowerOff Error detected on $vm" "ERROR" "1" 210 | [console]::ResetColor() 211 | } 212 | return $Shutdown 213 | } 214 | 215 | Function Check-ToolsStatus($vm) 216 | { 217 | $vmview = get-VM $vm | Get-View 218 | $status = $vmview.Guest.ToolsStatus 219 | 220 | if ($status -match "toolsOld") 221 | { 222 | $vmTools = "Old" 223 | } 224 | elseif($status -match "toolsNotRunning") 225 | { 226 | $vmTools = "NotRunning" 227 | } 228 | elseif($status -match "toolsNotInstalled") 229 | { 230 | $vmTools = "NotInstalled" 231 | } 232 | elseif($status -match "toolsOK") 233 | { 234 | $vmTools = "OK" 235 | } 236 | else 237 | { 238 | $vmTools = "ERROR" 239 | Read-Host "The ToolsStatus of $vm is $vmTools. Press +C to quit the script or press to continue" 240 | LogWrite "VMware Tools Error detected on $vm" "ERROR" "1" 241 | } 242 | return $vmTools 243 | } 244 | 245 | Function Check-VMHardwareVersion($vm) 246 | { 247 | $vmView = get-VM $vm | Get-View 248 | $vmVersion = $vmView.Config.Version 249 | $v7 = "vmx-07" 250 | $v8 = "vmx-08" 251 | $v9 = "vmx-09" 252 | $v10 = "vmx-10" 253 | $v11 = "vmx-11" 254 | $v13 = "vmx-13" 255 | if ($vmVersion -eq $v8) 256 | { 257 | $vmHardware = "Old" 258 | } 259 | elseif($vmVersion -eq $v7) 260 | { 261 | $vmHardware = "Old" 262 | } 263 | elseif($vmVersion -eq $v9) 264 | { 265 | $vmHardware = "Old" 266 | } 267 | elseif($vmVersion -eq $v10) 268 | { 269 | $vmHardware = "Old" 270 | } 271 | elseif($vmVersion -eq $v11) 272 | { 273 | $vmHardware = "Old" 274 | } 275 | elseif($vmVersion -eq $v13) 276 | { 277 | $vmHardware = "Ok" 278 | } 279 | else 280 | { 281 | $vmHardware = "ERROR" 282 | LogWrite "Hardware Version Error detected on $vm" "ERROR" "1" 283 | [console]::ForegroundColor = "Red" 284 | Read-Host "The Hardware version of $vm is not set to $v7 or $v8 or $v9 or $v10 or $v11 or $v13. This is unusual. Press +C to quit the script or press to continue" 285 | [console]::ResetColor() 286 | } 287 | return $vmHardware 288 | } 289 | 290 | Function Upgrade-VMHardware($vm) 291 | { 292 | $vmview = Get-VM $vm | Get-View 293 | $vmVersion = $vmView.Config.Version 294 | $v7 = "vmx-07" 295 | $v8 = "vmx-08" 296 | $v9 = "vmx-09" 297 | $v10 = "vmx-10" 298 | $v11 = "vmx-11" 299 | $v13 = "vmx-13" 300 | 301 | if ($vmVersion -eq $v7) 302 | { 303 | Write-Host "Version 7 detected" -ForegroundColor Red 304 | 305 | # Update Hardware 306 | Write-Host "Upgrading Hardware on" $vm -ForegroundColor Yellow 307 | Get-View ($vmView.UpgradeVM_Task($v13)) | Out-Null 308 | } 309 | 310 | if ($vmVersion -eq $v8) 311 | { 312 | Write-Host "Version 8 detected" -ForegroundColor Red 313 | 314 | # Update Hardware 315 | Write-Host "Upgrading Hardware on" $vm -ForegroundColor Yellow 316 | Get-View ($vmView.UpgradeVM_Task($v13)) | Out-Null 317 | } 318 | 319 | if ($vmVersion -eq $v9) 320 | { 321 | Write-Host "Version 9 detected" -ForegroundColor Red 322 | 323 | # Update Hardware 324 | Write-Host "Upgrading Hardware on" $vm -ForegroundColor Yellow 325 | Get-View ($vmView.UpgradeVM_Task($v13)) | Out-Null 326 | } 327 | 328 | if ($vmVersion -eq $v10) 329 | { 330 | Write-Host "Version 10 detected" -ForegroundColor Red 331 | 332 | # Update Hardware 333 | Write-Host "Upgrading Hardware on" $vm -ForegroundColor Yellow 334 | Get-View ($vmView.UpgradeVM_Task($v13)) | Out-Null 335 | } 336 | 337 | if ($vmVersion -eq $v11) 338 | { 339 | Write-Host "Version 10 detected" -ForegroundColor Red 340 | 341 | # Update Hardware 342 | Write-Host "Upgrading Hardware on" $vm -ForegroundColor Yellow 343 | Get-View ($vmView.UpgradeVM_Task($v13)) | Out-Null 344 | } 345 | } 346 | 347 | Function CreateHWList($vms, $csvfile) 348 | { 349 | # The setup for this hwlist comes from http://www.warmetal.nl/powerclicsvvminfo 350 | Write-Host "Creating a CSV File with VM info" -ForegroundColor Yellow 351 | 352 | $MyCol = @() 353 | ForEach ($item in $vms) 354 | { 355 | $vm = $item.Name 356 | # Variable getvm is required, for some reason the $vm cannot be used to query the host and the IP-address 357 | $getvm = Get-VM $VM 358 | $vmview = Get-VM $VM | Get-View 359 | 360 | # VM has to be turned on to make sure all information can be recorded 361 | $powerstate = $getvm.PowerState 362 | if ($powerstate -ne "PoweredOn") 363 | { 364 | PowerOn-VM $vm 365 | } 366 | 367 | $vmnic = Get-NetworkAdapter -VM $VM 368 | $nicmac = Get-NetworkAdapter -VM $VM | ForEach-Object {$_.MacAddress} 369 | $nictype = Get-NetworkAdapter -VM $VM | ForEach-Object {$_.Type} 370 | $nicname = Get-NetworkAdapter -VM $VM | ForEach-Object {$_.NetworkName} 371 | $VMInfo = "" | Select VMName,NICCount,IPAddress,MacAddress,NICType,NetworkName,GuestRunningOS,PowerState,ToolsVersion,ToolsStatus,ToolsRunningStatus,HWLevel,VMHost 372 | $VMInfo.VMName = $vmview.Name 373 | $VMInfo.NICCount = $vmview.Guest.Net.Count 374 | $VMInfo.IPAddress = [String]$getvm.Guest.IPAddress 375 | $VMInfo.MacAddress = [String]$nicmac 376 | $VMInfo.NICType = [String]$nictype 377 | $VMInfo.NetworkName = [String]$nicname 378 | $VMInfo.GuestRunningOS = $vmview.Guest.GuestFullname 379 | $VMInfo.PowerState = $getvm.PowerState 380 | $VMInfo.ToolsVersion = $vmview.Guest.ToolsVersion 381 | $VMInfo.ToolsStatus = $vmview.Guest.ToolsStatus 382 | $VMInfo.ToolsRunningStatus = $vmview.Guest.ToolsRunningStatus 383 | $VMInfo.HWLevel = $vmview.Config.Version 384 | $VMInfo.VMHost = $getvm.VMHost 385 | $myCol += $VMInfo 386 | } 387 | 388 | if ((Test-Path -path $csvfile) -ne $True) 389 | { 390 | $myCol |Export-csv -NoTypeInformation $csvfile 391 | } 392 | else 393 | { 394 | $myCol |Export-csv -NoTypeInformation $csvfile-after.csv 395 | } 396 | } 397 | 398 | Function CheckAndUpgradeTools($vm) 399 | { 400 | $vmview = Get-VM $VM | Get-View 401 | $family = $vmview.Guest.GuestFamily 402 | $vmToolsStatus = Check-ToolsStatus $vm 403 | 404 | if($vmToolsStatus -eq "OK") 405 | { 406 | Write-Host "The VM tools are $vmToolsStatus on $vm" 407 | } 408 | elseif(($family -eq "windowsGuest") -and ($vmToolsStatus -ne "NotInstalled")) 409 | { 410 | Write-Host "The VM tools are $vmToolsStatus on $vm. Starting update/install now! This will take at few minutes." -ForegroundColor Red 411 | Get-Date 412 | Get-VMGuest $vm | Update-Tools -NoReboot 413 | do 414 | { 415 | sleep 10 416 | Write-Host "Checking ToolsStatus $vm now" 417 | $vmToolsStatus = Check-ToolsStatus $vm 418 | }until($vmToolsStatus -eq "OK") 419 | PowerOff-VM $vm 420 | PowerOn-VM $vm 421 | } 422 | else 423 | { 424 | LogWrite "Linux / Windows (no tools installed) detected: $vm" "WARNING" "1" 425 | # ToDo: If the guest is running windows but tools notrunning/notinstalled it might be an option to invoke the installation through powershell. 426 | # Options are then Invoke-VMScript cmdlet or through windows installer: msiexec-i "D: \ VMware Tools64.msi" ADDLOCAL = ALL REMOVE = Audio, Hgfs, VMXNet, WYSE, GuestSDK, VICFSDK, VAssertSDK / qn 427 | # We're skipping all non-windows guest since automated installs are not supported 428 | # Write-Host "$vm is a $family with tools status $vmToolsStatus. Therefore we're skipping this VM" -ForegroundColor Red 429 | 430 | Write-Host "$vm is a $family with tools status $vmToolsStatus. We are going to do the upgrade, but we'll take a snapshot beforehand" 431 | if ($vmToolsStatus -ne "NotInstalled") 432 | { 433 | Make-Snapshot $vm 434 | Get-Date 435 | Get-VMGuest $vm | Update-Tools -NoReboot 436 | do 437 | { 438 | sleep 10 439 | Write-Host "Checking ToolsStatus $vm now" 440 | $vmToolsStatus = Check-ToolsStatus $vm 441 | }until($vmToolsStatus -eq "OK") 442 | PowerOff-VM $vm 443 | PowerOn-VM $vm 444 | 445 | } 446 | 447 | 448 | } 449 | } 450 | 451 | Function CheckAndUpgrade($vm) 452 | { 453 | $vmHardware = Check-VMHardwareVersion $vm 454 | $vmToolsStatus = Check-ToolsStatus $vm 455 | 456 | if($vmHardware -eq "OK") 457 | { 458 | Write-Host "The hardware level is $vmHardware on $vm" 459 | } 460 | elseif($vmToolsStatus -eq "OK") 461 | { 462 | Write-Host "The hardware level is $vmHardware on $vm." -ForegroundColor Red 463 | $PowerOffVM = PowerOff-VM $vm 464 | if($PowerOffVM -eq "OK") 465 | { 466 | Write-Host "Starting upgrade hardware level on $vm." 467 | Upgrade-VMHardware $vm 468 | sleep 5 469 | PowerOn-VM $vm 470 | Write-Host $vm "is up to date" -ForegroundColor Green 471 | } 472 | else 473 | { 474 | Write-Host "There is something wrong with the hardware level or the tools of $vm. Skipping $vm." 475 | } 476 | } 477 | } 478 | 479 | Connect-VIServer -Server $vcenter -Credential $vcCred -WarningAction SilentlyContinue | out-null 480 | Write-Host "connecting to $vcenter" 481 | 482 | $vms = VM-Selection 483 | CreateHWList $vms $csvfile 484 | foreach($item in $vms) 485 | { 486 | $vm = $item.Name 487 | Write-Host "Test $vm" 488 | CheckAndUpgradeTools $vm 489 | CheckAndUpgrade $vm 490 | } 491 | CreateHWList $vms $csvfile 492 | # $toggle = Read-Host "Would you like me to remove the snapshots taken on Linux VMs? (yes/no)" 493 | # if ($toggle -eq "yes") 494 | # { 495 | # Get-VM | Delete-Snap 496 | # } 497 | Disconnect-VIServer -Confirm:$false 498 | 499 | -------------------------------------------------------------------------------- /VmAutomatedDeployment.ps1: -------------------------------------------------------------------------------- 1 | ############################################################################################ 2 | # Script name: VmAutomatedDeployment.ps1 3 | # Description: For simple virtual machine container provisioning use only. 4 | # Version: 1.2 5 | # Date: 02.02.2017 6 | # Author: Dario Doerflinger 7 | # History: 02.02.2017 - First tested release 8 | # 19.07.2017 - Replaced Portgroup for Networkname, diskformat and resource pool based on hostname 9 | # 19.07.2017 - Added return value: MAC Address of created VM as requested by customer 10 | ############################################################################################ 11 | 12 | # Example: # e.g.: .\VmAutomatedDeployment.ps1 -vm_name Test_A053763 -vm_guestid windows9_64Guest -vm_memory 2048 -vm_cpu 2 -vm_network "Server_2037_L2" 13 | 14 | param ( 15 | 16 | [string]$vm_guestid, # GuestOS identifier from VMware e.g. windows_64Guest for Windows 10 x64 17 | [string]$vm_name, # Name of the virtual machine 18 | #[int64]$vm_disk, # System disk size in GB 19 | [int32]$vm_memory, # Memory size in MB 20 | [int32]$vm_cpu, # Amount of vCPUs 21 | [string]$vm_network # Portgroup name to connect 22 | #[string]$vm_folder # VM Folder location 23 | 24 | # to get the GuestOS identifier run: [VMware.Vim.VirtualMachineGuestOsIdentifier].GetEnumValues() 25 | # Common Windows versions: 26 | #------------------------- 27 | # windows7_64Guest // Windows 7 (x64) 28 | # windows7Server64Guest // Windows Server 2008 R2 29 | # windows8_64Guest // Windows 8 (x64) 30 | # windows8Server64Guest // Windows Server 2012 R2 31 | # windows9_64Guest // Windows 10 (x64) 32 | # windows9Server64Guest // Windows Server 2016 33 | ) 34 | 35 | # clear global ERROR variable 36 | $Error.Clear() 37 | 38 | # import vmware related modules, get the credentials and connect to the vCenter server 39 | Import-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue | Out-Null 40 | Import-Module -Name VMware.VimAutomation.Vds -ErrorAction SilentlyContinue |Out-Null 41 | $creds = Get-VICredentialStoreItem -file "C:\scripts\VmAutomatedDeployment\login.creds" 42 | Connect-VIServer -Server $creds.Host -User $creds.User -Password $creds.Password |Out-Null 43 | 44 | # define global variables 45 | $init_cluster = 'virtualFrogLab' 46 | $init_datastore = 'VF_ds_01' 47 | $vm_folder = 'VM-Staging' 48 | $current_date = $(Get-Date -format "dd.MM.yyyy HH:mm:ss") 49 | $log_file = "C:\Scripts\VmAutomatedDeployment\log_$(Get-Date -format "yyyyMMdd").txt" 50 | [int64]$vm_disk = 72 51 | $dvPortGroup = Get-VDPortgroup -Name $vm_network 52 | 53 | # check if var $VM_NAME already exists in the vCenter inventory 54 | 55 | $CheckInventoryByVmName = Get-VM -Name $vm_name -ErrorAction Ignore 56 | 57 | if ($CheckInventoryByVmName) { 58 | 59 | Write-Host "This virtual machine already exists!" 60 | 61 | } else { 62 | 63 | # check the inputs for provisioning sizing of the virtual machine 64 | # allowed maximums: 2 vCPU / 8192MB vRAM / 100GB vDISK 65 | 66 | if ($vm_cpu -gt 2) {Write-Host "You input is invalid! (max. 2 vCPUs allowed)"} 67 | elseif ($vm_memory -gt 8192) {Write-Host "You input is invalid! (max. 8GB vRAM allowed)"} 68 | elseif ($vm_disk -gt 100) {Write-Host "You input is invalid! (max. 100GB vDisk size allowed)"} 69 | else { 70 | 71 | # create new virtual machine container 72 | # e.g.: .\VmAutomatedDeployment.ps1 -vm_name Test_A054108 -vm_guestid windows9_64Guest -vm_disk 72 -vm_memory 2048 -vm_cpu 2 -vm_network "Test 10.10.0.0" 73 | if ($vm_name -like "vm-t*") 74 | { 75 | $diskformat = "Thin" 76 | $init_cluster ="Test" 77 | }else { 78 | $diskformat = "Thick" 79 | $init_cluster = "Production" 80 | } 81 | $create_vm = New-VM -Name $vm_name -GuestId $vm_guestid -Location $vm_folder -ResourcePool $init_cluster -Datastore $init_datastore -DiskGB $vm_disk -DiskStorageFormat $diskformat -MemoryMB $vm_memory -NumCpu $vm_cpu -Portgroup $dvPortGroup -CD -Confirm:$false -ErrorAction SilentlyContinue 82 | 83 | # check if virtual machine exists 84 | if ($create_vm) { 85 | # change all network adapters to VMXNET3 86 | $change_vm_network = Get-VM -Name $create_vm | Get-NetworkAdapter | Set-NetworkAdapter -Type Vmxnet3 -Confirm:$false -ErrorAction SilentlyContinue 87 | 88 | # check if network adapter exists 89 | if ($change_vm_network) { 90 | Add-Content -Path $log_file -Value "$current_date SCRIPT $message" 91 | $macaddress = (get-vm -Name $create_vm |get-networkadapter).MacAddress 92 | } else { 93 | Write-Host "There was an unexpected error during the provisioning. For more information see log file: $log_file" 94 | } 95 | } else { 96 | Write-Host "There was an unexpected error during the provisioning. For more information see log file: $log_file" 97 | 98 | } 99 | 100 | } 101 | 102 | } 103 | 104 | # cleanup and removal of loaded VMware modules 105 | Disconnect-VIServer -Server $creds.Host -Confirm:$false 106 | Remove-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue | Out-Null 107 | 108 | # write all error messages to the log file 109 | Add-Content -Path $log_file -Value $Error 110 | 111 | #return the MAC address 112 | return $macaddress 113 | -------------------------------------------------------------------------------- /bkp_rst_vcsa.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #*************************************************************** 4 | # Get Options from the command line 5 | #*************************************************************** 6 | while getopts "b:r:h" options 7 | do 8 | case $options in 9 | b ) opt_b=$OPTARG;; 10 | r ) opt_r=$OPTARG;; 11 | h ) opt_h=1;; 12 | \? ) opt_h=1;; 13 | esac 14 | done 15 | 16 | 17 | ############################################### 18 | # bkp_rst.sh 19 | #============================================= 20 | # Name: bkp_rst.sh 21 | # Datum: 24.07.2017 22 | # Ziel: Mache ein Backup der vCenter Appliance Datenbank, Restore die Datenbank 23 | # 24 | # Autor: Dario aka virtualFrog 25 | version="1.5" 26 | # 27 | # Changelog: 28 | # 0.1 dario Initial-Setup 29 | # 1.0 dario Testing, Testing, Testing 30 | # 1.1 dario Added dynamic filename & cleanUp Function 31 | # 1.2 dario Added local cleanup 32 | # 1.3 dario Changed local cleanup to delete all but most recent 3 files 33 | # 1.4 dario Added checkForErrors function and writeMail function 34 | # 1.5 dario Added CheckForErrors before every exit statement 35 | 36 | 37 | 38 | # Variablen 39 | # --------- 40 | 41 | #log-Variablen 42 | log=/var/log/vmware_backup_restore.log 43 | 44 | #Mail variabeln 45 | recipients="virtualfrog@virtualfrog.com" 46 | 47 | #NFS-Parameter 48 | nfsmount="vcsa" 49 | nfsserver="" 50 | nfsoptions="nfs4" 51 | 52 | # Funktionen 53 | # ---------- 54 | 55 | function print_banner 56 | { 57 | echo " 58 | 59 | ___ __ ____ ___________ 60 | \ \/ // ___\ / ___/\__ \ 61 | 62 | \ /\ \___ \___ \ / __ \_ 63 | \_/ \___ >____ >(____ / 64 | \/ \/ \/ 65 | " 66 | echo "v$version" 67 | } 68 | 69 | function get_parameter 70 | { 71 | echo "GET_PARAMETER" 72 | 73 | if [ $opt_h ]; then print_help 74 | fi 75 | 76 | #-------------------------------------- 77 | # Check to see if -b was passed in 78 | #-------------------------------------- 79 | if [ $opt_b ]; then 80 | backup_string=$opt_b 81 | echo -e "\tBackup: $backup_string" 82 | echo "Backup: $backup_string" >> $log 83 | echo "" 84 | validate_backup_path 85 | filename=`hostname`-`date +%Y-%d-%m:%H:%M:%S`.bak 86 | todo="backup" 87 | echo "" 88 | elif [ $opt_r ]; then 89 | restore_string=$opt_r 90 | echo -e "\tRestore: $restore_string" 91 | echo "Restore: $restore_string" >> $log 92 | echo "" 93 | validate_restore_path 94 | todo="restore" 95 | echo "" 96 | else 97 | echo "warning: no parameters supplied." >> $log 98 | echo -e "\tKeine Parameter gefunden." 99 | print_help 100 | fi 101 | 102 | } 103 | 104 | function print_help 105 | { 106 | echo "Gueltige Parameter: -b -r " 107 | echo "" 108 | echo "To restore you should mount the volume ($nfsmount) on ($nfsserver) which this script copies the backups to" 109 | exit 0 110 | } 111 | 112 | function init_log 113 | { 114 | 115 | echo `date` > $log 116 | echo "fzag_bkp_rst.sh in der Version $version auf `hostname -f`" >> $log 117 | echo "____________________________________________" >> $log 118 | 119 | #echo "Nun startet das Script in der Version $version" 120 | echo "" 121 | } 122 | function validate_backup_path 123 | { 124 | echo "VALIDATE BACKUP PATH" 125 | echo -e "\tChecking Backup Path: $backup_string" 126 | if [ ! -d "$backup_string" ]; then 127 | echo -e "\tDirectory did not exist. Creating.." 128 | mkdir -p $backup_string 129 | echo -e "\tDirectory created." 130 | else 131 | echo -e "\tDirectory does exist." 132 | fi 133 | echo "" 134 | } 135 | 136 | function validate_restore_path 137 | { 138 | echo "VALIDATE RESTORE PATH" 139 | echo -e "\tChecking Backup Path: $restore_string" 140 | if [ -f $restore_string ]; 141 | then 142 | echo -e "\tFile $restore_string exists." 143 | echo "File $restore_string exists." >> $log 144 | else 145 | echo -e "\tFile $restore_string does not exist. Exiting" 146 | echo "error: $restore_string does not exist." >> $log 147 | checkForErrors 148 | exit 1 149 | fi 150 | echo "" 151 | } 152 | function check_python_scripts 153 | { 154 | echo "CHECK PYTHON SCRIPTS" 155 | echo -e "\tChecking if Python Scripts are available" 156 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 157 | if [ -f "$DIR/backup_lin.py" ]; then 158 | echo -e "\tBackup Script found, continue.." 159 | echo "script for backup found" >> $log 160 | if [ -f "$DIR/restore_lin.py" ]; then 161 | echo -e "\tRestore Script found, continue.." 162 | echo "script for restore found" >> $log 163 | else 164 | echo -e "\tNo restore script found, exit" 165 | echo "error: no python restore script found" >> $log 166 | checkForErrors 167 | exit 1 168 | fi 169 | else 170 | echo -e "\tNo backup script found, exit" 171 | echo "error: no python backup scripts found" >> $log 172 | checkForErrors 173 | exit 1 174 | fi 175 | echo "" 176 | } 177 | 178 | function create_backup 179 | { 180 | echo "CREATE BACKUP" 181 | echo -e "\tCreating the Backup in the file $backup_string/bk.bak:" 182 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 183 | 184 | echo `python $DIR/backup_lin.py -f $backup_string/$filename` >> $log 185 | if [ $? -ne 0 ]; then 186 | echo -e "\tError: Return code from backup job was not 0" 187 | echo "error: return code from backup job was not 0" >> $log 188 | checkForErrors 189 | exit 1 190 | else 191 | if [ -f "$backup_string/$filename" ]; then 192 | echo -e "\tSuccess! Backup created." 193 | echo "success: backup created" >> $log 194 | fi 195 | fi 196 | echo "" 197 | } 198 | 199 | function restore_db 200 | { 201 | echo "RESTORE DB" 202 | echo -e "\tRestoring Database with supplied Backup-File: $restore_string" 203 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 204 | echo `python $DIR/restore_lin.py -f $restore_string` >> $log 205 | if [ $? -ne 0 ]; then 206 | echo -e "\tError: Return code from restore job was not 0" 207 | echo "error: return code from restore job was not 0" >> $log 208 | fi 209 | echo "" 210 | 211 | } 212 | 213 | function mountNFS 214 | { 215 | echo "MOUNT NFS" 216 | echo -e "\tMounting the given NFS Volume ($nfsmount) on server ($nfsserver)" 217 | if [[ ! -d /mnt/bkp ]]; then 218 | mkdir -p /mnt/bkp 219 | fi 220 | 221 | mount -t $nfsoptions $nfsserver:$nfsmount /mnt/bkp 222 | if [[ $? -ne 0 ]]; then 223 | echo -e "\tMount was not successful. Abort the operation" 224 | echo "mount was not successful" >> $log 225 | checkForErrors 226 | exit 1 227 | fi 228 | echo "" 229 | return 0 230 | } 231 | 232 | function copyBackup 233 | { 234 | echo "COPY BACKUP" 235 | echo -e "\tCopying Backup to NFS Mount" 236 | cp $backup_string/$filename /mnt/bkp/ 237 | if [[ $? -ne 0 ]]; then 238 | echo -e "\tCopy Operation was not successful. Abort the operation" 239 | echo "copy was not successful" >> $log 240 | checkForErrors 241 | exit 1 242 | fi 243 | echo "" 244 | } 245 | 246 | function unMountNFS 247 | { 248 | echo "UMOUNT NFS" 249 | echo -e "\tUnmounting the NFS Mount" 250 | umount /mnt/bkp 251 | if [[ $? -ne 0 ]]; then 252 | echo -e "\tumount Operation was not successful." 253 | echo "umount was not successful" >> $log 254 | fi 255 | echo "" 256 | } 257 | 258 | function cleanUp 259 | { 260 | echo "CLEAN UP" 261 | echo -e "\tCleaning up Backups older than 4 days and all local files but the 3 most recent" 262 | 263 | find /mnt/bkp -mtime +4 -exec rm -rf {} \; 264 | if [[ $? -ne 0 ]]; then 265 | echo -e "\tNFS cleanUp Operation was not successful." 266 | echo "NFS cleanUp was not successful" >> $log 267 | fi 268 | 269 | #find $backup_string -mtime +1 -exec rm -rf {} \; 270 | cd $backup_string 271 | ls -t1 $backup_string |tail -n +3 | xargs rm 272 | if [[ $? -ne 0 ]]; then 273 | echo -e "\tLocal cleanUp Operation was not successful." 274 | echo "local cleanUp was not successful" >> $log 275 | fi 276 | echo "" 277 | } 278 | 279 | function writeEmail 280 | { 281 | echo "WRITE EMAIL" 282 | echo -e "\tSending the logfile as a mail to $recipients" 283 | subject="VCSA Backup has run into a error" 284 | from="root@`hostname -f`" 285 | body=`cat $log` 286 | 287 | /usr/sbin/sendmail "$recipients" <> $log 327 | service vmware-vdcs stop >> $log 328 | restore_db 329 | service-control --start vmware-vpxd >> $log 330 | service-control --start vmware-vdcs >> $log 331 | unMountNFS 332 | checkForErrors 333 | fi -------------------------------------------------------------------------------- /get_percentage_cluster_usage.ps1: -------------------------------------------------------------------------------- 1 | $clusters = get-cluster 2 | $myClusters = @() 3 | foreach ($cluster in $clusters) { 4 | $hosts = $cluster |get-vmhost 5 | 6 | [double]$cpuAverage = 0 7 | [double]$memAverage = 0 8 | 9 | Write-Host $cluster 10 | foreach ($esx in $hosts) { 11 | Write-Host $esx 12 | [double]$esxiCPUavg = [double]($esx | Select-Object @{N = 'cpuAvg'; E = {[double]([math]::Round(($_.CpuUsageMhz) / ($_.CpuTotalMhz) * 100, 2))}} |Select-Object -ExpandProperty cpuAvg) 13 | $cpuAverage = $cpuAverage + $esxiCPUavg 14 | 15 | [double]$esxiMEMavg = [double]($esx | Select-Object @{N = 'memAvg'; E = {[double]([math]::Round(($_.MemoryUsageMB) / ($_.MemoryTotalMB) * 100, 2))}} |select-object -ExpandProperty memAvg) 16 | $memAverage = $memAverage + $esxiMEMavg 17 | } 18 | $cpuAverage = [math]::Round(($cpuAverage / ($hosts.count) ), 1) 19 | $memAverage = [math]::Round(($memAverage / ($hosts.count) ), 1) 20 | $ClusterInfo = "" | Select-Object Name, CPUAvg, MEMAvg 21 | $ClusterInfo.Name = $cluster.Name 22 | $ClusterInfo.CPUAvg = $cpuAverage 23 | $ClusterInfo.MEMAvg = $memAverage 24 | $myClusters += $ClusterInfo 25 | } 26 | $myClusters -------------------------------------------------------------------------------- /testHostNetworking.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Run various networking tests on all hosts in a cluster, using a test VM. 4 | Can be run on a dvSwitch or a Standard Switch 5 | .DESCRIPTION 6 | Using a Microsoft Windows test VM, iterate through a list of port groups and 7 | subnets (specified in the CSV input file) and run tests. 8 | Testing method involves assigning the test VM to a specific port group or VLAN ID, 9 | assigning IP information and running a test ping. 10 | 11 | Currently, performs the following tests: 12 | Test connectivity with VM on each port group 13 | Test connectivity for each VLAN ID on each uplink on each host in the cluster. 14 | .PARAMETER csvFile 15 | Input - CSV file containing IP info to test. Must contain the following columns. 16 | Port Group - a valid port group name available on the specified DVS 17 | Source IP - IP to assign to the test VM for this port group 18 | Gateway IP - Gateway to assign to the test VM 19 | SubnetMask - Subnet mask to assign to test VM 20 | Test IP - IP address to target for ping test 21 | 22 | This is example data: 23 | PortGroup,SourceIP,GatewayIP,SubnetMask,TestIP 24 | PG_NET1,10.10.101.55,10.10.101.1,255.255.255.0,10.0.0.1 25 | PG_NET2,10.10.102.55,10.10.102.1,255.255.255.0,10.0.0.1 26 | .PARAMETER creds 27 | The username and password for the guest OS of the test VM. 28 | .PARAMETER vmName 29 | A powered on Windows OS virtual machine with UAC disabled and VMware tools running. 30 | Note this VM will be vMotioned, network reassigned, and IP address changed by this script! 31 | .EXAMPLE 32 | . 33 | .NOTES 34 | Author: Jeff Green; Dario Doerflinger 35 | Date: July 10, 2015; July 25, 2017 36 | Original script from https://virtualdatacave.com/2015/07/test-host-networking-for-many-hosts-and-port-groups-vlans/ 37 | Port to Standard Switch requested by VMware Code Community 38 | Port Author: Dario Doerflinger 39 | 40 | #> 41 | 42 | param 43 | ( 44 | [Parameter(Mandatory=$true)] 45 | [string]$clusterName, 46 | [Parameter(Mandatory=$true)] 47 | [string]$dvsName, 48 | [Parameter(Mandatory=$true)] 49 | [boolean]$isStandard, 50 | [Parameter(Mandatory=$true)] 51 | [pscredential]$creds, 52 | [Parameter(Mandatory=$true)] 53 | [string]$vmName, 54 | [Parameter(Mandatory=$true)] 55 | [string]$csvFile, 56 | [int]$timesToPing = 1, 57 | [int]$pingReplyCountThreshold = 1, 58 | [Parameter(Mandatory=$true)] 59 | [string]$resultFile 60 | ) 61 | 62 | #Setup 63 | 64 | # Configure internal variables 65 | $trustVMInvokeable = $false #this is to speed development only. Set to false. 66 | $testResults = @() 67 | $testPortGroupName = "VirtualFrog" 68 | $data = import-csv $csvFile 69 | $cluster = get-cluster $clusterName 70 | $vm = get-vm $vmName 71 | 72 | if ($isStandard -eq $false) { 73 | $dvs = get-vdswitch $dvsName 74 | $originalVMPortGroup = ($vm | get-Networkadapter)[0].networkname 75 | if ($originalVMPortGroup -eq "") { 76 | $originalVMPortGroup = ($vm | get-virtualswitch -name $dvsName |get-virtualportgroup)[0] 77 | write-host -Foregroundcolor:red "Adding a fantasy Name to $originalVMPortGroup" 78 | } 79 | } else { 80 | $originalVMPortGroup = ($vm | get-Networkadapter)[0].networkname 81 | $temporaryVar = ($vm |get-networkadapter)[0].NetworkName 82 | if ($originalVMPortGroup -eq "") { 83 | $originalVMPortGroup = ($vm |get-vmhost |get-virtualswitch -name $dvsName |get-virtualportgroup -Standard:$true)[0] 84 | write-host -Foregroundcolor:red "Adding a fantasy Name to $originalVMPortGroup" 85 | } 86 | } 87 | #We'll use this later to reset the VM back to its original network location if it's empty for some reason wel'll populate it with the first portgroup 88 | 89 | 90 | 91 | 92 | 93 | 94 | #Test if Invoke-VMScript works 95 | if(-not $trustVMInvokeable) { 96 | if (-not (Invoke-VMScript -ScriptText "echo test" -VM $vm -GuestCredential $creds).ScriptOutput -eq "test") { 97 | write-output "Unable to run scripts on test VM guest OS!" 98 | return 1 99 | } 100 | } 101 | 102 | #Define Test Functions 103 | function TestPing($ip, $count, $mtuTest) { 104 | if($mtuTest) { 105 | $count = 4 #Less pings for MTU test 106 | $pingReplyCountThreshold = 3 #Require 3 responses for success on MTU test. Note this scope is local to function and will not impact variable for future run. 107 | $script = "ping -f -l 8972 -n $count $ip" 108 | } else { 109 | $script = "ping -n $count $ip" 110 | } 111 | 112 | write-host "Script to run: $script" 113 | $result = Invoke-VMScript -ScriptText $script -VM $vm -GuestCredential $creds 114 | 115 | #parse the output for the "received packets" number 116 | $rxcount = (( $result.ScriptOutput | ? { $_.indexof("Packets") -gt -1 } ).Split(',') | ? { $_.indexof("Received") -gt -1 }).split('=')[1].trim() 117 | 118 | #if we received enough ping replies, consider this a success 119 | $success = ([int]$rxcount -ge $pingReplyCountThreshold) 120 | 121 | #however there is one condition where this will be a false positive... gateway reachable but destination not responding 122 | if ( $result.ScriptOutput | ? { $_.indexof("host unreach") -gt -1 } ) { 123 | $success = $false 124 | $rxcount = 0; 125 | } 126 | 127 | write-host "Full results of ping test..." 128 | write-host $result.ScriptOutput 129 | 130 | return @($success, $count, $rxcount); 131 | } 132 | 133 | function SetGuestIP($ip, $subnet, $gw) { 134 | $script = @" 135 | `$iface = (gwmi win32_networkadapter -filter "netconnectionstatus = 2" | select -First 1).interfaceindex 136 | netsh interface ip set address name=`$iface static $ip $subnet $gw 137 | netsh interface ipv4 set subinterface `$iface mtu=9000 store=active 138 | "@ 139 | write-host "Script to run: " + $script 140 | return (Invoke-VMScript -ScriptText $script -VM $vm -GuestCredential $creds) 141 | } 142 | 143 | #Tests 144 | # Per Port Group Tests (Test each port group) 145 | 146 | $vmhost = $vm.vmhost 147 | if ($isStandard -eq $false) 148 | { 149 | foreach($item in $data) { 150 | if($testPortGroup = $dvs | get-vdportgroup -name $item.PortGroup) { 151 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup $testPortGroup -confirm:$false 152 | if( SetGuestIP $item.SourceIP $item.SubnetMask $item.GatewayIP ) { 153 | echo ("Set Guest IP to " + $item.SourceIP) 154 | 155 | #Run normal ping test 156 | $pingTestResult = TestPing $item.TestIP $timesToPing $false 157 | #Add to results 158 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 159 | $thisTest["Host"] = $vmhost.name 160 | $thisTest["PortGroupName"] = $testPortGroup.name 161 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 162 | $thisTest["SourceIP"] = $item.SourceIP 163 | $thisTest["DestinationIP"] = $item.TestIP 164 | $thisTest["Result"] = $pingTestResult[0].tostring() 165 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 166 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 167 | $thisTest["JumboFramesTest"] = "" 168 | $thisTest["Uplink"] = $thisUplink 169 | 170 | $testResults += new-object -typename psobject -Property $thisTest 171 | 172 | #DISABLED JUMBO FRAMES TEST! 173 | if($false) { 174 | #Run jumbo frames test 175 | $pingTestResult = TestPing $item.TestIP $timesToPing $true 176 | #Add to results 177 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 178 | $thisTest["Host"] = $vmhost.name 179 | $thisTest["PortGroupName"] = $testPortGroup.name 180 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 181 | $thisTest["SourceIP"] = $item.SourceIP 182 | $thisTest["DestinationIP"] = $item.TestIP 183 | $thisTest["Result"] = $pingTestResult[0].tostring() 184 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 185 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 186 | $thisTest["JumboFramesTest"] = "" 187 | $thisTest["Uplink"] = $thisUplink 188 | 189 | $testResults += new-object -typename psobject -Property $thisTest 190 | } 191 | 192 | 193 | } else { 194 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 195 | $thisTest["PortGroupName"] = $testPortGroup.name 196 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 197 | $thisTest["SourceIP"] = $item.SourceIP 198 | $thisTest["DestinationIP"] = $item.GatewayIP 199 | $thisTest["Result"] = "false - error setting guest IP" 200 | $testResults += new-object -typename psobject -Property $thisTest 201 | } 202 | } else { 203 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 204 | $thisTest["PortGroupName"] = $item.PortGroup 205 | $thisTest["Result"] = "false - could not find port group" 206 | $testResults += new-object -typename psobject -Property $thisTest 207 | } 208 | } 209 | } 210 | else { 211 | #This is for a Standard Switch 212 | foreach($item in $data) { 213 | $dvs = $vm |get-vmhost | get-virtualswitch -name $dvsName 214 | if($testPortGroup = $dvs | get-virtualportgroup -name $item.PortGroup) { 215 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup $testPortGroup -confirm:$false 216 | if( SetGuestIP $item.SourceIP $item.SubnetMask $item.GatewayIP ) { 217 | echo ("Set Guest IP to " + $item.SourceIP) 218 | 219 | #Run normal ping test 220 | $pingTestResult = TestPing $item.TestIP $timesToPing $false 221 | #Add to results 222 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 223 | $thisTest["Host"] = $vmhost.name 224 | $thisTest["PortGroupName"] = $testPortGroup.name 225 | $thisTest["VlanID"] = $testPortGroup.vlanid 226 | $thisTest["SourceIP"] = $item.SourceIP 227 | $thisTest["DestinationIP"] = $item.TestIP 228 | $thisTest["Result"] = $pingTestResult[0].tostring() 229 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 230 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 231 | $thisTest["JumboFramesTest"] = "" 232 | $thisTest["Uplink"] = $thisUplink 233 | 234 | $testResults += new-object -typename psobject -Property $thisTest 235 | 236 | #DISABLED JUMBO FRAMES TEST! 237 | if($false) { 238 | #Run jumbo frames test 239 | $pingTestResult = TestPing $item.TestIP $timesToPing $true 240 | #Add to results 241 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 242 | $thisTest["Host"] = $vmhost.name 243 | $thisTest["PortGroupName"] = $testPortGroup.name 244 | $thisTest["VlanID"] = $testPortGroup.vlanid 245 | $thisTest["SourceIP"] = $item.SourceIP 246 | $thisTest["DestinationIP"] = $item.TestIP 247 | $thisTest["Result"] = $pingTestResult[0].tostring() 248 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 249 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 250 | $thisTest["JumboFramesTest"] = "" 251 | $thisTest["Uplink"] = $thisUplink 252 | 253 | $testResults += new-object -typename psobject -Property $thisTest 254 | } 255 | 256 | 257 | } else { 258 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 259 | $thisTest["PortGroupName"] = $testPortGroup.name 260 | $thisTest["VlanID"] = $testPortGroup.vlanid 261 | $thisTest["SourceIP"] = $item.SourceIP 262 | $thisTest["DestinationIP"] = $item.GatewayIP 263 | $thisTest["Result"] = "false - error setting guest IP" 264 | $testResults += new-object -typename psobject -Property $thisTest 265 | } 266 | } else { 267 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 268 | $thisTest["PortGroupName"] = $item.PortGroup 269 | $thisTest["Result"] = "false - could not find port group" 270 | $testResults += new-object -typename psobject -Property $thisTest 271 | } 272 | } 273 | } 274 | 275 | 276 | # Per Host Tests (Test Each Link for Each VLAN ID on each host) 277 | $testPortGroup = $null 278 | 279 | if ($isStandard -eq $false) 280 | { 281 | 282 | ($testPortGroup = new-vdportgroup $dvs -Name $testPortGroupName -ErrorAction silentlyContinue) -or ($testPortGroup = $dvs | get-vdportgroup -Name $testPortGroupName) 283 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup $testPortGroup -confirm:$false 284 | 285 | $cluster | get-vmhost | ? {$_.ConnectionState -match "connected" } | foreach { 286 | $vmhost = $_ 287 | #Migrate VM to new host 288 | if(Move-VM -VM $vm -Destination $vmhost) { 289 | 290 | foreach($item in $data) { 291 | #Configure test port group VLAN ID for this particular VLAN test, or clear VLAN ID if none exists 292 | $myVlanId = $null 293 | $myVlanId = (get-vdportgroup -name $item.PortGroup).VlanConfiguration.Vlanid 294 | if($myVlanId) { 295 | $testPortGroup = $testPortGroup | Set-VDVlanConfiguration -Vlanid $myVlanId 296 | } else { 297 | $testPortGroup = $testPortGroup | Set-VDVlanConfiguration -DisableVlan 298 | } 299 | 300 | 301 | if( SetGuestIP $item.SourceIP $item.SubnetMask $item.GatewayIP ) { 302 | echo ("Set Guest IP to " + $item.SourceIP) 303 | 304 | #Run test on each uplink individually 305 | $uplinkset = ( ($testPortGroup | Get-VDUplinkTeamingPolicy).ActiveUplinkPort + ($testPortGroup | Get-VDUplinkTeamingPolicy).StandbyUplinkPort ) | sort 306 | foreach($thisUplink in $uplinkset) { 307 | #Disable all uplinks from the test portgroup 308 | $testPortGroup | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -UnusedUplinkPort $uplinkset 309 | #Enable only this uplink for the test portgroup 310 | $testPortGroup | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -ActiveUplinkPort $thisUplink 311 | 312 | #Run normal ping test 313 | $pingTestResult = TestPing $item.TestIP $timesToPing $false 314 | #Add to results 315 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 316 | $thisTest["Host"] = $vmhost.name 317 | $thisTest["PortGroupName"] = $testPortGroup.name 318 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 319 | $thisTest["SourceIP"] = $item.SourceIP 320 | $thisTest["DestinationIP"] = $item.TestIP 321 | $thisTest["Result"] = $pingTestResult[0].tostring() 322 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 323 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 324 | $thisTest["JumboFramesTest"] = "" 325 | $thisTest["Uplink"] = $thisUplink 326 | 327 | $testResults += new-object -typename psobject -Property $thisTest 328 | 329 | #DISABLED JUMBO FRAMES TEST! 330 | if($false) { 331 | #Run jumbo frames test 332 | $pingTestResult = TestPing $item.TestIP $timesToPing $true 333 | #Add to results 334 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 335 | $thisTest["Host"] = $vmhost.name 336 | $thisTest["PortGroupName"] = $testPortGroup.name 337 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 338 | $thisTest["SourceIP"] = $item.SourceIP 339 | $thisTest["DestinationIP"] = $item.TestIP 340 | $thisTest["Result"] = $pingTestResult[0].tostring() 341 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 342 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 343 | $thisTest["JumboFramesTest"] = "" 344 | $thisTest["Uplink"] = $thisUplink 345 | 346 | $testResults += new-object -typename psobject -Property $thisTest 347 | } 348 | } 349 | 350 | $testPortGroup | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -ActiveUplinkPort ($uplinkset | sort) 351 | 352 | } else { 353 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 354 | $thisTest["PortGroupName"] = $testPortGroup.name 355 | $thisTest["VlanID"] = $testPortGroup.vlanconfiguration.vlanid 356 | $thisTest["SourceIP"] = $item.SourceIP 357 | $thisTest["DestinationIP"] = $item.GatewayIP 358 | $thisTest["Result"] = "false - error setting guest IP" 359 | $testResults += new-object -typename psobject -Property $thisTest 360 | } 361 | } 362 | } else { 363 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 364 | $thisTest["Result"] = "false - unable to vMotion VM to this host" 365 | $testResults += new-object -typename psobject -Property $thisTest 366 | } 367 | } 368 | } 369 | else { 370 | #This is for a standard Switch 371 | $vmhost = $null 372 | 373 | #adding the testPortGroup on all hosts in the cluster 374 | $cluster | get-vmhost | ? {$_.ConnectionState -match "connected" } | sort | foreach { 375 | $dvs = get-virtualswitch -Name $dvsName -VMhost $_ 376 | $dvs | new-virtualportgroup -Name $testPortGroupName -ErrorAction silentlyContinue 377 | } 378 | 379 | $vmhost = $null 380 | $cluster | get-vmhost | ? {$_.ConnectionState -match "connected" } | sort | foreach { 381 | $vmhost = $_ 382 | $dvs = get-virtualswitch -Name $dvsName -VMhost $vmhost 383 | $testPortGroup = $dvs |get-virtualportgroup -Name $testPortGroupName -VMhost $vmhost -ErrorAction silentlyContinue 384 | 385 | 386 | #Migrate VM to new host 387 | if(Move-VM -VM $vm -Destination $vmhost) { 388 | write-host -Foregroundcolor:red "Sleeping 5 seconds..." 389 | start-sleep -seconds 5 390 | if (($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup ($dvs |get-virtualportgroup -Name $testPortGroupName -VMhost $vmhost) -confirm:$false -ErrorAction stop) 391 | { 392 | write-host -Foregroundcolor:green "Adapter Change successful" 393 | }else { 394 | write-host -Foregroundcolor:red "Cannot change adapter!" 395 | #$esxihost = $vm |get-vmhost 396 | #$newPortgroup = $esxihost | get-virtualportgroup -Name testPortGroupName -ErrorAction silentlyContinue 397 | #if (($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup ($newPortgroup) -confirm:$false -ErrorAction stop) { 398 | # write-host -Foregroundcolor:green "Adapter Change successful (2nd attempt)" 399 | #} else { 400 | # write-host -Foregroundcolor:red "Cannot change Adapter even on 2nd attempt. Exiting script" 401 | # exit 1 402 | #} 403 | } 404 | 405 | 406 | 407 | foreach($item in $data) { 408 | #Configure test port group VLAN ID for this particular VLAN test, or clear VLAN ID if none exists 409 | $myVlanId = $null 410 | $myVlanId = [int32](get-virtualportgroup -VMhost $vmhost -Standard:$true -name $item.PortGroup).Vlanid 411 | if($myVlanId) { 412 | $testPortGroup = $testPortGroup | Set-VirtualPortGroup -Vlanid $myVlanId 413 | } else { 414 | $testPortGroup = $testPortGroup | Set-VirtualPortGroup -VlanId 0 415 | } 416 | 417 | 418 | if( SetGuestIP $item.SourceIP $item.SubnetMask $item.GatewayIP ) { 419 | echo ("Set Guest IP to " + $item.SourceIP) 420 | 421 | #Run test on each uplink individually 422 | $uplinkset = ( ($testPortGroup | Get-NicTeamingPolicy).ActiveNic + ($testPortGroup |Get-NicTeamingPolicy).StandbyNic ) |sort 423 | foreach($thisUplink in $uplinkset) { 424 | #Disable all uplinks from the test portgroup 425 | $testPortGroup | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicUnused $uplinkset 426 | #Enable only this uplink for the test portgroup 427 | $testPortGroup | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive $thisUplink 428 | 429 | #Run normal ping test 430 | $pingTestResult = TestPing $item.TestIP $timesToPing $false 431 | #Add to results 432 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 433 | $thisTest["Host"] = $vmhost.name 434 | $thisTest["PortGroupName"] = $testPortGroup.name 435 | $thisTest["VlanID"] = $testPortGroup.vlanid 436 | $thisTest["SourceIP"] = $item.SourceIP 437 | $thisTest["DestinationIP"] = $item.TestIP 438 | $thisTest["Result"] = $pingTestResult[0].tostring() 439 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 440 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 441 | $thisTest["JumboFramesTest"] = "" 442 | $thisTest["Uplink"] = $thisUplink 443 | 444 | $testResults += new-object -typename psobject -Property $thisTest 445 | 446 | #DISABLED JUMBO FRAMES TEST! 447 | if($false) { 448 | #Run jumbo frames test 449 | $pingTestResult = TestPing $item.TestIP $timesToPing $true 450 | #Add to results 451 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 452 | $thisTest["Host"] = $vmhost.name 453 | $thisTest["PortGroupName"] = $testPortGroup.name 454 | $thisTest["VlanID"] = $testPortGroup.vlanid 455 | $thisTest["SourceIP"] = $item.SourceIP 456 | $thisTest["DestinationIP"] = $item.TestIP 457 | $thisTest["Result"] = $pingTestResult[0].tostring() 458 | $thisTest["TxCount"] = $pingTestResult[1].tostring() 459 | $thisTest["RxCount"] = $pingTestResult[2].tostring() 460 | $thisTest["JumboFramesTest"] = "" 461 | $thisTest["Uplink"] = $thisUplink 462 | 463 | $testResults += new-object -typename psobject -Property $thisTest 464 | } 465 | } 466 | 467 | $testPortGroup | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive ($uplinkset | sort) 468 | 469 | } else { 470 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 471 | $thisTest["PortGroupName"] = $testPortGroup.name 472 | $thisTest["VlanID"] = $testPortGroup.vlanid 473 | $thisTest["SourceIP"] = $item.SourceIP 474 | $thisTest["DestinationIP"] = $item.GatewayIP 475 | $thisTest["Result"] = "false - error setting guest IP" 476 | $testResults += new-object -typename psobject -Property $thisTest 477 | } 478 | } 479 | } else { 480 | $thisTest = [ordered]@{"VM" = $vm.name; "TimeStamp" = (Get-Date -f s); "Host" = $vmhost.name;} 481 | $thisTest["Result"] = "false - unable to vMotion VM to this host" 482 | $testResults += new-object -typename psobject -Property $thisTest 483 | } 484 | } 485 | } 486 | 487 | #Clean up 488 | if ($isStandard -eq $false) 489 | { 490 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup (get-vdportgroup $originalVMPortGroup) -confirm:$false 491 | Remove-VDPortGroup -VDPortGroup $testPortGroup -confirm:$false 492 | 493 | } else { 494 | $tempvm = get-vm $vmName 495 | $temphost = $tempvm |get-VMhost 496 | $portGroupToRevertTo = $temphost |get-virtualportgroup -name $temporaryVar -Standard:$true 497 | ($vm | get-Networkadapter)[0] | Set-NetworkAdapter -Portgroup $portGroupToRevertTo -confirm:$false 498 | write-host -Foregroundcolor:green "Waiting 5 seconds for $vm to revert back to $temporaryVar" 499 | start-sleep -seconds 5 500 | $cluster | get-vmhost | ? {$_.ConnectionState -match "connected" } | foreach { 501 | $vmhost = $_ 502 | $dvs = $vmhost | get-virtualswitch -Name $dvsName 503 | $testPortGroup = $dvs | get-virtualportgroup -name $testPortGroupName -Standard:$true -VMhost $vmhost 504 | remove-virtualportgroup -virtualportgroup $testPortGroup -confirm:$false 505 | } 506 | } 507 | 508 | #Future Test Ideas 509 | #Query driver/firmware for each host's network adapters ? 510 | 511 | #Show Results 512 | $testResults | ft 513 | $testResults | Export-CSV -notypeinformation $resultFile --------------------------------------------------------------------------------