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 {
        
    }
}