Files
Zack Meier 1d304511b8 update
2026-04-15 15:45:50 -05:00

341 lines
18 KiB
PowerShell

function New-ITDWindowsVMAzureStep2 {
[CmdletBinding()]
param (
[string]
$FQDN,
[string]
$AppName,
[string]
$VMEnvironment,
[PSCredential]
$Credential
)
begin {
$search = @()
#$Hostname = $VMName.split('-')[1]
$HostName = $FQDN.split('.')[0]
###$VMEnvironment = $VMName.split('-')[2] ####
Write-Verbose -Message ("Searching for Az VM name like " + $HostName)
Get-AzSubscription | ForEach-Object {
$Subscription = $_
Set-AzContext $_ | Out-Null
$search += Get-AzVM | Where-Object Name -Like "*$HostName*" | Select-Object *, @{n = 'SubscriptionName'; e = { $Subscription.Name } }
}
}
process {
switch (@($Search).count) {
{ $_ -gt 1 } { Write-Error -Message "More than one virtual machine match found." }
{ $_ -lt 1 } { Write-Error -Message "Less than one virtual machine match found." }
{ $_ -eq 1 } {
Write-Verbose -Message "Prep VM variables"
$VMName = $search.Name
$ResourceGroupName = $search.ResourceGroupName
#$VMEnvironment = $VMName.split('-')[2]
$SubscriptionName = $search.SubscriptionName
Set-AzContext -Subscription $SubscriptionName
$VM = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName
Write-Verbose -Message "Set firewall tag"
$Tags = @{"Network"="StandardWindows"}
New-AzTag -ResourceId $VM.Id -Tag $Tags
Write-Verbose -Message "Wait two minutes before Pre-Firewall Guest OS customization"
#Start-Sleep -Seconds 120
Write-Verbose -Message "Begin Pre-Firewall Guest OS customization"
$InvokeAzVMRunCommandParams = @{
ResourceGroupName = $ResourceGroupName;
Name = $VMName;
CommandId = 'RunPowerShellScript'
}
Write-Verbose -Message "1-Set WMI Tags"
$ScriptBlock = {
try {
Write-Verbose "Create new Class"
$Class = New-Object System.Management.ManagementClass("root\cimv2", [String]::Empty, $null);
$Class["__CLASS"] = "ITD";
$Class.Qualifiers.Add("Static", $true)
$Class.Properties.Add("MyKey", [System.Management.CimType]::String, $false)
$Class.Properties["MyKey"].Qualifiers.Add("Key", $true)
$Class.Properties.Add("LastModified", [System.Management.CimType]::String, $false)
$Class.Properties.Add("DTAP", [System.Management.CimType]::String, $false)
$Class.Properties.Add("Baseline", [System.Management.CimType]::String, $false)
$Class.Put()
Write-Verbose "Create single ITD Object"
Set-WmiInstance -Class ITD -Arguments @{LastModified = (Get-Date); DTAP = "Prod"; Baseline = "000" }
}
catch {
Throw $_
Break
}
}
Invoke-AzVMRunCommand @InvokeAzVMRunCommandParams -ScriptString $ScriptBlock
Write-Verbose -Message "3-Disk Configuration"
$ScriptBlock = {
try {
# Non-initialized and MBR-initialized disks will have 0 partitions by default, but GPT-initialized disks will have 1 system reserved partition by default
$disks = Get-Disk | Where-Object { $_.NumberOfPartitions -eq 0 -or ( $_.PartitionStyle -eq 'GPT' -and $_.NumberOfPartitions -eq 1 ) } | Sort-Object -Property Number
if ($disks) {
Write-Verbose -Message "Found $(@($disks).Count) unpartitioned disks."
# Prevent the "You must format this partition before using it." popup
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Stop-Service ShellHWDetection -ErrorAction SilentlyContinue }
foreach ($disk in $disks) {
if ($disk.IsOffline) {
Set-Disk $disk.Number -IsOffline $false
Write-Verbose -Message "Brought disk $($disk.Number)($("{0:n0}GB" -f ($disk.Size / 1GB))) online..."
}
if ($disk.IsReadOnly) { Set-Disk $disk.Number -IsReadOnly $false }
if ($disk.PartitionStyle -eq 'RAW') { Initialize-Disk $disk.Number -PartitionStyle GPT -ErrorAction SilentlyContinue }
$diskParam = @{
FileSystem = 'NTFS'
Confirm = $false
}
$driveLetter = [Int][Char]'D'
while (Get-Volume -DriveLetter $([Char]$driveLetter) -ErrorAction SilentlyContinue) {
$driveLetter++
}
$diskParam.DriveLetter = [Char]$driveLetter
if (@($disks).IndexOf($disk) -eq 0 -and (-not (Get-Volume -DriveLetter D -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Temporary Storage'
}
elseif (@($disks).IndexOf($disk) -eq 1 -and (-not (Get-Volume -DriveLetter E -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Data'
}
[void](New-Partition -DiskNumber $disk.Number -DriveLetter $diskParam.DriveLetter -UseMaximumSize)
[void](Format-Volume @diskParam)
}
}
else {
Write-Verbose -Message "No unpartitioned disks found, continuing..."
}
}
catch {
Throw $_
Break
}
finally {
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Start-Service ShellHWDetection -ErrorAction SilentlyContinue }
}
}
Invoke-AzVMRunCommand @InvokeAzVMRunCommandParams -ScriptString $ScriptBlock
Write-Verbose -Message "5-Time Zone"
$ScriptBlock = {
if ((Get-TimeZone).Id -ne 'Central Standard Time') {
Write-Verbose -Message "Current time zone set to $((Get-TimeZone).Id), setting to Central Standard Time."
Set-TimeZone -Id 'Central Standard Time'
Write-Verbose -Message "Time zone set to Central Standard Time."
}
else {
Write-Verbose -Message "Time zone is already set to Central Standard Time."
}
}
Invoke-AzVMRunCommand @InvokeAzVMRunCommandParams -ScriptString $ScriptBlock
Write-Verbose -Message "6-Enable Performance Counters"
$ScriptBlock = {
# Enable Performance Counters
try {
if (Get-ScheduledTask -TaskName "Server Manager Performance Monitor" | Where-Object State -NE "Running" -ErrorAction SilentlyContinue) {
Enable-ScheduledTask -TaskPath "\Microsoft\Windows\PLA\" -TaskName "Server Manager Performance Monitor" | Start-ScheduledTask
Write-Verbose -Message "Performance monitors enabled."
}
else {
Write-Verbose -Message "Performance monitors already enabled, continuing..."
}
}
catch {
Throw $_
Break
}
}
Invoke-AzVMRunCommand @InvokeAzVMRunCommandParams -ScriptString $ScriptBlock
Write-Verbose -Message "7-Disable Windows Firewall"
$ScriptBlock = {
# Disable Windows Firewall
Write-Verbose -Message "Checking for active Windows Firewall..."
if ((Get-NetFirewallProfile).Enabled -contains 'True') {
Write-Verbose -Message "Windows Firewall is still enabled, disabling it..."
Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False
Write-Verbose -Message "Windows Firewall disabled."
}
else {
Write-Verbose -Message "Windows Firewall already disabled, continuing..."
}
}
Invoke-AzVMRunCommand @InvokeAzVMRunCommandParams -ScriptString $ScriptBlock
# determine Active Directory Forest and OU
Write-Verbose -Message "8a-Determine domain join"
$DomainName = $FQDN.Substring($FQDN.IndexOf(".") + 1)
switch ($DomainName) {
'nd.gov' {
$SearchBaseDomain = "dc=nd,dc=gov"
}
'ndcloud.gov' {
$SearchBaseDomain = "dc=ndcloud,dc=gov"
}
}
If ($DomainName -eq "nd.gov") {
$OUAppName = Get-ADOrganizationalUnit -Server $DomainName -SearchBase ("OU=Windows,OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq $AppName }
If ($null -eq $OUAppName) {
Write-Verbose -Message "Dedicated AppName OU for $AppName not found, placing in All-General OU"
$OUAppName = Get-ADOrganizationalUnit -Server $DomainName -SearchBase ("OU=Windows,OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq 'All-General' }
}
Write-Verbose -Message ("OUAppName: " + $OUAppName.distinguishedName) -Verbose
# Determine if the Environment sub-ou is special for the selected AppName
switch ($OUAppName.Name) {
'Shared-PeopleSoft-HigherEd' {
switch ($VMEnvironment) {
'Test' { $EnvString = "Non-Prod" }
'Production' { $EnvString = "Prod" }
}
}
'Shared-PeopleSoft-State' {
switch ($VMEnvironment) {
'Test' { $EnvString = "Non-Prod" }
'Production' { $EnvString = "Prod" }
}
}
Default {
switch ($VMEnvironment) {
'Test' { $EnvString = "Test" }
'Production' { $EnvString = "Prod" }
}
}
}
# Gather all sub OUs for the AppName OU
Write-Verbose -Message "EnvString is $EnvString" -Verbose
$SubOUs = Get-ADOrganizationalUnit -Server $DomainName -SearchBase $OUAppName -Filter *
Write-Verbose -Message ("SubOUs:") -Verbose
$SubOUs | ForEach-Object { Write-Verbose -Message $_.DistinguishedName -Verbose }
$LikeFilter = ("OU=$EnvString,OU=" + $OUAppName.Name + "*")
Write-Verbose -Message "LikeFilter: $LikeFilter"
$OUToUse = $SubOUs | Where-Object { $_.DistinguishedName -like $LikeFilter }
Write-Verbose -Message ("OUToUse: " + $OUToUse.distinguishedName) -Verbose
<#$MatchFilter = ("OU=$EnvString,OU=" + $OUAppName.Name)
Write-Verbose -Message "MatchFiler: $MatchFilter"
$OutToUseMatch = ($SubOUs | Where-Object {$_.DistinguishedName -match "^$MatchFilter"})
Write-Verbose -Message ("OUToUseMatch: " + $OUToUseMatch.distinguishedName) -Verbose
#>
# Determine if AD Computer object already exists
$ExistingADComputer = Get-ADComputer -Filter { Name -eq $HostName }
If ($ExistingADComputer) {
Write-Verbose -Message "AD Object already exists in AD"
# Determine if AD Computer object is in the correct OU, or a sub-OU of the correct OU
If ($ExistingADComputer.DistinguishedName -like ("*" + $OUToUse.DistinguishedName)) {
Write-Verbose -Message "AD Object is in the correct OU, will attempt domain join"
$AttemptDomainJoin = $true
}
Else {
Write-Verbose -Message "AD Object is NOT in the correct OU, domain join will not occur, needs human review"
$AttemptDomainJoin = $false
}
}
Else {
$AttemptDomainJoin = $true
}
If ($AttemptDomainJoin) {
$OuFinal = $OUToUse.DistinguishedName
Write-Verbose -Message "OuFinal: $OuFinal" -Verbose
$FirstScriptBlock = { $DomainJoinCred = New-Object System.Management.Automation.PSCredential('svcitdvmdomainjoin', ('hypes-Vgv8h89' | ConvertTo-SecureString -AsPlainText -Force)) }
$SecondScriptText = 'Add-Computer -DomainName <DomainName> -OUPath "<OuPath>" -Credential $DomainJoinCred -Server itddc42.nd.gov -Verbose; Restart-Computer -Force -Verbose;'
$SecondScriptText = $SecondScriptText -replace '<DomainName>', $DomainName
$SecondScriptText = $SecondScriptText -replace '<OuPath>', $OuFinal
#Write-Verbose -Message "[$FQDN]:Invoke-VMScript to AD join"
$InvokeVMScriptFunc = [System.Management.Automation.ScriptBlock]::Create("$FirstScriptBlock ; $SecondScriptText")
}
Write-Verbose -Message $InvokeVMScriptFunc.tostring() -Verbose ###
<# wait for firewall and reconnect
Write-Verbose -Message "8b-Verify if firewall is open before domain join attempt"
$connectivity = $false
while ($connectivity -eq $false) {
If ( (Test-NetConnection -ComputerName $FQDN).PingSuccedded) {
Write-Verbose -Message "Ping successful" -Verbose
$connectivity = $true
}
Else {
Write-Verbose -Message "Ping failed, may need to wait for PA IP sync" -Verbose
Start-Sleep -Seconds 60
}
}
#>
Write-Verbose -Message "8c-Attempt domain join"
switch ($DomainName) {
'nd.gov' {
Write-Verbose -Message "Attempting domain join nd.gov"
Write-Verbose -Message "Domain: $DomainName"
Write-Verbose -Message "OuPath: $OuFinal"
<#Invoke-AzVMRunCommand @InvokeAzVMRunCommandParams -ScriptPath 'C:\AzWinBuild\8-Domain-ndgov.ps1' -Parameter @{
"DomainName" = 'nd.gov';
"OuPath" = "$OuFinal"
}#>
$ScriptBlock = {
Param(
[string]
$DomainName,
[string]
$OuPath
)
Write-Host $OuPath
Test-NetConnection -ComputerName nd.gov
$DomainJoinCred = New-Object System.Management.Automation.PSCredential('ndgov\svcitdvmdomainjoin', ('hypes-Vgv8h89' | ConvertTo-SecureString -AsPlainText -Force))
Add-Computer -DomainName $DomainName -OUPath $OuPath -Credential $DomainJoinCred
Restart-Computer -Force
}
Invoke-AzVMRunCommand @InvokeAzVMRunCommandParams -ScriptString $ScriptBlock -Parameter @{
"DomainName" = 'nd.gov';
"OuPath" = "$OuFinal"
}
#Invoke-AzVMRunCommand @InvokeAzVMRunCommandParams -ScriptString $InvokeVMScriptFunc
}
}
}
}
}
}
end {
}
}