functions/public/Start-SMBDeploymentGUI.ps1

Function Start-SMBDeploymentGUI {
    [CmdletBinding()]
    param()
    $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
        

    }
    write-host "Please wait while the graphical interface is being loaded"
    if($script:Log -eq $null){
        Start-Log
    }
    $SyncHash.Module = "$Root\SMBDeployment.psd1"
    $SyncHash.XAML = (get-xaml)
  
    $SyncHash.Root = $script:Root
    $SyncHash.LogFunction = "$Root\functions\private\write-log.ps1"
    $SyncHash.ClassFunction = "$Root\functions\private\register-classes.ps1"
    $SyncHash.OperationFunction = "$Root\functions\private\invoke-operation.ps1"
    $SyncHash.PopupFunction = "$Root\functions\private\invoke-message.ps1"
    $SyncHash.Log = $script:Log
    $SyncHash.LogName = $LogName
    
    
    $null = invoke-operation -log $script:log -root $script:root -synchash $SyncHash -code {
        try{

            # 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
                $SyncHash.WPF_Cmb_Licenses.ItemsSource = $SyncHash.ViewModel.Licenses.Values
                $SyncHash.WPF_Cmb_Licenses.SelectedIndex = 0
                $SyncHash.WPF_Txt_Mail.Text = (Get-MsolDomain -TenantId $Selectedtenant.Id|where{$_.IsDefault -eq $true}).Name
                $SyncHash.GUI.DataContext = $SyncHash.ViewModel
                 $SyncHash.GUI.Dispatcher.Invoke(
                            "Render",
                            [action]{
                                $SyncHash.WPF_Btn_AzureLink.Visibility = [System.Windows.Visibility]::Visible
                                $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
                
                    try {
                    
                        $job = invoke-operation -synchash $SyncHash -Code {
                        $SyncHash.WPF_Lbl_Title.Dispatcher.Invoke(
                            "Render",
                            [action]{$SyncHash.WPF_Lbl_Title.Text = "Retrieving Tenant Information"}
                        )
                       
                        Add-AzureRmAccount -Credential $SyncHash.ViewModel.AzureCredential
                        write-log -message "Connected to AzureRM" -type verbose
                        Connect-MSOLService -Credential $SyncHash.ViewModel.AzureCredential
                        write-log -message "Connected to MSOnline" -type verbose
                        $SyncHash.ViewModel.Tenants = @()
                        foreach($Tenant in Get-AzureRmTenant){
                            $TenantObject = new-object Tenant
                            $TenantObject.Id = $Tenant.TenantId
                            $TenantObject.Name = $Tenant.Domain
                            write-log -message "Found internal Tenant $($TenantObject.Name)" -type debug
                            $SyncHash.ViewModel.Tenants += $TenantObject
                        }
                        foreach($Tenant in Get-MSOLPartnerContract -All){
                            $TenantObject = new-object Tenant
                            $TenantObject.Id = $Tenant.TenantId
                            $TenantObject.Name = $Tenant.DefaultDomainName
                            $SyncHash.ViewModel.Tenants += $TenantObject
                            write-log -message "Found CSP Tenant $($TenantObject.Name)" -type debug
                        }
                        
                       
                        $SyncHash.GUI.Dispatcher.Invoke(
                            [action]{
                                $SyncHash.WPF_Cmb_Tenants.ItemsSource = $SyncHash.ViewModel.Tenants
                               # $SyncHash.WPF_Cmb_Tenants.SelectedIndex = 0
                                $SyncHash.WPF_Cmb_Tenants.IsDropDownOpen = $true
                                $SyncHash.WPF_Lbl_Title.Text = "Azure Solution Accelerator"
                        }
                        )
                        
                    
                    }
                    
               
                
            
            }
                catch {
                    Invoke-Message -Message "$_ @ $($_.InvocationInfo.ScriptLineNumber) - $($_.InvocationInfo.Line) Trace: $($_.ScriptStackTrace)"
                    return
                }
                }
              
            )

            $cmb_Tenants = [System.Windows.Controls.ComboBox]$SyncHash.WPF_Cmb_Tenants
        
            $cmb_Tenants.Add_SelectionChanged(
                {
  
                    Get-AzureSubscription
                }
            )
            
          

            $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_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
                }
             
                $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
                     }
                     $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_btn_Deploy.Add_Click(
                {
                    if(
                        ($SyncHash.ViewModel.CustomerName.length -eq 0) -or
                        ($SyncHash.ViewModel.Subscriptions.Count -eq 0) -or
                        (($SyncHash.ViewModel.ActiveSubscription) -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
                    }
                    
                    $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" +`
                        "`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

                        }
                        $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.Root)\functions\public\New-SBSAzureDeployment.ps1"
                                
                                $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: $_"
                                 }
                            } -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 = $SyncHash.WPF_Cmb_Country.SelectedItem.Tag
                        $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]', '')
                        $User.License = [License]$SyncHash.WPF_Cmb_Licenses.SelectedItem
                        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 nothing#>invoke-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_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_Btn_O365Link.Visibility = [System.Windows.Visibility]::collapsed
            $SyncHash.WPF_Btn_AzureLink.Visibility = [System.Windows.Visibility]::collapsed
            $SyncHash.GUI.DataContext = $SyncHash.ViewModel
            
            $SyncHash.GUI.ShowDialog()
            

        } catch {
            invoke-message "$_ @ $($_.InvocationInfo.ScriptLineNumber) - $($_.InvocationInfo.Line))"
            #Invoke-Message "$_ @ $($_.InvocationInfo.ScriptLineNumber))"
        }
        finally {
            if($SyncHash.GUI.IsVisible){
                $SyncHash.GUI.Close()
            }
            $SyncHash.LogWatcher.Stop()
            $SyncHash.LogGUI = $false;
           # Unregister-Event -SourceIdentifier FileChanged -ErrorAction Ignore
            
            
        }

    }
    

 
   
}