These rules are to stop VMs that provide the same services from ever being on the same node.  In doing this we hope to prevent a service interruption in the event of a node going offline.







#######################################################
###
### Created By: Jake Barlocker
### Created On: 23-MAR-2022
###
### NOTES - This script should be run on one of the cluster nodes that it is going to set anti-affinity in
###
### https://docs.microsoft.com/en-us/windows-server/failover-clustering/cluster-affinity
### https://learn.microsoft.com/en-us/previous-versions/windows/desktop/mscs/clusters-clusterenforcedantiaffinity
###
### Edits: - added load balancers on 10-MAR-2023
### - 22-OCT-2024 made the script capable of accepting dynamic input from the operator
###
#######################################################






# This can change whether or not cluster affinity rules will shut down a VM
#(Get-Cluster).ClusterEnforcedAntiAffinity = 0

# Show cluster affinity enforcement
clear
Write-Host ""
Write-Host "If ClusterEnforcedAntiAffinity is set to 1, it will prevent two instances of Exchange Server from running on the same node. However, if ClusterEnforcedAntiAffinity is set to the default value (0), the system will try to prevent, but not block the two groups from running on the same node." -BackgroundColor Black -ForegroundColor Green
Get-Cluster | fl ClusterEnforcedAntiAffinity




# List and sort all current anti-affinity rules on the cluster
Write-Host ""
Get-ClusterGroup | Sort-Object AntiAffinityClassNames, Name | ft AntiAffinityClassNames, Cluster, Name



# Query the operator for info about the action
$NumberOfServers = Read-Host "How many servers do you want to add to an Anti-Affinity Rule?"
$NameOfAntiAffinityRule = Read-Host "What do you want to name this Anti-Affinity Rule?"


# Create the Anti-Affinity Rule
$AntiAffinityRule = New-Object System.Collections.Specialized.StringCollection
$AntiAffinityRule.Add("$NameOfAntiAffinityRule")

# Loop to add VMs to the Anti-Affinity Rule
$Counter = 0
While ($Counter -lt $NumberOfServers) {
# Create the server number variable and add "1" because people dont like to think of "0" as a number, but computers do
$ServerNumber = $Counter + 1

# Get input from the operator about the VM name
Write-Host ""
Write-Host "Enter the name of the VM exactly as it appears in Failover Cluster Manager for Server $ServerNumber" -BackgroundColor Black -ForegroundColor Cyan
$VmName = (Read-Host " ").ToString()

# Add the VM to the Anti-Affinity Rule
(Get-ClusterGroup -Name $VmName).AntiAffinityClassNames = $AntiAffinityRule

# Increment the Counter variable
$Counter++
}





<#


#this command can show you what affinity group a VM is a part of

Get-ClusterGroup -Name "SWC7DC01.softwise.co" | Format-List -Property AntiAffinityClassNames
Get-ClusterGroup -Name "CCOC7DC01.ccoc7.com" | Format-List -Property AntiAffinityClassNames
Get-ClusterGroup -Name "CCOC7TESTDC01.ccoc7test.com" | Format-List -Property AntiAffinityClassNames
Get-ClusterGroup -Name "CCC7DC02" | Format-List -Property AntiAffinityClassNames
Get-ClusterGroup -Name "NVDBDC01.checkcitynv.com" | Format-List -Property AntiAffinityClassNames
Get-ClusterGroup -Name "CCDBSQL01.checkcity.local" | Format-List -Property AntiAffinityClassNames
Get-ClusterGroup -Name "LoadBalancers" | Format-List -Property AntiAffinityClassNames







# Setup antiaffinity for the HA Fileservers
$AntiAffinity_HaFileServers = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_HaFileServers.Add("HaFileServers")
(Get-ClusterGroup -Name "BARFScluster01.barlocker.org").AntiAffinityClassNames = $AntiAffinity_HaFileServers
(Get-ClusterGroup -Name "BARFScluster02.barlocker.org").AntiAffinityClassNames = $AntiAffinity_HaFileServers

# Setup antiaffinity for the 2 exchange servers
$AntiAffinity_ExchangeServers = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_ExchangeServers.Add("ExchangeServers")
(Get-ClusterGroup -Name "BARMX03.barlocker.org").AntiAffinityClassNames = $AntiAffinity_ExchangeServers
(Get-ClusterGroup -Name "BARMX04.barlocker.org").AntiAffinityClassNames = $AntiAffinity_ExchangeServers

# Setup antiaffinity for the 2 DCs
$AntiAffinity_DomainControllers = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_DomainControllers.Add("DomainControllers")
(Get-ClusterGroup -Name "BARDC01.barlocker.org").AntiAffinityClassNames = $AntiAffinity_DomainControllers
(Get-ClusterGroup -Name "BARDC05.barlocker.org").AntiAffinityClassNames = $AntiAffinity_DomainControllers


# Setup antiaffinity for the 2 Load Balancers
$AntiAffinity_LoadBalancer = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_LoadBalancer.Add("LoadBalancers")
(Get-ClusterGroup -Name "LoadBalancer01").AntiAffinityClassNames = $AntiAffinity_LoadBalancer
(Get-ClusterGroup -Name "LoadBalancer02").AntiAffinityClassNames = $AntiAffinity_LoadBalancer


# Setup antiaffinity for the 2 ccoc7 domain controllers
$AntiAffinity_CCOC7DomainController = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_CCOC7DomainController.Add("ccoc7.com.DomainController")
(Get-ClusterGroup -Name "CCOC7DC01.ccoc7.com").AntiAffinityClassNames = $AntiAffinity_CCOC7DomainController
(Get-ClusterGroup -Name "CCOC7DC02.ccoc7.com").AntiAffinityClassNames = $AntiAffinity_CCOC7DomainController


# Setup antiaffinity for the 2 ccoc7test.com domain controllers
$AntiAffinity_CCOC7TESTDomainController = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_CCOC7TESTDomainController.Add("ccoc7test.com.DomainController")
(Get-ClusterGroup -Name "CCOC7TESTDC01.ccoc7test.com").AntiAffinityClassNames = $AntiAffinity_CCOC7TESTDomainController
(Get-ClusterGroup -Name "CCOC7TESTDC02.ccoc7test.com").AntiAffinityClassNames = $AntiAffinity_CCOC7TESTDomainController


# Setup antiaffinity for the 2 checkcity.local domain controllers
$AntiAffinity_checkcityDomainController = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_checkcityDomainController.Add("checkcity.local.DomainController")
(Get-ClusterGroup -Name "CCDBDC21.checkcity.local").AntiAffinityClassNames = $AntiAffinity_checkcityDomainController
(Get-ClusterGroup -Name "CCDBDC22.checkcity.local").AntiAffinityClassNames = $AntiAffinity_checkcityDomainController
(Get-ClusterGroup -Name "CCDBDC23.checkcity.local").AntiAffinityClassNames = $AntiAffinity_checkcityDomainController


# Setup antiaffinity for the 2 checkcitynevada.com domain controllers
$AntiAffinity_checkcitynevadaDomainController = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_checkcitynevadaDomainController.Add("checkcitynevada.com.DomainController")
(Get-ClusterGroup -Name "NVDBDC01.checkcitynv.com").AntiAffinityClassNames = $AntiAffinity_checkcitynevadaDomainController
(Get-ClusterGroup -Name "NVDBDC02.checkcitynv.com").AntiAffinityClassNames = $AntiAffinity_checkcitynevadaDomainController


# Setup antiaffinity for the 3 softwise domain controllers
$AntiAffinity_SoftwiseDomainController = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_SoftwiseDomainController.Add("softwise.co.DomainController")
(Get-ClusterGroup -Name "SWC7DC01.softwise.co").AntiAffinityClassNames = $AntiAffinity_SoftwiseDomainController
(Get-ClusterGroup -Name "SWC7DC02.softwise.co").AntiAffinityClassNames = $AntiAffinity_SoftwiseDomainController
(Get-ClusterGroup -Name "SWC7DC03.softwise.co").AntiAffinityClassNames = $AntiAffinity_SoftwiseDomainController








# Setup antiaffinity for the 2 SQL Cluster nodes
$AntiAffinity_checkcitylocalSQLcluster = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_checkcitylocalSQLcluster.Add("SqlReport")
(Get-ClusterGroup -Name "CCDBSQLRprt01.checkcity.local").AntiAffinityClassNames = $AntiAffinity_checkcitylocalSQLcluster
(Get-ClusterGroup -Name "CCDBSQLRprt02.checkcity.local").AntiAffinityClassNames = $AntiAffinity_checkcitylocalSQLcluster





# Setup antiaffinity for the Terminal Servers
$AntiAffinity_checkcitylocalRDPfarm = New-Object System.Collections.Specialized.StringCollection
$AntiAffinity_checkcitylocalRDPfarm.Add("checkcity.local.RDP.Farm")
(Get-ClusterGroup -Name "CCC7STOREBROKER.checkcity.local").AntiAffinityClassNames = $AntiAffinity_checkcitylocalRDPfarm
(Get-ClusterGroup -Name "CCC7TS40.checkcity.local").AntiAffinityClassNames = $AntiAffinity_checkcitylocalRDPfarm
(Get-ClusterGroup -Name "CCC7TS41.checkcity.local").AntiAffinityClassNames = $AntiAffinity_checkcitylocalRDPfarm


#>