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?
$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-gt1){
$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
}
}