I've been working on a script to setup a dc and forest using PowerCLI. I've got the script working fine but its throwing the below error.
VERBOSE: Configuring AD Forest on testvmdc
Invoke-VMScript : 1/27/2020 10:39:56 PM Invoke-VMScript A general system error occurred: vix error codes = (3016, 0).
At C:\Scripts\Dev\Create-DomainController_DEV_Jay.ps1:88 char:1
+ Invoke-VMScript -ScriptText $ConfigureNewDomain -VM $DomainController ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Invoke-VMScript], SystemError
+ FullyQualifiedErrorId : Client20_VmGuestServiceImpl_GetProcessOutputInGuest_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.InvokeVmScript
I'm trying to figure out why I'm getting the error when it does not appear to effect the script.
Here's the script so for. I'm sure It's pretty ugly lol
$DomainControllerVMName = "testvmdc"
# ------This Section Sets the Credentials to be used to connect to Guest VMs that are NOT part of a Domain------
# NOTE - Make sure you input the local credentials for your domain controller virtual machines below. This is used for logins prior to them being promoted to DCs.
# This should be the same local credentials as defined within the template that you are using for the domain controller VM.
$DCLocalUser = "$DomainControllerVMName\administrator"
$DCLocalPWord = ConvertTo-SecureString -String "P@ssword" -AsPlainText -Force
$DCLocalCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $DCLocalUser, $DCLocalPWord
# The below credentials are used by operations below once the domain controller virtual machines and the new domain are in place. These credentials should match the credentials
# used during the provisioning of the new domain.
$DomainUser = "TEST\administrator"
$DomainPWord = ConvertTo-SecureString -String "P@ssword" -AsPlainText -Force
$DomainCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $DomainUser, $DomainPWord
$DCLocalCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $DCLocalUser, $DCLocalPWord
#####network Config######
# Domain Controller VM IPs Below
# NOTE: Insert IP info in IP SubnetMask Gateway Order
# NOTE: For the purposes of this script we do not define static DNS settings for this single DC VM as it will point to itself for DNS after provisioning of the new domain.
# You could add an additional netsh line below to assign static DNS settings in the event you need to do so. See the File Server Section below for further details.
$DCNetworkSettings = 'netsh interface ip set address "Ethernet0" static 172.69.0.20 255.255.255.0 172.69.0.254'
Write-Verbose -Message "Getting ready to change IP Settings on VM $DomainControllerVMName." -Verbose
Invoke-VMScript -ScriptText $DCNetworkSettings -VM $DomainControllerVMName -GuestCredential $DCLocalCredential
# NOTE - The Below Sleep Command is due to it taking a few seconds for VMware Tools to read the IP Change so that we can return the below output.
# This is strctly informational and can be commented out if needed, but it's helpful when you want to verify that the settings defined above have been
# applied successfully within the VM. We use the Get-VM command to return the reported IP information from Tools at the Hypervisor Layer.
Start-Sleep 30
$DCEffectiveAddress = (Get-VM $DomainControllerVMName).guest.ipaddress[0]
Write-Verbose -Message "Assigned IP for VM [$DomainControllerVMName] is [$DCEffectiveAddress]" -Verbose
#####Domain config##########
# This Command will Install the AD Role on the target virtual machine.
$InstallADRole = 'Install-WindowsFeature -Name "AD-Domain-Services" -Restart'
Write-Verbose -Message "Installing AD Roles on $DomainControllerVMName" -Verbose
Invoke-VMScript -ScriptText $InstallADRole -VM $DomainControllerVMName -GuestCredential $DCLocalCredential
Write-Verbose -Message "AD Roles have been installed on $DomainControllerVMName" -Verbose
#Install DNS Roles
Write-Verbose -Message "Installing DNS Roles on $DomainControllerVMName" -Verbose
# This section installs the DNS roles
$InstallDNSRole = 'Install-WindowsFeature -Name DNS -IncludeAllSubFeature -IncludeManagementTools'
Invoke-VMScript -ScriptText $InstallDNSRole -VM $DomainControllerVMName -GuestCredential $DCLocalCredential
#Invoke-VMScript -ScriptText 'Install-WindowsFeature -Name DNS -IncludeAllSubFeature -IncludeManagementTools' -VM TestVMDC -GuestCredential $DCLocalCredential
Write-Verbose -Message "DNS Roles have been installed on $DomainControllerVMName" -Verbose
# Configure Domain
# This Scriptblock will define settings for a new AD Forest and then provision it with said settings.
# NOTE - Make sure to define the DSRM Password below in the line below that defines the $DSRMPWord Variable!!!!
$ConfigureNewDomain = 'Write-Verbose -Message "Configuring Active Directory" -Verbose;
$DomainMode = "WinThreshold";
$ForestMode = "WinThreshold";
$DomainName = "Test.local";
$DSRMPWord = ConvertTo-SecureString -String "P@ssword" -AsPlainText -Force;
Install-ADDSForest -ForestMode $ForestMode -DomainMode $DomainMode -DomainName $DomainName -InstallDns -SafeModeAdministratorPassword $DSRMPWord -Force'
Write-Verbose -Message "Configuring AD Forest on $DomainControllerVMName" -Verbose
Invoke-VMScript -ScriptText $ConfigureNewDomain -VM $DomainControllerVMName -GuestCredential $DCLocalCredential | Out-Null
# Script Block for configuration of AD automatically reboots the machine after provisioning
Write-Verbose -Message "Rebooting $DomainControllerVMName to Complete Forest Provisioning" -Verbose
# Below sleep command is in place as the reboot needed from the above command doesn't always happen before the wait-tools command is run
Start-Sleep -Seconds 60
Wait-Tools -VM $DomainControllerVMName -TimeoutSeconds 300
Write-Verbose -Message "Installation of Domain Services and Forest Provisioning on $DomainControllerVMName Complete" -Verbose
#This section installs AD Tools
Write-Verbose -Message "Installing AD Tools on $DomainControllerVMName" -Verbose
$InstallADtools = 'ADD-WindowsFeature RSAT-Role-Tools'
Invoke-VMScript -ScriptText $InstallADtools -VM $DomainControllerVMName -GuestCredential $DomainCredential
Write-Verbose -Message "Install of AD Tools on $DomainControllerVMName completed" -Verbose
#Create SHORTCUTS
# Create Active directory Users and Computers shortcut on the public desktop
Write-Verbose -Message "Creating Active directory Users and Computers Desktop shortcut on $DomainControllerVMName" -Verbose
$ADshortcut = '
$SourceFileLocation = "$env:SystemRoot\System32\dsa.msc"
$ShortcutLocation = "C:\Users\Public\Desktop\Active directory Users and Computers.lnk"
#New-Object : Creates an instance of a Microsoft .NET Framework or COM object.
#-ComObject WScript.Shell: This creates an instance of the COM object that represents the WScript.Shell for invoke CreateShortCut
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutLocation)
$Shortcut.TargetPath = $SourceFileLocation
#Save the Shortcut to the TargetPath
$Shortcut.Save() '
Invoke-VMScript -ScriptText $ADshortcut -VM $DomainControllerVMName -GuestCredential $DomainCredential | Out-Null
Write-Verbose -Message "Done Creating Active directory Users and Computers Desktop shortcut on $DomainControllerVMName" -Verbose
# Create DNS on the public desktop
Write-Verbose -Message "Creating DNS Desktop shortcut on $DomainControllerVMName" -Verbose
$DNSshortcut = '
$SourceFileLocation = "$env:SystemRoot\System32\dnsmgmt.msc"
$ShortcutLocation = "C:\Users\Public\Desktop\DNS.lnk"
#New-Object : Creates an instance of a Microsoft .NET Framework or COM object.
#-ComObject WScript.Shell: This creates an instance of the COM object that represents the WScript.Shell for invoke CreateShortCut
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutLocation)
$Shortcut.TargetPath = $SourceFileLocation
#Save the Shortcut to the TargetPath
$Shortcut.Save() '
Invoke-VMScript -ScriptText $DNSshortcut -VM $DomainControllerVMName -GuestCredential $DomainCredential | Out-Null
Write-Verbose -Message "Done creating DNS Desktop shortcut on $DomainControllerVMName" -Verbose
Could this be caused by what is described in KB2148803?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
LucD - First off I'd like to thank you for you contributions to these forums!!!
That error kind of sounds like what might be happening. The VM is restarting and losing connection to vcenter in the process, causing the error.
I'm guessing PowerCLI is expecting the output the results of the Invoke-VMScript but since a domain forest is being configured the O/S is restarted and can't output the results of the script.
Only thing about that KB is I'm not using integrated containers, I'm cloning from a template.
The section of the script that throws the error is during the domain forest provisioning.
Like I said, the script is working but my OCD hates that error. I'd like everything to be as clean as possible.
Thanks.
I have experienced similar.
A script that needs to reboot the VM, but the reboot happens too fast for the Invoke-VMScript to return.
Hence a similar error.
What I did as a bypass, I added the script to the Windows Scheduled Task manager with a start time 10-20 seconds in the future.
Then my Invoke-VMScript comes back without error, and on the calling side I wait for the restart to have completed.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Managed to get the script working after redoing most of it. I'm sure it could use some cleaning up and formatting. I'm still trying to get my PowerShell Chops up to speed.
This will prompt the user for all required inputs. All except the DSRM password, this needs to be hard coded in the script for now. I haven't been able to get that working yet. I think the Read-Host in the variable for that password may need to be in paranises for it to work. I'll test that out later.
Next step it to make one to provision and configure a Horizon Connection server as well as a file server. My end goal is to automate an entire Horizon deployment. Wish me luck lol.
#####################################
# User defined Variables
#####################################
# Name of vCenter Server
$vCenter = Read-Host "vCenter Server"
# Username of vCenter Server
$vCenterUsr = Read-Host "vCenter Username"
# Password of vCenter Server
$vCenterPas = Read-Host "vCenter Password"
# Name of the newly created VM
$DomainControllerVMName = Read-Host "Provide Domain Controller VM name"
# Cluster where new VM will be provisoned
$TargetCluster = Get-Cluster -Name (Read-Host "Provide Target Cluster")
#Template to Cone for new VM
$SourceVMTemplate = Get-Template -Name (Read-Host "Provide VM Template to Clone")
#VM Customization Specifications to use for new VM
$SourceCustomSpec = Get-OSCustomizationSpec -Name (Read-Host "VM Customization Specifications to use for new VM")
# VM IP Address
$DCIP = Read-Host "Domain Controller IP"
# VM Subnetmask
$DCNemtsk = Read-Host "Domain Controller SubnetMask"
# VM Gateway
$DCGW = Read-Host "Domain Controller Gateway"
####User Information######
$localuser = Read-Host "Provide Local Admin User (administrator)"
$localpassword = Read-Host "Provide local user password"
# FQDN of New Domain
$FQDN = Read-Host "Enter Domin FQDN"
# ------This Section Sets the Credentials to be used to connect to Guest VMs that are NOT part of a Domain------
# NOTE - Make sure you input the local credentials for your domain controller virtual machines below. This is used for logins prior to them being promoted to DCs.
# This should be the same local credentials as defined within the template that you are using for the domain controller VM.
$DCLocalUser = "$DomainControllerVMName\$localuser"
$DCLocalPWord = ConvertTo-SecureString -String "$localpassword" -AsPlainText -Force
$DCLocalCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $DCLocalUser, $DCLocalPWord
# The below credentials are used by operations below once the domain controller virtual machines and the new domain are in place. These credentials should match the credentials
# used during the provisioning of the new domain.
$DomainUser = "$FQDN\$localuser"
$DomainPWord = ConvertTo-SecureString -String "$localpassword" -AsPlainText -Force
$DomainCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $DomainUser, $DomainPWord
$DCLocalCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $DCLocalUser, $DCLocalPWord
##############################################################################################################################################################
#####################################
# Script Execution starts here
#####################################
#Connect to vCenter
Connect-VIServer $vCenter -User $vCenterUsr -Password $vCenterPas
##############################################################################
######## This Section Deploys the new VM(s) using a pre-built template #######
######## and then applies a customization specification to it. #######
######## It then waits for Provisioning To Finish #######
##############################################################################
Write-Verbose -Message "Deploying Virtual Machine with Name: [$DomainControllerVMName] using Template: [$SourceVMTemplate] and Customization Specification: [$SourceCustomSpec] on Cluster: [$TargetCluster] and waiting for completion" -Verbose
New-VM -Name $DomainControllerVMName -Template $SourceVMTemplate -ResourcePool $TargetCluster -OSCustomizationSpec $SourceCustomSpec
Write-Verbose -Message "Virtual Machine $DomainControllerVMName Deployed. Powering On" -Verbose
Start-VM -VM $DomainControllerVMName
# We first verify that the guest customization has finished on on the new DC VM by using the below loops to look for the relevant events within vCenter.
Write-Verbose -Message "Verifying that Customization for VM $DomainControllerVMName has started ..." -Verbose
while($True)
{
$DCvmEvents = Get-VIEvent -Entity $DomainControllerVMName
$DCstartedEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationStartedEvent" }
if ($DCstartedEvent)
{
break
}
else
{
Start-Sleep -Seconds 5
}
}
Write-Verbose -Message "Customization of VM $DomainControllerVMName has started. Checking for Completed Status......." -Verbose
while($True)
{
$DCvmEvents = Get-VIEvent -Entity $DomainControllerVMName
$DCSucceededEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationSucceeded" }
$DCFailureEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationFailed" }
if ($DCFailureEvent)
{
Write-Warning -Message "Customization of VM $DomainControllerVMName failed" -Verbose
return $False
}
if ($DCSucceededEvent)
{
break
}
Start-Sleep -Seconds 5
}
Write-Verbose -Message "Customization of VM $DomainControllerVMName Completed Successfully!" -Verbose
# NOTE - The below Sleep command is to help prevent situations where the post customization reboot is delayed slightly causing
# the Wait-Tools command to think everything is fine and carrying on with the script before all services are ready. Value can be adjusted for your environment.
Start-Sleep -Seconds 60
Write-Verbose -Message "Waiting for VM $DomainControllerVMName to complete post-customization reboot." -Verbose
Wait-Tools -VM $DomainControllerVMName -TimeoutSeconds 300
# NOTE - Another short sleep here to make sure that other services have time to come up after VMware Tools are ready.
Start-Sleep -Seconds 200
##################################################################################
######## This Section Configures the Networking on the newly provisoned VM #######
##################################################################################
# Domain Controller VM IPs Below
# NOTE: Insert IP info in IP SubnetMask Gateway Order
# NOTE: For the purposes of this script we do not define static DNS settings for this single DC VM as it will point to itself for DNS after provisioning of the new domain.
# You could add an additional netsh line below to assign static DNS settings in the event you need to do so. See the File Server Section below for further details.
$DCNetworkSettings = "netsh interface ip set address Ethernet0 static $DCIP $DCNemtsk $DCGW"
Write-Verbose -Message "Getting ready to change IP Settings on VM $DomainControllerVMName." -Verbose
Invoke-VMScript -ScriptText $DCNetworkSettings -VM $DomainControllerVMName -GuestCredential $DCLocalCredential
# NOTE - The Below Sleep Command is due to it taking a few seconds for VMware Tools to read the IP Change so that we can return the below output.
# This is strctly informational and can be commented out if needed, but it's helpful when you want to verify that the settings defined above have been
# applied successfully within the VM. We use the Get-VM command to return the reported IP information from Tools at the Hypervisor Layer.
Start-Sleep 30
$DCEffectiveAddress = (Get-VM $DomainControllerVMName).guest.ipaddress[0]
Write-Verbose -Message "Assigned IP for VM [$DomainControllerVMName] is [$DCEffectiveAddress]" -Verbose
Start-Sleep 60
##############################################################################
######## This Section Installs the AD roles on the newly provisoned VM #######
##############################################################################
Write-Verbose -Message "Installing AD Roles on $DomainControllerVMName" -Verbose
$InstallADRole = 'Install-WindowsFeature -Name "AD-Domain-Services" -Restart'
Invoke-VMScript -ScriptText $InstallADRole -VM $DomainControllerVMName -GuestCredential $DCLocalCredential
Write-Verbose -Message "AD Roles have been installed on $DomainControllerVMName" -Verbose
Start-Sleep 60
###############################################################################################
##############################################################################
######## This Section Installs the DNS roles on the newly provisoned VM #######
##############################################################################
Write-Verbose -Message "Installing DNS Roles on $DomainControllerVMName" -Verbose
$InstallDNSRole = 'Install-WindowsFeature -Name DNS -IncludeAllSubFeature -IncludeManagementTools'
Invoke-VMScript -ScriptText $InstallDNSRole -VM $DomainControllerVMName -GuestCredential $DCLocalCredential
Write-Verbose -Message "DNS Roles have been installed on $DomainControllerVMName" -Verbose
Start-Sleep 60
################################################################################################
##############################################################################
######## This Section Installs the AD Tools on the newly provisoned VM #######
##############################################################################
Write-Verbose -Message "Installing AD Tools on $DomainControllerVMName" -Verbose
$InstallADtools = 'ADD-WindowsFeature RSAT-Role-Tools'
Invoke-VMScript -ScriptText $InstallADtools -VM $DomainControllerVMName -GuestCredential $DCLocalCredential
Write-Verbose -Message "AD Tools have have been installed on $DomainControllerVMName" -Verbose
Start-Sleep 60
##############################################################################
######## This Section Configures the Domain and AD Forest ###################
##############################################################################
# AD Forest varibles
$DomainMode = "WinThreshold"
$ForestMode = "WinThreshold"
$DomainName = $FQDN
# AD Forest install script input for Invoke-VMScript
$ConfigureNewDomain = "Install-ADDSForest -ForestMode $ForestMode -DomainMode $DomainMode -DomainName $DomainName -InstallDns -SafeModeAdministratorPassword (ConvertTo-SecureString -String Password -AsPlainText -Force) -Force"
Write-Verbose -Message "Configuring AD Forest $FQDN on $DomainControllerVMName" -Verbose
#Promots VM to domain controller and configures forest
Invoke-VMScript -ScriptText $ConfigureNewDomain -VM $DomainControllerVMName -GuestCredential $DCLocalCredential -ErrorAction SilentlyContinue
Write-Verbose -Message "Domain has been configured. Please wait for $DomainControllerVMName to Reboot and apply settings (This may take some time)" -Verbose
Start-Sleep -Seconds 120
Wait-Tools -VM $DomainControllerVMName -TimeoutSeconds 600 | Out-Null
Write-Verbose -Message "VM has finished Restarting" -Verbose
##############################################################################
######## This Section Configures the Desktop Shortcuts ###################
##############################################################################
# Create Active directory Users and Computers shortcut on the public desktop
Write-Verbose -Message "Creating Active directory Users and Computers Desktop shortcut on $DomainControllerVMName" -Verbose
$ADshortcut = '
$SourceFileLocation = "$env:SystemRoot\System32\dsa.msc"
$ShortcutLocation = "C:\Users\Public\Desktop\Active directory Users and Computers.lnk"
#New-Object : Creates an instance of a Microsoft .NET Framework or COM object.
#-ComObject WScript.Shell: This creates an instance of the COM object that represents the WScript.Shell for invoke CreateShortCut
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutLocation)
$Shortcut.TargetPath = $SourceFileLocation
#Save the Shortcut to the TargetPath
$Shortcut.Save() '
Invoke-VMScript -ScriptText $ADshortcut -VM $DomainControllerVMName -GuestCredential $DomainCredential | Out-Null
Write-Verbose -Message "Done Creating Active directory Users and Computers Desktop shortcut on $DomainControllerVMName" -Verbose
# Create DNS on the public desktop
Write-Verbose -Message "Creating DNS Desktop shortcut on $DomainControllerVMName" -Verbose
$DNSshortcut = '
$SourceFileLocation = "$env:SystemRoot\System32\dnsmgmt.msc"
$ShortcutLocation = "C:\Users\Public\Desktop\DNS.lnk"
#New-Object : Creates an instance of a Microsoft .NET Framework or COM object.
#-ComObject WScript.Shell: This creates an instance of the COM object that represents the WScript.Shell for invoke CreateShortCut
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutLocation)
$Shortcut.TargetPath = $SourceFileLocation
#Save the Shortcut to the TargetPath
$Shortcut.Save() '
Invoke-VMScript -ScriptText $DNSshortcut -VM $DomainControllerVMName -GuestCredential $DomainCredential | Out-Null
Write-Verbose -Message "Done creating DNS Desktop shortcut on $DomainControllerVMName" -Verbose