├── Cleanup standalone FCD ├── README.md └── standalone-fcd-cleanup.ps1 ├── Clone VM Set DHCP Alter CPUID ├── Clone_VM_Set_DHCP_Reservations_Alter_CPUID_with_GUI.ps1 └── README.md ├── Configure VM resources from RVTools Output file ├── README.md └── Set_VM_Values_From_RVTools_Output.ps1 ├── Create vCenter Roles ├── Create_App_Volumes_vCenter_Roles.ps1 ├── Create_CSI_Driver_vCenter_Roles.ps1 ├── Create_vCenter_OpenShift_Install_Role.ps1 └── README.md ├── HCX ├── HCX Migration - Bulk Migrations with varying destinations from CSV.ps1 ├── HCX Migration - Standard Bulk Migration from CSV file.ps1 ├── HCX Migration - Standard Bulk Migration.ps1 ├── HCX Migration Network - Select from HCX Network Extension or Local Network.ps1 ├── HCX Migration with Mobility Group.ps1 ├── HCX Migration.csv ├── HCX Mobility Group Migrations.csv ├── HCX Reverse Migration - Bulk Migration from CSV and move into correct VM folders.ps1 ├── HCX Reverse Migration - Bulk Migration from CSV.ps1 ├── HCX Reverse Migration - with folder move.csv └── README.md ├── LICENSE ├── README.md └── Setup Host networking and storage ready for ISCSI LUNs ├── Configure_Host_Networking_and_iSCSI_Storage.ps1 └── README.md /Cleanup standalone FCD/README.md: -------------------------------------------------------------------------------- 1 | # vSphere Standalone FCD Cleanup Tool 2 | 3 | A PowerShell / PowerCLI tool to safely identify and optionally delete standalone First Class Disks (FCDs) in VMware vSphere that are not associated with any Container Native Storage (CNS) volumes. 4 | 5 | This version includes advanced features like: 6 | - Auto-detect and use existing vCenter sessions 7 | - Multi-vCenter session handling 8 | - Dry-run mode (default, safe) 9 | - Parallel deletion for large-scale environments (PowerShell 7+) 10 | - Full structured logging and CSV export for audits 11 | - Clean human-readable logs 12 | 13 | --- 14 | 15 | ## 🔧 Prerequisites 16 | 17 | - VMware PowerCLI module installed 18 | - PowerShell 7+ (`pwsh`) strongly recommended (especially for parallel mode) 19 | - Connection to vSphere 7.0+ environment 20 | - Sufficient permissions to list and delete VDisks 21 | 22 | --- 23 | 24 | ## 💻 Usage 25 | 26 | ```powershell 27 | # Dry run (default, safe mode) 28 | .\standalone-fcd-cleanup.ps1 29 | 30 | # Delete orphaned FCDs (with confirmation prompt) 31 | .\standalone-fcd-cleanup.ps1 -DryRun:$false 32 | 33 | # Automatically delete orphaned FCDs without prompt (USE EXTREME CAUTION) 34 | .\standalone-fcd-cleanup.ps1 -DryRun:$false -AutoDelete 35 | ``` 36 | 37 | The script will: 38 | 1. Check for existing `$global:defaultviserver` connections and offer to reuse it. 39 | 2. If no default, list all active vCenter sessions and allow selection. 40 | 3. Otherwise, prompt for new vCenter connection. 41 | 4. Scan for orphaned standalone FCDs not associated with CNS. 42 | 5. Export a full CSV report of findings. 43 | 6. Optionally delete orphaned FCDs after confirmation. 44 | --- 45 | 46 | ## ⚠️ Important Safety Notice 47 | 48 | The script is **safe by default** (`DryRun:$true`). 49 | **No deletions will occur unless you explicitly disable Dry Run.** 50 | 51 | If using `-AutoDelete`, the script will delete orphaned FCDs without asking. 52 | **This is highly dangerous in production environments. Only use if fully confident.** 53 | 54 | Always review the exported CSV report before deletion. 55 | 56 | --- 57 | 58 | ## 📝 Example Output Files 59 | 60 | - `FCD-Cleanup--.log` → Full log of all actions 61 | - `StandaloneFCDs--.csv` → List of orphaned FCDs 62 | 63 | --- 64 | ### 🖥️ Example Terminal Output 65 | 66 | ```shell 67 | PS /home/dean/ocp> .\standalone-fcd-cleanup.ps1 -DryRun:$false 68 | ========================================== 69 | vSphere Standalone FCD Cleanup Tool v5 70 | ========================================== 71 | 72 | Existing vCenter session found: vcsa.veducate.lab 73 | Use this session? Type YES to proceed, NO to select or connect: yes 74 | 2025-05-15 15:00:23 [INFO] ========================================== 75 | 2025-05-15 15:00:23 [INFO] Connected to: vcsa.veducate.lab 76 | 2025-05-15 15:00:23 [INFO] DryRun: False 77 | 2025-05-15 15:00:23 [INFO] AutoDelete: False 78 | 2025-05-15 15:00:23 [INFO] ========================================== 79 | 2025-05-15 15:00:23 [INFO] Retrieving all FCDs... 80 | 2025-05-15 15:00:26 [INFO] Retrieving all CNS volumes... 81 | 2025-05-15 15:00:32 [WARNING] Found 136 orphaned FCD(s). 82 | 2025-05-15 15:00:32 [INFO] Exported report: .\\StandaloneFCDs-vcsa.veducate.lab-20250515-150023.csv 83 | Delete these orphaned FCDs? Type YES to proceed: yes 84 | 2025-05-15 15:00:36 [INFO] Starting serial deletion... 85 | 2025-05-15 15:00:38 [ERROR] Failed to delete pvc-450172a4-4690-4907-927a-2e57c7495c5d [Datastore-datastore-15:038daa3e-7aed-4506-95ce-b2b6c10e18ea] - 15/05/2025 15:00:38 Remove-VDisk The operation is not allowed in the current state. 86 | 2025-05-15 15:00:40 [SUCCESS] Deleted: pvc-d87317f0-597b-4c60-aabd-769c833072bc [Datastore-datastore-15:04527884-c716-400d-83f7-0afe55f2ae85] 87 | 2025-05-15 15:00:42 [SUCCESS] Deleted: pvc-64d8f3e6-26b5-4890-ab0d-862cc8b11e50 [Datastore-datastore-15:0b6b5036-b220-4c4e-8edb-0357bf9bc718] 88 | 2025-05-15 15:00:44 [SUCCESS] Deleted: pvc-81fb0ca9-c79f-48dc-af38-382d35f6417e [Datastore-datastore-15:0d0c7653-0f9e-4dc5-ba5b-0bf39aa715d9] 89 | 2025-05-15 15:00:46 [SUCCESS] Deleted: pvc-c80ccc47-0e85-465f-9bc9-f0673623728c [Datastore-datastore-15:0e2d09d8-4667-432c-bab1-c34189c000b9] 90 | 2025-05-15 15:00:49 [SUCCESS] Deleted: pvc-6a82348d-0e9f-4d85-b584-26d0f6820c34 [Datastore-datastore-15:0e8703cd-cfa0-4132-b712-6a49269fd8b2] 91 | 2025-05-15 15:00:51 [SUCCESS] Deleted: pvc-68c2f06b-f8ae-42a7-ad81-d21c87f26531 [Datastore-datastore-15:0e920507-466d-4258-8eb0-d1c25e7c8df3] 92 | 2025-05-15 15:00:53 [SUCCESS] Deleted: pvc-f69416af-7b11-4311-8fd9-c1b2a3faf254 [Datastore-datastore-15:0eb22e06-3fee-4f32-aed2-b568c69d285e] 93 | 2025-05-15 15:00:55 [SUCCESS] Deleted: pvc-ffd69b63-fbdd-48cf-a01c-f9cd9331992e [Datastore-datastore-15:11963262-5c77-4d22-946b-9da130ca9056] 94 | 2025-05-15 15:00:57 [SUCCESS] Deleted: pvc-b42376c1-d235-4e08-bf3f-374587857453 [Datastore-datastore-15:12db7137-b57c-454b-8458-9f3e1fa64e66] 95 | ``` 96 | 97 | --- 98 | 99 | ## 🤝 Ownership and Licensing 100 | 101 | Author: [Dean Lewis](https://bsky.app/profile/saintdle.bsky.social) 102 | GitHub: [https://github.com/saintdle/PowerCLI](https://github.com/saintdle/PowerCLI) 103 | 104 | Licensed under the MIT License. 105 | See [`LICENSE`](../LICENSE) file for full license text. 106 | 107 | --- 108 | 109 | ## 🙏 Acknowledgements 110 | 111 | This script was inspired by community best practices and operational challenges in managing large vSphere environments. 112 | Special thanks to VMware PowerCLI maintainers and the broader VMware community. 113 | 114 | --- 115 | 116 | ## 📣 Feedback and Contributions 117 | 118 | Pull requests and feedback are welcome! 119 | Please open an issue or PR at: [https://github.com/saintdle/PowerCLI](https://github.com/saintdle/PowerCLI) 120 | -------------------------------------------------------------------------------- /Cleanup standalone FCD/standalone-fcd-cleanup.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Safest enterprise cleanup tool for standalone FCDs not managed by CNS and not attached to any VM. 4 | 5 | .DESCRIPTION 6 | - Detects orphaned FCDs: not in CNS + not attached to any VM 7 | - Logs all actions, prevents deletion of any attached FCD 8 | - Safe serial deletion (no parallelism) 9 | - Dry-run enabled by default for safety 10 | - Highly annotated for maintainability and learning 11 | 12 | .VERSION 13 | 5.1 - Safe orphan detection version with attached disk pre-check and full inline documentation 14 | 15 | .AUTHOR 16 | Dean Lewis (@saintdle) | https://bsky.app/profile/saintdle.bsky.social 17 | 18 | .SOURCE 19 | https://github.com/saintdle/PowerCLI 20 | 21 | .LICENSE 22 | MIT License 23 | #> 24 | 25 | # ----------------------- 26 | # Script parameters 27 | # ----------------------- 28 | param ( 29 | [switch]$AutoDelete, # Optional: Skip prompt and auto-delete 30 | [switch]$DryRun = $true # Optional: Dry run ON by default for safety 31 | ) 32 | 33 | # ----------------------- 34 | # Function: Write-Log 35 | # Purpose: Output message to console and append to log file 36 | # ----------------------- 37 | function Write-Log { 38 | param ( 39 | [string]$Message, 40 | [string]$Level = "INFO" 41 | ) 42 | $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 43 | $logEntry = "$timestamp [$Level] $Message" 44 | Add-Content -Path $global:LogFile -Value $logEntry 45 | Write-Host $logEntry 46 | } 47 | 48 | # ----------------------- 49 | # Function: Select-vCenterSession 50 | # Purpose: Check for existing connection or prompt to connect 51 | # ----------------------- 52 | function Select-vCenterSession { 53 | # If PowerCLI already has a default connection, offer to reuse it 54 | if ($null -ne $global:defaultviserver -and $global:defaultviserver.IsConnected) { 55 | Write-Host "`nExisting vCenter session found: $($global:defaultviserver.Name)" -ForegroundColor Cyan 56 | $useDefault = Read-Host "Use this session? Type YES to proceed, NO to select or connect" 57 | if ($useDefault -eq "YES") { 58 | return $global:defaultviserver 59 | } 60 | } 61 | 62 | # List all connected sessions (if any) 63 | $sessions = Get-VIServer 64 | if ($sessions.Count -eq 0) { 65 | Write-Host "No active vCenter connections found." -ForegroundColor Yellow 66 | return $null 67 | } 68 | 69 | Write-Host "`nActive sessions:" -ForegroundColor Cyan 70 | $i = 1 71 | foreach ($session in $sessions) { 72 | Write-Host "$i) $($session.Name) [$($session.User)]" 73 | $i++ 74 | } 75 | 76 | # Allow user to select session or connect manually 77 | if ($sessions.Count -eq 1) { 78 | $useExisting = Read-Host "Use $($sessions[0].Name)? Type YES to proceed" 79 | if ($useExisting -eq "YES") { return $sessions[0] } 80 | } else { 81 | $choice = Read-Host "Enter session number, or 0 to connect manually" 82 | if ($choice -ne "0" -and $choice -match '^\d+$') { 83 | return $sessions[$choice - 1] 84 | } 85 | } 86 | return $null 87 | } 88 | 89 | # ----------------------- 90 | # Function: Connect-NewvCenter 91 | # Purpose: Connect to a new vCenter server 92 | # ----------------------- 93 | function Connect-NewvCenter { 94 | $vCenter = Read-Host -Prompt "Enter vCenter FQDN/IP" 95 | Connect-VIServer -Server $vCenter -ErrorAction Stop 96 | } 97 | 98 | # ----------------------- 99 | # Function: Test-FCDAttachedToVM 100 | # Purpose: Checks if an FCD is currently mounted to any VM 101 | # ----------------------- 102 | function Test-FCDAttachedToVM { 103 | param ($FCDId) 104 | $attached = $false 105 | $attachedVM = $null 106 | 107 | # Loop through all VMs and check hard disks for filename containing FCD ID 108 | Get-VM | ForEach-Object { 109 | $vm = $_ 110 | $vm | Get-HardDisk | Where-Object { $_.Filename -like "*$FCDId*.vmdk" } | ForEach-Object { 111 | $attached = $true 112 | $attachedVM = $vm.Name 113 | } 114 | } 115 | 116 | return @($attached, $attachedVM) 117 | } 118 | 119 | # ----------------------- 120 | # Function: Cleanup-StandaloneFCDs 121 | # Purpose: Main logic for identifying and deleting orphaned FCDs 122 | # ----------------------- 123 | function Cleanup-StandaloneFCDs { 124 | $scriptStart = Get-Date 125 | 126 | try { 127 | # Welcome message 128 | Write-Host "==================================================" -ForegroundColor Cyan 129 | Write-Host " vSphere Standalone FCD Cleanup Tool v5.1 SAFE" -ForegroundColor Cyan 130 | Write-Host "==================================================" -ForegroundColor Cyan 131 | 132 | # Check or connect to vCenter 133 | $session = Select-vCenterSession 134 | if (-not $session) { 135 | $session = Connect-NewvCenter 136 | } 137 | 138 | # Load Storage module required for Remove-VDisk 139 | Import-Module VMware.VimAutomation.Storage -ErrorAction Stop 140 | 141 | # Setup logging 142 | $vCenterName = $session.Name 143 | $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" 144 | $global:LogFile = ".\\FCD-Cleanup-$($vCenterName)-$timestamp.log" 145 | $reportFile = ".\\StandaloneFCDs-$($vCenterName)-$timestamp.csv" 146 | 147 | Write-Log "==================================================" 148 | Write-Log " Connected to: $vCenterName" 149 | Write-Log " DryRun: $DryRun" 150 | Write-Log " AutoDelete: $AutoDelete" 151 | Write-Log "==================================================" 152 | 153 | # Retrieve all FCDs and CNS volumes 154 | Write-Log "Retrieving all FCDs..." 155 | $allFCDs = Get-VDisk 156 | 157 | Write-Log "Retrieving all CNS volumes..." 158 | $cnsVolumes = Get-CnsVolume 159 | $cnsBackingIds = $cnsVolumes | ForEach-Object { $_.BackingObjectId } 160 | 161 | # Initial filter: exclude CNS backed disks 162 | $potentialOrphans = $allFCDs | Where-Object { $cnsBackingIds -notcontains $_.Id } 163 | 164 | if ($potentialOrphans.Count -eq 0) { 165 | Write-Log "No standalone FCDs found (after CNS filter)." "SUCCESS" 166 | return 167 | } 168 | 169 | Write-Log "Found $($potentialOrphans.Count) FCD(s) not part of CNS. Checking for VM attachments..." "WARNING" 170 | 171 | # Secondary filter: exclude any disk attached to a VM 172 | $finalOrphans = @() 173 | foreach ($fcd in $potentialOrphans) { 174 | $result = Test-FCDAttachedToVM -FCDId $fcd.Id 175 | if ($result[0]) { 176 | Write-Log "FCD $($fcd.Id) is attached to VM '$($result[1])'. Skipping deletion." "WARNING" 177 | } else { 178 | $finalOrphans += $fcd 179 | } 180 | } 181 | 182 | if ($finalOrphans.Count -eq 0) { 183 | Write-Log "No true orphaned FCDs found (not in CNS + not attached)." "SUCCESS" 184 | } else { 185 | Write-Log "Found $($finalOrphans.Count) true orphaned FCD(s)." "WARNING" 186 | 187 | # Export report 188 | $finalOrphans | Select-Object Name, Id, CapacityGB, Datastore, CreatedTime | 189 | Export-Csv -Path $reportFile -NoTypeInformation 190 | Write-Log "Exported report: $reportFile" 191 | 192 | # Ask for confirmation if DryRun is OFF 193 | if ($DryRun) { 194 | Write-Log "Dry run mode ON. No deletions will occur." "INFO" 195 | } elseif (-not $AutoDelete) { 196 | $confirm = Read-Host "Delete these orphaned FCDs? Type YES to proceed" 197 | if ($confirm -ne "YES") { 198 | Write-Log "User cancelled deletion step." "INFO" 199 | return 200 | } 201 | } 202 | 203 | # Delete FCDs (serial for safety) 204 | if (-not $DryRun) { 205 | Write-Log "Starting serial deletion..." "INFO" 206 | foreach ($fcd in $finalOrphans) { 207 | try { 208 | $fcd | Remove-VDisk -Confirm:$false -ErrorAction Stop 209 | Write-Log "Deleted: $($fcd.Name) [$($fcd.Id)]" "SUCCESS" 210 | } catch { 211 | Write-Log "Failed to delete $($fcd.Name) [$($fcd.Id)] - $_" "ERROR" 212 | } 213 | } 214 | Write-Log "All deletions attempted." "SUCCESS" 215 | } 216 | } 217 | 218 | # Script finished: report execution time 219 | $duration = (Get-Date) - $scriptStart 220 | Write-Log "==================================================" 221 | Write-Log " Completed in $($duration.TotalMinutes.ToString("0.00")) minutes." 222 | Write-Log "==================================================" 223 | } catch { 224 | Write-Log "Fatal error: $_" "ERROR" 225 | } finally { 226 | # Clean up session 227 | if (Get-VIServer) { 228 | Disconnect-VIServer -Server * -Confirm:$false 229 | Write-Log "Disconnected from vCenter." "INFO" 230 | } 231 | } 232 | } 233 | 234 | # ----------------------- 235 | # MAIN: Run the cleanup function 236 | # ----------------------- 237 | Cleanup-StandaloneFCDs 238 | -------------------------------------------------------------------------------- /Clone VM Set DHCP Alter CPUID/Clone_VM_Set_DHCP_Reservations_Alter_CPUID_with_GUI.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Clone_VM_Set_DHCP_Reservations_Alter_CPUID_with_GUI.ps1 - PowerShell Script to clone a virtual machine, create a DHCP reservation for this new VM, 4 | and alter the CPUID to mask the CPU attributes to the guest OS. 5 | .DESCRIPTION 6 | This script loads a GUI that is used to clone and existing virtual machine, set a DHCP reservation based on the new VM's MAC Address, and finally configure the new 7 | VM's CPUID to mask the CPU that is known to the guest OS. 8 | You can read more about this script the decisions made in its design here: https://veducate.co.uk/powercli-gui-clone-machine-dhcp-cpuid/ 9 | .OUTPUTS 10 | You are provided a GUI interface for interactions. 11 | .NOTES 12 | Author Dean Lewis, https://vEducate.co.uk, Twitter: @saintdle 13 | 14 | Change Log V1.00, 30/06/2020 - Initial version 15 | .LICENSE 16 | MIT License 17 | Copyright (c) 2020 Dean Lewis 18 | Permission is hereby granted, free of charge, to any person obtaining a copy 19 | of this software and associated documentation files (the "Software"), to deal 20 | in the Software without restriction, including without limitation the rights 21 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 22 | copies of the Software, and to permit persons to whom the Software is 23 | furnished to do so, subject to the following conditions: 24 | The above copyright notice and this permission notice shall be included in all 25 | copies or substantial portions of the Software. 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | SOFTWARE. 33 | #> 34 | 35 | function PickVcenter() 36 | { 37 | #Text label for vCenter selection 38 | $dropDownLabel = New-Object System.Windows.Forms.Label 39 | $dropDownLabel.Location = New-Object System.Drawing.Size(10,12) 40 | $dropDownLabel.Size = New-Object System.Drawing.Size(120, 20) 41 | $dropDownLabel.Text = "Select vCenter Server" 42 | $form.Controls.Add($dropDownLabel) 43 | 44 | #Dropdown list for vCenter names 45 | $dropDownList = New-Object System.Windows.Forms.ComboBox 46 | $dropDownList.Location = New-Object System.Drawing.Size(150,10) 47 | $dropDownList.Size = New-Object System.Drawing.Size(150,30) 48 | $dropDownList.Items.Add("vCenter01.vEducate.co.uk") 49 | $dropDownList.Items.Add("vCenter02.vEducate.co.uk") 50 | $form.Controls.Add($dropDownList) 51 | 52 | #Button to click off connect to selected vCenter 53 | $button = New-Object System.Windows.Forms.Button 54 | $button.Location = New-Object System.Drawing.Size(310, 10) 55 | $button.Size = New-Object System.Drawing.Size(60, 20) 56 | $button.Text = "Connect" 57 | $button.Add_Click({ConnectVIServer}) 58 | $form.Controls.Add($button) 59 | 60 | #Dialog title name of GUI Form, and size of form 61 | $form.Text = "Clone Me Baby!" 62 | $form.Size = New-Object System.Drawing.Size(1000,500) 63 | $form.StartPosition = "CenterScreen" 64 | 65 | $form.ShowDialog() 66 | 67 | } 68 | 69 | function ConnectVIServer() { 70 | #takes the selection in the previous function to a string, to be used as a variable 71 | $choice = $dropDownList.SelectedItem.ToString() 72 | try { 73 | $viServer = Connect-VIServer $choice 74 | if ($viServer -eq $null) { return } 75 | #Loads the ShowVMs function should a connection be made 76 | ShowVMs 77 | } 78 | catch { Write-Host -ForegroundColor Red "Exception: $_" } 79 | } 80 | 81 | function ShowVMs() { 82 | 83 | #Text Label for listbox of VMs returned 84 | $listBoxVMsLabel = New-Object System.Windows.Forms.Label 85 | $listBoxVMsLabel.Location = New-Object System.Drawing.Size(10,60) 86 | $listBoxVMsLabel.Text = "Select VM" 87 | $form.Controls.Add($listBoxVMsLabel) 88 | #Listbox populated with VMs 89 | $listBoxVMs.Location = New-Object System.Drawing.Size(10,85) 90 | $listBoxVMs.Size = New-Object System.Drawing.Size(200,20) 91 | $listBoxVMs.Height = 200 92 | #Command used to pull VMs from vCenter filtered on vCenter tag, this can be any mixture of the Get-VM command 93 | 94 | Get-VM -Tag "Clone-VM" | % { 95 | $listBoxVMs.Items.Add($_.Name) 96 | } 97 | $form.Controls.Add($listBoxVMs) 98 | 99 | #Datastore list box label 100 | $listBoxDSLabel = New-Object System.Windows.Forms.Label 101 | $listBoxDSLabel.Location = New-Object System.Drawing.Size(250,60) 102 | $listBoxDSLabel.Text = "Select Datastore" 103 | $form.Controls.Add($listBoxDSLabel) 104 | #Datastore list box 105 | $listBoxDS.Location = New-Object System.Drawing.Size(250,85) 106 | $listBoxDS.Size = New-Object System.Drawing.Size(200,20) 107 | $listBoxDS.Height = 200 108 | #Powershell command used to retrieve the datastore details 109 | Get-DataStore | % { 110 | 111 | $freeGB = [string]::Format("{0:#,##0}", $_.FreeSpaceGB) 112 | $listBoxDS.Items.Add("$($_.Name) | $freeGB GB Free") 113 | } 114 | $form.Controls.Add($listBoxDS) 115 | 116 | #Host list box label 117 | $listBoxHostLabel = New-Object System.Windows.Forms.Label 118 | $listBoxHostLabel.Location = New-Object System.Drawing.Size(475,60) 119 | $listBoxHostLabel.Text = "Select Target Host" 120 | $form.Controls.Add($listBoxHostLabel) 121 | #Host list box 122 | $listBoxHost.Location = New-Object System.Drawing.Size(475,85) 123 | $listBoxHost.Size = New-Object System.Drawing.Size(200,20) 124 | $listBoxHost.Height = 200 125 | #Powershell command to find hosts, and also parse the information so we can display the free memory on the host 126 | Get-VMHost | % { 127 | 128 | $memoryTotalMB = $_.MemoryTotalMB 129 | $memoryUsageMB = $_.MemoryUsageMB 130 | $memoryFreeMB = $_.MemoryTotalMB - $_.MemoryUsageMB 131 | $memoryFreePerc = 0.0 132 | try { $memoryFreePerc = $memoryFreeMB / $memoryTotalMB} 133 | catch { } 134 | $freeMB = [string]::Format("{0:#,##0.0%}", $memoryFreePerc) 135 | $listBoxHost.Items.Add("$($_.Name) | $freeMB Free") 136 | 137 | } 138 | $form.Controls.Add($listBoxHost) 139 | 140 | #New Virtual Machine name label 141 | $newNameLabel = New-Object System.Windows.Forms.Label 142 | $newNameLabel.Location = New-Object System.Drawing.Size(700, 60) 143 | $newNameLabel.Text = "New VM Name" 144 | $form.Controls.Add($newNameLabel) 145 | #New virtual machine name text box 146 | $newNameTextBox.Location = New-Object System.Drawing.Size(700, 85) 147 | $newNameTextBox.Size = New-Object System.Drawing.Size(200, 20) 148 | $form.Controls.Add($newNameTextBox) 149 | 150 | #Clone button on the GUI form 151 | $cloneButton = New-Object System.Windows.Forms.Button 152 | $cloneButton.Location = New-Object System.Drawing.Size(700, 120) 153 | $cloneButton.Size = New-Object System.Drawing.Size(60, 20) 154 | $cloneButton.Text = "Clone" 155 | #Confirming actions to be taken when button is clicked 156 | $cloneButton.Add_Click({CloneVM $listBoxVMs $listBoxDS $listBoxHost $newNameTextBox $VMIPAddrTextBox $DHCPScopeBox}) 157 | $form.Controls.Add($cloneButton) 158 | 159 | #Virtual Machine IP address on Production 160 | $VMIPaddr = New-Object system.windows.Forms.Label 161 | $VMIPaddr.Text = "Production IP address" 162 | $VMIPaddr.AutoSize = $true 163 | $VMIPaddr.Width = 25 164 | $VMIPaddr.Height = 10 165 | $VMIPaddr.location = new-object system.drawing.point(700,170) 166 | $Form.controls.Add($VMIPaddr) 167 | #Virtual Machine IP address text box 168 | $VMIPAddrTextBox.Width = 110 169 | $VMIPAddrTextBox.Height = 20 170 | $VMIPAddrTextBox.location = new-object system.drawing.point(700,190) 171 | $Form.controls.Add($VMIPAddrTextBox) 172 | 173 | #Production DHCP Server label 174 | $DHCPscopes = New-Object system.windows.Forms.Label 175 | $DHCPscopes.Text = "Production DHCP Scopes" 176 | $DHCPscopes.AutoSize = $true 177 | $DHCPscopes.Width = 25 178 | $DHCPscopes.Height = 10 179 | $DHCPscopes.location = new-object system.drawing.point(700,215) 180 | $Form.controls.Add($DHCPscopes) 181 | 182 | #DHCP list box for production 183 | $DHCPScopeBox.Text = "listBox" 184 | $DHCPScopeBox.Width = 115 185 | $DHCPScopeBox.Height = 75 186 | $DHCPScopeBox.location = new-object system.drawing.point(700,240) 187 | #Specifying a varible where the credentials to be used are stored securely 188 | $MyCredentials=IMPORT-CLIXML C:\Scripts\SecureCredentials.xml 189 | #Powershell command to remotely connect to a server in the DMZ 190 | Invoke-command -computername 10.10.1.1 -Scriptblock {get-dhcpserverv4scope } -credential $MyCredentials | % { 191 | $DHCPScopeBox.Items.Add("$($_.ScopeId)")} 192 | $Form.controls.Add($DHCPScopeBox) 193 | 194 | #Label for text box, for IP address to be removed from the DHCP scope 195 | $DBVMIPaddr = New-Object system.windows.Forms.Label 196 | $DBVMIPaddr.Text = "Prod DB IP address" 197 | $DBVMIPaddr.AutoSize = $true 198 | $DBVMIPaddr.Width = 25 199 | $DBVMIPaddr.Height = 10 200 | $DBVMIPaddr.location = new-object system.drawing.point(700,330) 201 | $Form.controls.Add($DBVMIPaddr) 202 | 203 | #Text box, for IP address that is to be removed from DHCP scope 204 | $DBVMIPAddrTextBox.Width = 110 205 | $DBVMIPAddrTextBox.Height = 20 206 | $DBVMIPAddrTextBox.location = new-object system.drawing.point(700,350) 207 | $Form.controls.Add($DBVMIPAddrTextBox) 208 | 209 | #Label for text box, virtual Machine IP address on DR environment 210 | $DRVMIPaddr = New-Object system.windows.Forms.Label 211 | $DRVMIPaddr.Text = "DR IP address" 212 | $DRVMIPaddr.AutoSize = $true 213 | $DRVMIPaddr.Width = 25 214 | $DRVMIPaddr.Height = 10 215 | $DRVMIPaddr.location = new-object system.drawing.point(820,170) 216 | $Form.controls.Add($DRVMIPaddr) 217 | 218 | #Text box, for IP address that is to be reserved in DHCP 219 | $DRVMIPAddrTextBox.Width = 110 220 | $DRVMIPAddrTextBox.Height = 20 221 | $DRVMIPAddrTextBox.location = new-object system.drawing.point(820,190) 222 | $Form.controls.Add($DRVMIPAddrTextBox) 223 | 224 | #DR DHCP Server label 225 | $DRDHCPscopes = New-Object system.windows.Forms.Label 226 | $DRDHCPscopes.Text = "DR DHCP Scopes" 227 | $DRDHCPscopes.AutoSize = $true 228 | $DRDHCPscopes.Width = 25 229 | $DRDHCPscopes.Height = 10 230 | $DRDHCPscopes.location = new-object system.drawing.point(820,215) 231 | $Form.controls.Add($DRDHCPscopes) 232 | 233 | #DR DHCP server scopes 234 | $DRDHCPScopeBox.Text = "listBox" 235 | $DRDHCPScopeBox.Width = 115 236 | $DRDHCPScopeBox.Height = 75 237 | $DRDHCPScopeBox.location = new-object system.drawing.point(820,240) 238 | #Secure creds location to be used as variable for connection to server 239 | $DRMyCredentials=IMPORT-CLIXML C:\Scripts\DRSecureCredentials.xml 240 | #Command used to connect to DR DHCP server 241 | Invoke-command -computername 10.50.1.1 -Scriptblock {get-dhcpserverv4scope } -credential $DRMyCredentials | % { 242 | $DRDHCPScopeBox.Items.Add("$($_.ScopeId)")} 243 | $Form.controls.Add($DRDHCPScopeBox) 244 | 245 | #Label for text box, for IP address to be removed from the DR DHCP scope 246 | $DRDBVMIPaddr = New-Object system.windows.Forms.Label 247 | $DRDBVMIPaddr.Text = "DR DB IP address" 248 | $DRDBVMIPaddr.AutoSize = $true 249 | $DRDBVMIPaddr.Width = 25 250 | $DRDBVMIPaddr.Height = 10 251 | $DRDBVMIPaddr.location = new-object system.drawing.point(820,330) 252 | $Form.controls.Add($DBVMIPaddr) 253 | 254 | #Text box, for IP address that is to be removed from DR DHCP scope 255 | $DRDBVMIPAddrTextBox.Width = 110 256 | $DRDBVMIPAddrTextBox.Height = 20 257 | $DRDBVMIPAddrTextBox.location = new-object system.drawing.point(820,350) 258 | $Form.controls.Add($DRDBVMIPAddrTextBox) 259 | 260 | } 261 | 262 | 263 | function CloneVM() 264 | { 265 | $vmName = $listBoxVMs.Items[$listBoxVMs.SelectedIndex].ToString() 266 | $dsName = $listBoxDS.Items[$listBoxDS.SelectedIndex].ToString().Split("|")[0].ToString().Trim() 267 | $hostName = $listBoxHost.Items[$listBoxHost.SelectedIndex].ToString().Split("|")[0].ToString().Trim() 268 | $DHCPscope = $DHCPScopeBox.Items[$DHCPScopeBox.SelectedIndex].ToString() 269 | $IPaddvm = $VMIPAddrTextBox.Text 270 | $DRIPaddvm = $DRVMIPAddrTextBox.Text 271 | $DBIPaddvm = $DBVMIPAddrTextBox.Text 272 | DRDHCPscope = $DRDHCPScopeBox.Items[$DRDHCPScopeBox.SelectedIndex].ToString() 273 | $DRDBIPaddvm = $DRDBVMIPAddrTextBox.Text 274 | $newName = $newNameTextBox.Text 275 | 276 | #Basic error checking, unable to continue if the below items are empty 277 | if ($vmName.Length -eq 0) { return } 278 | if ($dsName.Length -eq 0) { return } 279 | if ($hostName.Length -eq 0) { return } 280 | if ($newName.Length -eq 0) { return } 281 | if ($DHCPScope.Length -eq 0) { return } 282 | if ($IPaddvm.Length -eq 0) { return } 283 | if ($DRIPaddvm.Length -eq 0) {return} 284 | 285 | #Capture current date for logging purposes 286 | $Date = get-date 287 | 288 | #Output message which reads back the selected variables and confirms the action taken upon hitting the "clone" button 289 | $message = [string]::Format("Cloning {0} on DS {1}, host {2}, named {3}", $vmName, $dsName, $hostName, $newName) 290 | $OutputTextBox = New-Object System.Windows.Forms.TextBox 291 | $OutputTextBox.Location = New-Object System.Drawing.Size(10, 300) 292 | $OutputTextBox.Size = New-Object System.Drawing.Size(600, 200) 293 | $OutputTextBox.Text = $message 294 | $form.Controls.Add($OutputTextBox) 295 | 296 | ### Code to clone VM from selected objects ### 297 | $VM = New-VM -VM $vmName -Name $newName -VMHost $hostName -DiskStorageFormat Thick -Datastore $dsName -Notes "Clone created $(whoami) $Date" 298 | 299 | ### Configure CPUID in VMX File ### 300 | #Setup a connection to the datastore where the VM is located 301 | New-PSDrive -Location $ds -Name DS -PSProvider VimDatastore -Root "\" 302 | #copies VMX file from vmware datastore location to temporary location on c: drive 303 | copy-datastoreitem -item "DS:$vmname\$vmname.vmx" -destination "c:\scripts\$vmname.vmx" -Force 304 | #Regex to place CPUID settings into vmx file, thank you Ian Morris for the continued assistance with this! 305 | get-childitem "c:\scripts\$vmname.vmx" | % { 306 | $content = get-content $_ 307 | [System.Text.StringBuilder] $newContent = New-Object -TypeName "System.Text.StringBuilder" 308 | [int] $i = 0 309 | $stream = [System.IO.StreamWriter] $_.FullName 310 | foreach ($s in $content) 311 | { 312 | if ([Regex]::IsMatch($s, "cpuid\.") -eq $false) 313 | { 314 | $stream.WriteLine($s) 315 | [void]$newContent.Append($s) 316 | } 317 | } 318 | #These are the CPUID lines mask the VM into thinking it has a Intel Xeon 2.7 GHz chip from around 2007 319 | $stream.WriteLine("cpuid.2.eax=`"00000101101100001011000100000001`"") 320 | $stream.WriteLine("cpuid.2.ebx=`"00000000010101100101011111110000`"") 321 | $stream.WriteLine("cpuid.2.ecx=`"00000000000000000000000000000000`"") 322 | $stream.WriteLine("cpuid.2.edx=`"00101100101101000011000001001000`"") 323 | $stream.Close() 324 | } 325 | #Copy the modified VMX back to the datastore, by default any duplicate named will will be replaced 326 | copy-datastoreitem -item "c:\scripts\$vmname.vmx" -destination "DS:$vmname\$vmname.vmx" 327 | #close the PS Drive connection to the datastore 328 | Remove-PSDrive -Name DS 329 | #Delete the modified VMX file from the windows machine running the script 330 | Remove-item "c:\scripts\$vmname.vmx" 331 | 332 | ### Setup DHCP Scopes ### 333 | #Need to recall the secure stored credentials to connect to the DHCP Servers 334 | $MyCredentials=IMPORT-CLIXML C:\Scripts\SecureCredentials.xml 335 | $DRMyCredentials=IMPORT-CLIXML C:\Scripts\DRSecureCredentials.xml 336 | #Grab the new VMs MAC address and convert the string to a format usable with the DHCP Powershell Module 337 | $vmmac = get-vm $vmName | get-networkadapter 338 | $vmmacalt = $vmmac.MacAddress -replace ":" 339 | 340 | #Using invoke-command to connect to DHCP servers and setup the DHCP scope reservations and remove the IP address from the available range as a precaution 341 | Invoke-command -computername 10.10.1.1 -Scriptblock {Add-DhcpServerv4Reservation -ScopeId $Using:DHCPScope -IPAddress $Using:IPAddvm -Name $Using:vmName -ClientId $Using:vmmacalt} -credential $MyCredentials 342 | Invoke-command -computername 10.50.1.1 -Scriptblock {Add-DhcpServerv4Reservation -ScopeId $Using:DRDHCPScope -IPAddress $Using:DRIPAddvm -Name $Using:vmName -ClientId $Using:vmmacalt} -credential $DRMyCredentials 343 | Invoke-command -computername 10.10.1.1 -Scriptblock {Add-DhcpServerv4ExclusionRange -ScopeID $Using:DHCPScope -StartRange $Using:DBIPAddvm -EndRange $Using:DBIPAddvm } -credential $MyCredentials 344 | Invoke-command -computername 10.50.1.1 -Scriptblock {Add-DhcpServerv4ExclusionRange -ScopeID $Using:DRDHCPScope -StartRange $Using:DRDBIPAddvm -EndRange $Using:DRDBIPAddvm } -credential $DRMyCredentials 345 | } 346 | 347 | ### Start form 348 | #Add necessary modules and .Net to build GUI form 349 | Import-Module VMware.PowerCLI 350 | Add-Type -AssemblyName System.Windows.Forms 351 | 352 | #Hide PowerShell Console > code snippet from http://blog.dbsnet.fr/hide-powershell-console-from-a-gui 353 | Add-Type -Name Window -Namespace Console -MemberDefinition ' 354 | [DllImport("Kernel32.dll")] 355 | public static extern IntPtr GetConsoleWindow(); 356 | [DllImport("user32.dll")] 357 | public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow); 358 | ' 359 | $consolePtr = [Console.Window]::GetConsoleWindow() 360 | [Console.Window]::ShowWindow($consolePtr, 0) 361 | 362 | #Build form based on earlier configuration 363 | $form = New-Object System.Windows.Forms.Form 364 | $listBoxVMs = New-Object System.Windows.Forms.ListBox 365 | $listBoxDS = New-Object System.Windows.Forms.ListBox 366 | $listBoxHost = New-Object System.Windows.Forms.ListBox 367 | $newNameTextBox = New-Object System.Windows.Forms.TextBox 368 | $VMIPAddrTextBox = New-Object System.Windows.Forms.TextBox 369 | $DHCPScopeBox = New-Object System.Windows.Forms.ListBox 370 | $DRVMIPAddrTextBox = New-Object System.Windows.Forms.TextBox 371 | $DRDHCPScopeBox = New-Object System.Windows.Forms.ListBox 372 | $DBVMIPAddrTextBox = New-Object System.Windows.Forms.TextBox 373 | $DRDBVMIPAddrTextBox = New-Object System.Windows.Forms.TextBox 374 | 375 | PickVcenter 376 | -------------------------------------------------------------------------------- /Clone VM Set DHCP Alter CPUID/README.md: -------------------------------------------------------------------------------- 1 | ## PowerCLI with a GUI – Clone a machine, add DHCP Reservations, alter CPUID 2 | 3 | This script loads a GUI that is used to clone and existing virtual machine, set a DHCP reservation based on the new VM's MAC Address, and finally configure the new VM's CPUID to mask the CPU that is known to the guest OS. 4 | 5 | You can read more about this script the decisions made in its design here: 6 | - https://veducate.co.uk/powercli-gui-clone-machine-dhcp-cpuid/ -------------------------------------------------------------------------------- /Configure VM resources from RVTools Output file/README.md: -------------------------------------------------------------------------------- 1 | ## Configure VM resources from RVTools output file 2 | 3 | This script reads the values from an RVTOOLs output file, then sets the VMs in vCenter to these resources. 4 | 5 | This script was created for a customer who had to restore VMs from backups but needed to ensure the resources provided for the VMs were the same as the last RVTools output. -------------------------------------------------------------------------------- /Configure VM resources from RVTools Output file/Set_VM_Values_From_RVTools_Output.ps1: -------------------------------------------------------------------------------- 1 | $Server = Read-Host -Prompt 'Input your server name' 2 | $Restore = "_RestoreFriday" 3 | $ServerRestore = $Server + $Restore$old_vm = get-vm -name $server 4 | $new_vm = get-vm -name $ServerRestore 5 | set-vm -vm $new_vm -NumCpu $old_vm.NumCpu -MemoryMB $old_vm.MemoryMB -confirm:$false 6 | $newnics = Get-NetworkAdapter -vm $new_vm 7 | if ($newnics.count -eq 0) { 8 | $nics = Get-NetworkAdapter -vm $orig_vm 9 | $nics | %{ 10 | $nic = $_ 11 | New-Networkadapter -vm $new_vm -NetworkName $nic.networkname -Type $nic.type -startconnected:$true -confirm:$false 12 | } 13 | } else { Write-Host "`nINFO: " $(get-date -format "yyyyMMdd-HHmmss") "Restored VM already contain NICs please check manually" } 14 | -------------------------------------------------------------------------------- /Create vCenter Roles/Create_App_Volumes_vCenter_Roles.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Create_App_Volumes_vCenter_Roles.ps1 - PowerShell Script to create a new vCenter Roles algined with the prereqs for App Volumes. 4 | .DESCRIPTION 5 | This script is used to create a new roles on your vCenter server for App Volumes 2.x, 3.x and 4.x 6 | The newly created role will be filled with the needed permissions for App Volumes 7 | The permissions are based on the documentation found here: https://docs.vmware.com/en/VMware-App-Volumes/4/com.vmware.appvolumes.admin.doc/GUID-505624F3-F3EB-428C-BEA0-5BD7F6095A1F.html 8 | .OUTPUTS 9 | Results are printed to the console. 10 | .NOTES 11 | Author Dean Lewis, https://vEducate.co.uk, Twitter: @saintdle 12 | 13 | Change Log V1.00, 30/06/2020 - Initial version 14 | .LICENSE 15 | MIT License 16 | Copyright (c) 2020 Dean Lewis 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | The above copyright notice and this permission notice shall be included in all 24 | copies or substantial portions of the Software. 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | #> 33 | 34 | # Load the PowerCLI SnapIn and set the configuration 35 | Add-PSSnapin VMware.VimAutomation.Core -ea "SilentlyContinue" 36 | Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null 37 | 38 | # Get the vCenter Server Name to connect to 39 | $vCenterServer = Read-Host "Enter vCenter Server host name (DNS with FQDN or IP address)" 40 | 41 | # Get User to connect to vCenter Server 42 | $vCenterUser = Read-Host "Enter your user name (DOMAIN\User or user@domain.com)" 43 | 44 | # Get Password to connect to the vCenter Server 45 | $vCenterUserPassword = Read-Host "Enter your password (this will be converted to a secure string)" -AsSecureString:$true 46 | 47 | # Collect username and password as credentials 48 | $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $vCenterUser,$vCenterUserPassword 49 | 50 | # Connect to the vCenter Server with collected credentials 51 | Connect-VIServer -Server $vCenterServer -Credential $Credentials | Out-Null 52 | Write-Host "Connected to your vCenter server $vCenterServer" -ForegroundColor Green 53 | 54 | $cvRole = "App Volumes Role" 55 | $cvRoleIds = @( 56 | 'System.Anonymous', 57 | 'System.View', 58 | 'System.Read', 59 | 'Global.CancelTask', 60 | 'Folder.Create', 61 | 'Folder.Delete', 62 | 'Datastore.Browse', 63 | 'Datastore.DeleteFile', 64 | 'Datastore.FileManagement', 65 | 'Datastore.AllocateSpace', 66 | 'Datastore.UpdateVirtualMachineFiles', 67 | 'Host.Local.CreateVM', 68 | 'Host.Local.ReconfigVM', 69 | 'Host.Local.DeleteVM', 70 | 'VirtualMachine.Inventory.Create', 71 | 'VirtualMachine.Inventory.CreateFromExisting', 72 | 'VirtualMachine.Inventory.Register', 73 | 'VirtualMachine.Inventory.Delete', 74 | 'VirtualMachine.Inventory.Unregister', 75 | 'VirtualMachine.Inventory.Move', 76 | 'VirtualMachine.Interact.PowerOn', 77 | 'VirtualMachine.Interact.PowerOff', 78 | 'VirtualMachine.Interact.Suspend', 79 | 'VirtualMachine.Config.AddExistingDisk', 80 | 'VirtualMachine.Config.AddNewDisk', 81 | 'VirtualMachine.Config.RemoveDisk', 82 | 'VirtualMachine.Config.AddRemoveDevice', 83 | 'VirtualMachine.Config.Settings', 84 | 'VirtualMachine.Config.Resource', 85 | 'VirtualMachine.Provisioning.Customize', 86 | 'VirtualMachine.Provisioning.Clone', 87 | 'VirtualMachine.Provisioning.PromoteDisks', 88 | 'VirtualMachine.Provisioning.CreateTemplateFromVM', 89 | 'VirtualMachine.Provisioning.DeployTemplate', 90 | 'VirtualMachine.Provisioning.CloneTemplate', 91 | 'VirtualMachine.Provisioning.MarkAsTemplate', 92 | 'VirtualMachine.Provisioning.MarkAsVM', 93 | 'VirtualMachine.Provisioning.ReadCustSpecs', 94 | 'VirtualMachine.Provisioning.ModifyCustSpecs', 95 | 'Resource.AssignVMToPool', 96 | 'Task.Create', 97 | 'Sessions.TerminateSession', 98 | ) 99 | 100 | New-VIRole -name $cvRole -Privilege (Get-VIPrivilege -Server $viserver -id $cvRoleIds) -Server $viserver | Out-Null 101 | Write-Host "Creating vCenter role $cvRole" -ForegroundColor Green 102 | Set-VIRole -Role $cvRole -AddPrivilege (Get-VIPrivilege -Server $viserver -id $cvRoleIds) -Server $viserver | OUt-Null 103 | Write-Host "Setting vCenter role $cvRole" -ForegroundColor Cyan 104 | 105 | # Disconnecting from the vCenter Server 106 | Disconnect-VIServer -Confirm:$false 107 | Write-Host "Disconnected from your vCenter Server $vCenterServer" -ForegroundColor Green 108 | -------------------------------------------------------------------------------- /Create vCenter Roles/Create_CSI_Driver_vCenter_Roles.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Create-CNS-Roles.ps1 - PowerShell Script to create a new vCenter Roles algined with the prereqs for the Kubernetes vSphere CSI Driver. 4 | .DESCRIPTION 5 | This script is used to create a new roles on your vCenter server. 6 | The newly created role will be filled with the needed permissions for using it with Kubernetes vSphere CSI Driver. 7 | The permissions are based on the documentation found here: https://vsphere-csi-driver.sigs.k8s.io/driver-deployment/prerequisites.html 8 | .OUTPUTS 9 | Results are printed to the console. 10 | .NOTES 11 | Author Dean Lewis, https://vEducate.co.uk, Twitter: @saintdle 12 | 13 | Change Log V1.00, 28/05/2020 - Initial version 14 | .LICENSE 15 | MIT License 16 | Copyright (c) 2020 Dean Lewis 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | The above copyright notice and this permission notice shall be included in all 24 | copies or substantial portions of the Software. 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | #> 33 | 34 | # Load the PowerCLI SnapIn and set the configuration 35 | Add-PSSnapin VMware.VimAutomation.Core -ea "SilentlyContinue" 36 | Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null 37 | 38 | # Get the vCenter Server Name to connect to 39 | $vCenterServer = Read-Host "Enter vCenter Server host name (DNS with FQDN or IP address)" 40 | 41 | # Get User to connect to vCenter Server 42 | $vCenterUser = Read-Host "Enter your user name (DOMAIN\User or user@domain.com)" 43 | 44 | # Get Password to connect to the vCenter Server 45 | $vCenterUserPassword = Read-Host "Enter your password (this will be converted to a secure string)" -AsSecureString:$true 46 | 47 | # Collect username and password as credentials 48 | $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $vCenterUser,$vCenterUserPassword 49 | 50 | # Connect to the vCenter Server with collected credentials 51 | Connect-VIServer -Server $vCenterServer -Credential $Credentials | Out-Null 52 | Write-Host "Connected to your vCenter server $vCenterServer" -ForegroundColor Green 53 | 54 | # Create CNS-DATASTORE role 55 | $CNSDatastorePrivilege = @( 56 | 'Datastore.FileManagement', 57 | 'System.Anonymous', 58 | 'System.Read', 59 | 'System.View' 60 | ) 61 | $CNSDatastoreRole = New-VIRole -Name 'CNS-DATASTORE' -Privilege (Get-VIPrivilege -Id $CNSDatastorePrivilege) | Out-Null 62 | Write-Host "Creating vCenter role $CNSDatastoreRolee" -ForegroundColor Green 63 | 64 | # Create CNS-HOST-CONFIG-STORAGE role 65 | $CNSHostConfigStoragePrivilege = @( 66 | 'Host.Config.Storage', 67 | 'System.Anonymous', 68 | 'System.Read', 69 | 'System.View' 70 | ) 71 | $CNSHostConfigStorage = New-VIRole -Name 'CNS-HOST-CONFIG-STORAGE' -Privilege (Get-VIPrivilege -Id $CNSHostConfigStoragePrivilege) | Out-Null 72 | Write-Host "Creating vCenter role $CNSHostConfigStorage" -ForegroundColor Green 73 | 74 | # Create CNS-VM role 75 | $CNSVMPrivilege = @( 76 | 'VirtualMachine.Config.AddExistingDisk', 77 | 'VirtualMachine.Config.AddRemoveDevice' 78 | 'System.Anonymous', 79 | 'System.Read', 80 | 'System.View' 81 | ) 82 | $CNSVM = New-VIRole -Name 'CNS-VM' -Privilege (Get-VIPrivilege -Id $CNSVMPrivilege) | Out-Null 83 | Write-Host "Creating vCenter role $CNSVM" -ForegroundColor Green 84 | 85 | # Create CNS-SEARCH-AND-SPBM role 86 | $CNSSearchAndSPBMPrivilege = @( 87 | 'Cns.Searchable', 88 | 'StorageProfile.View' 89 | 'System.Anonymous', 90 | 'System.Read', 91 | 'System.View' 92 | ) 93 | $CNSSearchAndSPBM = New-VIRole -Name 'CNS-SEARCH-AND-SPBM' -Privilege (Get-VIPrivilege -Id $CNSSearchAndSPBMPrivilege) | Out-Null 94 | Write-Host "Creating vCenter role $CNSSearchAndSPBM" -ForegroundColor Green 95 | 96 | 97 | # Disconnecting from the vCenter Server 98 | Disconnect-VIServer -Confirm:$false 99 | Write-Host "Disconnected from your vCenter Server $vCenterServer" -ForegroundColor Green 100 | 101 | -------------------------------------------------------------------------------- /Create vCenter Roles/Create_vCenter_OpenShift_Install_Role.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Create_vCenter_OpenShift_Install_Role.ps1 - PowerShell Script to create a new vCenter Roles algined with the prereqs for the OpenShift Container Platform Install. 4 | .DESCRIPTION 5 | This script is used to create a new roles on your vCenter server. 6 | The newly created role will be filled with the needed permissions for installing OpenShift Container Platform using the IPI Method. 7 | The permissions are based on the documentation found here: https://docs.openshift.com/container-platform/4.6/installing/installing_vsphere/installing-vsphere-installer-provisioned.html#installation-vsphere-installer-infra-requirements_installing-vsphere-installer-provisioned 8 | .OUTPUTS 9 | Results are printed to the console. 10 | .NOTES 11 | Author Dean Lewis, https://vEducate.co.uk, Twitter: @saintdle 12 | 13 | Change Log V1.00, 07/11/2020 - Initial version 14 | .LICENSE 15 | MIT License 16 | Copyright (c) 2020 Dean Lewis 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | The above copyright notice and this permission notice shall be included in all 24 | copies or substantial portions of the Software. 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | #> 33 | 34 | # Load the PowerCLI SnapIn and set the configuration 35 | Add-PSSnapin VMware.VimAutomation.Core -ea "SilentlyContinue" 36 | Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null 37 | 38 | # Get the vCenter Server Name to connect to 39 | $vCenterServer = Read-Host "Enter vCenter Server host name (DNS with FQDN or IP address)" 40 | 41 | # Get User to connect to vCenter Server 42 | $vCenterUser = Read-Host "Enter your user name (DOMAIN\User or user@domain.com)" 43 | 44 | # Get Password to connect to the vCenter Server 45 | $vCenterUserPassword = Read-Host "Enter your password (this will be converted to a secure string)" -AsSecureString:$true 46 | 47 | # Collect username and password as credentials 48 | $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $vCenterUser,$vCenterUserPassword 49 | 50 | # Connect to the vCenter Server with collected credentials 51 | Connect-VIServer -Server $vCenterServer -Credential $Credentials | Out-Null 52 | Write-Host "Connected to your vCenter server $vCenterServer" -ForegroundColor Green 53 | 54 | # Create OpenShift-Install role 55 | $OpenShiftInstallPrivilege = @( 56 | 'System.Anonymous', 57 | 'System.View', 58 | 'System.Read', 59 | 'Folder.Create', 60 | 'Folder.Delete', 61 | 'Datastore.Browse', 62 | 'Datastore.DeleteFile', 63 | 'Datastore.FileManagement', 64 | 'Datastore.AllocateSpace', 65 | 'Network.Assign', 66 | 'VirtualMachine.Inventory.Create', 67 | 'VirtualMachine.Inventory.CreateFromExisting', 68 | 'VirtualMachine.Inventory.Register', 69 | 'VirtualMachine.Inventory.Delete', 70 | 'VirtualMachine.Inventory.Unregister', 71 | 'VirtualMachine.Inventory.Move', 72 | 'VirtualMachine.Interact.PowerOn', 73 | 'VirtualMachine.Interact.PowerOff', 74 | 'VirtualMachine.Interact.Suspend', 75 | 'VirtualMachine.Interact.SuspendToMemory', 76 | 'VirtualMachine.Interact.Reset', 77 | 'VirtualMachine.Interact.Pause', 78 | 'VirtualMachine.Interact.AnswerQuestion', 79 | 'VirtualMachine.Interact.ConsoleInteract', 80 | 'VirtualMachine.Interact.DeviceConnection', 81 | 'VirtualMachine.Interact.SetCDMedia', 82 | 'VirtualMachine.Interact.SetFloppyMedia', 83 | 'VirtualMachine.Interact.ToolsInstall', 84 | 'VirtualMachine.Interact.GuestControl', 85 | 'VirtualMachine.Interact.DefragmentAllDisks', 86 | 'VirtualMachine.Interact.CreateSecondary', 87 | 'VirtualMachine.Interact.TurnOffFaultTolerance', 88 | 'VirtualMachine.Interact.MakePrimary', 89 | 'VirtualMachine.Interact.TerminateFaultTolerantVM', 90 | 'VirtualMachine.Interact.DisableSecondary', 91 | 'VirtualMachine.Interact.EnableSecondary', 92 | 'VirtualMachine.Interact.Record', 93 | 'VirtualMachine.Interact.Replay', 94 | 'VirtualMachine.Interact.Backup', 95 | 'VirtualMachine.Interact.CreateScreenshot', 96 | 'VirtualMachine.Interact.PutUsbScanCodes', 97 | 'VirtualMachine.Interact.SESparseMaintenance', 98 | 'VirtualMachine.Interact.DnD', 99 | 'VirtualMachine.GuestOperations.Query', 100 | 'VirtualMachine.GuestOperations.Modify', 101 | 'VirtualMachine.GuestOperations.Execute', 102 | 'VirtualMachine.GuestOperations.QueryAliases', 103 | 'VirtualMachine.GuestOperations.ModifyAliases', 104 | 'VirtualMachine.Config.Rename', 105 | 'VirtualMachine.Config.Annotation', 106 | 'VirtualMachine.Config.AddExistingDisk', 107 | 'VirtualMachine.Config.AddNewDisk', 108 | 'VirtualMachine.Config.RemoveDisk', 109 | 'VirtualMachine.Config.RawDevice', 110 | 'VirtualMachine.Config.HostUSBDevice', 111 | 'VirtualMachine.Config.CPUCount', 112 | 'VirtualMachine.Config.Memory', 113 | 'VirtualMachine.Config.AddRemoveDevice', 114 | 'VirtualMachine.Config.EditDevice', 115 | 'VirtualMachine.Config.Settings', 116 | 'VirtualMachine.Config.Resource', 117 | 'VirtualMachine.Config.UpgradeVirtualHardware', 118 | 'VirtualMachine.Config.ResetGuestInfo', 119 | 'VirtualMachine.Config.ToggleForkParent', 120 | 'VirtualMachine.Config.AdvancedConfig', 121 | 'VirtualMachine.Config.DiskLease', 122 | 'VirtualMachine.Config.SwapPlacement', 123 | 'VirtualMachine.Config.DiskExtend', 124 | 'VirtualMachine.Config.ChangeTracking', 125 | 'VirtualMachine.Config.QueryUnownedFiles', 126 | 'VirtualMachine.Config.ReloadFromPath', 127 | 'VirtualMachine.Config.QueryFTCompatibility', 128 | 'VirtualMachine.Config.MksControl', 129 | 'VirtualMachine.Config.ManagedBy', 130 | 'VirtualMachine.State.CreateSnapshot', 131 | 'VirtualMachine.State.RevertToSnapshot', 132 | 'VirtualMachine.State.RemoveSnapshot', 133 | 'VirtualMachine.State.RenameSnapshot', 134 | 'VirtualMachine.Hbr.ConfigureReplication', 135 | 'VirtualMachine.Hbr.ReplicaManagement', 136 | 'VirtualMachine.Hbr.MonitorReplication', 137 | 'VirtualMachine.Provisioning.Customize', 138 | 'VirtualMachine.Provisioning.Clone', 139 | 'VirtualMachine.Provisioning.PromoteDisks', 140 | 'VirtualMachine.Provisioning.CreateTemplateFromVM', 141 | 'VirtualMachine.Provisioning.DeployTemplate', 142 | 'VirtualMachine.Provisioning.CloneTemplate', 143 | 'VirtualMachine.Provisioning.MarkAsTemplate', 144 | 'VirtualMachine.Provisioning.MarkAsVM', 145 | 'VirtualMachine.Provisioning.ReadCustSpecs', 146 | 'VirtualMachine.Provisioning.ModifyCustSpecs', 147 | 'VirtualMachine.Provisioning.DiskRandomAccess', 148 | 'VirtualMachine.Provisioning.DiskRandomRead', 149 | 'VirtualMachine.Provisioning.FileRandomAccess', 150 | 'VirtualMachine.Provisioning.GetVmFiles', 151 | 'VirtualMachine.Provisioning.PutVmFiles', 152 | 'VirtualMachine.Namespace.Management', 153 | 'VirtualMachine.Namespace.Query', 154 | 'VirtualMachine.Namespace.ModifyContent', 155 | 'VirtualMachine.Namespace.ReadContent', 156 | 'VirtualMachine.Namespace.Event', 157 | 'VirtualMachine.Namespace.EventNotify', 158 | 'Resource.AssignVMToPool', 159 | 'VApp.ResourceConfig', 160 | 'VApp.InstanceConfig', 161 | 'VApp.ApplicationConfig', 162 | 'VApp.ManagedByConfig', 163 | 'VApp.Export', 164 | 'VApp.Import', 165 | 'VApp.PullFromUrls', 166 | 'VApp.ExtractOvfEnvironment', 167 | 'VApp.AssignVM', 168 | 'VApp.AssignResourcePool', 169 | 'VApp.AssignVApp', 170 | 'VApp.Clone', 171 | 'VApp.Create', 172 | 'VApp.Delete', 173 | 'VApp.Unregister', 174 | 'VApp.Move', 175 | 'VApp.PowerOn', 176 | 'VApp.PowerOff', 177 | 'VApp.Suspend', 178 | 'VApp.Rename', 179 | 'InventoryService.Tagging.AttachTag', 180 | 'InventoryService.Tagging.ModifyUsedByForCategory', 181 | 'InventoryService.Tagging.DeleteCategory', 182 | 'InventoryService.Tagging.EditTag', 183 | 'InventoryService.Tagging.ModifyUsedByForTag', 184 | 'InventoryService.Tagging.CreateTag', 185 | 'InventoryService.Tagging.DeleteTag', 186 | 'InventoryService.Tagging.ObjectAttachable', 187 | 'StorageProfile.Update', 188 | 'StorageProfile.View', 189 | 'InventoryService.Tagging.EditCategory', 190 | 'InventoryService.Tagging.CreateCategory' 191 | ) 192 | $OpenShiftInstallRole = New-VIRole -Name 'OpenShift-Install' -Privilege (Get-VIPrivilege -Id $OpenShiftInstallPrivilege) | Out-Null 193 | Write-Host "Creating vCenter role $OpenShiftInstallRole" -ForegroundColor Green 194 | 195 | # Disconnecting from the vCenter Server 196 | Disconnect-VIServer -Confirm:$false 197 | Write-Host "Disconnected from your vCenter Server $vCenterServer" -ForegroundColor Green 198 | 199 | -------------------------------------------------------------------------------- /Create vCenter Roles/README.md: -------------------------------------------------------------------------------- 1 | ## Create vCenter Roles 2 | 3 | Script to create vCenter roles for the following use-cases: 4 | - App volumes 5 | - CSI Driver 6 | - OpenShift Installer 7 | 8 | -------------------------------------------------------------------------------- /HCX/HCX Migration - Bulk Migrations with varying destinations from CSV.ps1: -------------------------------------------------------------------------------- 1 | write-host(“Getting Time for Scheduling”) 2 | $startTime = [DateTime]::Now.AddDays(12) 3 | $endTime = [DateTime]::Now.AddDays(15) 4 | Connect-HCXServer -Server SOURCEHCXSERVER 5 | write-host(“Getting Source Site”) 6 | $HcxSrcSite = Get-HCXSite -Source “SourceSite” 7 | write-host(“Getting Target Site”) 8 | $HcxDstSite = Get-HCXSite -Destination “DestinationSite” 9 | $HCXVMS = Import-CSV .\Import_VM_list.csv 10 | ForEach ($HCXVM in $HCXVMS) { 11 | $DstFolder = Get-HCXContainer $HCXVM.DESTINATION_VM_FOLDER -Site $HcxDstSite 12 | $DstCompute = Get-HCXContainer $HCXVM.DESTINATION_CLUSTER_OR_HOST -Site $HcxDstSite 13 | $DstDatastore = Get-HCXDatastore $HCXVM.DESTINATION_DATASTORE -Site $HcxDstSite 14 | $SrcNetwork = Get-HCXNetwork $HCXVM.SOURCE_PORTGROUP -type DistributedVirtualPortgroup -Site $HcxSrcSite 15 | $DstNetwork = Get-HCXNetwork $HCXVM.DESTINATION_PORTGROUP -Site $HcxDstSite 16 | $NetworkMapping = New-HCXNetworkMapping -SourceNetwork $SrcNetwork -DestinationNetwork $DstNetwork 17 | $NewMigration = New-HCXMigration -VM (Get-HCXVM $HCXVM.VM_NAME) -MigrationType Bulk -SourceSite $HcxSrcSite -DestinationSite $HcxDstSite -Folder $DstFolder -TargetComputeContainer $DstCompute -TargetDatastore $DstDatastore -NetworkMapping $NetworkMapping -DiskProvisionType Thin -UpgradeVMTools $True -RemoveISOs $True -ForcePowerOffVm $True -RetainMac $True -UpgradeHardware $True -RemoveSnapshots $True -ScheduleStartTime $startTime -ScheduleEndTime $endTime 18 | Start-HCXMigration -Migration $NewMigration -Confirm:$false 19 | } 20 | -------------------------------------------------------------------------------- /HCX/HCX Migration - Standard Bulk Migration from CSV file.ps1: -------------------------------------------------------------------------------- 1 | write-host("Getting Time for Scheduling") 2 | $startTime = [DateTime]::Now.AddDays(12) 3 | $endTime = [DateTime]::Now.AddDays(15) 4 | 5 | #Connect-HCXServer -Server HCXSOURCESERVER 6 | write-host("Getting Source Site") 7 | $HcxSrcSite = get-hcxsite -source -server HCXSOURCESERVER 8 | write-host("Getting Target Site") 9 | $HcxDstSite = get-hcxsite -destination -server HCXSOURCESERVER -name "Destination VC" 10 | write-host("Getting VM (This may take a while)") 11 | $HcxVMS = Get-HCXVM -Name (Get-Content "location of textfile") -server HCXSOURCESERVER -site $HcxSrcSite 12 | write-host("Getting Folder") 13 | $DstFolder = Get-HCXContainer -Name "Dest VC Folder" -Site $HcxDstSite 14 | write-host("Getting Container") 15 | $DstCompute = Get-HCXContainer -Name "ESXIHOSTNAME or Dest Cluster" -Site $HcxDstSite 16 | write-host("Getting Datastore") 17 | $DstDatastore = Get-HCXDatastore -Name "Dest Datastore" -Site $HcxDstSite 18 | write-host("Getting Source Network") 19 | $SrcNetwork = Get-HCXNetwork -Name "Source PortGroup" -type DistributedVirtualPortgroup -Site $HcxSrcSite 20 | write-host("Getting Target Network") 21 | $DstNetwork = Get-HCXNetwork -Name "Destination Network" -type DistributedVirtualPortgroup -Site $HcxDstSite 22 | write-host("Creating Network Mapping") 23 | $NetworkMapping = New-HCXNetworkMapping -SourceNetwork $SrcNetwork -DestinationNetwork $DstNetwork 24 | 25 | write-host("Creating Migration Command") 26 | 27 | ForEach ($HCXVM in $HCXVMS) { 28 | 29 | $NewMigration = New-HCXMigration -VM $HcxVM -MigrationType Bulk -SourceSite $HcxSrcSite -DestinationSite $HcxDstSite -Folder $DstFolder ` 30 | -TargetComputeContainer $DstCompute -TargetDatastore $DstDatastore -NetworkMapping $NetworkMapping -DiskProvisionType Thin ` 31 | -UpgradeVMTools $True -RemoveISOs $True -ForcePowerOffVm $True -RetainMac $True -UpgradeHardware $True ` 32 | -RemoveSnapshots $True -ScheduleStartTime $startTime -ScheduleEndTime $endTime 33 | Start-HCXMigration -Migration $NewMigration -Confirm:$false 34 | -------------------------------------------------------------------------------- /HCX/HCX Migration - Standard Bulk Migration.ps1: -------------------------------------------------------------------------------- 1 | write-host("Getting Time for Scheduling") 2 | $startTime = [DateTime]::Now.AddDays(12) 3 | $endTime = [DateTime]::Now.AddDays(15) 4 | 5 | #Connect-HCXServer -Server HCXSOURCESERVER 6 | write-host("Getting Source Site") 7 | $HcxSrcSite = get-hcxsite -source -server HCXSOURCESERVER 8 | write-host("Getting Target Site") 9 | $HcxDstSite = get-hcxsite -destination -server HCXSOURCESERVER -name "Destination VC" 10 | write-host("Getting VM (This may take a while)") 11 | $HcxVMS = Get-HCXVM -Name * -server HCXSOURCESERVER -site $HcxSrcSite | Where-Object -Property Name -Like "*HCX*" #| Select-Object -Property Name 12 | write-host("Getting Folder") 13 | $DstFolder = Get-HCXContainer -Name "Dest VC Folder" -Site $HcxDstSite 14 | write-host("Getting Container") 15 | $DstCompute = Get-HCXContainer -Name "ESXIHOSTNAME or Dest Cluster" -Site $HcxDstSite 16 | write-host("Getting Datastore") 17 | $DstDatastore = Get-HCXDatastore -Name "Dest Datastore" -Site $HcxDstSite 18 | write-host("Getting Source Network") 19 | $SrcNetwork = Get-HCXNetwork -Name "Source PortGroup" -type DistributedVirtualPortgroup -Site $HcxSrcSite 20 | write-host("Getting Target Network") 21 | $DstNetwork = Get-HCXNetwork -Name "Destination Network" -type DistributedVirtualPortgroup -Site $HcxDstSite 22 | write-host("Creating Network Mapping") 23 | $NetworkMapping = New-HCXNetworkMapping -SourceNetwork $SrcNetwork -DestinationNetwork $DstNetwork 24 | 25 | write-host("Creating Migration Command") 26 | 27 | ForEach ($HCXVM in $HCXVMS) { 28 | 29 | $NewMigration = New-HCXMigration -VM $HcxVM -MigrationType Bulk -SourceSite $HcxSrcSite -DestinationSite $HcxDstSite -Folder $DstFolder ` 30 | -TargetComputeContainer $DstCompute -TargetDatastore $DstDatastore -NetworkMapping $NetworkMapping -DiskProvisionType Thin ` 31 | -UpgradeVMTools $True -RemoveISOs $True -ForcePowerOffVm $True -RetainMac $True -UpgradeHardware $True ` 32 | -RemoveSnapshots $True -ScheduleStartTime $startTime -ScheduleEndTime $endTime 33 | Start-HCXMigration -Migration $NewMigration -Confirm:$false 34 | } 35 | -------------------------------------------------------------------------------- /HCX/HCX Migration Network - Select from HCX Network Extension or Local Network.ps1: -------------------------------------------------------------------------------- 1 | # Get VM details from HCX in a variable that needs to be migrated 2 | $vmmig = Get-HCXVM -Name $HCXVM.VM_NAME -Site $HcxSrcSite 3 | # Get VM details from vCenter for the VMs network adapter 4 | $networkAdapterList = Get-VM -Name $HCXVM.VM_NAME -Server $sourceVIServer | get-networkadapter 5 | # For Each Loop 6 | # $j = 0 - sets an variable to 0 7 | # $j -le $networkAdapterList.count - checks if the variable is less than the count of the network adapter list 8 | # ($networkAdapterList.Count -1) - Gets the count of the number of objects in the variable, minus 1 9 | # $j++ - increments the variable by 1 10 | for($j = 0; $j -le ($networkAdapterList.Count -1); $j++) 11 | { 12 | # Sets variable of the network adapter to the current network adapter in the list using the $j variable as the index number of the list 13 | $sourceNetwork = $vmmig.Network[$j] 14 | 15 | # Sets variable of the HCX network Extention appliance - where it's linked to the Network from the Migration varibles set before the loop. Selects the first returned object. 16 | $networkExtension = Get-HCXNetworkExtension | where -Property Network -like $vmmig.Network[$j].DisplayName | Select -First 1 17 | 18 | # If Statetment 19 | # If the network extension variable is not null, then it will run the following code 20 | if(($null -ne $networkExtension)) 21 | 22 | # Set variable to get Destination network from HCX by looking for the destination network object within the network extension - selects first object 23 | {$destinationNetwork = Get-HCXNetwork -Name $networkExtension.DestinationNetwork -Site $HcxDstSite | Select -First 1} 24 | else 25 | # If the network extension variable is null, then it will run the following code 26 | # Set variable to get Destination network from HCX - get HCX network from available networks (not HCX network extension based) - selects first object 27 | {$destinationNetwork = Get-HCXNetwork -Name $networkAdapterList[$j].NetworkName -type DistributedVirtualPortgroup -Site $HcxDstSite | Select -First 1} 28 | # End of If Statement 29 | 30 | # Set variable for Target Network Mapping > += adds/appends the network to the list of network mappings 31 | $targetNetworkMapping += New-HCXNetworkMapping -SourceNetwork $sourceNetwork -DestinationNetwork $destinationNetwork 32 | 33 | # Write out the current network mapping to the host display 34 | Write-Host "Network Mapping -> $targetNetworkMapping" 35 | } 36 | -------------------------------------------------------------------------------- /HCX/HCX Migration with Mobility Group.ps1: -------------------------------------------------------------------------------- 1 | write-host(“Getting Time for Scheduling”) 2 | $startTime = [DateTime]::Now.AddDays(12) 3 | $endTime = [DateTime]::Now.AddDays(15) 4 | 5 | Connect-HCXServer -Server "HCX CONNECTOR" 6 | 7 | write-host(“Getting Source Site”) 8 | $HcxSrcSite = Get-HCXSite -Source 9 | 10 | write-host(“Getting Target Site”) 11 | $HcxDstSite = Get-HCXSite -Destination “DEST SITE” -ErrorAction SilentlyContinue 12 | 13 | write-host(“Define Mobility Group Source and Destination Sites”) 14 | $NewMGC = New-HCXMobilityGroupConfiguration -SourceSite $HcxSrcSite -DestinationSite $HcxDstSite 15 | 16 | write-host(“Define Mobility Group Name”) 17 | $MobilityGroupName = "Batman" 18 | 19 | write-host(“Import csv details for the VMs to be migrated”) 20 | $HCXVMS = Import-CSV .\Import_VM_list_mobility.csv 21 | 22 | ForEach ($HCXVM in $HCXVMS) { 23 | 24 | $DstFolder = Get-HCXContainer $HCXVM.DESTINATION_VM_FOLDER -Site $HcxDstSite 25 | $DstCompute = Get-HCXContainer $HCXVM.DESTINATION_CLUSTER_OR_HOST -Site $HcxDstSite 26 | $DstDatastore = Get-HCXDatastore $HCXVM.DESTINATION_DATASTORE -Site $HcxDstSite 27 | $SrcNetwork = Get-HCXNetwork $HCXVM.SOURCE_PORTGROUP -type DistributedVirtualPortgroup -Site $HcxSrcSite 28 | $DstNetwork = Get-HCXNetwork $HCXVM.DESTINATION_PORTGROUP -type NsxtSegment -Site $HcxDstSite 29 | $NetworkMapping = New-HCXNetworkMapping -SourceNetwork $SrcNetwork -DestinationNetwork $DstNetwork 30 | $NewMigration = New-HCXMigration -VM (Get-HCXVM $HCXVM.VM_NAME) -MigrationType Bulk -SourceSite $HcxSrcSite -DestinationSite $HcxDstSite -Folder $DstFolder -TargetComputeContainer $DstCompute -TargetDatastore $DstDatastore -NetworkMapping $NetworkMapping -DiskProvisionType Thin -UpgradeVMTools $False -RemoveISOs $True -ForcePowerOffVm $True -RetainMac $True -UpgradeHardware $False -RemoveSnapshots $True -ScheduleStartTime $startTime -ScheduleEndTime $endTime -MobilityGroupMigration 31 | 32 | #This is used the first time to create the mobility group with the required configuration, after the first go it will error saying its already created which is expected 33 | $mobilityGroup1 = New-HCXMobilityGroup -Name $MobilityGroupName -Migration $NewMigration -GroupConfiguration $NewMGC -ErrorAction SilentlyContinue 34 | 35 | #Even though this command will error with "Value cannot be null", it still works and adds each vm to the created mobility group 36 | Set-HCXMobilityGroup -MobilityGroup (get-hcxmobilitygroup -name $MobilityGroupName) -Migration $NewMigration -addMigration -ErrorAction SilentlyContinue 37 | 38 | } 39 | 40 | #This will error with "Value cannot be null" but it will start the migrations of the VMs in the mobility group 41 | Start-HCXMobilityGroupMigration -MobilityGroup (get-hcxmobilitygroup -name $MobilityGroupName) -ErrorAction SilentlyContinue 42 | -------------------------------------------------------------------------------- /HCX/HCX Migration.csv: -------------------------------------------------------------------------------- 1 | VM_NAME,,DESTINATION_VM_FOLDER,DESTINATION_CLUSTER_OR_HOST,DESTINATION_DATASTORE,SOURCE_PORTGROUP,DESTINATION_PORTGROUP 2 | mig-vm,vmfolder,vSphereCluster,Datastore,SrcPG,DstPG 3 | -------------------------------------------------------------------------------- /HCX/HCX Mobility Group Migrations.csv: -------------------------------------------------------------------------------- 1 | VM_NAME,DESTINATION_VM_FOLDER,DESTINATION_CLUSTER_OR_HOST,DESTINATION_DATASTORE,SOURCE_PORTGROUP,DESTINATION_PORTGROUP 2 | example-vm,dest-folder,dest-cluster,dest-datastore,source-pg,dest-pg 3 | -------------------------------------------------------------------------------- /HCX/HCX Reverse Migration - Bulk Migration from CSV and move into correct VM folders.ps1: -------------------------------------------------------------------------------- 1 | write-host(“Getting Time for Scheduling”) 2 | $startTime = [DateTime]::Now.AddDays(12) 3 | $endTime = [DateTime]::Now.AddDays(15) 4 | Connect-HCXServer -Server (Legacy HCX Connector) # Connect to HCX Connector at Legacy 5 | Connect-VIServer -Server w(LegacyVC) # Connect to Legacy vCenter 6 | write-host(“Getting Source Site”) 7 | 8 | $HcxSrcSite = Get-HCXSite -Destination -server (HCX Connctor) -name (Cloud VC) # Source site is the cloud 9 | 10 | write-host(“Getting Target Site”) 11 | 12 | $HcxDstSite = Get-HCXSite -Source (LegacyVC) # Destination is Legacy vCenter 13 | 14 | $HCXVMS = Import-CSV -Path 'E:\PowerCLI\Bulk\FromCloudtoLegacy\HCX_Reverse_BULK_Migration_From_Cloud_to_Legacy_withCSV.csv' 15 | 16 | ForEach ($HCXVM in $HCXVMS) { 17 | $folderfull = get-folder $HCXVM.DESTINATION_VM_FOLDER | where {$_.Parent -Match $HCXVM.DESTINATION_VM_ParentFOLDER} | select Id 18 | $foldershort = $folderfull.Id.Replace("Folder-group-","*") 19 | $ContainerUid = Get-HCXContainer | where {$_.Id -Like $foldershort} | Select Uid 20 | $DstFolder = Get-hcxcontainer -Uid $ContainerUid.Uid 21 | $DstCompute = Get-HCXContainer -Type Cluster $HCXVM.DESTINATION_CLUSTER_OR_HOST -Site $HcxDstSite 22 | $DstDatastore = Get-HCXDatastore $HCXVM.DESTINATION_DATASTORE -Site $HcxDstSite 23 | $SrcNetwork = Get-HCXNetwork $HCXVM.SOURCE_PORTGROUP -type DistributedVirtualPortgroup -Site $HcxSrcSite 24 | $DstNetwork = Get-HCXNetwork $HCXVM.DESTINATION_PORTGROUP -Type DistributedVirtualPortgroup -Site $HcxDstSite 25 | $NetworkMapping = New-HCXNetworkMapping -SourceNetwork $SrcNetwork -DestinationNetwork $DstNetwork 26 | $NewMigration = New-HCXMigration -VM (Get-HCXVM -name $HCXVM.VM_NAME -site $HcxSrcSite ) -MigrationType Bulk -SourceSite $HcxSrcSite -DestinationSite $HcxDstSite -Folder $DstFolder -TargetComputeContainer $DstCompute -TargetDatastore $DstDatastore -NetworkMapping $NetworkMapping -DiskProvisionType Thin -UpgradeVMTools $False -RemoveISOs $True -ForcePowerOffVm $True -RetainMac $True -UpgradeHardware $False -RemoveSnapshots $True -ScheduleStartTime $startTime -ScheduleEndTime $endTime 27 | Start-HCXMigration -Migration $NewMigration -Confirm:$false -WhatIf 28 | 29 | } 30 | Disconnect-HCXServer -Server (HCX Connector at Legacy) -Confirm:$false 31 | Disconnect-VIServer -Server (Legacy VC) -Confirm:$False 32 | 33 | # This script is used for bulk migrations, you can populate the csv with VMs to migrate from Cloud to the Legacy VC/clusters 34 | # The -WhatIf is used for testing, once you have populated the csv uncomment the -WhatIf and run it, if it runs without errors you can comment it out again and run the command for it to configure actual migrations 35 | # Bulk Syncs will start but the cut over is scheduled for 12 days in advance, this allows you to configure the syncs to start in advance of the migration event, and during the event you can cut over VMs by brinng the date forward to what suits you (in the web interface) 36 | # Since the legacy side has multiple sub folders with the same name in vCenter, this script needs to connect to vcenter and pull the IDs for the correct folder based on its uid and then pass that back to hcx, since hcx does not support this directly, 37 | # which is what the script is doing with #folderfull #foldershot #containeruid 38 | -------------------------------------------------------------------------------- /HCX/HCX Reverse Migration - Bulk Migration from CSV.ps1: -------------------------------------------------------------------------------- 1 | write-host(“Getting Source Site”) 2 | 3 | $HcxSrcSite = Get-HCXSite -Destination -server (Legacy HCX Connector) -name (Cloud vCenter) 4 | 5 | write-host(“Getting Target Site”) 6 | 7 | $HcxDstSite = Get-HCXSite -Source (Legacy vCenter) 8 | $HCXVMS = Import-CSV -Path 'E:\PowerCLI\HCX_Reverse Migration_From_Cloud_to_Legacy_withCSV.csv' 9 | 10 | ForEach ($HCXVM in $HCXVMS) { 11 | $DstFolder = Get-HCXContainer $HCXVM.DESTINATION_VM_FOLDER -Site $HcxDstSite 12 | $DstCompute = Get-HCXContainer -Type Cluster $HCXVM.DESTINATION_CLUSTER_OR_HOST -Site $HcxDstSite 13 | $DstDatastore = Get-HCXDatastore $HCXVM.DESTINATION_DATASTORE -Site $HcxDstSite 14 | $SrcNetwork = Get-HCXNetwork $HCXVM.SOURCE_PORTGROUP -type DistributedVirtualPortgroup -Site $HcxSrcSite 15 | $DstNetwork = Get-HCXNetwork $HCXVM.DESTINATION_PORTGROUP -Type DistributedVirtualPortgroup -Site $HcxDstSite 16 | $NetworkMapping = New-HCXNetworkMapping -SourceNetwork $SrcNetwork -DestinationNetwork $DstNetwork 17 | $NewMigration = New-HCXMigration -VM (Get-HCXVM -name $HCXVM.VM_NAME -site $HcxSrcSite ) -MigrationType vMotion -SourceSite $HcxSrcSite -DestinationSite $HcxDstSite -Folder $DstFolder -TargetComputeContainer $DstCompute -TargetDatastore $DstDatastore -NetworkMapping $NetworkMapping -DiskProvisionType Thin -UpgradeVMTools $False -RemoveISOs $True -ForcePowerOffVm $True -RetainMac $True -UpgradeHardware $False -RemoveSnapshots $True 18 | Start-HCXMigration -Migration $NewMigration -Confirm:$false #-WhatIf 19 | } 20 | Disconnect-HCXServer -Server (Legacy HCX Connector) -Confirm:$false 21 | -------------------------------------------------------------------------------- /HCX/HCX Reverse Migration - with folder move.csv: -------------------------------------------------------------------------------- 1 | VM_NAME,DESTINATION_VM_ParentFOLDER,DESTINATION_VM_FOLDER,DESTINATION_CLUSTER_OR_HOST,DESTINATION_DATASTORE,SOURCE_PORTGROUP,DESTINATION_PORTGROUP 2 | mig-vm,"LegacyFolder","SubFolderinLegacy",vSphereCluster,Datastore,SrcPG,DstPG 3 | -------------------------------------------------------------------------------- /HCX/README.md: -------------------------------------------------------------------------------- 1 | ## HCX Migration Scripts 2 | 3 | These are the migration scripts that I produced with [Bilal Ahmed](https://twitter.com/Dark_KnightUK), to automate the HCX migrations and failback capabilities. 4 | 5 | ## Blog Posts 6 | 7 | These blog posts describe the usage of the scripts 8 | 9 | * https://vmusketeers.com/2020/01/06/hcx-powercli-scripts/ 10 | * https://vmusketeers.com/2020/04/27/hcx-powercli-and-reverse-migrations-hcx-powercli-saintdle-virtual_simon/ 11 | * https://vmusketeers.com/2021/07/08/hcx-mobility-group-migrations-using-powercli-scripts-hcx-vmwarehcx-powercli-vexpert-saintdle/ 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Dean 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## PowerCLI Scripts 2 | 3 | This repository is a number of scripts I've created over the years to assist with various tasks. 4 | 5 | I've tried to organise this as best as possible, and provide the relevant information or links to the supporting blog posts. -------------------------------------------------------------------------------- /Setup Host networking and storage ready for ISCSI LUNs/Configure_Host_Networking_and_iSCSI_Storage.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Configure_Host_Networking_and_iSCSI_Storage.ps1 - PowerShell Script configure a VMware ESXi host's networking and setup the iSCSI Software Adapter 4 | .DESCRIPTION 5 | You can read more about this script the decisions made in its design here: https://veducate.co.uk/powercli-setup-host-networking-and-storage-ready-for-iscsi-luns 6 | .OUTPUTS 7 | You are provided a GUI interface for interactions. 8 | .NOTES 9 | Author Dean Lewis, https://vEducate.co.uk, Twitter: @saintdle 10 | 11 | Change Log V1.00, 30/06/2020 - Initial version 12 | .LICENSE 13 | MIT License 14 | Copyright (c) 2020 Dean Lewis 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | The above copyright notice and this permission notice shall be included in all 22 | copies or substantial portions of the Software. 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | SOFTWARE. 30 | #> 31 | 32 | #Setup which host to target 33 | $VMhost = 'hostname' 34 | 35 | #Create vSwitch2 for storage, add vmnics, add two vmkernels with Storage IPs, setup NIC teaming (based on the fact you probably have vSwitch0 for mgmt and vSwitch1 for VM traffic) 36 | 37 | $vswitch2 = get-vmhost $VMhost | new-virtualswitch -Name vSwitch2 -Nic 'vmnic2','vmnic5' -Mtu 9000 -NumPorts 120 38 | 39 | New-VMHostNetworkAdapter -VMhost $VMhost -virtualswitch $vswitch2 -portgroup iSCSI_ESX_01 -ip IP_ADDR -subnetmask SUBNET_MASK -Mtu 9000 40 | 41 | New-VMHostNetworkAdapter -VMhost $VMhost -virtualswitch $vswitch2 -portgroup iSCSI_ESX_02 -ip IP_ADDR -subnetmask SUBNET_MASK -Mtu 9000 42 | 43 | Get-VirtualPortGroup -VMhost $VMhost -virtualswitch $vswitch2 -Name iSCSI_ESX_01 | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive vmnic2 -MakeNicUnused vmnic5 44 | 45 | Get-VirtualPortGroup -VMhost $VMhost -virtualswitch $vswitch2 -Name iSCSI_ESX_02 | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive vmnic5 -MakeNicUnused vmnic2 46 | 47 | #Create Software iSCSI Adapter 48 | 49 | get-vmhoststorage $vmhost | set-vmhoststorage -softwareiscsienabled $True 50 | 51 | #Get Software iSCSI adapter HBA number and put it into an array 52 | 53 | $HBA = Get-VMHostHba -VMHost $VMHost -Type iSCSI | %{$_.Device} 54 | 55 | #Set your VMKernel numbers, Use ESXCLI to create the iSCSI Port binding in the iSCSI Software Adapter 56 | 57 | $vmk1number = 'vmk1' 58 | $vmk2number = 'vmk2' 59 | $esxcli = Get-EsxCli -VMhost $VMhost 60 | $Esxcli.iscsi.networkportal.add($HBA, $Null, $vmk1number) 61 | $Esxcli.iscsi.networkportal.add($HBA, $Null, $vmk2number) 62 | 63 | #Setup the Discovery iSCSI IP addresses on the iSCSI Software Adapter 64 | 65 | $hbahost = get-vmhost $VMhost | get-vmhosthba -type iscsi 66 | new-iscsihbatarget -iscsihba $hbahost -address IP_ADDR 67 | 68 | #Rescan the HBA to discover any storage 69 | get-vmhoststorage $VMhost -rescanallhba -rescanvmfs 70 | -------------------------------------------------------------------------------- /Setup Host networking and storage ready for ISCSI LUNs/README.md: -------------------------------------------------------------------------------- 1 | ## Setup Host networking and storage ready for ISCSI LUNs 2 | 3 | You can read more about this script the decisions made in its design here: https://veducate.co.uk/powercli-setup-host-networking-and-storage-ready-for-iscsi-luns --------------------------------------------------------------------------------