Delete commit history (containing proprietary code)
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		
							
								
								
									
										269
									
								
								scripts/ADDS/payload/Apply-OVFProperties.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								scripts/ADDS/payload/Apply-OVFProperties.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,269 @@ | ||||
| #Requires -Modules 'ADDSDeployment' | ||||
| [CmdletBinding()] | ||||
| Param( | ||||
|     # No parameters | ||||
| ) | ||||
|  | ||||
| $NewEventLogSplat = @{ | ||||
|     LogName     = 'Application' | ||||
|     Source      = 'OVF-Properties' | ||||
|     ErrorAction = 'SilentlyContinue' | ||||
| } | ||||
| New-EventLog @NewEventLogSplat | ||||
| $WriteEventLogSplat = @{ | ||||
|     LogName   = 'Application' | ||||
|     Source    = 'OVF-Properties' | ||||
|     EntryType = 'Information' | ||||
|     EventID   = 1 | ||||
|     Message   = 'OVF-Properties sequence initiated' | ||||
| } | ||||
| Write-EventLog @WriteEventLogSplat | ||||
|  | ||||
| $VMwareToolsExecutable = "C:\Program Files\VMware\VMware Tools\vmtoolsd.exe" | ||||
|  | ||||
| [xml]$ovfEnv = & $VMwareToolsExecutable --cmd "info-get guestinfo.ovfEnv" | Out-String | ||||
| $ovfProperties = $ovfEnv.ChildNodes.NextSibling.PropertySection.Property | ||||
|  | ||||
| $ovfPropertyValues = @{} | ||||
| foreach ($ovfProperty in $ovfProperties) { | ||||
|     $ovfPropertyValues[$ovfProperty.key] = $ovfProperty.Value | ||||
| } | ||||
|  | ||||
| # Check for mandatory values | ||||
| If (!($ovfPropertyValues['guestinfo.hostname'] -and | ||||
|     $ovfPropertyValues['guestinfo.ipaddress'] -and | ||||
|     $ovfPropertyValues['guestinfo.dnsserver'] -and | ||||
|     $ovfPropertyValues['guestinfo.prefixlength'] -and | ||||
|     $ovfPropertyValues['guestinfo.gateway'] -and | ||||
|     $ovfPropertyValues['addsconfig.domainname'] -and | ||||
|     $ovfPropertyValues['addsconfig.netbiosname'] -and | ||||
|     $ovfPropertyValues['addsconfig.administratorpw'] -and | ||||
|     $ovfPropertyValues['addsconfig.safemodepw'])) { | ||||
|         # Mandatory values missing, cannot provision. | ||||
|         $WriteEventLogSplat = @{ | ||||
|             LogName   = 'Application' | ||||
|             Source    = 'OVF-Properties' | ||||
|             EntryType = 'Error' | ||||
|             EventID   = 66 | ||||
|             Message   = 'Mandatory values missing, cannot provision.' | ||||
|         } | ||||
|         Write-EventLog @WriteEventLogSplat | ||||
|         & schtasks.exe /Change /TN 'OVF-Properties' /DISABLE | ||||
|         Stop-Computer -Force | ||||
|         Exit | ||||
| } | ||||
|  | ||||
| # Set hostname and description | ||||
| If ($Env:ComputerName -ne $ovfPropertyValues['guestinfo.hostname']) { | ||||
|     $RenameComputerSplat = @{ | ||||
|         NewName     = $ovfPropertyValues['guestinfo.hostname'] | ||||
|         Force       = $True | ||||
|         Confirm     = $False | ||||
|     } | ||||
|     Rename-Computer @RenameComputerSplat | ||||
|     $SetCimInstanceSplat = @{ | ||||
|         InputObject = (Get-CimInstance -ClassName 'Win32_OperatingSystem') | ||||
|         Property    = @{ | ||||
|             Description = $ovfPropertyValues['guestinfo.hostname'] | ||||
|         } | ||||
|     } | ||||
|     Set-CimInstance  @SetCimInstanceSplat | ||||
|  | ||||
|     # Restart the computer to apply changes | ||||
|     Restart-Computer -Force | ||||
|     Exit | ||||
| } | ||||
|  | ||||
| # Configure network interface | ||||
| If ((Get-WmiObject -Class 'Win32_NetworkAdapterConfiguration').IPAddress -NotContains $ovfPropertyValues['guestinfo.ipaddress']) { | ||||
|     $NewNetIPAddressSplat = @{ | ||||
|         InterfaceAlias = (Get-NetAdapter).Name | ||||
|         AddressFamily  = 'IPv4' | ||||
|         IPAddress      = $ovfPropertyValues['guestinfo.ipaddress'] | ||||
|         PrefixLength   = $ovfPropertyValues['guestinfo.prefixlength'] | ||||
|         DefaultGateway = $ovfPropertyValues['guestinfo.gateway'] | ||||
|     } | ||||
|     New-NetIPAddress @NewNetIPAddressSplat | ||||
|  | ||||
|     # Wait for network connection to become available | ||||
|     $Timestamp, $TimeoutMinutes = (Get-Date), 5 | ||||
|     Do { | ||||
|         If ($Timestamp.AddMinutes($TimeoutMinutes) -lt (Get-Date)) { | ||||
|             $WriteEventLogSplat = @{ | ||||
|                 LogName   = 'Application' | ||||
|                 Source    = 'OVF-Properties' | ||||
|                 EntryType = 'Warning' | ||||
|                 EventID   = 13 | ||||
|                 Message   = "Timeout after $($TimeoutMinutes) minutes waiting for network connection to become available." | ||||
|             } | ||||
|             Write-EventLog @WriteEventLogSplat | ||||
|             Break | ||||
|         } | ||||
|  | ||||
|         Start-Sleep -Milliseconds 250 | ||||
|  | ||||
|         $GetNetIPAddressSplat = @{ | ||||
|             InterfaceAlias = (Get-NetAdapter).Name | ||||
|             AddressFamily  = 'IPv4' | ||||
|             ErrorAction    = 'SilentlyContinue' | ||||
|         } | ||||
|     } Until ((Get-NetIPAddress @GetNetIPAddressSplat).AddressState -eq 'Preferred') | ||||
|  | ||||
|     $OldErrorActionPreference, $ErrorActionPreference = $ErrorActionPreference, 'SilentlyContinue' | ||||
|     $TestNetConnectionSplat = @{ | ||||
|         ComputerName     = ([IPAddress]$ovfPropertyValues['guestinfo.dnsserver']).IPAddressToString | ||||
|         InformationLevel = 'Quiet' | ||||
|     } | ||||
|     $SetDnsClientServerAddressSplat = @{ | ||||
|         InterfaceAlias  = (Get-NetAdapter).Name | ||||
|         ServerAddresses = If ( | ||||
|             [boolean]($ovfPropertyValues['guestinfo.dnsserver'] -as [IPaddress]) -and (Test-NetConnection @TestNetConnectionSplat)) { | ||||
|                 ($ovfPropertyValues['guestinfo.dnsserver']) | ||||
|             } else { | ||||
|                 ('127.0.0.1') | ||||
|             } | ||||
|         Validate        = $False | ||||
|     } | ||||
|     Set-DnsClientServerAddress @SetDnsClientServerAddressSplat | ||||
|     $ErrorActionPreference, $OldErrorActionPreference = $OldErrorActionPreference, $NULL | ||||
| } | ||||
|  | ||||
| # Promote to Domain Controller | ||||
| If ((4,5) -NotContains (Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole) { | ||||
|     # Change password of built-in Administrator | ||||
|     $BuiltinAdministrator = (Get-LocalUser | Where-Object {$_.SID -match '-500'}) | ||||
|     $ConvertToSecureStringSplat = @{ | ||||
|         String      = $ovfPropertyValues['addsconfig.administratorpw'] | ||||
|         AsPlainText = $True | ||||
|         Force       = $True | ||||
|     } | ||||
|     $SetLocalUserSplat = @{ | ||||
|         InputObject           = $BuiltinAdministrator | ||||
|         Password              = ConvertTo-SecureString @ConvertToSecureStringSplat | ||||
|         PasswordNeverExpires  = $True | ||||
|         AccountNeverExpires   = $True | ||||
|         ### This setting is not allowed on the last administrator | ||||
|         #UserMayChangePassword = $False | ||||
|         Confirm               = $False | ||||
|     } | ||||
|     Set-LocalUser @SetLocalUserSplat | ||||
|  | ||||
|     $ResolveDNSNameSplat = @{ | ||||
|         Name        = "_ldap._tcp.dc._msdcs.$($ovfPropertyValues['addsconfig.domainname'])" | ||||
|         ErrorAction = 'SilentlyContinue' | ||||
|     } | ||||
|     $DNSRecord = Resolve-DnsName @ResolveDNSNameSplat | ||||
|     If ([boolean]$DNSRecord.PrimaryServer -eq $False) { | ||||
|         # No Primary Domain Controller found, installing as primary | ||||
|         $InstallADDSForestSplat = @{ | ||||
|             DomainName                    = $ovfPropertyValues['addsconfig.domainname'] | ||||
|             DomainNetbiosName             = $ovfPropertyValues['addsconfig.netbiosname'] | ||||
|             SafeModeAdministratorPassword = ConvertTo-SecureString $ovfPropertyValues['addsconfig.safemodepw'] -AsPlainText -Force | ||||
|             InstallDns                    = $True | ||||
|             DomainMode                    = 'WinThreshold' | ||||
|             ForestMode                    = 'WinThreshold' | ||||
|             Confirm                       = $False | ||||
|             Force                         = $True | ||||
|             ErrorAction                   = 'Stop' | ||||
|         } | ||||
|         Try { | ||||
|             Install-ADDSForest @InstallADDSForestSplat | ||||
|  | ||||
|             # Previous cmdlet performs a reboot on completion; so these are commented out | ||||
|             # Restart-Computer -Force | ||||
|             # Exit | ||||
|         } | ||||
|         Catch { | ||||
|             & schtasks.exe /Change /TN 'OVF-Properties' /DISABLE | ||||
|             Stop-Computer -Force | ||||
|             Exit | ||||
|         } | ||||
|     } | ||||
|     Else { | ||||
|         # Primary Domain Controller is present, installing as secondary | ||||
|         $InstallADDSDomainControllerSplat = @{ | ||||
|             DomainName                    = $ovfPropertyValues['addsconfig.domainname'] | ||||
|             Credential                    = New-Object System.Management.Automation.PSCredential("$($ovfPropertyValues['addsconfig.netbiosname'])\$($BuiltinAdministrator.Name)", (ConvertTo-SecureString @ConvertToSecureStringSplat)) | ||||
|             SafeModeAdministratorPassword = ConvertTo-SecureString $ovfPropertyValues['addsconfig.safemodepw'] -AsPlainText -Force | ||||
|             InstallDns                    = $True | ||||
|             Confirm                       = $False | ||||
|             Force                         = $True | ||||
|             ErrorAction                   = 'Stop' | ||||
|         } | ||||
|         Try { | ||||
|             Install-ADDSDomainController @InstallADDSDomainControllerSplat | ||||
|  | ||||
|             # Previous cmdlet performs a reboot on completion; so these are commented out | ||||
|             # Restart-Computer -Force | ||||
|             # Exit | ||||
|         } | ||||
|         Catch { | ||||
|             & schtasks.exe /Change /TN 'OVF-Properties' /DISABLE | ||||
|             Stop-Computer -Force | ||||
|             Exit | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| # Wait for Active Directory to become available | ||||
| $Timestamp, $TimeoutMinutes = (Get-Date), 15 | ||||
| Do { | ||||
|     If ($Timestamp.AddMinutes($TimeoutMinutes) -lt (Get-Date)) { | ||||
|         $WriteEventLogSplat = @{ | ||||
|             LogName   = 'Application' | ||||
|             Source    = 'OVF-Properties' | ||||
|             EntryType = 'Warning' | ||||
|             EventID   = 13 | ||||
|             Message   = "Timeout after $($TimeoutMinutes) minutes waiting for Active Directory to become available." | ||||
|         } | ||||
|         Write-EventLog @WriteEventLogSplat | ||||
|         Break | ||||
|     } | ||||
|  | ||||
|     Start-Sleep -Seconds 30 | ||||
|  | ||||
|     $GetADComputerSplat = @{ | ||||
|         Identity    = $Env:ComputerName | ||||
|         ErrorAction = 'SilentlyContinue' | ||||
|     } | ||||
|     Get-ADComputer @GetADComputerSplat | Out-Null | ||||
| } Until ($?) | ||||
|  | ||||
| # Iterate through and invoke all payload scripts | ||||
| #! TODO: add registry values to determine which scripts have already been invoked (in case of intermediate reboots) | ||||
| $GetItemSplat = @{ | ||||
|     Path = "$($PSScriptRoot)\Scripts\*.ps1" | ||||
| } | ||||
| Get-Item @GetItemSplat | ForEach-Object { | ||||
|     Try { | ||||
|         $WriteEventLogSplat = @{ | ||||
|             LogName   = 'Application' | ||||
|             Source    = 'OVF-Properties' | ||||
|             EntryType = 'Information' | ||||
|             EventID   = 4 | ||||
|             Message   = "Running script: '$($_.FullName)'" | ||||
|         } | ||||
|         Write-EventLog @WriteEventLogSplat | ||||
|         & $_.FullName -Parameter $ovfPropertyValues | ||||
|     } | ||||
|     Catch { | ||||
|         $WriteEventLogSplat = @{ | ||||
|             LogName   = 'Application' | ||||
|             Source    = 'OVF-Properties' | ||||
|             EntryType = 'Error' | ||||
|             EventID   = 66 | ||||
|             Message   = $_.Exception.Message | ||||
|         } | ||||
|         Write-EventLog @WriteEventLogSplat | ||||
|     } | ||||
| } | ||||
|  | ||||
| $WriteEventLogSplat = @{ | ||||
|     LogName   = 'Application' | ||||
|     Source    = 'OVF-Properties' | ||||
|     EntryType = 'Information' | ||||
|     EventID   = 42 | ||||
|     Message   = 'OVF-Properties sequence applied and finished' | ||||
| } | ||||
| Write-EventLog @WriteEventLogSplat | ||||
| & schtasks.exe /Change /TN 'OVF-Properties' /DISABLE | ||||
							
								
								
									
										16
									
								
								scripts/ADDS/payload/scripts/01.Organizational units.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								scripts/ADDS/payload/scripts/01.Organizational units.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| "DistinguishedName","Description" | ||||
| "OU=Computer accounts","" | ||||
| "OU=Clients,OU=Computer accounts","" | ||||
| "OU=Desktops,OU=Clients,OU=Computer accounts","" | ||||
| "OU=Laptops,OU=Clients,OU=Computer accounts","" | ||||
| "OU=Servers,OU=Computer accounts","" | ||||
| "OU=Groups","" | ||||
| "OU=Resources,OU=Groups","" | ||||
| "OU=Roles,OU=Groups","" | ||||
| "OU=User accounts","" | ||||
| "OU=Privileged,OU=User accounts","" | ||||
| "OU=Administrators,OU=Privileged,OU=User accounts","" | ||||
| "OU=Service accounts,OU=Privileged,OU=User accounts","" | ||||
| "OU=Non-privileged,OU=User accounts","" | ||||
| "OU=Employees,OU=Non-privileged,OU=User accounts","" | ||||
| "OU=Contractors,OU=Non-privileged,OU=User accounts","" | ||||
| 
 | 
							
								
								
									
										29
									
								
								scripts/ADDS/payload/scripts/01.Organizational units.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								scripts/ADDS/payload/scripts/01.Organizational units.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #Requires -Modules 'ActiveDirectory' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', ".csv") | ||||
|     } | ||||
|     $CSVImport = (Get-Content @GetContentSplat) | ConvertFrom-Csv | ||||
|  | ||||
|     ForEach ($OU in $CSVImport) { | ||||
|         $OUName, $OUPath = $OU.DistinguishedName -split ',', 2 | ||||
|         If ($OUPath.Length -ne 0) { | ||||
|             $OUPath += ',' | ||||
|         } | ||||
|  | ||||
|         $NewADOrganizationalUnitSplat = @{ | ||||
|             Name                            = $OUName.Substring(3) | ||||
|             Path                            = $OUPath + 'DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|             Description                     = $OU.Description | ||||
|             ProtectedFromAccidentalDeletion = $False | ||||
|             ErrorAction                     = 'SilentlyContinue' | ||||
|         } | ||||
|         New-ADOrganizationalUnit @NewADOrganizationalUnitSplat | ||||
|     } | ||||
| } | ||||
							
								
								
									
										6
									
								
								scripts/ADDS/payload/scripts/02.Groups.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								scripts/ADDS/payload/scripts/02.Groups.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| "DistinguishedName","Description" | ||||
| "CN=RemoteDesktop - Management servers,OU=Resources,OU=Groups","" | ||||
| "CN=ContentLibraryAdmin - vSphere servers,OU=Resources,OU=Groups","" | ||||
| "CN=DatastoreAdmin - vSphere servers,OU=Resources,OU=Groups","" | ||||
| "CN=Hypervisor administrators,OU=Roles,OU=Groups","" | ||||
| "CN=Firewall administrators,OU=Roles,OU=Groups","" | ||||
| 
 | 
							
								
								
									
										25
									
								
								scripts/ADDS/payload/scripts/02.Groups.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								scripts/ADDS/payload/scripts/02.Groups.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #Requires -Modules 'ActiveDirectory' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', ".csv") | ||||
|     } | ||||
|     $CSVImport = (Get-Content @GetContentSplat) | ConvertFrom-Csv | ||||
|  | ||||
|     ForEach ($Group in $CSVImport) { | ||||
|         $NewADGroupSplat = @{ | ||||
|             Name          = ($Group.DistinguishedName -split ',', 2)[0].Substring(3) | ||||
|             Path          = ($Group.DistinguishedName -split ',', 2)[1] + ',DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|             Description   = $Group.Description | ||||
|             GroupCategory = 'Security' | ||||
|             GroupScope    = 'Global' | ||||
|             ErrorAction   = 'SilentlyContinue' | ||||
|         } | ||||
|         New-ADGroup @NewADGroupSplat | ||||
|     } | ||||
| } | ||||
							
								
								
									
										5
									
								
								scripts/ADDS/payload/scripts/03.Users.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								scripts/ADDS/payload/scripts/03.Users.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| "DistinguishedName","Password","MemberOf" | ||||
| "CN=Jane Doe,OU=Employees,OU=Non-privileged,OU=User accounts","Complex42!","" | ||||
| "CN=John Doe,OU=Contractors,OU=Non-privileged,OU=User accounts","Complex42!","" | ||||
| "CN=admJaneD,OU=Administrators,OU=Privileged,OU=User accounts","Complex42!","" | ||||
| "CN=zzLDAP,OU=Service accounts,OU=Privileged,OU=User accounts","Complex42!","" | ||||
| 
 | 
							
								
								
									
										42
									
								
								scripts/ADDS/payload/scripts/03.Users.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								scripts/ADDS/payload/scripts/03.Users.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| #Requires -Modules 'ActiveDirectory' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', ".csv") | ||||
|     } | ||||
|     $CSVImport = (Get-Content @GetContentSplat) | ConvertFrom-Csv | ||||
|  | ||||
|     ForEach ($User in $CSVImport) { | ||||
|         # Create new user | ||||
|         $NewADUserSplat = @{ | ||||
|             Name            = ($User.DistinguishedName -split ',', 2)[0].Substring(3) | ||||
|             Path            = ($User.DistinguishedName -split ',', 2)[1] + ',DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|             AccountPassword = ConvertTo-SecureString $User.Password -AsPlainText -Force | ||||
|             PassThru        = $True | ||||
|             ErrorAction     = 'SilentlyContinue' | ||||
|         } | ||||
|         $NewADUser = New-ADUser @NewADUserSplat | ||||
|         # Add user to group(s) | ||||
|         If ($User.MemberOf -ne '') { | ||||
|             ForEach ($Group in $User.MemberOf.Split('|')) { | ||||
|                 $AddADGroupMemberSplat = @{ | ||||
|                     Identity    = $Group + ',DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|                     Members     = $NewADUser.DistinguishedName | ||||
|                     ErrorAction = 'SilentlyContinue' | ||||
|                 } | ||||
|                 Add-ADGroupMember @AddADGroupMemberSplat | ||||
|             } | ||||
|         } | ||||
|         # Enable user | ||||
|         $EnableADAccountSplat = @{ | ||||
|             Identity    = $NewADUser.DistinguishedName | ||||
|             ErrorAction = 'Continue' | ||||
|         } | ||||
|         Enable-ADAccount @EnableADAccountSplat | ||||
|     } | ||||
| } | ||||
							
								
								
									
										126
									
								
								scripts/ADDS/payload/scripts/04.Delegation of Control.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								scripts/ADDS/payload/scripts/04.Delegation of Control.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| #Requires -Modules 'ActiveDirectory' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $PSDrive = Get-PSDrive -Name 'AD' | ||||
|     If ([boolean]$PSDrive -eq $False) { | ||||
|         $NewPSDriveSplat = @{ | ||||
|             Name       = 'ADDS' | ||||
|             Root       = '' | ||||
|             PSProvider = 'ActiveDirectory' | ||||
|         } | ||||
|         $PSDrive = New-PSDrive @NewPSDriveSplat | ||||
|     } | ||||
|  | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', ".yml") | ||||
|         Raw  = $True | ||||
|     } | ||||
|     $RawContent = Get-Content @GetContentSplat | ||||
|     $ConvertFromYamlSplat = @{ | ||||
|         Yaml         = $RawContent | ||||
|         AllDocuments = $True | ||||
|     } | ||||
|     $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|  | ||||
|     # Check if the respective .yml file declared substitutions which need to be parsed | ||||
|     If (($YamlDocuments.Count -gt 1) -and $YamlDocuments[-1].Variables) { | ||||
|         ForEach ($Pattern in $YamlDocuments[-1].Variables) { | ||||
|             $RawContent = $RawContent -replace "\{\{ ($($Pattern.Name)) \}\}", [string](Invoke-Expression -Command $Pattern.Expression) | ||||
|         } | ||||
|         # Perform conversion to Yaml again, now with parsed file contents | ||||
|         $ConvertFromYamlSplat = @{ | ||||
|             Yaml         = $RawContent | ||||
|             AllDocuments = $True | ||||
|         } | ||||
|         $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|         $Delegations = $YamlDocuments[0..($YamlDocuments.Count - 2)] | ||||
|     } | ||||
|     Else { | ||||
|         $Delegations = $YamlDocuments | ||||
|     } | ||||
|  | ||||
|     # Store GUIDs for all known AD schema classes | ||||
|     $GUIDMap, $GetADObjectSplat = @{}, @{ | ||||
|         SearchBase = (Get-ADRootDSE).SchemaNamingContext | ||||
|         LDAPFilter = '(schemaidguid=*)' | ||||
|         Properties = 'lDAPDisplayName','schemaIDGUID' | ||||
|     } | ||||
|     Get-ADObject @GetADObjectSplat | ForEach-Object { | ||||
|         $GUIDMap[$_.lDAPDisplayName] = [GUID]$_.schemaIDGUID | ||||
|     } | ||||
|     # Store GUIDs for all extended rights | ||||
|     $GetADObjectSplat = @{ | ||||
|         SearchBase = (Get-ADRootDSE).ConfigurationNamingContext | ||||
|         LDAPFilter = '(&(objectclass=controlAccessRight)(rightsguid=*))' | ||||
|         Properties = 'displayName','rightsGuid' | ||||
|     } | ||||
|     Get-ADObject @GetADObjectSplat | ForEach-Object { | ||||
|         $GUIDMap[$_.displayName] = [GUID]$_.rightsGuid | ||||
|     } | ||||
|     $GUIDMap['null'] = [Guid]::Empty | ||||
|  | ||||
|     ForEach ($Entry in $Delegations.DelegationEntries) { | ||||
|         $GetADObjectSplat = @{ | ||||
|             Filter      = '*' | ||||
|             SearchBase  = 'DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|             SearchScope = 'OneLevel' | ||||
|         } | ||||
|         $OU = Get-ADObject @GetADObjectSplat | Where-Object {$_.DistinguishedName -match $Entry.OrganizationalUnit} | ||||
|         $GetACLSPlat = @{ | ||||
|             Path = "$($PSDrive.Name):\$($OU.DistinguishedName)" | ||||
|         } | ||||
|         $ACL = Get-ACL @GetACLSPlat | ||||
|  | ||||
|         $GetADObjectSplat = @{ | ||||
|             Filter = "sAMAccountName -eq '$($Entry.Principal)'" | ||||
|             Properties = 'objectSID' | ||||
|         } | ||||
|         $Principal = Get-ADObject @GetADObjectSplat | ||||
|  | ||||
|         ForEach ($Rule in $Entry.AccessRules) { | ||||
|             If ($Rule.ObjectType -eq '') { | ||||
|                 $Rule.ObjectType = 'null' | ||||
|             } | ||||
|             If ($Rule.InheritedObjectType -eq '') { | ||||
|                 $Rule.InheritedObjectType = 'null' | ||||
|             } | ||||
|  | ||||
|             $NewACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule( | ||||
|                 # An IdentityReference object that identifies the trustee of the access rule. | ||||
|                 [System.Security.Principal.IdentityReference]$Principal.objectSID, | ||||
|                 # A combination of one or more of the ActiveDirectoryRights enumeration values that specifies the rights of the access rule. | ||||
|                 [System.DirectoryServices.ActiveDirectoryRights]$Rule.ActiveDirectoryRights, | ||||
|                 # One of the AccessControlType enumeration values that specifies the access rule type. | ||||
|                 [System.Security.AccessControl.AccessControlType]$Rule.AccessControlType, | ||||
|                 # The schema GUID of the object to which the access rule applies. | ||||
|                 [Guid]$GUIDMap[$Rule.ObjectType], | ||||
|                 # One of the ActiveDirectorySecurityInheritance enumeration values that specifies the inheritance type of the access rule. | ||||
|                 [System.DirectoryServices.ActiveDirectorySecurityInheritance]$Rule.ActiveDirectorySecurityInheritance, | ||||
|                 # The schema GUID of the child object type that can inherit this access rule. | ||||
|                 [Guid]$GUIDMap[$Rule.InheritedObjectType] | ||||
|             ) | ||||
|             $ACL.AddAccessRule($NewACE) | ||||
|         } | ||||
|  | ||||
|         $SetAclSplat = @{ | ||||
|             Path        = "$($PSDrive.Name):\$($OU.DistinguishedName)" | ||||
|             AclObject   = $ACL | ||||
|             ErrorAction = 'Continue' | ||||
|         } | ||||
|         Set-Acl @SetAclSplat | ||||
|     } | ||||
|  | ||||
|     If ([boolean]($PSDrive.Name -eq 'ADDS') -eq $True) { | ||||
|         $RemovePSDriveSplat = @{ | ||||
|             Name    = 'ADDS' | ||||
|             Force   = $True | ||||
|             Confirm = $False | ||||
|         } | ||||
|         Remove-PSDrive @RemovePSDriveSplat | Out-Null | ||||
|     } | ||||
| } | ||||
							
								
								
									
										73
									
								
								scripts/ADDS/payload/scripts/04.Delegation of Control.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								scripts/ADDS/payload/scripts/04.Delegation of Control.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| DelegationEntries: | ||||
| - Principal: admJaneD | ||||
|   OrganizationalUnit: CN=Computers                   # Entries will be concatenated with ',DC=<example>,DC=<org>' automatically | ||||
|   AccessRules: | ||||
|   - ActiveDirectoryRights: Self                      # A combination of one or more of the ActiveDirectoryRights enumeration values that specifies the rights of the access rule. | ||||
|     AccessControlType: Allow                         # One of the AccessControlType enumeration values that specifies the access rule type. | ||||
|     ActiveDirectorySecurityInheritance: Descendents  # One of the ActiveDirectorySecurityInheritance enumeration values that specifies the inheritance type of the access rule. | ||||
|     ObjectType: Validated write to DNS host name     # The object type to which the access rule applies. | ||||
|     InheritedObjectType: Computer                    # The child object type that can inherit this access rule. | ||||
|   - ActiveDirectoryRights: Self | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: Validated write to service principal name | ||||
|     InheritedObjectType: Computer | ||||
|   - ActiveDirectoryRights: WriteProperty, WriteDacl | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: '' | ||||
|     InheritedObjectType: Computer | ||||
|   - ActiveDirectoryRights: ExtendedRight | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: Reset Password | ||||
|     InheritedObjectType: Computer | ||||
|   - ActiveDirectoryRights: ExtendedRight | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: Change Password | ||||
|     InheritedObjectType: Computer | ||||
|   - ActiveDirectoryRights: ReadProperty | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: '' | ||||
|     InheritedObjectType: Computer | ||||
|   - ActiveDirectoryRights: WriteProperty | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: '' | ||||
|     InheritedObjectType: Computer | ||||
|   - ActiveDirectoryRights: CreateChild, DeleteChild | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: All | ||||
|     ObjectType: Computer | ||||
|     InheritedObjectType: '' | ||||
|   - ActiveDirectoryRights: GenericAll | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: Computer | ||||
|     InheritedObjectType: '' | ||||
| - Principal: admJaneD | ||||
|   OrganizationalUnit: OU=Clients,OU=Computer accounts | ||||
|   AccessRules: | ||||
|   - ActiveDirectoryRights: CreateChild, DeleteChild | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: All | ||||
|     ObjectType: User | ||||
|     InheritedObjectType: '' | ||||
|   - ActiveDirectoryRights: GenericAll | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: '' | ||||
|     InheritedObjectType: '' | ||||
|   - ActiveDirectoryRights: WriteProperty, ReadProperty | ||||
|     AccessControlType: Allow | ||||
|     ActiveDirectorySecurityInheritance: Descendents | ||||
|     ObjectType: Member | ||||
|     InheritedObjectType: Group | ||||
|  | ||||
| # --- | ||||
| # Variables: | ||||
| # - Name: foo | ||||
| #   Expression: | | ||||
| #     Write-Host 'bar' | ||||
							
								
								
									
										109
									
								
								scripts/ADDS/payload/scripts/05.Firewall.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								scripts/ADDS/payload/scripts/05.Firewall.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| #Requires -Modules 'NetSecurity' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', '.yml') | ||||
|         Raw  = $true | ||||
|     } | ||||
|     $RawContent = Get-Content @GetContentSplat | ||||
|     $ConvertFromYamlSplat = @{ | ||||
|         Yaml         = $RawContent | ||||
|         AllDocuments = $True | ||||
|     } | ||||
|     $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|  | ||||
|     # Check if the respective .yml file declared substitutions which need to be parsed | ||||
|     If (($YamlDocuments.Count -gt 1) -and $YamlDocuments[-1].Variables) { | ||||
|         ForEach ($Pattern in $YamlDocuments[-1].Variables) { | ||||
|             $RawContent = $RawContent -replace "\{\{ ($($Pattern.Name)) \}\}", [string](Invoke-Expression -Command $Pattern.Expression) | ||||
|         } | ||||
|         # Perform conversion to Yaml again, now with parsed file contents | ||||
|         $ConvertFromYamlSplat = @{ | ||||
|             Yaml         = $RawContent | ||||
|             AllDocuments = $True | ||||
|         } | ||||
|         $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|         $Settings = $YamlDocuments[0..($YamlDocuments.Count - 2)] | ||||
|     } | ||||
|     Else { | ||||
|         $Settings = $YamlDocuments | ||||
|     } | ||||
|  | ||||
|     $NewGPOSplat = @{ | ||||
|         Name = 'COMP: Firewall (Servers)' | ||||
|     } | ||||
|     $NewGPO = New-GPO @NewGPOSplat | ||||
|  | ||||
|     $OpenNetGPOSplat = @{ | ||||
|         PolicyStore = "$($Parameter['addsconfig.domainname'])\$($NewGPO.DisplayName)" | ||||
|     } | ||||
|     $GPOSession = Open-NetGPO @OpenNetGPOSplat | ||||
|  | ||||
|     ForEach ($Rule in $Settings.FirewallRules) { | ||||
|         $NewNetFirewallRuleSplat = @{ | ||||
|             # Using so-called string formatting with the '-f' operator (looks more complicated than it is) to create consistent policy names: | ||||
|             # Examples: | ||||
|             #   'DENY: Inbound port 443 (TCP)' | ||||
|             #   'ALLOW: Inbound 'D:\MSSQL\bin\sqlservr.exe' | ||||
|             DisplayName = ("{0}: {1} {2} {3} {4}" -f | ||||
|                     $Rule.Action.ToUpper(), | ||||
|                     $Rule.Direction, | ||||
|                     ("'$($Rule.Program)'", $NULL)[!($Rule.Program)], | ||||
|                     ("Port $($Rule.Port)", $NULL)[!($Rule.Port)], | ||||
|                     ("($($Rule.Protocol))", $NULL)[!($Rule.Protocol)] | ||||
|                 ) -replace '\s+',' ' | ||||
|             Description = $Rule.Description | ||||
|             Action      = $Rule.Action | ||||
|             Direction   = $Rule.Direction | ||||
|             Program     = ($Rule.Program, 'Any')[!($Rule.Program)] | ||||
|             LocalPort   = ($Rule.Port.Split(','), 'Any')[!($Rule.Port)] | ||||
|             Protocol    = ($Rule.Protocol, 'Any')[!($Rule.Protocol)] | ||||
|             GPOSession  = $GPOSession | ||||
|             PolicyStore = $NewGPO.DisplayName | ||||
|             Confirm     = $False | ||||
|         } | ||||
|         New-NetFirewallRule @NewNetFirewallRuleSplat | ||||
|     } | ||||
|  | ||||
|     ForEach ($Profile in $Settings.FirewallProfiles) { | ||||
|         $SetNetFirewallProfileSplat = @{ | ||||
|             Name                    = $Profile.Name | ||||
|             Enabled                 = $Profile.Enabled | ||||
|             DefaultInboundAction    = $Profile.Connections.Inbound | ||||
|             DefaultOutboundAction   = $Profile.Connections.Outbound | ||||
|             LogAllowed              = $Profile.Logging.LogSuccessfullConnections | ||||
|             LogBlocked              = $Profile.Logging.LogDroppedPackets | ||||
|             LogFileName             = $Profile.Logging.Name | ||||
|             LogMaxSizeKilobytes     = $Profile.Logging.SizeLimit | ||||
|             AllowLocalFirewallRules = $Profile.Settings.ApplyLocalFirewallRules | ||||
|             AllowLocalIPsecRules    = $Profile.Settings.ApplyLocalConnectionSecurityRules | ||||
|             NotifyOnListen          = $Profile.Settings.DisplayNotification | ||||
|             GPOSession              = $GPOSession | ||||
|             PolicyStore             = $NewGPO.DisplayName | ||||
|             Confirm                 = $False | ||||
|         } | ||||
|         Set-NetFirewallProfile @SetNetFirewallProfileSplat | ||||
|     } | ||||
|  | ||||
|     $SaveNetGPOSplat = @{ | ||||
|         GPOSession = $GPOSession | ||||
|     } | ||||
|     Save-NetGPO @SaveNetGPOSplat | ||||
|  | ||||
|     $NewGPLinkSplat = @{ | ||||
|         Name   = $NewGPO.DisplayName | ||||
| #        Should probably be configurable through yml | ||||
|         Target = 'OU=Servers,OU=Computer accounts,DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|     } | ||||
|     New-GPLink @NewGPLinkSplat | ||||
|     $NewGPLinkSplat = @{ | ||||
|         Name   = $NewGPO.DisplayName | ||||
|         Target = 'OU=Domain Controllers,DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|     } | ||||
|     New-GPLink @NewGPLinkSplat | ||||
| } | ||||
							
								
								
									
										62
									
								
								scripts/ADDS/payload/scripts/05.Firewall.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								scripts/ADDS/payload/scripts/05.Firewall.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| FirewallRules: | ||||
| - Description: Rule A | ||||
|   Action: Block | ||||
|   Direction: Inbound | ||||
|   Program: '' | ||||
|   Port: '21-22,25' | ||||
|   Protocol: TCP | ||||
| - Description: Rule B | ||||
|   Action: Allow | ||||
|   Direction: Inbound | ||||
|   Program: D:\MSSQL\sqlsvr.exe | ||||
|   Port: '' | ||||
|   Protocol: '' | ||||
| FirewallProfiles: | ||||
| - Name: Domain | ||||
|   Enabled: 'True' | ||||
|   Connections: | ||||
|     Inbound: Block | ||||
|     Outbound: Allow | ||||
|   Settings: | ||||
|     DisplayNotification: 'False' | ||||
|     ApplyLocalFirewallRules: 'True' | ||||
|     ApplyLocalConnectionSecurityRules: 'True' | ||||
|   Logging: | ||||
|     Name: '%SYSTEMROOT%\System32\Logfiles\Firewall\domainfw.log' | ||||
|     SizeLimit: 16384 | ||||
|     LogDroppedPackets: 'True' | ||||
|     LogSuccessfullConnections: 'False' | ||||
| - Name: Private | ||||
|   Enabled: 'True' | ||||
|   Connections: | ||||
|     Inbound: Block | ||||
|     Outbound: Allow | ||||
|   Settings: | ||||
|     DisplayNotification: 'False' | ||||
|     ApplyLocalFirewallRules: 'True' | ||||
|     ApplyLocalConnectionSecurityRules: 'True' | ||||
|   Logging: | ||||
|     Name: '%SYSTEMROOT%\System32\Logfiles\Firewall\privatefw.log' | ||||
|     SizeLimit: 16384 | ||||
|     LogDroppedPackets: 'True' | ||||
|     LogSuccessfullConnections: 'False' | ||||
| - Name: Public | ||||
|   Enabled: 'True' | ||||
|   Connections: | ||||
|     Inbound: Block | ||||
|     Outbound: Allow | ||||
|   Settings: | ||||
|     DisplayNotification: 'False' | ||||
|     ApplyLocalFirewallRules: 'True' | ||||
|     ApplyLocalConnectionSecurityRules: 'True' | ||||
|   Logging: | ||||
|     Name: '%SYSTEMROOT%\System32\Logfiles\Firewall\publicfw.log' | ||||
|     SizeLimit: 16384 | ||||
|     LogDroppedPackets: 'True' | ||||
|     LogSuccessfullConnections: 'False' | ||||
|  | ||||
| # --- | ||||
| # Variables: | ||||
| # - Name: foo | ||||
| #   Expression: | | ||||
| #     Write-Host 'bar' | ||||
							
								
								
									
										27
									
								
								scripts/ADDS/payload/scripts/06.DHCP service.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								scripts/ADDS/payload/scripts/06.DHCP service.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #Requires -Modules 'DhcpServer' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Configure DHCP (if and only if this server is not already an authorized DHCP server) | ||||
| If ((Get-DHCPServerInDC).IPAddress -NotContains $Parameter['guestinfo.ipaddress']) { | ||||
|     # Add DHCP security groups | ||||
|     & netsh dhcp add securitygroups | ||||
|  | ||||
|     # Authorize DHCP server | ||||
|     $AddDhcpServerInDCSplat = @{ | ||||
|         DnsName   = "$($Parameter['guestinfo.hostname']).$($Parameter['addsconfig.domainname'])" | ||||
|         IPAddress = $($Parameter['guestinfo.ipaddress']) | ||||
|         Confirm   = $False | ||||
|     } | ||||
|     Add-DhcpServerInDC @AddDhcpServerInDCSplat | ||||
|  | ||||
|     # Notify Server Manager post-install configuration has completed | ||||
|     $SetItemPropertySplat = @{ | ||||
|         Path  = 'HKLM:\SOFTWARE\Microsoft\ServerManager\Roles\12' | ||||
|         Name  = 'ConfigurationState' | ||||
|         Value = 2 | ||||
|     } | ||||
|     Set-ItemProperty @SetItemPropertySplat | ||||
| } | ||||
							
								
								
									
										54
									
								
								scripts/ADDS/payload/scripts/07.DHCP scopes.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								scripts/ADDS/payload/scripts/07.DHCP scopes.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #Requires -Modules 'DhcpServer' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on secondary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 4) { | ||||
|     $AddDhcpServerv4ScopeSplat = @{ | ||||
|         Name          = 'Default DHCP scope' | ||||
|         StartRange    = [ipaddress]$Parameter['dhcpconfig.startip'] | ||||
|         EndRange      = [ipaddress]$Parameter['dhcpconfig.endip'] | ||||
|         SubnetMask    = [ipaddress]$Parameter['dhcpconfig.subnetmask'] | ||||
|         LeaseDuration = [timespan]$Parameter['dhcpconfig.leaseduration'] | ||||
|         State         = 'Active' | ||||
|         PassThru      = $True | ||||
|         Confirm       = $False | ||||
|     } | ||||
|     $DhcpScope = Add-DhcpServerv4Scope @AddDhcpServerv4ScopeSplat | ||||
|  | ||||
|     $ScopeOptions = @( | ||||
|         @{ | ||||
|             # 003 Router | ||||
|             OptionId = 3 | ||||
|             Value    = $Parameter['dhcpconfig.gateway'] | ||||
|         }, | ||||
|         @{ | ||||
|             # 004 Time Server | ||||
|             OptionId = 4 | ||||
|             Value    = (Resolve-DnsName -Name $Parameter['addsconfig.domainname']).IPAddress | ||||
|         }, | ||||
|         @{ | ||||
|             # 006 DNS Server | ||||
|             OptionId = 6 | ||||
|             Value    = (Resolve-DnsName -Name $Parameter['addsconfig.domainname']).IPAddress | ||||
|         }, | ||||
|         @{ | ||||
|             # 015 DNS Domain Name | ||||
|             OptionId = 15 | ||||
|             Value    = $Parameter['addsconfig.domainname'] | ||||
|         } | ||||
|     ) | ||||
|  | ||||
|     ForEach ($Option in $ScopeOptions) { | ||||
|         $SetDhcpServerv4OptionValueSplat = @{ | ||||
|             ScopeId  = $DhcpScope.ScopeId | ||||
|             OptionId = $Option.OptionId | ||||
|             Value    = $Option.Value | ||||
|             Force    = $True | ||||
|             Confirm  = $False | ||||
|         } | ||||
|         Set-DhcpServerv4OptionValue @SetDhcpServerv4OptionValueSplat | ||||
|     } | ||||
| } | ||||
							
								
								
									
										43
									
								
								scripts/ADDS/payload/scripts/08.DHCP failover.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								scripts/ADDS/payload/scripts/08.DHCP failover.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| #Requires -Modules 'DhcpServer' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on secondary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 4) { | ||||
|     # Wait for secondary DHCP server to be registered in DNS | ||||
|     $Timestamp, $TimeoutMinutes = (Get-Date), 5 | ||||
|     Do { | ||||
|         If ($Timestamp.AddMinutes($TimeoutMinutes) -lt (Get-Date)) { | ||||
|             $WriteEventLogSplat = @{ | ||||
|                 LogName   = 'Application' | ||||
|                 Source    = 'OVF-Properties' | ||||
|                 EntryType = 'Warning' | ||||
|                 EventID   = 13 | ||||
|                 Message   = "Timeout after $($TimeoutMinutes) minutes waiting for secondary Domain Controller to be registered in DNS." | ||||
|             } | ||||
|             Write-EventLog @WriteEventLogSplat | ||||
|             Break | ||||
|         } | ||||
|  | ||||
|         Start-Sleep -Seconds 5 | ||||
|  | ||||
|     } Until ((Get-DhcpServerInDC).Count -gt 1) | ||||
|  | ||||
|     $NewCimSessionSplat = @{ | ||||
|         Credential   = New-Object System.Management.Automation.PSCredential( | ||||
|             ###! TODO: Replace this with code to automagically find required accountname (this hardcoded value might not be correct due to GPO's) | ||||
|             (Get-ADUser -Filter * | Where-Object {$_.SID -match '-500'}).SamAccountName, | ||||
|             (ConvertTo-SecureString $Parameter['addsconfig.administratorpw'] -AsPlainText -Force) | ||||
|         ) | ||||
|     } | ||||
|     $AddDhcpServerv4FailoverSplat = @{ | ||||
|         Name          = 'Failover #42' | ||||
|         PartnerServer = (Get-DhcpServerInDC).DnsName | Where-Object {$_ -ne "$($Parameter['guestinfo.hostname']).$($Parameter['addsconfig.domainname'])"} | ||||
|         ServerRole    = 'Active' | ||||
|         ScopeId       = (Get-DhcpServerv4Scope).ScopeId.IPAddressToString | ||||
|         CimSession    = New-CimSession @NewCimSessionSplat | ||||
|     } | ||||
|     Add-DhcpServerv4Failover @AddDhcpServerv4FailoverSplat | ||||
| } | ||||
							
								
								
									
										88
									
								
								scripts/ADDS/payload/scripts/09.DNS records.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								scripts/ADDS/payload/scripts/09.DNS records.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| #Requires -Modules 'DnsServer' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on secondary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 4) { | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', '.yml') | ||||
|         Raw  = $True | ||||
|     } | ||||
|     $RawContent = Get-Content @GetContentSplat | ||||
|     $ConvertFromYamlSplat = @{ | ||||
|         Yaml         = $RawContent | ||||
|         AllDocuments = $True | ||||
|     } | ||||
|     $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|  | ||||
|     # Check if the respective .yml file declared substitutions which need to be parsed | ||||
|     If (($YamlDocuments.Count -gt 1) -and $YamlDocuments[-1].Variables) { | ||||
|         ForEach ($Pattern in $YamlDocuments[-1].Variables) { | ||||
|             $RawContent = $RawContent -replace "\{\{ ($($Pattern.Name)) \}\}", [string](Invoke-Expression -Command $Pattern.Expression) | ||||
|         } | ||||
|         # Perform conversion to Yaml again, now with parsed file contents | ||||
|         $ConvertFromYamlSplat = @{ | ||||
|             Yaml         = $RawContent | ||||
|             AllDocuments = $True | ||||
|         } | ||||
|         $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|         $Records = $YamlDocuments[0..($YamlDocuments.Count - 2)] | ||||
|     } | ||||
|     Else { | ||||
|         $Records = $YamlDocuments | ||||
|     } | ||||
|  | ||||
|     ForEach ($Record in $Records.Entries) { | ||||
|         $AddDnsServerResourceRecordSplat = @{ | ||||
|             ComputerName = $Parameter['guestinfo.dnsserver'] | ||||
|             ZoneName     = $Parameter['addsconfig.domainname'] | ||||
|             Name         = [string]$Record.Name | ||||
|             TimeToLive   = (New-TimeSpan -Hours 1) | ||||
|             AgeRecord    = $False | ||||
|             Confirm      = $False | ||||
|         } | ||||
|         Switch ($Record.Type) { | ||||
|             'A' { | ||||
|                 $AddDnsServerResourceRecordSplat.Add('A', $True) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('IPv4Address', $Record.Value) | ||||
|             } | ||||
|             'AAAA' { | ||||
|                 $AddDnsServerResourceRecordSplat.Add('AAAA', $True) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('IPv6Address', $Record.Value) | ||||
|             } | ||||
|             'CNAME' { | ||||
|                 $AddDnsServerResourceRecordSplat.Add('CNAME', $True) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('HostNameAlias', $Record.Value) | ||||
|             } | ||||
|             'MX' { | ||||
|                 $AddDnsServerResourceRecordSplat.Add('MX', $True) | ||||
|                 # Value should match pattern '<fqdn>:<preference>' | ||||
|                 # ie. 'mail.contoso.com:10' | ||||
|                 $MailExch = $Record.Value -split ':' | ||||
|                 $AddDnsServerResourceRecordSplat.Add('MailExchange', $MailExch[0]) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('Preference', $MailExch[1]) | ||||
|             } | ||||
|             'NS' { | ||||
|                 $AddDnsServerResourceRecordSplat.Add('NS', $True) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('NameServer', $Record.Value) | ||||
|             } | ||||
|             'SRV' { | ||||
|                 $AddDnsServerResourceRecordSplat.Add('SRV', $True) | ||||
|                 # Value should match pattern '<fqdn>:<priority>:<weight>:<port>' | ||||
|                 # ie. 'sipserver.contoso.com:0:0:5060' | ||||
|                 $SrvLocator = $Record.Value -split ':' | ||||
|                 $AddDnsServerResourceRecordSplat.Add('DomainName', $SrvLocator[0]) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('Priority', $SrvLocator[1]) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('Weight', $SrvLocator[2]) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('Port', $SrvLocator[3]) | ||||
|             } | ||||
|             'TXT' { | ||||
|                 $AddDnsServerResourceRecordSplat.Add('TXT', $True) | ||||
|                 $AddDnsServerResourceRecordSplat.Add('DescriptiveText', $Record.Value) | ||||
|             } | ||||
|         } | ||||
|         Add-DnsServerResourceRecord @AddDnsServerResourceRecordSplat | ||||
|     } | ||||
| } | ||||
							
								
								
									
										27
									
								
								scripts/ADDS/payload/scripts/09.DNS records.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								scripts/ADDS/payload/scripts/09.DNS records.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Entries: | ||||
| - Name: ldap | ||||
|   Type: A | ||||
|   Value: "{{ primarydc }}" | ||||
| - Name: ldap | ||||
|   Type: A | ||||
|   Value: "{{ secondarydc }}" | ||||
| - Name: timeserver | ||||
|   Type: A | ||||
|   Value: "{{ primarydc }}" | ||||
| - Name: timeserver | ||||
|   Type: A | ||||
|   Value: "{{ secondarydc }}" | ||||
| # - Name: mail | ||||
| #   Type: MX | ||||
| #   Value: mail.contoso.com:10       # Value should match pattern '<fqdn>:<preference>' | ||||
| # - Name: voipserver | ||||
| #   Type: SRV | ||||
| #   Value: sip.contoso.com:0:0:5060  # Value should match pattern '<fqdn>:<priority>:<weight>:<port>' | ||||
| --- | ||||
| Variables: | ||||
| - Name: primarydc | ||||
|   Expression: | | ||||
|     (Resolve-DnsName -Name $Parameter['addsconfig.domainname'] | Sort-Object)[0].IPAddress | ||||
| - Name: secondarydc | ||||
|   Expression: | | ||||
|     (Resolve-DnsName -Name $Parameter['addsconfig.domainname'] | Sort-Object)[1].IPAddress | ||||
							
								
								
									
										47
									
								
								scripts/ADDS/payload/scripts/10.Group Policy WMI Filters.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								scripts/ADDS/payload/scripts/10.Group Policy WMI Filters.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| #Requires -Modules 'GPWmiFilter' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', '.yml') | ||||
|         Raw  = $True | ||||
|     } | ||||
|     $RawContent = Get-Content @GetContentSplat | ||||
|     $ConvertFromYamlSplat = @{ | ||||
|         Yaml         = $RawContent | ||||
|         AllDocuments = $True | ||||
|     } | ||||
|     $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|  | ||||
|     # Check if the respective .yml file declared substitutions which need to be parsed | ||||
|     If (($YamlDocuments.Count -gt 1) -and $YamlDocuments[-1].Variables) { | ||||
|         ForEach ($Pattern in $YamlDocuments[-1].Variables) { | ||||
|             $RawContent = $RawContent -replace "\{\{ ($($Pattern.Name)) \}\}", [string](Invoke-Expression -Command $Pattern.Expression) | ||||
|         } | ||||
|         # Perform conversion to Yaml again, now with parsed file contents | ||||
|         $ConvertFromYamlSplat = @{ | ||||
|             Yaml         = $RawContent | ||||
|             AllDocuments = $True | ||||
|         } | ||||
|         $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|         $WmiFilters = $YamlDocuments[0..($YamlDocuments.Count - 2)] | ||||
|     } | ||||
|     Else { | ||||
|         $WmiFilters = $YamlDocuments | ||||
|     } | ||||
|  | ||||
|     ForEach ($Filter in $WmiFilters) { | ||||
|         $NewGPWmiFilterSplat = @{ | ||||
|             Name        = $Filter.Name | ||||
|             Description = $Filter.Description | ||||
|             Expression  = $Filter.Expressions | ||||
|             Server      = $Parameter['addsconfig.domainname'] | ||||
|             ErrorAction = 'SilentlyContinue' | ||||
|         } | ||||
|         New-GPWmiFilter @NewGPWmiFilterSplat | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| - Name: PDC Emulator | ||||
|   Description: Primary Domain Controller Emulator only | ||||
|   Expressions: | ||||
|   - 'SELECT * FROM Win32_ComputerSystem WHERE DomainRole = 5' | ||||
| # --- | ||||
| # Variables: | ||||
| # - Name: foo | ||||
| #   Expression: | | ||||
| #     Write-Host 'bar' | ||||
| @@ -0,0 +1,9 @@ | ||||
| Name: 'COMP: Loopback processing (Merge)' | ||||
| Type: Object | ||||
| LinkedOUs: OU=Servers,OU=Computer accounts | ||||
| WMIFilters: [] | ||||
| RegistryEntries: | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\Server\ServerManager | ||||
|   Type: Dword | ||||
|   ValueName: DoNotOpenAtLogon | ||||
|   Value: 1 | ||||
| @@ -0,0 +1,19 @@ | ||||
| Name: 'COMP: Loopback processing (Merge)' | ||||
| Type: Object | ||||
| LinkedOUs: [] | ||||
| WMIFilters: [] | ||||
| RegistryEntries: | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\System | ||||
|   Type: Dword | ||||
|   ValueName: UserPolicyMode | ||||
|   Value: 1 | ||||
| --- | ||||
| Name: 'COMP: Loopback processing (Replace)' | ||||
| Type: Object | ||||
| LinkedOUs: [] | ||||
| WMIFilters: [] | ||||
| RegistryEntries: | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\System | ||||
|   Type: Dword | ||||
|   ValueName: UserPolicyMode | ||||
|   Value: 2 | ||||
							
								
								
									
										36
									
								
								scripts/ADDS/payload/scripts/11.GPO+GPP.PDC Timeserver.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								scripts/ADDS/payload/scripts/11.GPO+GPP.PDC Timeserver.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| Name: 'COMP: Timeserver configuration (W32Time)' | ||||
| Type: Object | ||||
| LinkedOUs: | ||||
| - OU=Domain Controllers | ||||
| WMIFilters: | ||||
| - PDC Emulator | ||||
| RegistryEntries: | ||||
| - Key: HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Parameters | ||||
|   Type: String | ||||
|   ValueName: | ||||
|   - Type | ||||
|   - NtpServer | ||||
|   Value: | ||||
|   - NTP | ||||
|   - "{{ addsconfig.ntpserver }}" | ||||
| - Key: HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config | ||||
|   Type: DWord | ||||
|   ValueName: AnnounceFlags | ||||
|   Value: 0xA | ||||
| - Key: HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config | ||||
|   Type: DWord | ||||
|   ValueName: MaxPosPhaseCorrection | ||||
|   Value: 0xFFFFFFFF | ||||
| - Key: HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config | ||||
|   Type: DWord | ||||
|   ValueName: MaxNegPhaseCorrection | ||||
|   Value: 0xFFFFFFFF | ||||
| - Key: HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer | ||||
|   Type: DWord | ||||
|   ValueName: Enabled | ||||
|   Value: 1 | ||||
| --- | ||||
| Variables: | ||||
| - Name: addsconfig.ntpserver | ||||
|   Expression: | | ||||
|     ($Parameter['addsconfig.ntpserver'] -split ',' | ForEach-Object {'{0},0x1' -f $_}) -join ' ' | ||||
| @@ -0,0 +1,116 @@ | ||||
| Name: 'COMP: Restrict Internet Communication' | ||||
| Type: Object | ||||
| LinkedOUs: | ||||
| - OU=Servers | ||||
| WMIFilters: [] | ||||
| RegistryEntries: | ||||
| - Key: HKLM\Software\Policies\Microsoft\InternetManagement | ||||
|   Type: DWord | ||||
|   ValueName: RestrictCommunication | ||||
|   Value: 1 | ||||
| # All below settings are set such that their respective features cannot access the Internet | ||||
| # If any of these settings are in conflict with the above setting, gpmc.msc will behave erratic! | ||||
| - Key: HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer | ||||
|   Type: Dword | ||||
|   ValueName: NoPublishingWizard | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer | ||||
|   Type: Dword | ||||
|   ValueName: NoWebServices | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer | ||||
|   Type: DWord | ||||
|   ValueName: NoOnlinePrintsWizard | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer | ||||
|   Type: DWord | ||||
|   ValueName: NoInternetOpenWith | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\EventViewer | ||||
|   Type: DWord | ||||
|   ValueName: MicrosoftEventVwrDisableLinks | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Messenger\Client | ||||
|   Type: DWord | ||||
|   ValueName: CEIP | ||||
|   Value: 2 | ||||
| - Key: HKLM\Software\Policies\Microsoft\PCHealth\ErrorReporting | ||||
|   Type: DWord | ||||
|   ValueName: DoReport | ||||
|   Value: 0 | ||||
| - Key: HKLM\Software\Policies\Microsoft\PCHealth\HelpSvc | ||||
|   Type: DWord | ||||
|   ValueName: Headlines | ||||
|   Value: 0 | ||||
| - Key: HKLM\Software\Policies\Microsoft\PCHealth\HelpSvc | ||||
|   Type: DWord | ||||
|   ValueName: MicrosoftKBSearch | ||||
|   Value: 0 | ||||
| - Key: HKLM\Software\Policies\Microsoft\SearchCompanion | ||||
|   Type: DWord | ||||
|   ValueName: DisableContentFileUpdates | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\SystemCertificates\AuthRoot | ||||
|   Type: DWord | ||||
|   ValueName: DisableRootAutoUpdate | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\SQMClient\Windows | ||||
|   Type: DWord | ||||
|   ValueName: CEIPEnable | ||||
|   Value: 0 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\DriverSearching | ||||
|   Type: DWord | ||||
|   ValueName: DontSearchWindowsUpdate | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\HandwritingErrorReports | ||||
|   Type: DWord | ||||
|   ValueName: PreventHandwritingErrorReports | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\Internet Connection Wizard | ||||
|   Type: DWord | ||||
|   ValueName: ExitOnMSICW | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\NetworkConnectivityStatusIndicator | ||||
|   Type: Dword | ||||
|   ValueName: NoActiveProbe | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\Registration Wizard Control | ||||
|   Type: DWord | ||||
|   ValueName: NoRegistration | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\TabletPC | ||||
|   Type: DWord | ||||
|   ValueName: PreventHandwritingDataSharing | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\Windows Error Reporting | ||||
|   Type: DWord | ||||
|   ValueName: Disabled | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate | ||||
|   Type: DWord | ||||
|   ValueName: DisableWindowsUpdateAccess | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows NT\CurrentVersion\Software Protection Platform | ||||
|   Type: DWord | ||||
|   ValueName: NoGenTicket | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows NT\Printers | ||||
|   Type: DWord | ||||
|   ValueName: DisableHTTPPrinting | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\Windows NT\Printers | ||||
|   Type: DWord | ||||
|   ValueName: DisableWebPnPDownload | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\WindowsMovieMaker | ||||
|   Type: DWord | ||||
|   ValueName: WebHelp | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\WindowsMovieMaker | ||||
|   Type: DWord | ||||
|   ValueName: CodecDownload | ||||
|   Value: 1 | ||||
| - Key: HKLM\Software\Policies\Microsoft\WindowsMovieMaker | ||||
|   Type: DWord | ||||
|   ValueName: WebPublish | ||||
|   Value: 1 | ||||
							
								
								
									
										44
									
								
								scripts/ADDS/payload/scripts/11.GPO+GPP._GPOexample
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								scripts/ADDS/payload/scripts/11.GPO+GPP._GPOexample
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| Name: 'COMP: Example GPO' # Prefix the name with either 'COMP:' or 'USER:' | ||||
| Type: Object              # Either 'Object' or 'Preference' (respectively for GPO or GPP) | ||||
| LinkedOUs:                # Entries will be concatenated with ',DC=<example>,DC=<org>' automatically | ||||
| - OU=Servers | ||||
| WMIFilters: | ||||
| - FilterA | ||||
| - FilterB | ||||
| RegistryEntries: | ||||
| - Key: HKLM\SOFTWARE\Policies\Microsoft\Windows\System | ||||
|   Type: DWord | ||||
|   ValueName: PropertyA | ||||
|   Value: 1 | ||||
| - Key: HKLM\SOFTWARE\Policies\Microsoft\Windows\System | ||||
|   Type: DWord | ||||
|   ValueName: PropertyB | ||||
|   Value: 0xFFFFFFFF       # Hexadecimal values are prefixed with '0x' | ||||
| - Key: HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Parameters | ||||
|   Type: String | ||||
|   ValueName:              # Multiple entries are possible, but *only* for the data type 'String' and 'ExpandString' (REG_SZ and REG_EXPAND_SZ) | ||||
|   - PropertyP | ||||
|   - PropertyQ | ||||
|   - PropertyR | ||||
|   Value:                  # The amount of entries must match with 'ValueName' | ||||
|   - ValueP | ||||
|   - ValueQ | ||||
|   - ValueR | ||||
| - Key: HKLM\Software\Test | ||||
|   Type: String | ||||
|   ValueName: | ||||
|   - PropertyX | ||||
|   - PropertyDate | ||||
|   - PropertyOVF | ||||
|   Value:                  # Values can contain variablenames (respective entries must be declared under 'Variables' below) | ||||
|   - ValueX | ||||
|   - "{{ date }}" | ||||
|   - "{{ guestinfo.dnsserver }}" | ||||
| --- | ||||
| Variables:                # Each variable consists of a name that is used as a placeholder in the yaml file above, and a PowerShell expression | ||||
| - Name: date | ||||
|   Expression: |           # The PowerShell script's output must evaluate to a [string] | ||||
|     Get-Date | ||||
| - Name: guestinfo.dnsserver | ||||
|   Expression: |          # The variable '$Parameter' will automatically contain all defined OVF Properties | ||||
|     $Parameter['guestinfo.dnsserver'] | ||||
							
								
								
									
										34
									
								
								scripts/ADDS/payload/scripts/11.GPO+GPP._GPPexample
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								scripts/ADDS/payload/scripts/11.GPO+GPP._GPPexample
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| Name: 'COMP: Example GPO' # Prefix the name with either 'COMP:' or 'USER:' | ||||
| Type: Preference          # Either 'Object' or 'Preference' (respectively for GPO or GPP) | ||||
| LinkedOUs:                # Entries will be concatenated with ',DC=<example>,DC=<org>' automatically | ||||
| - OU=Servers | ||||
| WMIFilters: | ||||
| - FilterA | ||||
| - FilterB | ||||
| RegistryEntries: | ||||
| - Key: HKLM\SOFTWARE\Policies\Microsoft\Windows\System | ||||
|   Type: DWord | ||||
|   ValueName: PropertyA | ||||
|   Value: 1 | ||||
|   Action: Replace         # Valid values are: Create, Update, Replace or Delete | ||||
|   Context: Computer       # Valid values are: User or Computer | ||||
|   Disable: False          # Change to 'True' when GPP entry should not be applied | ||||
| - Key: HKLM\SOFTWARE\Policies\Microsoft\Windows\System | ||||
|   Type: DWord | ||||
|   ValueName: PropertyB | ||||
|   Value: 0xFFFFFFFF       # Hexadecimal values are prefixed with '0x' | ||||
|   Action: Replace | ||||
|   Context: Computer | ||||
|   Disable: False | ||||
| - Key: HKLM\Software\Test | ||||
|   Type: String | ||||
|   ValueName: PropertyOVF | ||||
|   Value: "{{ guestinfo.dnsserver }}"  # Values can contain variablenames (respective entries must be declared under 'Variables' below) | ||||
|   Action: Replace | ||||
|   Context: Computer | ||||
|   Disable: False | ||||
| --- | ||||
| Variables:                # Each variable consists of a name that is used as a placeholder in the yaml file above, and a PowerShell expression | ||||
| - Name: guestinfo.dnsserver | ||||
|   Expression: |           # The variable '$Parameter' will automatically contain all defined OVF Properties | ||||
|     $Parameter['guestinfo.dnsserver'] | ||||
							
								
								
									
										175
									
								
								scripts/ADDS/payload/scripts/11.GPO+GPP.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								scripts/ADDS/payload/scripts/11.GPO+GPP.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | ||||
| #Requires -Modules 'powershell-yaml' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $NewPSSessionSplat = @{ | ||||
|         ComputerName = $Parameter['guestinfo.hostname'] | ||||
|         Credential   = New-Object System.Management.Automation.PSCredential( | ||||
|             (Get-ADUser -Filter * | Where-Object {$_.SID -match '-500'}).SamAccountName, | ||||
|             (ConvertTo-SecureString $Parameter['addsconfig.administratorpw'] -AsPlainText -Force) | ||||
|         ) | ||||
|     } | ||||
|     $PSSession = New-PSSession @NewPSSessionSplat | ||||
|  | ||||
|     $GetItemSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', '.*.yml') | ||||
|     } | ||||
|     Get-Item @GetItemSplat | ForEach-Object { | ||||
|         Write-Host "Loading/parsing file '$($_)' ..." | ||||
|         $GetContentSplat = @{ | ||||
|             Path = $_ | ||||
|             Raw  = $True | ||||
|         } | ||||
|         $RawContent = Get-Content @GetContentSplat | ||||
|         $ConvertFromYamlSplat = @{ | ||||
|             Yaml         = $RawContent | ||||
|             AllDocuments = $True | ||||
|         } | ||||
|         $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|  | ||||
|         # Check if the respective .yml file declared substitutions which need to be parsed | ||||
|         If (($YamlDocuments.Count -gt 1) -and $YamlDocuments[-1].Variables) { | ||||
|             ForEach ($Pattern in $YamlDocuments[-1].Variables) { | ||||
|                 $RawContent = $RawContent -replace "\{\{ ($($Pattern.Name)) \}\}", [string](Invoke-Expression -Command $Pattern.Expression) | ||||
|             } | ||||
|             # Perform conversion to Yaml again, now with parsed file contents | ||||
|             $ConvertFromYamlSplat = @{ | ||||
|                 Yaml         = $RawContent | ||||
|                 AllDocuments = $True | ||||
|             } | ||||
|             $YamlDocuments = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|             $GroupPolicies = $YamlDocuments[0..($YamlDocuments.Count - 2)] | ||||
|         } | ||||
|         Else { | ||||
|             $GroupPolicies = $YamlDocuments | ||||
|         } | ||||
|  | ||||
|         ForEach ($GroupPolicy in $GroupPolicies) { | ||||
|             Write-Host "Initiating policy '$($GroupPolicy.Name)' ..." | ||||
|             $NewGPOSplat = @{ | ||||
|                 Name          = $GroupPolicy.Name | ||||
|                 ErrorAction   = 'SilentlyContinue' | ||||
|                 ErrorVariable = 'Failure' | ||||
|             } | ||||
|             $NewGPO = New-GPO @NewGPOSplat | ||||
|             If ($Failure) { | ||||
|                 Continue | ||||
|             } | ||||
|  | ||||
|             Switch ($GroupPolicy.Type) { | ||||
|                 'Object' { | ||||
|                     ForEach ($ValueSet in $GroupPolicy.RegistryEntries) { | ||||
|                         Write-Host "Adding key/value to policy '$($NewGPO.DisplayName)' ...`n  [$($ValueSet.Key)/$($ValueSet.ValueName)]" | ||||
|                         $SetGPRegistryValueSplat = @{ | ||||
|                             Name        = $NewGPO.DisplayName | ||||
|                             Key         = $ValueSet.Key | ||||
|                             ValueName   = $ValueSet.ValueName | ||||
|                             Type        = $ValueSet.Type | ||||
|                             Value       = Switch ($ValueSet.Type) { | ||||
|                                 'Binary' { | ||||
|                                     # Accepted formats: | ||||
|                                     # 000A0F0100 | ||||
|                                     # 00 0A 0F 01 00 | ||||
|                                     # 00,0A,0F,01,00 | ||||
|                                     [byte[]]([regex]::split(($ValueSet.Value -replace '[ ,]'), '([0-9a-eA-E]{2})') | Where-Object {$_} | ForEach-Object {'0x{0}' -f $_}) | ||||
|                                 } | ||||
|                                 'DWord' { | ||||
|                                     [uint32]$ValueSet.Value | ||||
|                                 } | ||||
|                                 'QWord' { | ||||
|                                     [uint64]$ValueSet.Value | ||||
|                                 } | ||||
|                                 Default { | ||||
|                                     $ValueSet.Value | ||||
|                                 } | ||||
|                             } | ||||
|                             ErrorAction = 'SilentlyContinue' | ||||
|                         } | ||||
|                         Set-GPRegistryValue @SetGPRegistryValueSplat | Out-Null | ||||
|                     } | ||||
|                 } | ||||
|                 'Preference' { | ||||
|                     ForEach ($ValueSet in $GroupPolicy.RegistryEntries) { | ||||
|                         Write-Host "Adding key/value to policy '$($NewGPO.DisplayName)' ...`n  [$($ValueSet.Key)/$($ValueSet.ValueName)]" | ||||
|                         $SetGPPrefRegistryValueSplat = @{ | ||||
|                             Name        = $NewGPO.DisplayName | ||||
|                             Key         = $ValueSet.Key | ||||
|                             Context     = $ValueSet.Context | ||||
|                             Action      = $ValueSet.Action | ||||
|                             ValueName   = $ValueSet.ValueName | ||||
|                             Type        = $ValueSet.Type | ||||
|                             Value       = Switch ($ValueSet.Type) { | ||||
|                                 'Binary' { | ||||
|                                     # Accepted formats: | ||||
|                                     # 000A0F0100 | ||||
|                                     # 00 0A 0F 01 00 | ||||
|                                     # 00,0A,0F,01,00 | ||||
|                                     [byte[]]([regex]::split(($ValueSet.Value -replace '[ ,]'), '([0-9a-eA-E]{2})') | Where-Object {$_} | ForEach-Object {'0x{0}' -f $_}) | ||||
|                                 } | ||||
|                                 'DWord' { | ||||
|                                     [uint32]$ValueSet.Value | ||||
|                                 } | ||||
|                                 'QWord' { | ||||
|                                     [uint64]$ValueSet.Value | ||||
|                                 } | ||||
|                                 Default { | ||||
|                                     $ValueSet.Value | ||||
|                                 } | ||||
|                             } | ||||
|                             Disable     = [Convert]::ToBoolean($ValueSet.Disable) | ||||
|                             ErrorAction = 'SilentlyContinue' | ||||
|                         } | ||||
|                         Set-GPPrefRegistryValue @SetGPPrefRegistryValueSplat | Out-Null | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             ForEach ($Filter in $GroupPolicy.WMIFilters) { | ||||
|                 $InvokeCommandSplat = @{ | ||||
|                     Session      = $PSSession | ||||
|                     ArgumentList = $Filter, $Parameter, $NewGPO | ||||
|                     ScriptBlock  = { | ||||
|                         #Requires -Modules 'GPWmiFilter' | ||||
|                         Param( | ||||
|                             $Filter, | ||||
|                             $Parameter, | ||||
|                             $NewGPO | ||||
|                         ) | ||||
|  | ||||
|                         $GetGPWmiFilterSplat = @{ | ||||
|                             Name        = $Filter | ||||
|                             Server      = $Parameter['addsconfig.domainname'] | ||||
|                             ErrorAction = 'SilentlyContinue' | ||||
|                         } | ||||
|                         If (Get-GPWMIFilter @GetGPWmiFilterSplat) { | ||||
|                             $SetGPWmiFilterAssignmentSplat = @{ | ||||
|                                 Policy          = $NewGPO | ||||
|                                 Filter          = $Filter | ||||
|                                 EnableException = $True | ||||
|                                 ErrorAction     = 'SilentlyContinue' | ||||
|                             } | ||||
|                             Set-GPWmiFilterAssignment @SetGPWmiFilterAssignmentSplat | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 Invoke-Command @InvokeCommandSplat | ||||
|             } | ||||
|  | ||||
|             ForEach ($OU in $GroupPolicy.LinkedOUs) { | ||||
|                 If (Test-Path "AD:\$($OU + ',DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC='))") { | ||||
|                     Write-Host "Linking policy '$($NewGPO.DisplayName)' to OU '$($OU)' ..." | ||||
|                     $NewGPLinkSplat = @{ | ||||
|                         Name        = $NewGPO.DisplayName | ||||
|                         Target      = $OU + ',DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|                         ErrorAction = 'SilentlyContinue' | ||||
|                     } | ||||
|                     New-GPLink @NewGPLinkSplat | Out-Null | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										83
									
								
								scripts/ADDS/payload/scripts/12.Restrict OU Permissions.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								scripts/ADDS/payload/scripts/12.Restrict OU Permissions.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| #Requires -Modules 'ActiveDirectory','powershell-yaml' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $PSDrive = Get-PSDrive -Name 'AD' | ||||
|     If ([boolean]$PSDrive -eq $False) { | ||||
|         $NewPSDriveSplat = @{ | ||||
|             Name       = 'ADDS' | ||||
|             Root       = '' | ||||
|             PSProvider = 'ActiveDirectory' | ||||
|         } | ||||
|         $PSDrive = New-PSDrive @NewPSDriveSplat | ||||
|     } | ||||
|  | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', '.yml') | ||||
|         Raw  = $True | ||||
|     } | ||||
|     $RawContent = Get-Content @GetContentSplat | ||||
|     $ConvertFromYamlSplat = @{ | ||||
|         Yaml         = $RawContent | ||||
|         AllDocuments = $True | ||||
|     } | ||||
|     $WhiteList = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|  | ||||
|     $GetADObjectSplat = @{ | ||||
|         Filter      = '*' | ||||
|         SearchBase  = 'DC=' + $Parameter['addsconfig.domainname'].Replace('.', ',DC=') | ||||
|         SearchScope = 'OneLevel' | ||||
|     } | ||||
|     $WhiteListedOUs = @() | ||||
|     ForEach ($OU in $WhiteList.WhiteListedOUs) { | ||||
|         $WhiteListedOUs += Get-ADObject @GetADObjectSplat | Where-Object { | ||||
|             $_.DistinguishedName -match $OU | ||||
|         } | ||||
|     } | ||||
|     $ParentContainers = Get-ADObject @GetADObjectSplat | Where-Object { | ||||
|         ('builtinDomain', 'container', 'organizationalUnit', <#'lostAndFound',#> 'msDS-QuotaContainer', 'msTPM-InformationObjectsContainer') -contains $_.ObjectClass | ||||
|     } | ||||
|  | ||||
|     ForEach ($Parent in $ParentContainers) { | ||||
|         If ($WhiteListedOUs.DistinguishedName -notcontains $Parent.DistinguishedName) { | ||||
|             ForEach ($SecurityPrincipal in $WhiteList.LimitedSecurityPrincipals) { | ||||
|                 $GetACLSPlat = @{ | ||||
|                     Path = "$($PSDrive.Name):\$($Parent.DistinguishedName)" | ||||
|                 } | ||||
|                 $ACL = Get-ACL @GetACLSPlat | ||||
|  | ||||
|                 $GetADObjectSplat = @{ | ||||
|                     Filter = "sAMAccountName -eq '$($SecurityPrincipal)'" | ||||
|                     Properties = 'objectSID' | ||||
|                 } | ||||
|                 $NewACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule( | ||||
|                     (Get-ADObject @GetADObjectSplat).objectSID, | ||||
|                     [System.DirectoryServices.ActiveDirectoryRights]"GenericAll", | ||||
|                     [System.Security.AccessControl.AccessControlType]"Deny", | ||||
|                     [System.DirectoryServices.ActiveDirectorySecurityInheritance]"All" | ||||
|                 ) | ||||
|                 $ACL.AddAccessRule($NewACE) | ||||
|  | ||||
|                 $SetAclSplat = @{ | ||||
|                     Path        = "$($PSDrive.Name):\$($Parent.DistinguishedName)" | ||||
|                     AclObject   = $ACL | ||||
|                     ErrorAction = 'Continue' | ||||
|                 } | ||||
|                 Set-Acl @SetAclSplat | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     If ([boolean]$PSDrive.Name -eq 'ADDS') { | ||||
|         $RemovePSDriveSplat = @{ | ||||
|             Name    = 'ADDS' | ||||
|             Force   = $True | ||||
|             Confirm = $False | ||||
|         } | ||||
|         Remove-PSDrive @RemovePSDriveSplat | Out-Null | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| WhiteListedOUs: []            # Entries will be concatenated with ',DC=<example>,DC=<org>' automatically | ||||
| #- OU=User accounts | ||||
| LimitedSecurityPrincipals: [] | ||||
| #- Servicedesk employees | ||||
| @@ -0,0 +1,34 @@ | ||||
| #Requires -Modules 'ActiveDirectory' | ||||
| Param( | ||||
|     [Parameter(Mandatory)] | ||||
|     [hashtable]$Parameter | ||||
| ) | ||||
|  | ||||
| # Only executed on primary Domain Controller | ||||
| If ((Get-WmiObject -Class 'Win32_ComputerSystem').DomainRole -eq 5) { | ||||
|     $GetContentSplat = @{ | ||||
|         Path = "$($PSScriptRoot)\$($MyInvocation.MyCommand)".Replace('.ps1', ".yml") | ||||
|         Raw  = $True | ||||
|     } | ||||
|     $RawContent = Get-Content @GetContentSplat | ||||
|     $ConvertFromYamlSplat = @{ | ||||
|         Yaml         = $RawContent | ||||
|         AllDocuments = $True | ||||
|     } | ||||
|     $Policy = ConvertFrom-Yaml @ConvertFromYamlSplat | ||||
|  | ||||
|     $SetADDefaultDomainPasswordPolicySplat = @{ | ||||
|         Identity                    = $Parameter['addsconfig.domainname'] | ||||
|         ComplexityEnabled           = [Convert]::ToBoolean($Policy.Password.RequireComplexity) | ||||
|         LockoutThreshold            = [uint32]$Policy.Account.Lockout.Threshold | ||||
|         # LockoutDuration             = [timespan]$Policy.Account.Lockout.Duration | ||||
|         # LockoutObservationWindow    = [timespan]$Policy.Account.Lockout.ObservationWindow | ||||
|         MaxPasswordAge              = [timespan]$Policy.Password.Age.Maximum | ||||
|         MinPasswordAge              = [timespan]$Policy.Password.Age.Minimum | ||||
|         MinPasswordLength           = [uint32]$Policy.Password.Length.Minimum | ||||
|         PasswordHistoryCount        = [uint32]$Policy.Password.History | ||||
|         ReversibleEncryptionEnabled = [Convert]::ToBoolean($Policy.Password.ReversibleEncryption) | ||||
|         Confirm                     = $False | ||||
|     } | ||||
|     Set-ADDefaultDomainPasswordPolicy @SetADDefaultDomainPasswordPolicySplat | ||||
| } | ||||
| @@ -0,0 +1,14 @@ | ||||
| Account: | ||||
|   Lockout: | ||||
|     Threshold: 0 | ||||
|     # Duration: '00:15:00.00' | ||||
|     # ObservationWindow: '00:05:00.00' | ||||
| Password: | ||||
|   RequireComplexity: True | ||||
|   Age: | ||||
|     Minimum: 0 | ||||
|     Maximum: 0 | ||||
|   Length: | ||||
|     Minimum: 10 | ||||
|   History: 0 | ||||
|   ReversibleEncryption: False | ||||
		Reference in New Issue
	
	Block a user