Packer.Images/scripts/ADDS/payload/Apply-OVFProperties.ps1

358 lines
13 KiB
PowerShell
Raw Normal View History

#Requires -Modules 'ADDSDeployment'
[CmdletBinding()]
Param(
# No parameters
)
2021-01-27 14:47:29 +00:00
Function New-ToastNotification {
Param(
[Parameter()]
2021-01-27 14:47:29 +00:00
[string]$Stream = 'OVF Properties',
[Parameter(Mandatory)]
[string]$Title,
[Parameter(Mandatory)]
[string]$Text
)
[void][Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
2021-01-27 14:47:29 +00:00
$Template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
$XML = [xml]$Template.GetXml()
$XML.SelectSingleNode("toast/visual/binding/text[@id='1']").InnerText = $Title
$XML.SelectSingleNode("toast/visual/binding/text[@id='2']").InnerText = $Text
$SerializedXml = New-Object Windows.Data.Xml.Dom.XmlDocument
$SerializedXml.LoadXml($XML.OuterXml)
$Notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($Stream)
$Notifier.Show([Windows.UI.Notifications.ToastNotification]::new($SerializedXml))
}
$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
Switch ($ovfPropertyValues['deployment.type']) {
'primary' {
$MandatoryProperties, $MissingProperties = @('guestinfo.hostname', 'guestinfo.ipaddress', 'guestinfo.prefixlength', 'guestinfo.gateway', 'addsconfig.domainname', 'addsconfig.netbiosname', 'addsconfig.administratorpw', 'addsconfig.safemodepw', 'addsconfig.ntpserver'), @()
}
'secondary' {
$MandatoryProperties, $MissingProperties = @('guestinfo.hostname', 'guestinfo.ipaddress', 'guestinfo.prefixlength', 'guestinfo.dnsserver', 'guestinfo.gateway', 'addsconfig.domainname', 'addsconfig.netbiosname', 'addsconfig.administratorpw', 'addsconfig.safemodepw', 'dhcpconfig.startip', 'dhcpconfig.endip', 'dhcpconfig.subnetmask', 'dhcpconfig.gateway', 'dhcpconfig.leaseduration'), @()
}
'standalone' {
$MandatoryProperties, $MissingProperties = @('guestinfo.hostname', 'guestinfo.ipaddress', 'guestinfo.prefixlength', 'guestinfo.gateway', 'addsconfig.domainname', 'addsconfig.netbiosname', 'addsconfig.administratorpw', 'addsconfig.safemodepw', 'addsconfig.ntpserver', 'dhcpconfig.startip', 'dhcpconfig.endip', 'dhcpconfig.subnetmask', 'dhcpconfig.gateway', 'dhcpconfig.leaseduration'), @()
}
default {
# Mandatory values missing, cannot provision.
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'OVF-Properties'
EntryType = 'Error'
EventID = 66
Message = "Unexpected or no value set for property 'deployment.type', cannot provision."
}
Write-EventLog @WriteEventLogSplat
& schtasks.exe /Change /TN 'OVF-Properties' /DISABLE
Stop-Computer -Force
Exit
}
}
ForEach ($Property in $MandatoryProperties) {
If (!$ovfPropertyValues[$Property]) {
$MissingProperties += $Property
}
}
If ($MissingProperties.Length -gt 0) {
# Mandatory values missing, cannot provision.
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'OVF-Properties'
EntryType = 'Error'
EventID = 66
Message = "Missing values for mandatory properties $(($MissingProperties | ForEach-Object {'{0}' -f $_}) -join ', '), 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']) {
2021-01-28 05:49:39 +00:00
# $NewToastSplat = @{
# Title = 'OVF Properties'
# Text = 'Configuring hostname and description...'
# }
# New-ToastNotification @NewToastSplat
$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']) {
2021-01-28 05:49:39 +00:00
# $NewToastSplat = @{
# Title = 'OVF Properties'
# Text = 'Configuring network...'
# }
# New-ToastNotification @NewToastSplat
$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) {
2021-01-28 05:49:39 +00:00
# $NewToastSplat = @{
# Title = 'OVF Properties'
# Text = 'Configuring local administrator password...'
# }
# New-ToastNotification @NewToastSplat
# 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
2021-01-28 05:49:39 +00:00
# $NewToastSplat = @{
# Title = 'OVF Properties'
# Text = 'Promoting to Domain Controller...'
# }
# New-ToastNotification @NewToastSplat
$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
2021-01-28 05:49:39 +00:00
# $NewToastSplat = @{
# Title = 'OVF Properties'
# Text = 'Waiting for Active Directory services...'
# }
# New-ToastNotification @NewToastSplat
$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 {
2021-01-28 05:49:39 +00:00
# $NewToastSplat = @{
# Title = 'OVF Properties'
# Text = "Running script: '$($_.FullName)'"
# }
# New-ToastNotification @NewToastSplat
$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
}
}
2021-01-28 05:49:39 +00:00
# $NewToastSplat = @{
# Title = 'OVF Properties'
# Text = "Sequence finished; ready for use!"
# }
# New-ToastNotification @NewToastSplat
$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