Azure/Office 365 test environment

By | July 19, 2020

If you want a test environment it works out very pricey very fast, especially once you are running ad connect severs and domain controllers to play with that functionality.

The bad, but only, answer here is trial accounts. Pretty sure you aren’t meant to do this but if they want us to sell businesses on this stuff we need to play with it.

Test subscriptions are free for a month before you have to start paying so you dont want to waste 3 days every month rebuilding your test environment – hence this script. It builds out my environment with an azure resource group, network and nsg, domain controller (Standard_D2_V3 – when ms make machine unavailable you have to edit this bit), a bunch of test accounts and groups, an ad connect server (you have to do the install manually still since you cant script it yet)

You will need to create a new Microsoft account each time and to use the free trial you need a new credit card. Would it be completely immoral to leave a Revolut referral link here? Possibly, Ill just add a raw link1

Once you have your trial you can edit the script to change the MySeed variable (this becomes the prefix for all resources), region, local admin credentials for the vms that get built then just follow the menu options.

You will need a Powershell environment with the AzureRM modules installed which is NOT covered by my profile I discussed in an earlier post as that is generally for Microsoft 365 work.

#Create Azure free trial at
# https://azure.microsoft.com/en-gb/free/
# - create account, record below
# Install-Module AzureRM
#Seed will be domain name with .com
$MySeed = 'mattstuff01'
#$MyUser = 'mattsstuff01@outlook.com'
#$MyPassword = 'APassword1974!'
$MyRegion = 'North Europe'

#Local Admin creds - Also becomes Domain Admin during build out
$MachineUserName = "LocalAdmin"
$MachinePassword = "APassword1974!"
$MachineSecurePassword = ConvertTo-SecureString $MachinePassword -AsPlainText -Force
$MachineCredential = New-Object System.Management.Automation.PSCredential ($MachineUserName, $MachineSecurePassword);


#Script will create:
#Resource Group
#VM network /16 with single 10.0.0.0/24 subnet
#NSG access turned on for RDP, WinRMHTTP and WinRMHTTPS
#DC with single disk, single nic, publicIP


Import-Module AzureRM.Resources
Import-Module AzureRM.Network
Import-Module AzureRM.Compute

#Functions
#VMBuilder
function Build_Infrastructure {
#ResourceGroup
Write-Host "1. Building Resource Group" -ForegroundColor Cyan
$ResourceGroups = Get-AzureRmResourceGroup
If ($ResourceGroups) {
    write-host "There is an existing resource group in this subscription!"
    write-host $ResourceGroups.ResourceGroupName
    Read-Host -Prompt "Press any key to continue or CTRL+C to quit" 
    }
$ResourceGroupName = $Myseed+'_RG01'
$NoReturn = New-AzureRmResourceGroup -Name $ResourceGroupName -Location $MyRegion
Write-Host "Resource Group"$ResourceGroupName" created" -ForegroundColor Green

#Network
#Network Subnet
write-host "2. Building Network" -ForegroundColor Cyan
write-host "2.1 Creating Subnet" -ForegroundColor Cyan
$SubnetName = $Myseed+'_SubnetInternal01'
$SubnetObj = New-AzureRMVirtualNetworkSubnetConfig -Name $SubnetName -AddressPrefix "10.0.0.0/24"
write-host "-Subnet Created" -ForegroundColor Green
#Network VMNet
write-host "2.2 Creating Virtual Network" -ForegroundColor Cyan
$VirtualNetworkName = $Myseed+'_VMNetwork01'
$VirtualNetworkObj = New-AzureRmVirtualNetwork -Name $virtualnetworkname -ResourceGroupName $resourcegroupname -Location $MyRegion -AddressPrefix "10.0.0.0/16" -Subnet $SubnetObj -WarningAction SilentlyContinue
Write-Host "-VM Network"$VirtualNetworkName" created" -ForegroundColor Green
#Network NSG
#Network NSG RDP Rule
write-host "2.3 Network Security Group Rules" -ForegroundColor Cyan
$RDPrule = New-AzureRmNetworkSecurityRuleConfig -Name rdp-rule -Description "Allow RDP" -Access Allow -Protocol Tcp -Direction Inbound -Priority 100 -SourceAddressPrefix Internet -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 3389
Write-Host "-Network Security Group RDP Rule created" -ForegroundColor Green
$WinRMHTTPSrule = New-AzureRmNetworkSecurityRuleConfig -Name WinRMHTTPS-rule -Description "Allow WinRMHTTPS" -Access Allow -Protocol Tcp -Direction Inbound -Priority 101 -SourceAddressPrefix Internet -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 5986
Write-Host "-Network Security Group WinRMHTTPS Rule created" -ForegroundColor Green
$WinRMHTTPrule = New-AzureRmNetworkSecurityRuleConfig -Name WinRMHTTP-rule -Description "Allow WinRMHTTP" -Access Allow -Protocol Tcp -Direction Inbound -Priority 102 -SourceAddressPrefix Internet -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 5985
Write-Host "-Network Security Group WinRMHTTP Rule created" -ForegroundColor Green
#Network NSG
write-host "2.4 Network Security group" -ForegroundColor Cyan
$NSGName = $Myseed+'_NSG01'
$NSGObj = New-AzureRMNetworkSecurityGroup -Name $NSGName -ResourceGroupName $resourcegroupname -Location $MyRegion -SecurityRules $RDPRule, $WinRMHTTPSrule, $WinRMHTTPrule -WarningAction SilentlyContinue
Write-Host "-Network Security Group"$NSGName" created" -ForegroundColor Green
Write-Host "3. Building Domain Controller" -ForegroundColor Cyan

$VMName = Build_VM -vmsuffix "DC01"

#enable powershell remoting
Write-Host "4. Enable Remote Powershell on"$VMName -ForegroundColor Cyan
Write-Host "This takes a minute...." -ForegroundColor Red
$NoReturn = New-Item -ItemType File -Path .\WinRMscript.ps1
$Content = "winrm qc /force
netsh advfirewall firewall add rule name= WinRMHTTP dir=in action=allow protocol=TCP localport=5985
netsh advfirewall firewall add rule name= WinRMHTTPS dir=in action=allow protocol=TCP localport=5986"
Add-Content .\WinRMscript.ps1 $Content
#$NoReturn = Invoke-AzureRmVMRunCommand -ResourceGroupName $ResourceGroupName -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath .\WinRMscript.ps1
Remove-Item .\WinRMscript.ps1
Write-Host "-Enabled WinRM on"$VMName -ForegroundColor Green

#install AD feature
Write-Host "5. Installing AD on"$VMName -ForegroundColor Cyan
Write-Host "This takes longer...." -ForegroundColor Red
$NoReturn = New-Item -ItemType File -Path .\ADscript.ps1
$Content = 'install-windowsfeature AD-Domain-Services'
Add-Content .\ADscript.ps1 $Content
Invoke-AzureRmVMRunCommand -ResourceGroupName $ResourceGroupName -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath .\ADscript.ps1
Remove-Item .\ADscript.ps1
Write-Host "-Installed AD and Domain on"$VMName -ForegroundColor Green

#install Forest
Write-Host "6. Installing Forest on"$VMName -ForegroundColor Cyan
Write-Host "This takes MUCH longer...." -ForegroundColor Red
$NoReturn = New-Item -ItemType File -Path .\ADscript.ps1
$Content1 = '$SafeModePassword = "5-M0nk3y"'
$Content2 = '$SafeModeSecurePassword = ConvertTo-SecureString $SafeModePassword -AsPlainText -Force'
$Content3 = 'Import-Module ADDSDeployment'
$Content4 = 'Install-ADDSForest -CreateDnsDelegation:$false -SafeModeAdministratorPassword $SafeModeSecurePassword -DatabasePath "C:\Windows\NTDS" -DomainMode "Win2012R2" -DomainName "'+$MySeed+'.com" -DomainNetbiosName "'+$MySeed+'" -ForestMode "Win2012R2" -InstallDns:$true -LogPath "C:\Windows\NTDS" -NoRebootOnCompletion:$false -SysvolPath "C:\Windows\SYSVOL" -Force:$true'

Add-Content .\ADscript.ps1 $Content1
Add-Content .\ADscript.ps1 $Content2
Add-Content .\ADscript.ps1 $Content3
Add-Content .\ADscript.ps1 $Content4
Invoke-AzureRmVMRunCommand -ResourceGroupName $ResourceGroupName -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath .\ADscript.ps1
Remove-Item .\ADscript.ps1
Write-Host "-Installed Forest and Domain on"$VMName -ForegroundColor Green
Write-Host "YOU MUST WAIT for restart on"$VMName -ForegroundColor Red
Write-Host "I recommend logging on to it via external IP and bouncing manually to be sure" -ForegroundColor Red
menu_build
}

#machine builder function
Function Build_VM ([string] $vmsuffix){
$VMName = $Myseed+$vmsuffix
Write-Host "Building "$VMName -ForegroundColor Cyan
#publicIP
write-host "Creating Public IP" -ForegroundColor Cyan
$PublicIPName = $Myseed+'_ExtIP_'+$vmname
$PublicIPDNSPrefix = $VMName.ToLower()
$PublicIPObj = New-AzureRmPublicIpAddress -Name $PublicIPName -AllocationMethod Dynamic -ResourceGroupName $ResourceGroupName -Location $MyRegion -DomainNameLabel $PublicIPDNSPrefix -WarningAction SilentlyContinue
Write-Host "-Public IP created" -ForegroundColor Green
#network interface
write-host "Creating Network Interface" -ForegroundColor Cyan
$NICName = $Myseed+'_NIC_'+$vmname
$NICObj = New-AzureRmNetworkInterface -Name $NICName -ResourceGroupName $ResourceGroupName -Location $MyRegion -NetworkSecurityGroup $NSGObj -Subnet (Get-AzureRmVirtualNetworkSubnetConfig -name $SubnetName -VirtualNetwork (Get-AzureRmVirtualNetwork -name $VirtualNetworkName -ResourceGroupName $ResourceGroupName)) -publicipaddress $PublicIPObj -WarningAction SilentlyContinue
Write-Host "-Network Interface created" -ForegroundColor Green
#Build VM
write-host "Build VM" -ForegroundColor Cyan
write-host "This will take SEVERAL Minutes" -Foregroundcolor Red


$VMSize = "Standard_D2_V3"
$VirtualMachine = New-AzureRmVMConfig -VMName $VMName -VMSize $VMSize
$VirtualMachine = Set-AzureRmVMOperatingSystem -VM $VirtualMachine -Windows -ComputerName $VMName -Credential $MachineCredential -ProvisionVMAgent -EnableAutoUpdate
$VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $NICObj.Id
$VirtualMachine = Set-AzureRmVMSourceImage -VM $VirtualMachine -PublisherName 'MicrosoftWindowsServer' -Offer 'WindowsServer' -Skus '2016-Datacenter' -Version latest
$VirtualMachineObj = New-AzureRmVM -ResourceGroupName $ResourceGroupName -Location $MyRegion -VM $VirtualMachine -WarningAction SilentlyContinue
Write-Host "-VM"$VMName" Created" -ForegroundColor Green

Return $VMName
}

Function Remove_RG {
write-host "This will delete the resource group and all provisioned resources!" -ForegroundColor Red
    Read-Host -Prompt "Press any key to continue or CTRL+C to quit" 
$RGName = $MySeed+'_RG01'
Remove-AzureRMResourceGroup -Name $RGName
}

Function Populate_AD {
#check machine is on
$ResourceGroupName = $Myseed+'_RG01'
$VMName = $Myseed+'dc01'
$runstate = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMName -Status
$VMRunning = $runstate.Statuses.DisplayStatus
If ($VMRunning -eq "VM running") {
Write-Host "Domain Controller is built and Running" -ForegroundColor Red
#Creates Users
Write-Host "Creating Users" -ForegroundColor Cyan
$userarr = @()
$userarr += ,@('Domain Admin','DomAdmin',$MachinePassword)
$userarr += ,@('Jim Kirk','Jim.Kirk','PasswordJim1')
$userarr += ,@('Spock','Spock','PasswordSpo1')
$userarr += ,@('Montgomery Scott','Monty.Scott','PasswordMon1')
$userarr += ,@('Leonard McCoy','Leonard.McCoy','PasswordLeo1')
$userarr += ,@('Jean-Luc Picard','JL.Picard','PasswordJea1')
$userarr += ,@('Beverley Crusher','Bev.Crusher','PasswordBev1')
$userarr += ,@('Katherine Polaski','Kat.Polaski','PasswordKat1')
$userarr += ,@('Geordi LaForge','Geordie.LaForge','PasswordGeo1')
$userarr += ,@('William Riker','Will.Riker','PasswordWil1')
$userarr += ,@('Data','Data','PasswordDat1')
$userarr += ,@('Kathryn Janeway','Kat.Janeway','PasswordKat1')
$userarr += ,@('Tuvok','Tuvok','PasswordTuv1')
$userarr += ,@('Harry Kim','Harry.Kim','PasswordHar1')
$userarr += ,@('Doctor','Doctor','PasswordDoc1')
$userarr += ,@('Ben Sisko','Ben.Sisko','PasswordBen1')
$userarr += ,@('Worf','Worf','PasswordWor1')
$userarr += ,@('Christopher Pike','Chris.Pike','PasswordChr1')

$NoReturn = New-Item -ItemType File -Path .\Users.ps1

foreach($uservar in $userarr){
    $content1 = '$Userpassword= ConvertTo-SecureString '+$uservar[2]+' -AsPlainText -Force'
    $Content2 = 'New-ADUser -Name "'+$uservar[0]+'" -SAMAccountName "'+$uservar[1]+'" -AccountPassword $Userpassword -ChangePasswordAtLogon $false -Enable $true'
    Add-Content .\Users.ps1 $content1
    Add-Content .\Users.ps1 $content2
}

Invoke-AzureRmVMRunCommand -ResourceGroupName $ResourceGroupName -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath .\Users.ps1
Remove-Item .\Users.ps1
Write-Host "-Users Created" -ForegroundColor Green

#Creates Groups
Write-Host "Creating Groups" -ForegroundColor Cyan
$grouparr = @()
$grouparr += ,@('E5_License')
$grouparr += ,@('Command')
$grouparr += ,@('Medical')
$grouparr += ,@('Science')
$grouparr += ,@('Engineering')
$grouparr += ,@('Security')
$grouparr += ,@('Enterprise')
$grouparr += ,@('EnterpriseD')
$grouparr += ,@('Voyager')
$grouparr += ,@('DS9')

$NoReturn = New-Item -ItemType File -Path .\Groups.ps1

foreach($groupvar in $grouparr){
    $Content = 'New-ADGroup -Name "'+$groupvar+'" -GroupScope 1'
    Add-Content .\Groups.ps1 $content
}

Invoke-AzureRmVMRunCommand -ResourceGroupName $ResourceGroupName -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath .\Groups.ps1
Remove-Item .\Groups.ps1
Write-Host "-Groups Created" -ForegroundColor Green


#Assigns users to groups
Write-Host "Adding Users to Groups" -ForegroundColor Cyan

$content1 = 'Add-ADGroupMember -Identity "Domain Admins" -Members DomAdmin'
$content2 = 'Add-ADGroupMember -Identity "Enterprise Admins" -Members DomAdmin'
$content3 = 'Add-ADGroupMember -Identity "Command" -Members Jim.Kirk,JL.Picard,Will.Riker,Kat.Janeway,Ben.Sisko,Chris.Pike'
$content4 = 'Add-ADGroupMember -Identity "Medical" -Members Leonard.McCoy,Bev.Crusher,Kat.Polaski,Doctor'
$content5 = 'Add-ADGroupMember -Identity "Science" -Members Spock,Data,Harry.Kim'
$content6 = 'Add-ADGroupMember -Identity "Engineering" -Members Monty.Scott,Geordie.LaForge,Data,Harry.Kim'
$content7 = 'Add-ADGroupMember -Identity "Security" -Members Tuvok,Worf'
$content8 = 'Add-ADGroupMember -Identity "Enterprise" -Members Jim.Kirk,Spock,Monty.Scott,Leonard.McCoy,Chris.Pike'
$content9 = 'Add-ADGroupMember -Identity "EnterpriseD" -Members JL.Picard,Bev.Crusher,Kat.Polaski,Geordie.LaForge,Will.Riker,Data,Worf'
$content10 = 'Add-ADGroupMember -Identity "Voyager" -Members Kat.Janeway,Tuvok,Harry.Kim,Doctor'
$content11 = 'Add-ADGroupMember -Identity "DS9" -Members Ben.Sisko,Worf'
$content12 = 'Add-ADGroupMember -Identity "E5_License" -Members DomAdmin,Jim.Kirk,Spock,Monty.Scott,Leonard.McCoy,Chris.Pike,JL.Picard,Bev.Crusher,Kat.Polaski,Geordie.LaForge,Will.Riker,Data,Worf,Kat.Janeway,Tuvok,Harry.Kim,Doctor,Ben.Sisko'

$NoReturn = New-Item -ItemType File -Path .\GroupsAssign.ps1

Add-Content .\GroupsAssign.ps1 $content1
Add-Content .\GroupsAssign.ps1 $content2
Add-Content .\GroupsAssign.ps1 $content3
Add-Content .\GroupsAssign.ps1 $content4
Add-Content .\GroupsAssign.ps1 $content5
Add-Content .\GroupsAssign.ps1 $content6
Add-Content .\GroupsAssign.ps1 $content7
Add-Content .\GroupsAssign.ps1 $content8
Add-Content .\GroupsAssign.ps1 $content9
Add-Content .\GroupsAssign.ps1 $content10
Add-Content .\GroupsAssign.ps1 $content11
Add-Content .\GroupsAssign.ps1 $content12

Invoke-AzureRmVMRunCommand -ResourceGroupName $ResourceGroupName -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath .\GroupsAssign.ps1
Remove-Item .\GroupsAssign.ps1
Write-Host "-Groups Assigned" -ForegroundColor Green

}
Else {
Write-Host "Domain Controller is not built or not yet running" -ForegroundColor Red
}
menu_build

}

Function AD_ConnectSetup {
$currentAzureContext = Get-AzureRmContext
$tenantId = $currentAzureContext.Tenant.Id
$accountId = $currentAzureContext.Account.Id
$NoReturn = Connect-AzureAD -TenantId $tenantId -AccountId $accountId
$addomain = (Get-AzureRmADUser).UserPrincipalName.Split("@")[1]

$newuser = $myseed+"Admin"
$newuserUPN = $newuser+"@"+$addomain
$newpassword = $myseed+"Password1"
$newuserupn
Write-Host "Adding Azure AD user"$newuser -ForegroundColor Cyan

$newsecurepassword = ConvertTo-SecureString $newpassword -AsPlainText -Force


New-AzureRMADUser -DisplayName $newuser -Password $newsecurepassword -UserPrincipalName $newuserUPN -MailNickname $newuser

$roleMember = Get-AzureADUser -ObjectId $newuserUPN
$role = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq 'Company Administrator'}
Add-AzureADDirectoryRoleMember -ObjectId $role.ObjectId -RefObjectId $roleMember.ObjectId


Write-Host "AD COnnect setup cannot be scripted yet as Microsoft are being dicks about it" -foregroundcolor Red
Write-Host "To do this manually:" -foregroundcolor Yellow
$extipname = $myseed+"_ExtIP_"+$myseed+"DC01"
$RGName = $Myseed+'_RG01'
$FQDN = (Get-AzureRmPublicIpAddress -Name $extipname -ResourceGroupName $RGName).DnsSettings.Fqdn
Write-Host "1. Remote onto " -NoNewline  -foregroundcolor Yellow
Write-Host $FQDN -foregroundcolor White
Write-Host "2. Install ADConnect from " -NoNewline -ForegroundColor Yellow 
Write-Host "https://www.microsoft.com/en-us/download/details.aspx?id=47594" -foregroundcolor Whit
Write-Host "3. Accept the license and Continue" -foregroundcolor Yellow
Write-Host "4. Use express settings and continue" -foregroundcolor Yellow
Write-Host "5. Connect to the "$myseed" Azure AD using " -NoNewline -ForegroundColor Yellow
Write-Host $newuserUPN"//"$newpassword -ForegroundColor White
Write-Host "6. Connect to On Premise AD with Account" -NoNewLin -foregroundcolor Yellow
Write-Host $Myseed"\DomAdmin//"$machinepassword -NoNewline -ForegroundColor White
Write-Host "7. Select tick box to disable UPN matching unless you have a custom domain and continue" -ForegroundColor Yellow
Write-Host "8. Click Install"

menu_build
}

Function AAD_Setup {
#$currentAzureContext = Get-AzureRmContext
#$tenantId = $currentAzureContext.Tenant.Id
#$accountId = $currentAzureContext.Account.Id
#this bit is for when ms allow group based licensing through powershell....
##$addomain = (Get-AzureRmADUser).UserPrincipalName.Split("@")[1]
##$Admuser = $myseed+"Admin"
##$AdmuserUPN = $Admuser+"@"+$addomain
##$Admpassword = $myseed+"Password1"
##$AdmSecurePassword = ConvertTo-SecureString $AdmPassword -AsPlainText -Force
##$AdmCredential = New-Object System.Management.Automation.PSCredential ($AdmUserUPN, $AdmSecurePassword);
##Connect-MsolService -Credential $AdmCredential
##$E5Group = New-MsolGroup -DisplayName E5_Users
##$E5Group | Get-MsolGroup

write-host "MS havent written the group based licensing powershell stuff yet. Log into the portal and assign the test e5 licenses to the group E5_License" -foregroundcolor yellow

menu_build
}



#menu build
function menu_build {
$menuA=@"
1 Show current azure context
2 Build VM environment and Domain Controller
3 Populate AD
4 Set ADConnect Sync
5 Set up AAD groups and config
D Destroy Environment
Q Quit 
"@
Write-Host "Main Menu" -ForegroundColor Cyan
$r = Read-Host $menuA
Switch ($r) {
"1" {
    Write-Host "Current Azure account info"
    Get-AzureRMContext
    menu_build
}
 
"2" {
    Write-Host "Building Environment" -ForegroundColor Red
    Build_Infrastructure
}

"3" {
    Write-Host "Populating AD with test data" -ForegroundColor Red
    Populate_AD
}
"4" {
    Write-Host "Setting Up AD Connect" -ForegroundColor Red
    AD_ConnectSetup
}
"5" {
    Write-Host "Setting Up AAD Groups" -ForegroundColor Red
    AAD_Setup
}

"D" {
    Write-Host "Destroying Environment" -ForegroundColor Red
    Remove_RG
}
 
"Q" {
    Write-Host "Quitting" -ForegroundColor Green
}
 
default {
    Write-Host "Pick a number idiot." -ForegroundColor Yellow
    menu_build
 }
} #end switch

}

#script
#connect + build menu
$MSAccount = Connect-AzureRmAccount

If ($MSAccount) {
write-host " Logged into Azure"
menu_build
}
Else {
Write-Host "Well that failed, have you got the AzureRM Module installed? You have to open an admin session and run 'Install-Module AzureRM -Repository PSGallery -AllowClobber'"
}

Links

1 – Revolut (free bank card) – https://www.revolut.com/
2 – Microsoft Azure Free trial – https://azure.microsoft.com/en-gb/free

Loading

Leave a Reply

Your email address will not be published. Required fields are marked *