#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 Switch ($ovfPropertyValues['deployment.type']) { 'standalone-root' { $MandatoryProperties, $MissingProperties = @('guestinfo.hostname', 'guestinfo.ipaddress', 'guestinfo.prefixlength', 'guestinfo.dnsserver', 'guestinfo.gateway', 'guestinfo.administratorpw', 'adcsconfig.organizationname', 'adcsconfig.foo'), @() } 'enterprise-intermediate' { $MandatoryProperties, $MissingProperties = @('guestinfo.hostname', 'guestinfo.ipaddress', 'guestinfo.prefixlength', 'guestinfo.dnsserver', 'guestinfo.gateway', 'guestinfo.administratorpw', 'adcsconfig.foo'), @() } 'standalone-intermediate' { $MandatoryProperties, $MissingProperties = @('guestinfo.hostname', 'guestinfo.ipaddress', 'guestinfo.prefixlength', 'guestinfo.dnsserver', 'guestinfo.gateway', 'guestinfo.administratorpw', 'adcsconfig.foo'), @() } default { # Mandatory values missing, cannot provision. $WriteEventLogSplat = @{ LogName = 'Application' Source = 'FirstBoot' EntryType = 'Error' EventID = 66 Message = "Unexpected or no value set for property 'deployment.type', cannot provision." } Write-EventLog @WriteEventLogSplat & schtasks.exe /Change /TN 'FirstBoot' /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 = 'FirstBoot' 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 'FirstBoot' /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'] } $IPAddress = 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 = @{ IPAddress = $ovfPropertyValues['guestinfo.ipaddress'] InterfaceIndex = $IPAddress.InterfaceIndex 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 } # Install and configure certificate authority If ((& certutil.exe | Select-String "Server:") -notmatch "$Env:ComputerName") { # Change password of built-in Administrator $BuiltinAdministrator = (Get-LocalUser | Where-Object {$_.SID -match '-500'}) $ConvertToSecureStringSplat = @{ String = $ovfPropertyValues['guestinfo.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 Switch ($ovfPropertyValues['deployment.type']) { 'standalone-root' { $InstallADCSCertificationAuthoritySplat = @{ CACommonName = "$($ovfPropertyValues['deployment.organizationname']) Root CA" CAType = 'StandaloneRootCA' } Install-ADCSCertificationAuthority @InstallADCSCertificationAuthoritySplat } # Foo # Bar } } # 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" } ForEach ($Script in (Get-Item @GetItemSplat)) { Try { $WriteEventLogSplat = @{ LogName = 'Application' Source = 'OVF-Properties' EntryType = 'Information' EventID = 4 Message = "Running script: '$($Script.FullName)'" } Write-EventLog @WriteEventLogSplat & $Script.FullName -Parameter $ovfPropertyValues } Catch { $WriteEventLogSplat = @{ LogName = 'Application' Source = 'OVF-Properties' EntryType = 'Error' EventID = 66 Message = @" Error occurred while executing script '$($Script.Name)': $($_.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