Like everyone else in the connected world, I’ve been hearing a lot about ChatGPT and how it’s going to replace the workforce. To test this out, I put on the hat of an Active Directory administrator and chose to use the tool to build my lab.

First, a little background. I’ve been playing around with for about 6 weeks, and the new for around half that time. I’ve used it to create PowerShell scripts, short stories, poems (many poems), topic summaries, comparisons, cooking recipes, and a small application in C# (which I know nothing about).

Very informative, and the capability amazes me, but nothing technical actually worked copy-paste. If I put in a hastily worded e-mail, some effective prompts will turn it into a very nice e-mail. This was the only thing that I’ve actually used productively (yet) that came out of ChatGP, except the topic of this blog, of course!

With the Plus subscription on OpenAI, I was granted access to the GPT-4 model last week. My first question, however, was a complete failure:

Work got busy, so I haven’t been back in a few days, but today I decided to try out some scripting and compare the results between 3.5 and 4. For my test, I used the following prompt for both:

Create a PowerShell Script that performs the following:
1. Enables Nested Virtualization for Hyper-V in Windows Server 2022.
2. Creates an internal Virtual Switch in Hyper-V.
3. Creates 3 virtual machines and installs Windows Server 2022 Evaluation edition on each.  Use the minimum hardware requirements for a Windows Server 2022 Domain Controller.  Specify the location of the VM's configuration and VHDX files.  Automate the download of the ISO from the internet.
4. Promote one virtual machine to a domain controller, creating a new Active Directory domain.  Use the ActiveDirectory PowerShell module to complete this.
5. Configures Sites and Services with 4 sites, and 2 subnets in each site.
6. Promotes the second virtual machine as a domain controller and places it in one of the other three sites.
7. Configures DNS and DHCP.
8. The third VM should be configured with 2 NICs and Routing and Remote Access to provide internet access to VMs on the Internal vSwitch.
Any environment-specific details should use variables.  At the beginning of the script there should be a list of all the variables used, and they should be pre-populated with generic names and addresses that will allow the script to run.  Expect that this script is being executed from the Hyper-V host.  When required to connect to a child VM to execute a portion of the script, like during OS install, please advise.  List any caveats as comments in the PowerShell code at the bottom of the script.

I also asked each model to create a 500-word blog on the Pros and Cons of using ChatGPT for advanced infrastructure tasks using the following script. Those blogs will be posted on and identified as created by ChatGPT.

Create a 500-word blog that discusses the pros and cons of using ChatGPT 3.5 to create PowerShell scripts that build test environment in Hyper-V, versus an administrator performing those tasks manually.
Include the possibility of an experienced systems engineer using the tool, as well as a junior or unskilled resource (your choice, whatever best fits the mood of the article).
The article is a continuation of a previous post that examined a generated script at a technical level.  Refer to it in the blog as "our earlier post on GPT" and please advise the reader that the content of this article was 100% authored by this prompt.
After the blog is finished, include this full prompt for the reader's benefit.

In ChatGPT3.5, it took less than 2 minutes to create. ChatGPT4.0 was twice the amount of time, but I expect that to be due to resource allocation on OpenAI’s side. What was interesting is that each script used different formatting, specified different caveats, and omitted some requests entirely. Even with a prompt that was fairly specific, neither script would actually work if you ran them. The individual steps are more likely to work when executed individually, though some must have come from open air rather than what boils down to a 2021 copy of the internet. Most surprising to me was that both models added the variables at the beginning, but neither understood that the RRAS server had to be set up before the domain controllers could download the ISO.

I could have re-written the prompt to specify the RRAS server first, state that the ISO must be downloaded by the host and then mounted as a DVD drive on the VM through Hyper-V, and eventually reached a point where it would complete. As a novice administrator, I would lack the knowledge of what components are absolutely required to build a functional lab, and struggle with the prompting and debugging of the resulting code to make this work. It would teach me many different ways of working in PowerShell, however, and I am willing to bet can create some amazing tutorials for learning…anything.

When I’m creating code, half my battle is getting started and building that structure. ChatGPT is amazing for that. If I need to add error checking to a script, I can paste it in and ChatGPT will wrap it up for me. I pasted a script that I had written 7 years ago and asked ChatGPT to add variables for all the unique items, and that worked spectacularly.

It’s a great tool, and seems to be the next biggest thing since the internet, but it’s still a tool. It will continue to need skilled operators to use it to effectively assist with technology.

I hope you’ve enjoyed reading this as much as I did viewing the results. Looking at both scripts, while neither one would do what I needed it to, both come pretty close for the time it took.  Taking pieces from both, switching some things around a bit, and a little manual intervention and this would become usable in a much shorter time than if I had built everything from scratch…

Here is the output script from ChatGPT 3.5 (DOES NOT WORK…fully)

# Created using ChatGPT 3.5</pre>
# Environment-specific variables
$VMPath = "C:\VMs" # Directory where VM configuration files will be stored
$ISOPath = "C:\ISOs" # Directory where ISO files will be downloaded
$InternalSwitchName = "InternalSwitch" # Name of the internal virtual switch
$DomainName = "" # Name of the Active Directory domain to be created
$DomainNetBIOSName = "EXAMPLE" # NetBIOS name of the Active Directory domain
$DomainAdministratorPassword = ConvertTo-SecureString -String "P@ssw0rd" -AsPlainText -Force # Password for the Domain Administrator account
$DomainDNSName = "" # DNS name of the first domain controller

# Enable Nested Virtualization
Set-VMProcessor -VMName "HOST" -ExposeVirtualizationExtensions $true

# Create internal virtual switch
New-VMSwitch -Name $InternalSwitchName -SwitchType Internal

# Create virtual machines
$VM1 = New-VM -Name "DC1" -Path $VMPath -MemoryStartupBytes 2GB -SwitchName $InternalSwitchName
$VM2 = New-VM -Name "DC2" -Path $VMPath -MemoryStartupBytes 2GB -SwitchName $InternalSwitchName
$VM3 = New-VM -Name "Router" -Path $VMPath -MemoryStartupBytes 1GB -SwitchName $InternalSwitchName
$VMs = $VM1, $VM2, $VM3

# Download Windows Server 2022 Evaluation ISO
$ISOUrl = ""
$ISOFile = Join-Path $ISOPath "Windows_Server_2022_x64_Eval_en-us.ISO"
Invoke-WebRequest -Uri $ISOUrl -OutFile $ISOFile

# Install Windows Server 2022 on virtual machines
ForEach ($VM in $VMs) {
$VM | Start-VM
$VM | Get-VM | Wait-VM
$DVD = $VM | Get-VMDvdDrive
$DVD | Set-VMDvdDrive -Path $ISOFile
$VM | Get-VM | Start-VM
$VM | Get-VM | Wait-VM
$DVD | Set-VMDvdDrive -Path $null

# Promote VM1 to Domain Controller
$Credential = New-Object System.Management.Automation.PSCredential("EXAMPLE\Administrator", $DomainAdministratorPassword)
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
Install-ADDSForest -DomainName $DomainName -DomainNetbiosName $DomainNetBIOSName -DomainMode WinThreshold -ForestMode WinThreshold -InstallDns -Credential $Credential
$DomainController = Get-ADDomainController -Identity $DomainDNSName
$DomainController | Set-ADDomainController -SiteName "Default-First-Site-Name"

# Configure Sites and Services
Import-Module ActiveDirectory
$SiteNames = "Site1", "Site2", "Site3", "Site4"
$SubnetAddresses = "", "", "", ""

# Create sites
ForEach ($SiteName in $SiteNames) {
New-ADReplicationSite -Name $SiteName

# Create subnets
ForEach ($SubnetAddress in $SubnetAddresses) {
$Subnet = $SubnetAddress.Split('/')[0]
$MaskBits = $SubnetAddress.Split('/')[1]
New-ADReplicationSubnet -Name $Subnet -Site $SiteNames[($Subnet -split '\.')[2]] -IPv4Subnet $SubnetAddress -Location "Location" -Description "Description"

# Configure Sites and Services
Set-ADReplicationSiteLink -Name "DEFAULTIPSITELINK" -SitesIncluded $SiteNames -ReplicationSchedule (New-Object System.DirectoryServices.ActiveDirectory.ActiveDirectorySchedule)
ForEach ($SiteName in $SiteNames) {
Get-ADReplicationSite -Identity $SiteName | Set-ADReplicationSite -InterSiteTopologyGenerator $DomainController
ForEach ($SubnetAddress in $SubnetAddresses) {
$Subnet = $SubnetAddress.Split('/')[0]
Get-ADReplicationSubnet -Identity $Subnet | Set-ADReplicationSubnet -Site $SiteNames[($Subnet -split '\.')[2]]

# Promote VM2 to Domain Controller and place it in Site2
$Credential = New-Object System.Management.Automation.PSCredential("EXAMPLE\Administrator", $DomainAdministratorPassword)
$VM2Name = "DC2"
$VM2IP = ""
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
Install-ADDSDomainController -DomainName $DomainName -SiteName "Site2" -InstallDns -Credential $Credential -IPv4Address $VM2IP -Force
$DomainController = Get-ADDomainController -Identity $DomainDNSName
$DomainController | Set-ADDomainController -SiteName "Default-First-Site-Name"

# Configure DNS
$VM1Name = "DC1"
$VM1IP = ""
$DNSForwarder = ""
$DNSZoneName = $DomainName.Replace('.', '\.')
$DNSZone = Get-DnsServerZone -Name $DNSZoneName -ComputerName $VM1Name
Set-DnsServerForwarder -IPAddress $DNSForwarder -ComputerName $VM1Name
Add-DnsServerPrimaryZone -Name $DNSZoneName -ReplicationScope Forest -DynamicUpdate Secure -ComputerName $VM1Name
$DnsServer = Get-DnsServer -ComputerName $VM1Name
$DnsRecord = New-DnsRecord -ZoneName $DNSZoneName -Name $DomainDNSName -RecordType A -IPv4Address $VM1IP
$DnsZone | Add-DnsServerResourceRecord -ZoneName $DNSZoneName -DnsRecord $DnsRecord

# Configure DHCP
$VM1NICName = "Ethernet"
$VM1ScopeName = "Scope1"
$VM1Subnet = ""
$VM1RangeStart = ""
$VM1RangeEnd = ""
$VM1DefaultGateway = ""
$VM1DNSServer = ""
Add-DhcpServerV4Scope -Name $VM1ScopeName -StartRange $VM1RangeStart -EndRange $VM1RangeEnd -SubnetMask -Description "Description" -State Active -ScopeId $VM1Subnet -LeaseDuration 8.00:00:00 -Delay 00:00:02 -NapEnable $false -DnsServer $VM1DNSServer -Router $VM1DefaultGateway -ComputerName $VM1Name
Set-DhcpServerV4OptionValue -Router $VM1DefaultGateway -DnsServer $VM1DNSServer -ComputerName $VM1Name
Add-DhcpServerv4Reservation -ScopeId $VM1Subnet -IPAddress $VM3IP -ClientId "00155D01826B" -Description "Router" -Name $VM3Name -Type DhcpIPAddressReservation

# Configure Routing and Remote Access
$VM3Name = "Router"
$VM3IP1 = ""
$VM3IP2 = ""
Install-WindowsFeature RemoteAccess -IncludeManagementTools
$Routing = Get-RemoteAccess
$NetworkInterfaces = Get-NetAdapter
$InternalInterface = $NetworkInterfaces | Where-Object {$_.Name -eq $InternalSwitchName}
$ExternalInterface = $NetworkInterfaces | Where-Object {$_.Name -eq $VM3NIC2Name}
$InternalAddressPool = New-Object System.Collections.ArrayList
$InternalAddressPool.Add($VM1Subnet + "/24") | Out-Null
$StaticRoutes = New-Object System.Collections.ArrayList
$StaticRoutes.Add(("", "", $VM3IP2, 1)) | Out-Null
$Routing | Set-RemoteAccess -RoutingEnabled $true -NatEnabled $true -NatEnableNatOnInterfaces @($ExternalInterface.Name) -NatAddressingMode "Private" -NatAddressPool @($VM3IP2) -NatTcpTimeoutSeconds 1800 -NatUdpTimeoutSeconds 1800 -NatInterfaceMode "All" -NatPortRestriction "Restricted" -NatEnableInterfaceNaptInbound $true -IpsecEnabled $false -IpsecQuickModeSupported $false -IpsecEcNaptSupported $false -IpsecExtendedModeSupported $false -IpsecPresharedKey "P@ssw0rd" -IpsecPreSharedKeyType "Passphrase" -IpsecSoftSAIdleSeconds 600 -IpsecSoftSAIdleSecondsRenew 600 -IpsecHardSAIdleSeconds 3600 -IpsecHardSAIdleSecondsRenew 3600 -IpsecSADataSize 100000 -IpsecSADataSizeRenew 100000 -IpsecSoftSADataSize 100000 -IpsecSoftSADataSizeRenew 100000 -IpsecHardSADataSize 100000 -IpsecHardSADataSizeRenew 100000 -IpsecPfsGroup "PFS2048" -

# 1. This script assumes that the Hyper-V host is running Windows Server 2022 and has hardware that supports Nested Virtualization.
# 2. The script assumes that the necessary network infrastructure is in place to support the creation of the internal virtual switch and the assignment of IP addresses to the virtual machines.
# 3. The script downloads the Windows Server 2022 Evaluation ISO from the internet. If the Hyper-V host does not have internet connectivity, you will need to download the ISO manually and modify the script accordingly.
# 4. The script installs Windows Server 2022 Evaluation edition on the virtual machines, which has a 180-day trial period. If you want to continue using the virtual machines after the trial period ends, you will need to obtain valid licenses.
# 5. The script creates a new Active Directory domain, which should not be done in a production environment without proper planning and testing.
# 6. The script configures DNS and DHCP, which should be done carefully to avoid disrupting any existing network services.
# 7. The script configures Routing and Remote Access on the third virtual machine to provide internet access to the other virtual machines on the internal virtual switch. This should be done carefully to avoid any security risks, and proper firewall rules should be put in place to restrict access to the internal network.
# 8. This script is provided as an example and may need to be modified to fit your specific environment and requirements. Please review the script carefully before running it and test it in a non-production environment before deploying it in a production environment.

And here is the output script from ChatGPT 4 (again, DOES NOT WORK…fully)

# Created in ChatGPT 4.0</pre>
# Variables
$VMPath = "C:\VMs"
$VHDXPath = "C:\VMs\VHDs"
$ISOPath = "C:\VMs\ISOs\WindowsServer2022.iso"
$ISODownloadURL = ""
$DomainName = "example.local"
$VMNames = "DC1", "DC2", "RRAS"
$SiteNames = "Site1", "Site2", "Site3", "Site4"
$Subnets = @{
"Site1" = "", "";
"Site2" = "", "";
"Site3" = "", "";
"Site4" = "", "";

# Step 1: Enable Nested Virtualization
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

# Step 2: Create Internal Virtual Switch
New-VMSwitch -Name "InternalSwitch" -SwitchType Internal

# Step 3: Create and Install Windows Server 2022 on 3 VMs
if (!(Test-Path -Path $ISOPath)) {
Invoke-WebRequest -Uri $ISODownloadURL -OutFile $ISOPath
$VMNames | ForEach-Object {
$VMName = $_
$VHDPath = Join-Path -Path $VHDXPath -ChildPath "${VMName}.vhdx"
New-VM -Name $VMName -Path $VMPath -MemoryStartupBytes 2GB -Generation 2 -NewVHDPath $VHDPath -NewVHDSizeBytes 60GB
Add-VMDvdDrive -VMName $VMName -Path $ISOPath
Set-VMProcessor -VMName $VMName -Count 2
Start-VM -Name $VMName

# Connect to the VM and proceed with OS installation
# Instruct the user to install the OS with the provided ISO
Write-Host "Please install Windows Server 2022 on VM $VMName using the mounted ISO, then shutdown the VM."

# Step 4: Promote the first VM to a domain controller
$DC1 = $VMNames[0]
Start-VM -Name $DC1
Enter-PSSession -VMName $DC1
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools
Import-Module ADDSDeployment
Install-ADDSForest -DomainName $DomainName -InstallDns -SafeModeAdministratorPassword (Read-Host -AsSecureString "Enter the Safe Mode Administrator password")

# Step 5: Configure Sites and Services
$DC2 = $VMNames[1]
Start-VM -Name $DC2
Enter-PSSession -VMName $DC1
Import-Module ActiveDirectory
$SiteNames | ForEach-Object {
New-ADReplicationSite -Name $_
$Subnets[$_] | ForEach-Object {
New-ADReplicationSubnet -Name $_ -Site $_

# Step 6: Promote the second VM to a domain controller and move it to another site
$DC2Site = "Site2"
Enter-PSSession -VMName $DC2
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools
Import-Module ADDSDeployment
Install-ADDSDomainController -DomainName $DomainName -InstallDns -SafeModeAdministratorPassword (Read-Host -AsSecureString "Enter the Safe Mode Administrator password")

Enter-PSSession -VMName $DC1
Import-Module ActiveDirectory
Move-ADDirectoryServer -Identity $DC2 -Site $DC2Site

# Step 7: Configure DNS and DHCP
Enter-PSSession -VMName $DC1
Install-WindowsFeature -Name DNS,DHCP -IncludeManagementTools
Add-DhcpServerv4Scope -Name "IPv4Scope" -StartRange -EndRange -SubnetMask
Set-DhcpServerv4OptionValue -DnsServer

# Step 8: Configure the third VM with 2 NICs and Routing and Remote Access
$RRAS = $VMNames[2]
$InternalSwitch = "InternalSwitch"
$ExternalSwitch = "ExternalSwitch"
Add-VMNetworkAdapter -VMName $RRAS -Name "InternalNIC" -SwitchName $InternalSwitch
Add-VMNetworkAdapter -VMName $RRAS -Name "ExternalNIC" -SwitchName $ExternalSwitch
Start-VM -Name $RRAS
Enter-PSSession -VMName $RRAS
Install-WindowsFeature -Name RemoteAccess -IncludeManagementTools
Install-RemoteAccess -VpnType Vpn
Set-VpnS2SInterface -Name "InternalNIC" -IPv4Subnet @( $Subnets.Values | ForEach-Object { $_ + "" } )
Enable-VpnS2SInterface -Name "InternalNIC"

# Caveats:
# 1. ISO download URL: Replace the placeholder URL with the actual URL for downloading the Windows Server 2022 Evaluation ISO.
# 2. External virtual switch: Create an external virtual switch named "ExternalSwitch" on the Hyper-V host before running the script, or include a step to create it within the script.
# 3. User intervention during OS installation: The script requires the user to install the OS manually for each VM using the mounted ISO. Consider automating this using an answer file or other deployment tools.
# 4. Credentials and sensitive information: Store and retrieve sensitive information securely, using secure strings or other methods, rather than hardcoding it in the script.
# 5. Network configuration: Adjust the generic IP addresses and subnet masks for the DHCP scope and DNS configuration to match your network requirements.
# 6. Error handling: Add error handling and validation checks to ensure the script runs smoothly and provides useful feedback in case of issues.
# 7. Execution policy: Adjust the execution policy on the Hyper-V host to allow the script to run, if necessary.
# 8. Permissions: Ensure that you have the required administrative permissions to execute the script successfully.