functions/public/Start-SMBDeploymentGUI.ps1

Function Start-SMBDeploymentGUI {
    [CmdletBinding()]
    param(
        [Parameter()]
        [switch] $NoUpdateCheck
    )
    $SyncHash = Get-JobVariable
    $Log = Start-Log -InstanceId $SyncHash.InstanceId
    $SyncHash.Log = $Log
    # Set Module Version
    $SyncHash.ModuleVersion = (Get-Module -Name SMBBlueprint).Version.ToString()
    $PSDefaultParameterValues = @{"Write-Log:Log" = "$Log"}
    if (!$PSBoundParameters.ContainsKey('NoUpdateCheck')) {
        Test-ModuleVersion -ModuleName SMBBluePrint
    }
    #$script:SyncHash = [hashtable]::Synchronized(@{})
    # Create empty view-model
    $SyncHash.ViewModel = new-object psobject -Property @{
        Tenants = @()
        Subscriptions = @()
        AzureCredential = $null
        OfficeCredential = $null
        Groups = @()
        Users = @()
        VMSize = 'none'
        SQLSize = 'none'
        Backup = 'none'
        VPN = 'none'
        CustomerName = 'Inovativ'
        Customersize = 'small'
        Password = New-SWRandomPassword -MinPasswordLength 16 -MaxPasswordLength 16
        Licenses = @()
        ResourceGroup = $null
        ActiveTenant = $null
        ActiveSubscription = $null
        TabState = "Collapsed"
        CommandName = $null
        CommandParameters = $null
        MailDomain = $null
        AzureLocation = $null
        AutomationLocation = $null
        LogAnalyticsLocation = $null
        Management = 'free'
        OS = '2016'
        StorageType = $null
    }
    write-host "Please wait while the graphical interface is being loaded"
    # if($Log -eq $null){
    # $Log = Start-Log
    # }

    $SyncHash.Module = "$global:root\SMBDeployment.psd1"
    $SyncHash.XAML = (get-xaml)
    
    $SyncHash.Root = $global:root

    
    
    $null = invoke-operation -log $SyncHash.Log -root $SyncHash.Root -synchash $SyncHash -code {
        try {
            $ModuleVersion = $SyncHash.ModuleVersion
            # Create GUI windows from WPF XAML
            Add-Type -AssemblyName System.Windows.Forms
            Add-Type -AssemblyName PresentationCore
            Add-Type -AssemblyName PresentationFramework
            Add-Type -AssemblyName WindowsBase
            [xml]$XAML = $SyncHash.XAML
            $XAMLReader = new-object -typename System.Xml.XmlNodeReader -ArgumentList $XAML
            $SyncHash.GUI = [Windows.Markup.XamlReader]::Load( $XAMLReader )
            
            $XAML.SelectNodes("//*[@Name]")|
                ForEach-Object {
                # write-log -Type Debug -Message "Adding variable for control $($_.Name): $($SyncHash.GUI.FindName($_.Name))"
                $SyncHash."WPF_$($_.Name)" = $SyncHash.GUI.FindName($_.Name)
            }
            
        } catch {
            
            return
        }
        
        # UI functions


        
        
        function Get-AzureSubscription {
            try {
                $SyncHash.ViewModel.Subscriptions = @()
                $cmb_Tenants = $SyncHash.WPF_Cmb_Tenants
                write-log -type debug -message "Reconnecting to Azure with selected tenant"
                if ($cmb_Tenants.SelectedItem -ne "") {
                    $SelectedTenant = [Tenant]$cmb_Tenants.selecteditem
                    $SyncHash.ViewModel.ActiveTenant = $SelectedTenant
                    $SyncHash.ViewModel.Licenses = Get-O365License -TenantId $SelectedTenant.Id
                    $SyncHash.GUI.FindName('Txt_Customer').Text = $SelectedTenant.Name.Replace(".", "")
                    Add-AzureRmAccount -Credential $SyncHash.ViewModel.AzureCredential -TenantId $($SelectedTenant.Id)
                    write-log -Message "Getting subscriptions for Tenant $SelectedTenant" -type Debug
                    foreach ($Subscription in (Get-AzureRmSubscription -TenantId $SelectedTenant.Id)) {
                        $SubscriptionObject = New-Object Subscription
                        $SubscriptionObject.Name = $Subscription.SubscriptionName
                        $SubscriptionObject.Id = $Subscription.SubscriptionId
                        write-log -Type Debug -Message "Found Subscription '$($SubscriptionObject.Name)'"
                        $SyncHash.ViewModel.Subscriptions += $SubscriptionObject
                        
                    }
                }
                
                $SyncHash.WPF_Cmb_Subscriptions.ItemsSource = $SyncHash.ViewModel.Subscriptions
                $SyncHash.WPF_Cmb_Subscriptions.SelectedIndex = 0
                $LocationObject = get-azurermlocation
                $Locations = @()
                foreach ($Location in $LocationObject) {
                    $Locations += $Location.Location
                }
                $Locations = $Locations|sort
                $SyncHash.WPF_Cmb_PrimaryLocation.ItemsSource = $Locations
                
                $AutomationLocations = @()
                foreach ($AutomationLocation in ($LocationObject|Where-Object {$_.Providers -contains "Microsoft.Automation"})) {
                    $AutomationLocations += $AutomationLocation.Location
                }
                $AutomationLocations = $AutomationLocations|sort
                $SyncHash.WPF_Cmb_AutomationLocation.ItemsSource = $AutomationLocations

                $OILocations = @()
                foreach ($OILocation in ($LocationObject|Where-Object {$_.Providers -contains "Microsoft.OperationalInsights"})) {
                    $OILocations += $OILocation.Location
                }
                $OILocations = $OILocations|sort
                $SyncHash.WPF_Cmb_LogAnalyticsLocation.ItemsSource = $OILocations


                # Some tinkering to get the license selection box working properly
                $array = new-object Object[] $SyncHash.ViewModel.Licenses.Values.Count
                $SyncHash.ViewModel.Licenses.Values.CopyTo($array, 0)
                $SyncHash.WPF_Lst_Licenses.ItemsSource = $array
                
                #$SyncHash.WPF_Lst_Licenses.SelectedIndex = 0
                $SyncHash.ViewModel.MailDomain = (Get-AzureADDomain|where {$_.IsDefault -eq $true}).Name
                ### Debug Code:
                $SyncHash.WPF_Txt_Mail.IsReadOnly = $false
                ###
                $SyncHash.WPF_Txt_Mail.Text = $SyncHash.ViewModel.MailDomain
                $SyncHash.GUI.DataContext = $SyncHash.ViewModel
                $SyncHash.GUI.Dispatcher.Invoke(
                    "Render",
                    [action] {
                        $SyncHash.WPF_Btn_O365Link.Visibility = [System.Windows.Visibility]::Visible
                        $SyncHash.WPF_Btn_AzureLink.Visibility = [System.Windows.Visibility]::visible
                        if ($SyncHash.ViewModel.Subscriptions.Count -gt 0) {
                            $SyncHash.WPF_Btn_AzureLink.Visibility = [System.Windows.Visibility]::Visible
                        }
                        if ($SyncHash.ViewModel.Licenses.Count -gt 0) {
                            $SyncHash.WPF_Btn_O365Link.Visibility = [System.Windows.Visibility]::Visible
                        }
                    
                    }
                )
                
                
            } catch {
                write-log -Message $_ -Type Debug
            }
        } 

        

        


        ##################################################################################################################################################

        
        try {
            
            

            # Define the GUI control variable
            #$SyncHash.GUI.SelectNodes("//*[@Name]") | %{Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name)}

            # Add listeners to controls
            $SyncHash.WPF_Btn_ConnectToAzure.Add_Click(
                <# {
                Set-Busy -On -Activity "Connecting with Azure"
                Get-AzureConnection
                Set-Busy -Off
            } #>
 {
                
                    Write-Log -Message "Connecting to Azure using the provided credentials"
                    $txt_logonuser = $SyncHash.WPF_Txt_LogonUser
                    $txt_logonpass = $SyncHash.WPF_Txt_LogonPass
                    if ([String]::IsNullOrEmpty($txt_LogonUser.Text) -or [String]::IsNullOrEmpty($txt_logonpass.Password)) {
                        Invoke-Message -Message "User or Password not provided. Please fill in all information."
                        return
                    }
                    $User = $txt_logonuser.Text
                    $Password = ($txt_logonpass.Password|ConvertTo-Securestring -AsPlainText -Force)
                    $SyncHash.ViewModel.AzureCredential = new-object pscredential $User, $Password
                
                
                
                    $job = invoke-operation -synchash $SyncHash -Log $SyncHash.Log -Root $SyncHash.Root -Code {
                        try {                 
                        
                            $SyncHash.GUI.Dispatcher.Invoke(
                                "Render",
                                [action] {
                            
                                    $SyncHash.WPF_Lbl_Title.Text = "Retrieving Tenant Information"}
                            )
                         
                            $null = Connect-Cloud -Credential $SyncHash.ViewModel.AzureCredential
                            $SyncHash.ViewModel.Tenants = @($(Get-Tenant -All))

                        
                        
                            $SyncHash.GUI.Dispatcher.Invoke(
                                [action] {
                                    $SyncHash.WPF_Cmb_Tenants.ItemsSource = $SyncHash.ViewModel.Tenants

                                    $SyncHash.WPF_Cmb_Tenants.IsDropDownOpen = $true
                                }
                        
                            )
                        
                        
                        
                        } 
                    
                        catch {
                            Invoke-Message -Message "$_ @ $($_.InvocationInfo.ScriptLineNumber) - $($_.InvocationInfo.Line) Trace: $($_.ScriptStackTrace)"
                            return
                        }
                        finally {
                            $SyncHash.GUI.Dispatcher.Invoke(
                                [action] {
                                    $SyncHash.WPF_Lbl_Title.Text = "SMB Deployment GUI - $($SyncHash.ModuleVersion)"
                            
                                })
                        }
                    }
                }
            
            
            )

            $cmb_Tenants = [System.Windows.Controls.ComboBox]$SyncHash.WPF_Cmb_Tenants
            
            $cmb_Tenants.Add_SelectionChanged( {

                    Get-AzureSubscription
                }
            )

            $SyncHash.WPF_Txt_Mail.Add_TextChanged( {
    
                    $SyncHash.ViewModel.MailDomain = $SyncHash.WPF_Txt_Mail.Text
                })
            
            

            $SyncHash.WPF_Txt_Customer.Add_TextChanged( {
                    $SyncHash.WPF_Txt_Customer.Text = [Regex]::Replace($SyncHash.WPF_Txt_Customer.Text, '[^a-zA-Z0-9]', '')
                    $SyncHash.ViewModel.CustomerName = $SyncHash.WPF_Txt_Customer.Text
                })
            $SyncHash.WPF_Rad_Small.Add_Checked( {
                    $SyncHash.ViewModel.CustomerSize = "small"
                    Write-Log -Message "CustomerSize set to $($SyncHash.ViewModel.CustomerSize)"
                })
            $SyncHash.WPF_Rad_Medium.Add_Checked( {
                    $SyncHash.ViewModel.CustomerSize = "medium"
                    Write-Log -Message "CustomerSize set to $($SyncHash.ViewModel.CustomerSize)"
                })
            $SyncHash.WPF_Rad_Large.Add_Checked( {
                    $SyncHash.ViewModel.CustomerSize = "large"
                    Write-Log -Message "CustomerSize set to $($SyncHash.ViewModel.CustomerSize)"
                })

            $SyncHash.WPF_Cmb_ExtraVMSize.Add_SelectionChanged( {
                    $SyncHash.ViewModel.VMSize = $SyncHash.WPF_Cmb_ExtraVMSize.SelectedItem.Tag
                    Write-Log -Message "ExtraVMSize set to $($SyncHash.ViewModel.VMSize)"
                })
            $SyncHash.WPF_Cmb_AutomationLocation.Add_SelectionChanged( {
                    $SyncHash.ViewModel.AutomationLocation = $SyncHash.WPF_Cmb_AutomationLocation.SelectedItem
                    Write-Log -Message "AutomationLocation set to $($SyncHash.ViewModel.AutomationLocation)"
                })
            $SyncHash.WPF_Cmb_LogAnalyticsLocation.Add_SelectionChanged( {
                    $SyncHash.ViewModel.LogAnalyticsLocation = $SyncHash.WPF_Cmb_LogAnalyticsLocation.SelectedItem
                    Write-Log -Message "LogAnalyticsLocation set to $($SyncHash.ViewModel.LogAnalyticsLocation)"
                })
            $SyncHash.WPF_Cmb_ExtraSQLSize.Add_SelectionChanged( {
                    $SyncHash.ViewModel.SQLSize = $SyncHash.WPF_Cmb_ExtraSQLSize.SelectedItem.Tag
                    Write-Log -Message "ExtraSQLSize set to $($SyncHash.ViewModel.SQLSize)"
                })
            $SyncHash.WPF_Cmb_Subscriptions.Add_SelectionChanged( {
                    $SyncHash.ViewModel.ActiveSubscription = ($SyncHash.WPF_Cmb_Subscriptions.SelectedItem)
                })
            $SyncHash.WPF_Cmb_Backup.Add_SelectionChanged( {
                    $SyncHash.ViewModel.Backup = $SyncHash.WPF_Cmb_Backup.SelectedItem.Tag
                    Write-Log -Message "Backup set to $($SyncHash.WPF_Cmb_Backup.SelectedItem.Tag)"
                })
            $SyncHash.WPF_Cmb_VPN.Add_SelectionChanged( {
                    $SyncHash.ViewModel.VPN = $SyncHash.WPF_Cmb_VPN.SelectedItem.Tag
                    Write-Log -Message "VPN set to $($SyncHash.WPF_Cmb_VPN.SelectedItem.Tag)"
                })
            $SyncHash.WPF_Btn_CopyCredential.Add_Click( {
                    "User: sysadmin Password: $($SyncHash.ViewModel.Password)"|clip
                    invoke-message "Credentials copied to clipboard"
                })
            $SyncHash.WPF_Btn_CopyCommand.Add_Click( {
                    if ($SyncHash.ViewModel.CommandName -eq $null) {
                        invoke-message "Start the deployment to be able to obtain the code-behind"
                    }
                    else {
                        $Command = $SyncHash.ViewModel.CommandName
                        foreach ($Item in $SyncHash.ViewModel.CommandParameters.Keys) {
                            $Command += " -$($Item) $($SyncHash.ViewModel.CommandParameters[$Item])"
                        }
                        $Command|clip
                        invoke-message "The command has been pasted to the clipboard:`r`n$Command"
                    }
                })
            $SyncHash.WPF_Btn_OfficeDeploy.Add_Click( {
                    if (
                        [string]::IsNullOrEmpty($SyncHash.ViewModel.ActiveTenant) -or 
                        $SyncHash.ViewModel.Users.Count -eq 0
                    ) {
                        invoke-message "Not all parameters are present for deployment"
                        return
                    }
                    $SyncHash.ViewModel.Password = $SyncHash.WPF_Txt_OfficePassword.Password
                    if ((Test-AADPasswordComplexity -MinimumLength 8 -Password $SyncHash.ViewModel.Password) -eq $false) {
                        invoke-message "Password does not meet complexity requirements"
                        return
                    }
                
                    $Overview = `
                "The deployment will be started with the following parameters:`r`n" + `
                "Target Tenant: $(($SyncHash.ViewModel.ActiveTenant.Name))`r`n" + `
                "Number of Groups: $($SyncHash.ViewModel.Groups.Count)`r`n" + `
                "Number of Users: $($SyncHash.ViewModel.Users.Count)`r`n" + `
                "Initial Password for login: $($SyncHash.ViewModel.Password)`r`n"
                    [System.Windows.Forms.MessageBox]::Show($Overview, "Deployment Info")
                    [System.Windows.Forms.DialogResult] $DialogResult = [System.Windows.Forms.MessageBox]::Show("Are you sure you want to deploy this Azure solution?", "Confirm Deployment", [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Information)
                    if ($DialogResult -eq [System.Windows.Forms.DialogResult]::Yes) {
                        $SyncHash.GUI.Dispatcher.invoke(
                            "Render",
                            [action] {
                                $SyncHash.WPF_Tab_MainControl.SelectedItem = $SyncHash.WPF_Tab_Log
                                $SyncHash.WPF_Btn_O365Link.Visibility = [System.Windows.Visibility]::collapsed
                                $SyncHash.WPF_Btn_AzureLink.Visibility = [System.Windows.Visibility]::collapsed
                                $SyncHash.WPF_Btn_HomeLink.Visibility = [System.Windows.Visibility]::collapsed     
                            })
                        $CSVLocation = "$env:TEMP\SMBUsers.csv"
                        ConvertFrom-O365 -Users $SyncHash.ViewModel.Users -Path $CSVLocation
                        $SyncHash.DeploymentJob = new-object psobject
                        $Parameters = @{
                            Credential = $SyncHash.ViewModel.AzureCredential
                            CSV = $CSVLocation
                            TenantId = $SyncHash.ViewModel.ActiveTenant.Id
                            DefaultPassword = $SyncHash.ViewModel.Password
                            SyncHash = $SyncHash
                            Log = $Log
                            MailDomain = $SyncHash.ViewModel.MailDomain
                            NoUpdateCheck = $true
                        }
                        $SyncHash.ViewModel.CommandName = "New-SMBOfficeDeployment"
                        $SyncHash.ViewModel.CommandParameters = $Parameters
                        $job = invoke-operation -Parameters $Parameters -log $SyncHash.Log -root $SyncHash.Root -SyncHash $SyncHash -Code {
                        
                            try {
                            
                                $job = invoke-operation -Parameters $Parameters -log $SyncHash.Log -root $SyncHash.Root -SyncHash $SyncHash -Code {
                                    try {
                                        new-smbofficedeployment @Parameters
                                    } catch {
                                        write-log -type error -message "Error during Office Deployment: $_"
                                    }
                                }
                                start-sleep 5
                                $DeploymentStart = get-date
                                while (($SyncHash.DeploymentJob.Completed -ne $true) -or (new-timespan -Start $DeploymentStart -End (get-date)).TotalMinutes -le 1) {
                                    $ErrorActionPreference = "Stop"
                                    $DeploymentEnd = get-date
                                    $DeploymentDuration = New-TimeSpan -Start $DeploymentStart -End $DeploymentEnd
                                    $SyncHash.DeploymentJob.Duration = $("{0:HH:mm:ss}" -f ([datetime]$DeploymentDuration.Ticks))
                                    $Status = "Please check the logging for progress"
                                    $SyncHash.GUI.Dispatcher.invoke(
                                        "Render",
                                        [action] {
                                            $SyncHash.WPF_Txt_DeploymentType.Text = $SyncHash.DeploymentJob.Type
                                            $SyncHash.WPF_Txt_DeploymentStatus.Text = $Status
                                            $SyncHash.WPF_Txt_DeploymentTime.Text = $SyncHash.DeploymentJob.Duration
                                        })
                                
                                
                                    start-sleep -Seconds 10
                                
                                }
                            
                                if ($SyncHash.DeploymentJob.Error) {
                                    throw $SyncHash.DeploymentJob.Error
                                }
                                else {
                                    $Status = "Office Deployment Completed`r`n"
                                    foreach ($User in $SyncHash.DeploymentJob.Status.ProvisionedUsers) {
                                        $Status += "Login: $($User.Login) Password: $($User.Password)`r`n"
                                    }
                                    $SyncHash.GUI.Dispatcher.invoke(
                                        "Render",
                                        [action] {
                                    
                                            $SyncHash.WPF_Txt_DeploymentStatus.Text = $Status
                                    
                                        })
                                }

                            } catch {
                                write-log -type error -message "Error during Office Deployment: $_"
                                return
                            }


                        

                        }
                    }

                })

            $SyncHash.WPF_Cmb_PrimaryLocation.Add_SelectionChanged( {
                    $SyncHash.ViewModel.AzureLocation = $SyncHash.WPF_Cmb_PrimaryLocation.SelectedItem
                    Write-Log -Type Information -Message "Azure Location changed to '$($SyncHash.ViewModel.AzureLocation)', checking compatibility using file '$($SyncHash.Root)\resources'"
                    $Result = Test-AzureResourceLocation -Location $SyncHash.WPF_Cmb_PrimaryLocation.SelectedItem -ResourceFile "$($SyncHash.Root)\resources"
                    if (((get-variable -Name Result -ErrorAction Ignore) -eq $null) -or ($Result -eq $null)) {
                        $Count = 0
                    }
                    else {
                        $Count = $Result.Count
                    }
                    if ($Count -gt 0) {
                        if (($Result|Where-Object {$_["Resource"] -eq 'Microsoft.Automation'}) -and ($SyncHash.ViewModel.AutomationLocation -eq $null)) {
                            Invoke-Message "The location you selected does not support automation. Please choose another automation location."
                            $SyncHash.GUI.Dispatcher.Invoke(
                                'Render',
                                [action] {
                                  
                                }
                            )
                        }
                        else {
                            $SyncHash.GUI.Dispatcher.Invoke(
                                'Render',
                                [action] {
                                    $SyncHash.WPF_Cmb_AutomationLocation.SelectedItem = $SyncHash.WPF_Cmb_PrimaryLocation.SelectedItem

                                }
                            )

                        }
                        if (($Result|Where-Object {$_["Resource"] -eq 'Microsoft.OperationalInsights'}) -and ($SyncHash.ViewModel.LogAnalyticsLocation -eq $null)) {
                            Invoke-Message "The location you selected does not support Log Analytics. Please choose another Log Analytics action."
                            $SyncHash.GUI.Dispatcher.Invoke(
                                'Render',
                                [action] {
                                  
                                }
                            )
                        }
                        else {
                       
                            $SyncHash.GUI.Dispatcher.Invoke(
                                'Render',
                                [action] {
                                    $SyncHash.WPF_Cmb_LogAnalyticsLocation.SelectedItem = $SyncHash.WPF_Cmb_PrimaryLocation.SelectedItem

                                }
                            )

                        }
                        if ($Result|Where-Object {$_["Resource"] -eq 'Microsoft.RecoveryServices'}) {
                            Invoke-Message "Backup is not availabe at this location. The option will be disabled"
                            $SyncHash.GUI.Dispatcher.Invoke(
                                'Render',
                                [action] {
                                    $SyncHash.WPF_Cmb_Backup.SelectedIndex = 0
                                    $SyncHash.ViewModel.Backup = 'none'
                                    $SyncHash.WPF_Cmb_Backup.IsEnabled = $false

                                }
                            )

                        }
                        else {
                            $SyncHash.GUI.Dispatcher.Invoke(
                                'Render',
                                [action] {

                                    $SyncHash.WPF_Cmb_Backup.IsEnabled = $true

                                }
                            )

                        }
                    }
                    else {
                        $SyncHash.GUI.Dispatcher.Invoke(
                            'Render',
                            [action] {
                            
                                $SyncHash.WPF_Cmb_Backup.IsEnabled = $true
                                $SyncHash.WPF_Cmb_AutomationLocation.SelectedItem = $SyncHash.WPF_Cmb_PrimaryLocation.SelectedItem
                                $SyncHash.WPF_Cmb_LogAnalyticsLocation.SelectedItem = $SyncHash.WPF_Cmb_PrimaryLocation.SelectedItem

                            }
                        )

                    }
                })
            

         
            $SyncHash.WPF_Cmb_OS.Add_SelectionChanged( {
                    $SyncHash.ViewModel.OS = $SyncHash.WPF_Cmb_OS.SelectedItem.Tag
                    Write-Log -Message "OS set to $($SyncHash.ViewModel.OS)"
                })
            $SyncHash.WPF_Cmb_StorageType.Add_SelectionChanged( {
                    $SyncHash.ViewModel.StorageType = $SyncHash.WPF_Cmb_StorageType.SelectedItem.Tag
                    Write-Log -Message "Storage Type set to $($SyncHash.ViewModel.StorageType)"
                })

            $SyncHash.WPF_btn_Deploy.Add_Click( {
                    if (
                        ($SyncHash.ViewModel.CustomerName.length -eq 0) -or 
                        ($SyncHash.ViewModel.Subscriptions.Count -eq 0) -or 
                        (($SyncHash.ViewModel.ActiveSubscription) -eq $null) -or 
                        (($SyncHash.ViewModel.AutomationLocation) -eq $null) -or 
                        (($SyncHash.ViewModel.LogAnalyticsLocation) -eq $null) -or 
                        ($SyncHash.ViewModel.AzureLocation) -eq $null
                    ) {
                        invoke-message "Not all parameters are provided for deployment"
                        return
                    }
                    $SyncHash.ViewModel.Resourcegroup = "smb_rg_$($SyncHash.ViewModel.CustomerName)"
                    Add-AzureRmAccount -Credential $SyncHash.ViewModel.AzureCredential -TenantId $SyncHash.ViewModel.ActiveTenant.Id -SubscriptionId $SyncHash.ViewModel.ActiveSubscription.Id
                    if ((($RG = Get-AzureRmResourceGroup -Name $SyncHash.ViewModel.ResourceGroup -ErrorAction SilentlyContinue)) -ne $null) {
                        Invoke-Message -Message "The target resource group $($SyncHash.ViewModel.ResourceGroup) already exists, please modify the customer prefix"
                        return
                    }
                    if ((Test-AzureRmDnsAvailability -DomainNameLabel $SyncHash.ViewModel.CustomerName.ToLower() -Location $SyncHash.ViewModel.AzureLocation) -eq $false) {
                        write-log -type error -Message "The public DNS record for this customer name is already taken, please choose another customer name"
                        return
                    }
                    if ($SyncHash.ViewModel.CustomerName -like "*microsoft*") {
                        invoke-message -message "'Microsoft' can not be a part of the customer name, please choose another customer name"
                        return
                    }
                    $SyncHash.ViewModel.Password = $SyncHash.WPF_Txt_AzurePassword.Password
                    if ((Test-AADPasswordComplexity -MinimumLength 12 -Password $SyncHash.ViewModel.Password) -eq $false) {
                        invoke-message "Password does not meet complexity requirements"
                        return
                    }
                    $SyncHash.ViewModel.StorageType = $SyncHash.WPF_Cmb_StorageType.SelectedItem.Tag
                
                
                    $Overview = `
                "The deployment will be started with the following parameters:`r`n" + `
                "Target Tenant: $(($SyncHash.ViewModel.ActiveTenant.Name))`r`n" + `
                "Target Subscription: $(($SyncHash.ViewModel.ActiveSubscription.Name))`r`n" + `
                "Target Group: $($SyncHash.ViewModel.ResourceGroup)`r`n" + `
                "Customer Prefix: $($SyncHash.ViewModel.CustomerName)`r`n" + `
                "Customer Size: $($SyncHash.ViewModel.CustomerSize)`r`n" + `
                "Extra SQL Size: $($SyncHash.ViewModel.SQLSize)`r`n" + `
                "Extra VM Size: $($SyncHash.ViewModel.VMSize)`r`n" + `
                "Backup Plan: $($SyncHash.ViewModel.Backup)`r`n" + `
                "VPN Plan: $($SyncHash.ViewModel.VPN)`r`n" + `
                "Management: $($SyncHash.viewModel.Management)`r`n" + 
                    "Primary Location: $($SyncHash.viewModel.AzureLocation)`r`n" + 
                    "Automation Location: $($SyncHash.viewModel.AutomationLocation)`r`n" + 
                    "Log Analytics Location: $($SyncHash.viewModel.LogAnalyticsLocation)`r`n" + 
                    "OS: $($SyncHash.viewModel.OS)`r`n" + 
                    "Storage Type: $($SyncHash.viewModel.StorageType)`r`n" + 
                    "`r`n" + `
                "Please note this credential for use with the solution:`r`n" + `
                "User: sysadmin`r`n" + `
                "Password: $($SyncHash.ViewModel.Password)`r`n"

                    [System.Windows.Forms.MessageBox]::Show($Overview, "Deployment Info")

                    [System.Windows.Forms.DialogResult] $DialogResult = [System.Windows.Forms.MessageBox]::Show("Are you sure you want to deploy this Azure solution?", "Confirm Deployment", [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Information)
                
                    if ($DialogResult -eq [System.Windows.Forms.DialogResult]::Yes) {
                        $DeploymentParameters = @{
                            AdditionalSQLInstanceSize = $SyncHash.ViewModel.SQLSize
                            AdditionalVMSize = $SyncHash.ViewModel.VMSize
                            CustomerSize = $SyncHash.ViewModel.CustomerSize
                            CustomerName = $SyncHash.ViewModel.CustomerName
                            SysAdminPassword = $($SyncHash.ViewModel.Password)
                            TenantId = $SyncHash.ViewModel.ActiveTenant.Id
                            SubscriptionId = $SyncHash.ViewModel.ActiveSubscription.Id
                            AsJob = $true
                            Credential = $SyncHash.ViewModel.AzureCredential
                            VPN = $SyncHash.ViewModel.VPN
                            Backup = $SyncHash.ViewModel.Backup
                            InstanceId = $SyncHash.InstanceId
                            Location = $SyncHash.ViewModel.AzureLocation
                            Management = $SyncHash.ViewModel.Management
                            OS = $SyncHash.ViewModel.OS
                            StorageType = $SyncHash.ViewModel.StorageType
                            NoUpdateCheck = $true
                            AutomationLocation = $SyncHash.ViewModel.AutomationLocation
                            LogAnalyticsLocation = $SyncHash.ViewModel.LogAnalyticsLocation

                        }
                       
                        $SyncHash.ViewModel.CommandName = "New-SMBAzureDeployment"
                        $SyncHash.ViewModel.CommandParameters = $DeploymentParameters
                        $SyncHash.GUI.Dispatcher.invoke(
                            "Render",
                            [action] {
                                $SyncHash.WPF_Tab_MainControl.SelectedItem = $SyncHash.WPF_Tab_Log
                                $SyncHash.WPF_Btn_O365Link.Visibility = [System.Windows.Visibility]::collapsed
                                $SyncHash.WPF_Btn_AzureLink.Visibility = [System.Windows.Visibility]::collapsed
                                $SyncHash.WPF_Btn_HomeLink.Visibility = [System.Windows.Visibility]::collapsed    
                            })
                    
                        $job = invoke-operation -synchash $SyncHash -root $SyncHash.Root -log $SyncHash.Log -code {
                            try {
                            
                                $SyncHash.DeploymentJob = New-SMBAzureDeployment @Parameters
                                while ($SyncHash.DeploymentJob.Completed -ne $true) {
                                    $SyncHash.GUI.Dispatcher.invoke(
                                        "Render",
                                        [action] { $SyncHash.WPF_Txt_DeploymentType.Text = $SyncHash.DeploymentJob.Type })
                                    $Status = ""
                                    foreach ($Item in $SyncHash.DeploymentJob.Status.Deployment) {
                                        $Status += "$($Item.Name): $($Item.Status)`r`n"
                                    }
                                    $SyncHash.GUI.Dispatcher.invoke(
                                        "Render",
                                        [action] { 
                                            $SyncHash.WPF_Txt_DeploymentType.Text = $SyncHash.DeploymentJob.Type
                                            $SyncHash.WPF_Txt_DeploymentStatus.Text = $Status
                                            $SyncHash.WPF_Txt_DeploymentTime.Text = $SyncHash.DeploymentJob.Duration
                                        })
                                
                                    start-sleep -Seconds 10
                                }
                                if ($SyncHash.DeploymentJob.Error) {
                                    throw $SyncHash.DeploymentJob.Error
                                }
                                else {
                                    $Status = "The solution is available: $($SyncHash.DeploymentJob.Status.Configuration.Connection)`r`n" + `
                                "Login: $($SyncHash.DeploymentJob.Status.Configuration.Domain)\$($SyncHash.DeploymentJob.Status.Configuration.Login)`r`n" + `
                                "Password: $($SyncHash.DeploymentJob.Status.Configuration.Password)"

                                    $SyncHash.GUI.Dispatcher.invoke(
                                        "Render",
                                        [action] { $SyncHash.WPF_Txt_DeploymentStatus.Text = $Status })
                                }
                            
                            } catch {
                                invoke-message -message "Error while deploying solution: '$_' ($($_.InvocationInfo.ScriptLineNumber) - $($_.InvocationInfo.Line))"
                            }
                        } -Parameters $DeploymentParameters
                    }
                }
            
            
            
            )

            

            ###############################################################################################################################################
            # Data grid

            
            
            
            # Fill DataGrid - Users details in GUI
            $Btn_AddUsers = $SyncHash.WPF_Btn_AddUser
            $Btn_AddUsers.Add_Click( {
                    try {
                        $User = new-object User
                        $User.First = $SyncHash.WPF_Txt_FirstName.Text
                        $User.Last = $SyncHash.WPF_Txt_LastName.Text
                        $User.Title = $SyncHash.WPF_Txt_Function.Text
                        $User.Department = $SyncHash.WPF_Txt_Department.Text
                        $User.Country = ([country]($SyncHash.WPF_Cmb_Country.SelectedItem)).Code
                        $User.Office = $SyncHash.WPF_Txt_Office.Text
                        $User.Mobile = $SyncHash.WPF_Txt_Mobile.Text
                        $User.DisplayName = [Regex]::Replace($User.First, '[^a-zA-Z0-9]', '') + "." + [Regex]::Replace($User.Last, '[^a-zA-Z0-9]', '')
                    
                    
                        ForEach ($Item in $SyncHash.WPF_Lst_Licenses.SelectedItems) {
            
                            $User.Licenses.Add([License]$Item)
                        }
                    
                        if (($SyncHash.WPF_Cmb_Groups.SelectedItem -eq $null) -and ([string]::IsNullOrEmpty($SyncHash.WPF_Cmb_Groups.Text) -ne $true)) {
                            if ($Group = ($SyncHash.ViewModel.Groups.Where{$_.Name -eq $SyncHash.WPF_Cmb_Groups.Text})) {
                                $User.Groups.Add($Group)
                            }
                            else {
                                $Group = new-object Group
                                $Group.Name = $SyncHash.WPF_Cmb_Groups.Text
                                $Group.Owner = $User
                                $SyncHash.ViewModel.Groups += $Group
                                $SyncHash.GUI.DataContext = $SyncHash.ViewModel
                                $User.Groups.Add($Group)
                                #invoke-message "new group"
                            }
                        
                        }
                        elseif (($SyncHash.WPF_Cmb_Groups.SelectedItem -ne $null) -and ($SyncHash.WPF_Cmb_Groups.SelectedItem.GetType() -eq [Group])) {
                            $User.Groups.Add([Group]$SyncHash.WPF_Cmb_Groups.SelectedItem)
                            #invoke-message "existing group"
                        }
                        else {
                            <#do nothinginvoke-message "do nothing"#>
                        }
                    
                    
                    
                        $User.Mobile = $SyncHash.WPF_Txt_Mobile.Text
                    
                        if (
                            [String]::IsNullOrEmpty($User.First) -or `
                            [String]::IsNullOrEmpty($User.Last) -or `
                            [String]::IsNullOrEmpty($User.Title) -or `
                            [String]::IsNullOrEmpty($User.Department) -or `
                            [String]::IsNullOrEmpty($User.Mobile) -or `
                            [String]::IsNullOrEmpty($User.Office)

                        ) {
                            invoke-message "Not all user properties were filled in"
                            return
                        }
                        $Exists = $false
                        if ($SyncHash.ViewModel.Users -contains $User) {
                            invoke-message "The user already exists"
                            $Exists = $true
                        
                        }
                        if ($Exists) {
                            return
                        }
                        $SyncHash.ViewModel.Users += $User
                        $SyncHash.GUI.Dispatcher.Invoke(
                            "Render",
                            [action] {
                                $SyncHash.WPF_GroupGrid.ItemsSource = $SyncHash.ViewModel.Groups
                                $SyncHash.WPF_UserGrid.ItemsSource = $SyncHash.ViewModel.Users
                                $SyncHash.WPF_Cmb_Groups.ItemsSource = $SyncHash.ViewModel.Groups
                                $SyncHash.GUI.DataContext = $SyncHash.ViewModel
                            }) 

                    
                    
                    } catch {
                        invoke-message "$_ @ $($_.InvocationInfo.ScriptLineNumber) - $($_.InvocationInfo.Line))"
                    }
                
                }
            )

            $SyncHash.WPF_Btn_DeleteUsers.Add_Click( {
                    $User = [User]$SyncHash.WPF_UserGrid.SelectedItem
                    $UserArray = $SyncHash.ViewModel.Users.Where{$_ -ne $User}
                    $GroupArray = $SyncHash.ViewModel.Groups
                    $Flag = $false
                    $SyncHash.ViewModel.Groups.ForEach{
                        $Group = $_
                        if ($_.Owner -eq $User) {
                            $SyncHash.ViewModel.Users.ForEach{
                                if (($_.Groups[0] -eq $Group) -and $_ -ne $User) {
                                    $Group.Owner = $_
                                    $GroupArray = $SyncHash.ViewModel.Groups.Where{$_ -ne $Group}
                                    $GroupArray += $Group
                                
                                    $Flag = $true
                                }
                            }
                            if ($Flag -eq $false) {
                                $GroupArray = $SyncHash.ViewModel.Groups.Where{$_ -ne $Group}
                            }
                        }
                    }
                
                    $SyncHash.ViewModel.Users = $UserArray
                    $SyncHash.ViewModel.Groups = $GroupArray
                    $SyncHash.GUI.Dispatcher.Invoke(
                        "Render",
                        [action] {
                            $SyncHash.WPF_GroupGrid.ItemsSource = $SyncHash.ViewModel.Groups
                            $SyncHash.WPF_UserGrid.ItemsSource = $SyncHash.ViewModel.Users
                            $SyncHash.WPF_Cmb_Groups.ItemsSource = $SyncHash.ViewModel.Groups
                            $SyncHash.GUI.DataContext = $SyncHash.ViewModel
                        }) 
                }   )

            $SyncHash.WPF_Btn_ClearUsers.Add_Click( {
                    $SyncHash.ViewModel.Users = @()
                    $SyncHash.ViewModel.Groups = @()
                    $SyncHash.GUI.Dispatcher.Invoke(
                        "Render",
                        [action] {
                            $SyncHash.WPF_GroupGrid.ItemsSource = $SyncHash.ViewModel.Groups
                            $SyncHash.WPF_UserGrid.ItemsSource = $SyncHash.ViewModel.Users
                            $SyncHash.WPF_Cmb_Groups.ItemsSource = $SyncHash.ViewModel.Groups
                            $SyncHash.GUI.DataContext = $SyncHash.ViewModel
                        }) 
                })
            $TabControl = $SyncHash.WPF_Tab_MainControl
            $Btn_HomeLink = $SyncHash.WPF_Btn_HomeLink
            $Btn_HomeLink.Add_Click( {
                    $TabControl.Items[0] | % {$_.IsSelected = $true}
                
                })
            $Btn_O365Link = $SyncHash.WPF_Btn_O365Link
            $Btn_O365Link.Add_Click( {
                    $TabControl.Items[1] | % {$_.IsSelected = $true}
                
                })    
            $Btn_AzureLink = $SyncHash.WPF_Btn_AzureLink
            $Btn_AzureLink.Add_Click( {
                    $TabControl.Items[2] | % {$_.IsSelected = $true}
                
                })
            $SyncHash.WPF_Btn_LogLink.Add_Click( {
                    $TabControl.Items[3] | % {$_.IsSelected = $true}
                })
            # Window Placement & Behavior
            $SyncHash.GUI.Add_MouseLeftButtonDown( {
                    $SyncHash.GUI.DragMove()
                }
            )
            $SyncHash.WPF_CloseButton.Add_Click( {
                    $SyncHash.GUI.Close()
                }
            )
            $SyncHash.GUI.Add_Closing( {

                    [System.Windows.Forms.DialogResult] $DialogResult = [System.Windows.Forms.MessageBox]::Show("Are you sure you want to exit?", "Confirm Close", [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Information)
                    if ($DialogResult -ne [System.Windows.Forms.DialogResult]::Yes) {
                        $_.Cancel = $true
                    }

                }

            )

            $SyncHash.WPF_Btn_ShowAzurePassword.Add_Click( {
                    $SyncHash.GUI.Dispatcher.Invoke(
                        "Render",
                        [action] {
                            if ($SyncHash.WPF_Btn_ShowAzurePassword.Content -eq "Show") {
                                $SyncHash.WPF_Txt_AzurePasswordVisible.Text = $SyncHash.WPF_Txt_AzurePassword.Password
                                $SyncHash.WPF_Txt_AzurePasswordVisible.Visibility = [System.Windows.Visibility]::visible
                                $SyncHash.WPF_Txt_AzurePassword.Visibility = [System.Windows.Visibility]::collapsed
                                $SyncHash.WPF_Btn_ShowAzurePassword.Content = "Hide"
                            }
                            else {
                                $SyncHash.WPF_Txt_AzurePassword.Password = $SyncHash.WPF_Txt_AzurePasswordVisible.Text
                                $SyncHash.WPF_Txt_AzurePasswordVisible.Text = ""
                                $SyncHash.WPF_Txt_AzurePasswordVisible.Visibility = [System.Windows.Visibility]::collapsed
                                $SyncHash.WPF_Txt_AzurePassword.Visibility = [System.Windows.Visibility]::visible
                                $SyncHash.WPF_Btn_ShowAzurePassword.Content = "Show"
                            }
                    
                        }) 
                
                })

            $SyncHash.WPF_Btn_ShowOfficePassword.Add_Click( {
                    $SyncHash.GUI.Dispatcher.Invoke(
                        "Render",
                        [action] {
                            if ($SyncHash.WPF_Btn_ShowOfficePassword.Content -eq "Show") {
                                $SyncHash.WPF_Txt_OfficePasswordVisible.Text = $SyncHash.WPF_Txt_OfficePassword.Password
                                $SyncHash.WPF_Txt_OfficePasswordVisible.Visibility = [System.Windows.Visibility]::visible
                                $SyncHash.WPF_Txt_OfficePassword.Visibility = [System.Windows.Visibility]::collapsed
                                $SyncHash.WPF_Btn_ShowOfficePassword.Content = "Hide"
                            }
                            else {
                                $SyncHash.WPF_Txt_OfficePassword.Password = $SyncHash.WPF_Txt_OfficePasswordVisible.Text
                                $SyncHash.WPF_Txt_OfficePasswordVisible.Visibility = [System.Windows.Visibility]::collapsed
                                $SyncHash.WPF_Txt_OfficePassword.Visibility = [System.Windows.Visibility]::visible
                                $SyncHash.WPF_Btn_ShowOfficePassword.Content = "Show"
                            }
                    
                        }) 
                
                })
            

            $SyncHash.WPF_btnImportCSV.Add_Click( {
                    [System.Windows.Forms.OpenFileDialog] $OpenFileDialog = new-object System.Windows.Forms.OpenFileDialog
                    $OpenFileDialog.Filter = "CSV-File (.csv)|*.csv"
                    [System.Windows.Forms.DialogResult] $Result = $OpenFileDialog.ShowDialog()
                    if ($Result -eq [System.Windows.Forms.DialogResult]::OK) {
                        if ((test-path $OpenFileDialog.FileName) -ne $true) {
                            invoke-message "File does not exist"
                            return
                        }
                        try {
                            $Inventory = ConvertTo-O365 -Path $OpenFileDialog.FileName -Licenses $SyncHash.ViewModel.Licenses -separator ','
                            $SyncHash.ViewModel.Groups = $Inventory.Groups
                            $SyncHash.ViewModel.Users = $Inventory.Users
                        
                            $SyncHash.GUI.Dispatcher.Invoke(
                                "Render",
                                [action] {
                                    $SyncHash.WPF_GroupGrid.ItemsSource = $SyncHash.ViewModel.Groups
                                    $SyncHash.WPF_UserGrid.ItemsSource = $SyncHash.ViewModel.Users
                                    $SyncHash.WPF_Cmb_Groups.ItemsSource = $SyncHash.ViewModel.Groups
                                    $SyncHash.GUI.DataContext = $SyncHash.ViewModel
                                }
                            ) 
                        
                        } catch {
                            invoke-message "$_"
                            return
                        }
                    }
                })
            # Setup Log Watcher
            
            
            $SyncHash.LogWatcher = new-object timers.timer
            $SyncHash.LogWatcher.Interval = 1000
            
            

            if (Get-Event -SourceIdentifier FileChanged -ErrorAction Ignore) {
                Unregister-Event -SourceIdentifier FileChanged -ErrorAction Ignore
            }
            $MessageData = new-object psobject -Property @{
                Log = $SyncHash.Log
                GUI = $SyncHash.GUI
            }
            
            $SyncHash.LogGUI = $true
            invoke-operation -synchash $SyncHash -root $SyncHash.Root -Log $SyncHash.Log -Code {
                try {
                    $Log = $SyncHash.Log
                    $GUI = $syncHash.GUI
                    $SyncHash.LogVisible = $false
                    while ($SyncHash.LogGUI -eq $true) {
                        
                        $GUI.Dispatcher.Invoke(
                            [action] {$GUI.FindName('Dgr_Log').ItemsSource = $Entries
                                $SyncHash.LogVisible = $GUI.FindName('Dgr_Log').IsVisible

                            })
                        if ($SyncHash.LogVisible) {
                            $content = get-content $Log
                            
                            $Entries = @()
                            foreach ($line in $content) {
                                if ($line -match '<!\[LOG\[(.+?(?=]LOG))\]LOG\]\!><time="([^\"]+)" date="([^"]+)" component="([^"]+)" context="([^\"]+)" type="(\d)" thread="([0-9]+)">') {
                                    
                                    $Entry = new-object psobject -Property @{
                                        Severity = $Matches[6]
                                        Message = $Matches[1]
                                        TimeStamp = $Matches[2]
                                        Component = $Matches[4]

                                    }
                                    $Entries += $Entry
                                    
                                    
                                }
                            }

                            $GUI.Dispatcher.Invoke(
                                "Render",
                                [action] {$GUI.FindName('Dgr_Log').ItemsSource = $Entries
                                    if (($GUI.FindName('Dgr_Log').Items.Count -gt 0) -and ($GUI.FindName('Chk_AutoScroll').IsChecked)) {
                                        $GUI.FindName('Dgr_Log').ScrollIntoView($GUI.FindName('Dgr_Log').Items.GetItemAt($GUI.FindName('Dgr_Log').Items.Count - 1));
                                    }
                                
                                }
                            )
                            
                            
                        }
                        start-sleep -Seconds 1
                    }

                    
                    
                } catch {
                    write-log -type error -message "Log Watcher Error: $_"
                }
                
            }
            $SyncHash.WPF_Txb_LogName.Text = $Log
            $SyncHash.WPF_Btn_OpenLog.Add_Click( {
                    Invoke-Expression "explorer.exe '/select,$Log'"
                })
            $SyncHash.WPF_Btn_O365Link.Visibility = [System.Windows.Visibility]::collapsed
            $SyncHash.WPF_Btn_AzureLink.Visibility = [System.Windows.Visibility]::collapsed
            $SyncHash.GUI.DataContext = $SyncHash.ViewModel
            $SyncHash.WPF_Cmb_Country.Items.Clear()
            $SyncHash.WPF_Cmb_Country.ItemsSource = Get-Country
            $SyncHash.WPF_Txt_OfficePassword.Password = $SyncHash.ViewModel.Password
            $SyncHash.WPF_Txt_AzurePassword.Password = $SyncHash.ViewModel.Password
            $SyncHash.GUI.Dispatcher.Invoke(
                [action] {
                    $SyncHash.WPF_Lbl_Title.Text = "SMB Deployment GUI - $ModuleVersion"
                            
                })
            
            $SyncHash.GUI.ShowDialog()
            

        } catch {
            invoke-message "$_ @ $($_.InvocationInfo.ScriptLineNumber) - $($_.InvocationInfo.Line))"

        }
        finally {
            if ($SyncHash.GUI.IsVisible) {
                $SyncHash.GUI.Close()
            }
            $SyncHash.LogWatcher.Stop()
            $SyncHash.LogGUI = $false;
            
            
            
        }

    }
    



}