Without actually testing the code against the requirements, I think Group-Object might be your best friend here.
It will let PowerShell do the required grouping for you.
Since skeleton code is easier to read, compared to a lot of text (at least for me), I would start testing and validating with below code.
I added some comments, documenting the main steps.
PS: why CustomFields and not Tags?
$caDeployment = 'deployment'$caJob = 'job'
$rootFolderName = 'Project'
# Folder where all 'deployment' folders shall go
$folder = Get-Folder -Name $rootFolderName
Get-VM -Name vm-* |
Group-Object -Property {$_.CustomFields[$caDeployment]} |
where {$_.Name} |
ForEach-Object -Process {
$deployment = $_.Name
# Group the VMs in a deployment on job type
Group-Object -InputObject $_.Group -Property {$_.CustomFields[$caJob]} |
ForEach-Object -Process {
# Handling the masters
if ($_.Name -eq 'master') {
$_.Group | Select Name, @{N = 'Cluster'; E = {Get-Cluster -VM $_ }} |
Group-Object -Property Cluster |
ForEach-Object -Process {
# More than 1 master
if ($_.Group.Count -gt 1) {
$sRule = @{
Cluster = $_.Name
Name = "$($deployment) Anti-affinity rule"
VM = $_.Group.Name
KeepTogether = $false
Confirm = $false
}
# Create the anti-affinity rule
# Not taking into account when there are more masters than ESXi nodes
New-DrsRule @sRule
}
}
}
# Create the VM folder for this deployment and move all VMs in there
$targetFolder = New-Folder -Name "Deployment $($deployment)" -Location $folder -Confirm:$false
$_.Group | Move-VM -InventoryLocation $targetFolder -Confirm:$false
}
}