IBTool.psm1

$script:ModuleRoot = $PSScriptRoot
$script:ModuleVersion = (Import-PowerShellDataFile -Path "$($script:ModuleRoot)\IBTool.psd1").ModuleVersion

# Detect whether at some level dotsourcing was enforced
$script:doDotSource = Get-PSFConfigValue -FullName IBTool.Import.DoDotSource -Fallback $false
if ($IBTool_dotsourcemodule) { $script:doDotSource = $true }

<#
Note on Resolve-Path:
All paths are sent through Resolve-Path/Resolve-PSFPath in order to convert them to the correct path separator.
This allows ignoring path separators throughout the import sequence, which could otherwise cause trouble depending on OS.
Resolve-Path can only be used for paths that already exist, Resolve-PSFPath can accept that the last leaf my not exist.
This is important when testing for paths.
#>


# Detect whether at some level loading individual module files, rather than the compiled module was enforced
$importIndividualFiles = Get-PSFConfigValue -FullName IBTool.Import.IndividualFiles -Fallback $false
if ($IBTool_importIndividualFiles) { $importIndividualFiles = $true }
if (Test-Path (Resolve-PSFPath -Path "$($script:ModuleRoot)\..\.git" -SingleItem -NewChild)) { $importIndividualFiles = $true }
if ("<was compiled>" -eq '<was not compiled>') { $importIndividualFiles = $true }
    
function Import-ModuleFile
{
    <#
        .SYNOPSIS
            Loads files into the module on module import.
         
        .DESCRIPTION
            This helper function is used during module initialization.
            It should always be dotsourced itself, in order to proper function.
             
            This provides a central location to react to files being imported, if later desired
         
        .PARAMETER Path
            The path to the file to load
         
        .EXAMPLE
            PS C:\> . Import-ModuleFile -File $function.FullName
     
            Imports the file stored in $function according to import policy
    #>

    [CmdletBinding()]
    Param (
        [string]
        $Path
    )
    
    $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath
    if ($doDotSource) { . $resolvedPath }
    else { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($resolvedPath))), $null, $null) }
}

#region Load individual files
if ($importIndividualFiles)
{
    # Execute Preimport actions
    foreach ($path in (& "$ModuleRoot\internal\scripts\preimport.ps1")) {
        . Import-ModuleFile -Path $path
    }
    
    # Import all internal functions
    foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore))
    {
        . Import-ModuleFile -Path $function.FullName
    }
    
    # Import all public functions
    foreach ($function in (Get-ChildItem "$ModuleRoot\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore))
    {
        . Import-ModuleFile -Path $function.FullName
    }
    
    # Execute Postimport actions
    foreach ($path in (& "$ModuleRoot\internal\scripts\postimport.ps1")) {
        . Import-ModuleFile -Path $path
    }
    
    # End it here, do not load compiled code below
    return
}
#endregion Load individual files

#region Load compiled code
<#
This file loads the strings documents from the respective language folders.
This allows localizing messages and errors.
Load psd1 language files for each language you wish to support.
Partial translations are acceptable - when missing a current language message,
it will fallback to English or another available language.
#>

Import-PSFLocalizedString -Path "$($script:ModuleRoot)\en-us\*.psd1" -Module 'IBTool' -Language 'en-US'

function Add-ArrayToDataGrid {
    <#
    .SYNOPSIS
    Adds passed data to the DataGrid
     
    .DESCRIPTION
    Adds passed Array data to the DataGrid
     
    .PARAMETER ArrayData
    Array data source to add to the DataGrid
 
    .PARAMETER DataGrid
    DataGrid object to add the array data.
     
    .PARAMETER Form
    Windows main Form to be refreshed.
 
    .EXAMPLE
    PS C:\> Add-ArrayToDataGrid -ArrayData $MyData -DataGrid $MyGrid
    Adds array data '$MyData' to the DataGrid '$MyGrid'
    #>

    [CmdletBinding()]
    param (
        [System.Collections.ArrayList]$ArrayData,

        [System.Windows.Forms.DataGridView]$DataGrid,

        [System.Windows.Forms.Form]$Form
    )
    $DataGrid.datasource = $ArrayData
    $DataGrid.AutoResizeColumns()
    $Form.Refresh()
}

function Assert-ServiceConnection {
    <#
    .SYNOPSIS
    Checks current connection status for SCC, EXO and AzureAD
     
    .DESCRIPTION
    Checks current connection status for SCC, EXO and AzureAD
 
    .EXAMPLE
    PS C:\> Assert-ServiceConnection
    Checks current connection status for SCC, EXO and AzureAD
    #>

    [OutputType([System.Collections.ArrayList])]
    [CmdletBinding()]
    param (
        # Parameters
    )
    $Sessions = Get-PSSession
    $ServicesToConnect = New-Object -TypeName "System.Collections.ArrayList"

    # Check if SCC connection
    if ( -not ($Sessions.ComputerName -match "ps.compliance.protection.outlook.com") ) { $null = $ServicesToConnect.add("SCC") }

    # Check if EXO connection
    if ( $Sessions.ComputerName -notcontains "outlook.office365.com" ) { $null = $ServicesToConnect.add("EXO") }

    # Connecting to AzAccount
    $azContext = Get-AzContext
    if ( -not($null -eq $azContext) ) {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Azure context is connected with: $($azcontext.Account). If it is not correct, click on the button 'Change AzContext Account'" -DefaultColor Yellow
    }
    else {
        $null = $ServicesToConnect.add("AzAccount")
    }
    
    return $ServicesToConnect
}

function Connect-OnlineServices {
    <#
    .SYNOPSIS
    Connect to Online Services.
 
    .DESCRIPTION
    Use this function to connect to EXO, SCC, MicrosoftTeams, MS Online and AzureAD Online Services.
 
    .PARAMETER Credential
    Credential to use for the connection.
 
    .PARAMETER Services
    List of the desired services to connect to. Current available services: EXO, SCC, MicrosoftTeams, MSOnline, AzureAD, AzureADPreview, Azure.
 
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
    
    .EXAMPLE
    PS C:\> Connect-OnlineServices -Credential $UserCredential -EXO -AzureAD
    Connects to Exchange and AzureAD Online Services with the passed User Credentials variable.
     
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    param(
        #[PSCredential]
        #$Credential = (Get-Credential -Message "Please specify O365 Global Admin Credentials"),

        [ValidateSet('EXO', 'SCC', 'MicrosoftTeams', 'MSOnline', 'AzureAD', 'AzureADPreview', 'Azure', 'AzAccount')]
        [String[]]
        $Services
    )
    if(-not $Credential){
        $Credential = Get-Credential -Message "Please specify O365 Global Admin Credentials"
    }
    if(-not $Credential){
        Stop-PSFFunction -Message "Credentials entered are invalid." -EnableException $true -Cmdlet $PSCmdlet
    }

    Switch ( $Services ) {
        Azure {
            Invoke-PSFProtectedCommand -Action "Connecting to Azure" -Target "Azure" -ScriptBlock {
                Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Connecting to Azure"
                Install-Module Azure -Force -ErrorAction Stop
                Import-Module Azure -ErrorAction Stop
            } -EnableException $true -PSCmdlet $PSCmdlet
        }

        AzAccount {
            Invoke-PSFProtectedCommand -Action "Connecting to Az.Accounts" -Target "Az.Accounts" -ScriptBlock {
                Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Connecting to Az.Accounts"
                $null = Connect-AzAccount -Credential $Credential -ErrorAction Stop
            } -EnableException $true -PSCmdlet $PSCmdlet
        }

        AzureAD {
            Invoke-PSFProtectedCommand -Action "Connecting to AzureAD" -Target "AzureAD" -ScriptBlock {
                Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Connecting to AzureAD"
                if ( !(Get-Module AzureAD -ListAvailable) -and !(Get-Module AzureAD) ) {
                    Install-Module AzureAD -Force -ErrorAction Stop
                }
                try {
                    Import-module AzureAD
                    $null = Connect-AzureAD -Credential $Credential -ErrorAction Stop
                }
                catch {
                    if ( ($_.Exception.InnerException.InnerException.InnerException.InnerException.ErrorCode | ConvertFrom-Json).error -eq 'interaction_required' ) {
                        Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Your account seems to be requiring MFA to connect to Azure AD. Requesting to authenticate"
                        $null = Connect-AzureAD -AccountId $Credential.UserName.toString() -ErrorAction Stop
                    }
                    else {
                        return $_
                    }
                }
            } -EnableException $true -PSCmdlet $PSCmdlet
        }

        AzureADPreview {
            Invoke-PSFProtectedCommand -Action "Connecting to AzureAD Preview" -Target "AzureAD" -ScriptBlock {
                Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Connecting to AzureAD Preview"
                if ( !(Get-Module AzureADPreview -ListAvailable) -and !(Get-Module AzureADPreview) ) {
                    Install-Module AzureADPreview -Force -ErrorAction Stop
                }
                try {
                    Import-module AzureADPreview
                    $null = Connect-AzureAD -Credential $Credential -ErrorAction Stop
                }
                catch {
                    if ( ($_.Exception.InnerException.InnerException.InnerException.InnerException.ErrorCode | ConvertFrom-Json).error -eq 'interaction_required' ) {
                        Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Your account seems to be requiring MFA to connect to Azure AD. Requesting to authenticate"
                        $null = Connect-AzureAD -AccountId $Credential.UserName.toString() -ErrorAction Stop
                    }
                    else {
                        return $_
                    }
                }
            } -EnableException $true -PSCmdlet $PSCmdlet
        }

        MSOnline {
            Invoke-PSFProtectedCommand -Action "Connecting to MSOnline" -Target "MSOnline" -ScriptBlock {
                Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Connecting to MSOnline"
                if ( !(Get-Module MSOnline -ListAvailable) -and !(Get-Module MSOnline) ) {
                    Install-Module MSOnline -Force -ErrorAction Stop
                }
                try {
                    Import-Module MSOnline
                    Connect-MsolService -Credential $Credential -ErrorAction Stop
                }
                catch {
                    Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Your account seems to be requiring MFA to connect to MS Online. Requesting to authenticate"
                    Connect-MsolService -ErrorAction Stop
                }
            } -EnableException $true -PSCmdlet $PSCmdlet
        }

        MicrosoftTeams {
            Invoke-PSFProtectedCommand -Action "Connecting to MicrosoftTeams" -Target "MicrosoftTeams" -ScriptBlock {
                Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Connecting to MicrosoftTeams"
                if ( !(Get-Module MicrosoftTeams -ListAvailable) -and !(Get-Module MicrosoftTeams) ) {
                    Install-Module MicrosoftTeams -Force -ErrorAction Stop
                }
                try {
                    #Connect to Microsoft Teams
                    $null = Connect-MicrosoftTeams -Credential $Credential -ErrorAction Stop
    
                    #Connection to Skype for Business Online and import into Ps session
                    $session = New-CsOnlineSession -Credential $Credential -ErrorAction Stop
                    $null = Import-PsSession $session
                }
                catch {
                    if ( ($_.Exception.InnerException.InnerException.InnerException.InnerException.ErrorCode | ConvertFrom-Json).error -eq 'interaction_required' ) {
                        Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Your account seems to be requiring MFA to connect to MicrosoftTeams. Requesting to authenticate"
                        #Connect to Microsoft Teams
                        $null = Connect-MicrosoftTeams -ErrorAction Stop
    
                        #Connection to Skype for Business Online and import into Ps session
                        $session = New-CsOnlineSession -ErrorAction Stop
                        $null = Import-PsSession $session
                    }
                    else {
                        return $_
                    }
                }
            } -EnableException $true -PSCmdlet $PSCmdlet
        }

        SCC {
            Invoke-PSFProtectedCommand -Action "Connecting to Security and Compliance" -Target "SCC" -ScriptBlock {
                Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Connecting to Security and Compliance"
                try {
                    Connect-IPPSSession -Credential $Credential -ErrorAction Stop -WarningAction SilentlyContinue
                }
                catch {
                    if ( ($_.Exception.InnerException.InnerException.InnerException.InnerException.ErrorCode | ConvertFrom-Json).error -eq 'interaction_required' ) {
                        Write-PSFHostColor -String  "[$((Get-Date).ToString("HH:mm:ss"))] Your account seems to be requiring MFA to connect to Security and Compliance. Requesting to authenticate"
                        Connect-IPPSSession -UserPrincipalName $Credential.Username.toString() -ErrorAction Stop -WarningAction SilentlyContinue
                    }
                    else {
                        return $_
                    }
                }
            } -EnableException $true -PSCmdlet $PSCmdlet
        }

        EXO {
            Invoke-PSFProtectedCommand -Action "Connecting to Exchange Online" -Target "EXO" -ScriptBlock {
                Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Connecting to Exchange Online"
                try {
                    # Getting current PS Sessions
                    $Sessions = Get-PSSession
                    if ($Sessions.ComputerName -eq "outlook.office365.com") { return }
                    else { Connect-ExchangeOnline -Credential $Credential -ShowBanner:$False -ErrorAction Stop }
                }
                catch {
                    if ( $_.Exception.InnerException.Message.StartsWith("AADSTS50076") ) {
                        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Your account seems to be requiring MFA to connect to Exchange Online. Requesting to authenticate"
                        Connect-ExchangeOnline -UserPrincipalName $Credential.Username.toString() -ShowBanner:$False -ErrorAction Stop
                    }
                    else {
                        return $_
                    }
                }
            } -EnableException $true -PSCmdlet $PSCmdlet
        }
    }
}

Function Get-AuditLogStatus {
    <#
    .SYNOPSIS
    Function to check Audit log status in the tenant.
     
    .DESCRIPTION
    Function to check Audit log status in the tenant.
     
    .EXAMPLE
    PS C:\> Get-AuditLogStatus
    Function to check Audit log status in the tenant.
    #>

    [cmdletbinding()]
    Param(
        # Parameters
    )
    # Verify Audit Logging is enabled
    Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Verifing if Audit Logging is enabled."
    if ( -not (Get-AdminAuditLogConfig).UnifiedAuditLogIngestionEnabled ){
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Audit Logging is not enabled. please run 'Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled `$true' and wait at least 1 hour." -DefaultColor Red
        $labelAuditLogStatusValue.ForeColor = "Red"
        $labelAuditLogStatusValue.Text = "False"
    }
    else{
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Audit Logging is enabled." -DefaultColor Green
        $labelAuditLogStatusValue.ForeColor = "Green"
        $labelAuditLogStatusValue.Text = "True"
    }
}

Function Get-ExchangeABPStatus {
    <#
    .SYNOPSIS
    Function to verify if Exchange AddressBook Policies are in place.
     
    .DESCRIPTION
    Function to verify if Exchange AddressBook Policies are in place.
     
    .EXAMPLE
    PS C:\> Get-ExchangeABPStatus
    Function to verify if Exchange AddressBook Policies are in place.
    #>

    [CmdletBinding()]
    Param(
        # Parameters
    )
    # Verify no Exchange AddressBook Policies are in place
    Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Verifing if no Exchange AddressBook Policies are in place."
    if ( Get-AddressBookPolicy ){
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Existing Address Book Policies in Exchange will get in conflict with Information Barriers." -DefaultColor Red
        $labelABPStatusValue.ForeColor = "Red"
        $labelABPStatusValue.Text = "False"
    }
    else{
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] No Exchange AddressBook Policies were found." -DefaultColor Green
        $labelABPStatusValue.ForeColor = "Green"
        $labelABPStatusValue.Text = "True"
    }
}

Function Get-IBPolicies {
    <#
    .SYNOPSIS
    This function gets the current Information Barriers Policies in the tenant.
     
    .DESCRIPTION
    This function gets the current Information Barriers Policies in the tenant.
 
    .PARAMETER ShowOutputLine
    Use this switch to show a small output line to Powershell session.
     
    .EXAMPLE
    PS C:\> Get-IBPolicies
    This function gets the current Information Barriers Policies in the tenant.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [OutputType([System.Collections.ArrayList])]
    [CmdletBinding()]
    Param(
        [Switch]$ShowOutputline
    )
    if ( $ShowOutputline ) { Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Getting current Information Barriers Policies." }
    $statusBarLabel.Text = "Running..."
    $array = New-Object System.Collections.ArrayList
    $array.AddRange( (Get-InformationBarrierPolicy | Select-Object Name, State, AssignedSegment, SegmentsAllowed, SegmentsBlocked, block*) )
    $statusBarLabel.Text = "Ready. IB Policies found: $($array.count)"
    return $array
}

Function Get-IBPoliciesAppStatus {
    <#
    .SYNOPSIS
    This function will get the current Information Barriers Policies Application Status.
     
    .DESCRIPTION
    This function will get the current Information Barriers Policies Application Status.
     
    .PARAMETER ShowOutputLine
    Use this switch to show a small output line to Powershell session.
 
    .EXAMPLE
    PS C:\> Get-IBPoliciesAppStatus
    This function will get the current Information Barriers Policies Application Status.
 
    #>

    [OutputType([System.Collections.ArrayList])]
    [CmdletBinding()]
    param (
        [Switch]$ShowOutputline
    )
    if ( $ShowOutputline ) { Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Getting current Information Barriers Policies Application status." }
    $statusBarLabel.Text = "Running..."
    $array = New-Object System.Collections.ArrayList
    $results = Get-InformationBarrierPoliciesApplicationStatus -All:$true | Select-Object Identity, ApplicationStartTime, ApplicationEndTime, Status, PercentProgress
    $results | ForEach-Object { $null = $array.Add($_) }
    $statusBarLabel.Text = "Ready."
    return $array
}

function Get-IBPoliciesRecipientStatus {
    <#
    .SYNOPSIS
    This function gets the current Information Barrier Recipient status.
     
    .DESCRIPTION
    This function gets the current Information Barrier Recipient status between 2 users.
     
    .PARAMETER User1
    Defines the first user identity to compare.
    You can use any value that uniquely identifies each user, such as name, alias, distinguished name, canonical domain name, email address, or GUID.
 
    .PARAMETER User2
    Defines the second user identity to compare.
    You can use any value that uniquely identifies each user, such as name, alias, distinguished name, canonical domain name, email address, or GUID.
     
    .PARAMETER ShowOutputLine
    Use this switch to show a small output line to Powershell session.
     
    .EXAMPLE
    PS C:\> Get-IBPoliciesRecipientStatus -User1 "john@contoso.com" -User2 "mark@contoso.com"
    This function gets the current Information Barrier Recipient status between john@contoso.com and mark@contoso.com.
     
    #>

    [OutputType([System.Collections.ArrayList])]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, HelpMessage = "Defines the first user identity to compare.")]
        [string]$user1,

        [Parameter(Mandatory = $true, HelpMessage = "Defines the second user identity to compare.")]
        [string]$user2,

        [Switch]$ShowOutputline
    )
    if ( $ShowOutputline ) { Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Getting current information Barrier Recipient status between $user1 and $user2." }
    $statusBarLabel.Text = "Running..."
    #$array = New-Object System.Collections.ArrayList
    $array = New-Object System.Collections.ArrayList
    $SegmentsFound1 = New-Object System.Collections.ArrayList
    $SegmentsFound2 = New-Object System.Collections.ArrayList
    $AllSegments = get-OrgSegments
    foreach ($segment in $AllSegments){
        $Members = Get-SegmentMembers -SegmentName $segment.name
        if ( $Members.PrimarySMTPAddress -eq $user1 ) { $null = $SegmentsFound1.add($segment) }
        if ( $Members.PrimarySMTPAddress -eq $user2 ) { $null = $SegmentsFound2.add($segment) }
    }
    $matchedPolicies = Get-IBPolicies | Where-Object { $_.AssignedSegment -eq $SegmentsFound1.name -and ($_.SegmentsAllowed -match $SegmentsFound2.name -or $_.SegmentsBlocked -match $SegmentsFound2.name)}
    $matchedPolicies | ForEach-Object { $null = $array.Add( $_ ) }

    $statusBarLabel.Text = "Ready. Matched: $($array.count)"
    return $array
}

function Get-IBServicePrincipal {
    <#
    .SYNOPSIS
    This function gets the current Information Barriers Service Principal in the tenant.
     
    .DESCRIPTION
    This function gets the current Information Barriers Service Principal in the tenant.
     
    .EXAMPLE
    PS C:\> Get-IBServicePrincipal
    This function gets the current Information Barriers Service Principal in the tenant.
    #>

    [CmdletBinding()]
    param (
        # Parameters
    )
    Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Getting Information Barriers Service Principal."
    #$Sp = Get-AzureADServicePrincipal -All:$True | Where-Object appid -eq "bcf62038-e005-436d-b970-2a472f8c1982"
    $Sp = Get-AzADServicePrincipal | Where-Object ApplicationId -eq "bcf62038-e005-436d-b970-2a472f8c1982"
    if ($null -eq $sp) {
        $labelIBServicePrincipalValue.ForeColor = "Red"
        $labelIBServicePrincipalValue.Text = "False"
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Information Barriers Service Principal not found." -DefaultColor "Red"

        $buttonChangeAzContext = New-Object System.Windows.Forms.Button
        $buttonChangeAzContext.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonChangeAzContext.ForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
        $buttonChangeAzContext.Location = New-Object System.Drawing.Point(270,78)
        $buttonChangeAzContext.Size = New-Object System.Drawing.Size(250,25)
        $buttonChangeAzContext.Name = "NewServicePrincipal"
        $buttonChangeAzContext.Text = "Add Service Principal and Grant consent"
        $buttonChangeAzContext.UseVisualStyleBackColor = $True
        $buttonChangeAzContext.add_Click({New-IBServicePrincipal})
        $MainForm.Controls.Add($buttonChangeAzContext)
    }
    else{
        $labelIBServicePrincipalValue.ForeColor = "Green"
        $labelIBServicePrincipalValue.text = "True"
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Information Barriers Service Principal found." -DefaultColor "Green"
    }
}

Function Get-OrgSegments {
    <#
    .SYNOPSIS
    This function gets the current Organization Segments in the tenant.
     
    .DESCRIPTION
    This function gets the current Organization Segments in the tenant.
     
    .PARAMETER ShowOutputLine
    Use this switch to show a small output line to Powershell session.
 
    .EXAMPLE
    PS C:\> Get-OrgSegments
    This function gets the current Organization Segments in the tenant.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [OutputType([System.Collections.ArrayList])]
    [CmdletBinding()]
    Param(
        [Switch]$ShowOutputline
    )
    if ( $ShowOutputline ) { Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Getting current Organization Segments." }
    $statusBarLabel.Text = "Running..."
    $array = New-Object System.Collections.ArrayList
    $array.AddRange( (Get-OrganizationSegment | Select-Object Name,UserGroupFilter,CreatedBy,WhenCreated) )

    $statusBarLabel.Text = "Ready. Segments found: $($array.count)"
    return $array
}

function Get-SegmentMembers {
    <#
    .SYNOPSIS
    This function gets the current Organization Segment members.
 
    .DESCRIPTION
    This function gets the current Organization Segment members for the specified Segment.
 
    .PARAMETER SegmentName
    Defines the Organization Segment name.
 
    .PARAMETER ShowOutputLine
    Use this switch to show a small output line to Powershell session.
     
 
    .EXAMPLE
    PS C:\> Get-SegmentMembers -SegmentName "HR Members"
    Gets the current members for the Organization Segment named 'HR Members'.
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [OutputType([System.Collections.ArrayList])]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $True, HelpMessage = "Enter Organization Segment Name.")]
        [String]$SegmentName,

        [Switch]$ShowOutputline
    )
    if ( $ShowOutputline ) { Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Getting Organization Segment Members." }
    $statusBarLabel.Text = "Running..."
    $array = New-Object System.Collections.ArrayList
    $filter = (Get-OrganizationSegment -Identity $SegmentName).UserGroupFilter
    try { $array.AddRange( (Get-EXORecipient -Filter $filter -ResultSize Unlimited | Select-Object Name,PrimarySMTPAddress,*recipientType* ) ) }
    catch {
        $null
    }

    $statusBarLabel.Text = "Ready. Members found: $($array.count)"
    return $array
}

function Get-UnifiedLog {
    <#
    .SYNOPSIS
    Function to get Unified audit logs for InformationBarrierPolicyApplication.
     
    .DESCRIPTION
    Function to get Unified audit logs for InformationBarrierPolicyApplication.
     
    .PARAMETER StartDate
    Date to search audit logs from.
     
    .PARAMETER EndDate
    Date to search audit logs until.
     
    .PARAMETER AppId
    InformationBarrierPolicyApplication Identity to search audits for.
     
    .EXAMPLE
    PS C:\> Get-UnifiedLog -StartDate "01/19/2021" -EndDate "02/19/2021" -AppId "74c593f9-beca-45a2-b77e-cbf36fcfbd81"
 
    The function will search for all logs about InformationBarrierPolicyApplication related to AppId "74c593f9-beca-45a2-b77e-cbf36fcfbd81" between "01/19/2021" and "02/19/2021".
    #>

    [OutputType([System.Collections.ArrayList])]
    [CmdletBinding()]
    Param (
        [datetime]$StartDate,
        [datetime]$EndDate,
        [String]$AppId
    )
    Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Searching Unified Audit Logs."
    $statusBarLabel.Text = "Running..."
    
    $records = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -RecordType InformationBarrierPolicyApplication -ResultSize 5000 -ObjectIds $AppId
    if ($null -ne $records) {
        $array = New-Object System.Collections.ArrayList
        $array.AddRange( ($records.auditdata | convertfrom-json | Select-Object CommandId, CommandStarted, CommandType, CreationTime, EndTime, GalChangeType, Id, ObjectId, Operation, OrganizationId, policyChangeType, recipientId, RecordType, StartTime, UserId, UserKey, UserType, Version, Workload) )
        $statusBarLabel.Text = "Ready. Records found: $($records.Count)"
        return $array
    }
    else {
        $statusBarLabel.Text = "Ready. No records found"
    }
}


function New-IBPolicy
{
    <#
    .SYNOPSIS
    Creates a new Information Barrier policy.
     
    .DESCRIPTION
    Creates a new Information Barrier policy.
     
    .PARAMETER PolicyName
    Defines the Information Barrier Policy Name.
     
    .PARAMETER AssignedSegment
    Defines the assigned segment to the policy.
     
    .PARAMETER AssignedAction
    Defines the Policy action to Allow or Block to other segments.
     
    .PARAMETER AorBSegments
    Defines the segment(s) to be Allowed or Blocked in the policy.
     
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
     
    .EXAMPLE
    PS C:\> New-IBPolicy -PolicyName "Allowed HR to Sales" -AssignedSegment "HR" -AssignedAction "SegmentsAllowed" -AorBSegments "Sales"
    This function will create the new Information Barrier policy named "Allowed HR to Sales" allowing communications to "Sales" team.
 
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param (
        [Parameter(Mandatory = $true, HelpMessage = "Defines the Information Barrier Policy Name.")]
        [String]$PolicyName,

        [Parameter(Mandatory = $true, HelpMessage = "Defines the assigned segment to the policy.")]
        [String]$AssignedSegment,

        [ValidateSet('SegmentsAllowed','SegmentsBlocked')]
        [Parameter(Mandatory = $true, HelpMessage = "Defines the Policy action to Allow or Block to other segments.")]
        [String]$AssignedAction,

        [Parameter(Mandatory = $true, HelpMessage = "Defines the segment(s) to be Allowed or Blocked in the policy.")]
        [String]$AorBSegments
    )
    $statusBarLabel.Text = "Running..."
    try {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Creating new Information Barrier Policy '$PolicyName'."
        $segmentsList = New-Object System.Collections.ArrayList
        $List = $AorBSegments.replace("'",'').split(",")
        foreach ($item in $list) { $null = $segmentsList.add($item.Trim() ) }

        if ($AssignedAction -eq "SegmentsAllowed") {
            $null = $segmentsList.add( $AssignedSegment )
            New-InformationBarrierPolicy -Name $PolicyName -AssignedSegment $AssignedSegment -SegmentsAllowed $segmentsList -State Inactive -Confirm:$False -ErrorAction Stop
        }
        else {
            New-InformationBarrierPolicy -Name $PolicyName -AssignedSegment $AssignedSegment -SegmentsBlocked $segmentsList -State Inactive -Confirm:$False -ErrorAction Stop
        }
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Successfully created Information Barrier Policy '$PolicyName'."
        $statusBarLabel.Text = "Ready. Created Information Barrier Policy '$PolicyName'."
    }
    catch {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Something failed to create the new Information Barrier Policy '$PolicyName'. $_"
        $statusBarLabel.Text = "Ready. Someting failed to create the new Information Barrier Policy '$PolicyName'. Please see the Powershell window to verify error message."
    }
}

function New-IBServicePrincipal {
    <#
    .SYNOPSIS
    This function creates a new Information Barriers Service Principal in the tenant.
     
    .DESCRIPTION
    This function creates a new Information Barriers Service Principal in the tenant.
 
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
 
    .EXAMPLE
    PS C:\> New-IBServicePrincipal
    This function creates a new Information Barriers Service Principal in the tenant.
 
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    param (
        # Parameters
    )
    Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Creating new Information Barriers Service Principal in AzureAD."
    #$newSP = New-AzureADServicePrincipal -AppId "bcf62038-e005-436d-b970-2a472f8c1982" -ErrorAction Stop
    $newSP = New-AzADServicePrincipal -ApplicationId "bcf62038-e005-436d-b970-2a472f8c1982" -ErrorAction Stop
    #Start-Process "https://login.microsoftonline.com/common/adminconsent?client_id=$($newSp.appId)"
    Start-Process "https://login.microsoftonline.com/common/adminconsent?client_id=$($newSp.applicationId)"
    
    # Refresh IB Service Principal Status
    Get-IBServicePrincipal
    $MainForm.Controls.RemoveByKey("NewServicePrincipal")
    $MainForm.Refresh()

    <#
    $AdminObjectId = (get-AzureAdUser -searchstring (Get-AzureADCurrentSessionInfo).Account).ObjectId
 
    if ( -not (Get-AzureADServiceAppRoleAssignment -ObjectId $newsp.ObjectId -All:$true | Where-Object {$_.PrincipalId -eq $AdminObjectId}) ){
        $AppRoleAssignment = $newSP | New-AzureADServiceAppRoleAssignment -PrincipalId $AdminObjectId -ResourceId $newSP.ObjectId -id "00000000-0000-0000-0000-000000000000" -ErrorAction Stop
    }
 
    if ( -not (Get-AzureADServicePrincipalOAuth2PermissionGrant -ObjectId $newSP.ObjectId -All:$True) ){
        $TenantId = (Get-AzureADTenantDetail).objectid
 
        $result = Login-AzAccount -Credential $credential -ErrorAction Stop
        $context = Get-AzContext
        $refreshToken = @($context.TokenCache.ReadItems() | Where-Object {$_.tenantId -eq $tenantId -and $_.ExpiresOn -gt (Get-Date)}).AccessToken
        $body = "grant_type=refresh_token&refresh_token=$($refreshToken)&resource=$($newsp.ObjectId)"
        $apiToken = Invoke-RestMethod "https://login.windows.net/$tenantId/oauth2/token" -Method POST -Body $body -ContentType 'application/x-www-form-urlencoded' -ErrorAction Stop
        $header = @{
            'Authorization' = 'Bearer ' + $apiToken.access_token
            'X-Requested-With'= 'XMLHttpRequest'
            'x-ms-client-request-id'= [guid]::NewGuid()
            'x-ms-correlation-id' = [guid]::NewGuid()}
        $url = "https://main.iam.ad.ext.azure.com/api/RegisteredApplications/$($newSP.AppId)/Consent?onBehalfOfAll=true"
        Invoke-RestMethod –Uri $url –Headers $header –Method POST -ErrorAction Stop
    }
    #>

}

function New-OrgSegment
{
    <#
    .SYNOPSIS
    Creates a new organization Segment.
     
    .DESCRIPTION
    Creates a new organization Segment to be used in Information Barriers.
     
    .PARAMETER Name
    Defines the Organization Segment Name.
     
    .PARAMETER GroupFilter
    Defines the User Group filter attribute to be use.
     
    .PARAMETER Comparison
    Defines the condition's comparison. Can be "Equals" or "Not Equals".
     
    .PARAMETER AttributeValue
    Defines the attribute value.
     
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
    
    .EXAMPLE
    PS C:\> New-OrgSegment -Name "test users" -GroupFilter "Company" -Comparison "equals" -AttributeValue "Contoso.com"
    This command will create the new Organization Segment named "Test users" based on the "Company" user's attribute, being Equals to "Contoso.com".
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param (
        [Parameter(Mandatory = $true, HelpMessage = "Defines the Organization Segment Name.")]
        [String]$Name,

        [Parameter(Mandatory = $true, HelpMessage = "Defines the User Group filter attribute to be use.")]
        [String]$GroupFilter,

        [Parameter(Mandatory = $true, HelpMessage = "Defines the condition comparison.")]
        [String]$Comparison,

        [Parameter(Mandatory = $true, HelpMessage = "Defines the attribute value.")]
        [String]$AttributeValue
    )
    if ($Comparison -eq "Equals") {$comp = "eq"}
    else {$comp = "ne"}

    $statusBarLabel.Text = "Running..."
    try {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Creating / editing Organization Segment '$Name'."
        if ( Get-OrganizationSegment -identity $Name ) {
            Set-OrganizationSegment -identity $name -UserGroupFilter "$GroupFilter -$comp '$AttributeValue'" -ErrorAction Stop
        }
        else {
            New-OrganizationSegment -Name $Name -UserGroupFilter "$GroupFilter -$comp '$AttributeValue'" -errorAction Stop
        }
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Successfully created / modified Organization Segment '$Name'."
        $statusBarLabel.Text = "Ready. Created / edited Organization Segment '$Name'."
    }
    catch {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Something failed to create / edit the Organization Segment '$Name'. $_"
        $statusBarLabel.Text = "Ready. Someting failed to create / edit the Organization Segment '$Name'. Please see the Powershell window to verify error message."
    }
}

function Remove-IBPolicy
{
    <#
    .SYNOPSIS
    Removes an Information Barrier Policy.
     
    .DESCRIPTION
    Removes an Information Barrier Policy to be used in Information Barriers.
     
    .PARAMETER Identity
    Defines the Information Barrier Policy Name to be removed.
     
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
    
    .EXAMPLE
    PS C:\> Remove-IBPolicy -Identity "Manager Users"
    This command will remove the Information Barrier Policy named "Manager Users".
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param (
        [String]$Identity
    )
    $statusBarLabel.Text = "Running..."
    try {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Removing Information Barrier Policy '$Identity'."

        Remove-InformationBarrierPolicy -Identity $Identity -Confirm:$false -ErrorAction Stop

        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Successfully removed Information Barrier Policy '$Identity'."
        $statusBarLabel.Text = "Ready. Removed Information Barrier Policy '$Identity'."
    }
    catch {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Something failed to remove the Information Barrier Policy '$Identity'. $_"
        $statusBarLabel.Text = "Ready. Someting failed to remove the Information Barrier Policy '$Identity'. Please see the Powershell window to verify error message."
    }
}


function Remove-OrgSegment
{
    <#
    .SYNOPSIS
    Removes an organization Segment.
     
    .DESCRIPTION
    Removes an organization Segment to be used in Information Barriers.
     
    .PARAMETER Identity
    Defines the Organization Segment Name to be removed.
     
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
    
    .EXAMPLE
    PS C:\> Remove-OrgSegment -Identity "Manager Users"
    This command will remove the Organization Segment named "Manager Users".
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param (
        [String]$Identity
    )
    $statusBarLabel.Text = "Running..."
    try {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Removing Organization Segment '$Identity'."

        Remove-OrganizationSegment -Identity $Identity -Confirm:$false -ErrorAction Stop

        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Successfully removed Organization Segment '$Identity'."
        $statusBarLabel.Text = "Ready. Removed Organization Segment '$Identity'."
    }
    catch {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Something failed to remove the Organization Segment '$Identity'. $_"
        $statusBarLabel.Text = "Ready. Someting failed to remove the Organization Segment '$Identity'. Please see the Powershell window to verify error message."
    }
}


function Start-IBpolicyApp {
    <#
    .SYNOPSIS
    Function to start Information Barrier Policies application to users
     
    .DESCRIPTION
    Function to start Information Barrier Policies application to users.
    Allow 30 minutes for the system to start applying the policies. The system applies policies user by user. The system processes about 5,000 user accounts per hour.
     
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
    
    .EXAMPLE
    PS C:\> Start-IBpolicyApp
    Executes Start-InformationBarrierPoliciesApplication
 
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param (
        # Parameters
    )
    $statusBarLabel.Text = "Running..."
    try {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Setting all IB Policies status to 'Active'."
        Get-InformationBarrierPolicy | ForEach-Object { Set-InformationBarrierPolicy -Identity $_.name -State active -Confirm:$false -force -WarningAction SilentlyContinue }
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Starting to apply Information Barrier Policies application."
        Start-InformationBarrierPoliciesApplication -ErrorAction Stop
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Started successfully. Allow 30 minutes for the system to start applying the policies. The system applies policies user by user. The system processes about 5,000 user accounts per hour."
        $statusBarLabel.Text = "Ready. Started successfully."
    }
    catch {
        Write-PSFHostColor -String "[$((Get-Date).ToString("HH:mm:ss"))] Something failed to start applying Information Barrier Policies application. $_"
    }
}


Function Start-ModuleUpdate {
    <#
    .SYNOPSIS
    Function to start checking for updates on this module.
     
    .DESCRIPTION
    Function to start checking for updates on this module.
     
    .PARAMETER ModuleRoot
    Modules root path.
 
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
     
    .EXAMPLE
    PS C:\> Start-ModuleUpdate -ModuleRoot "C:\Temp"
    Runs the function to start checking for update for current module in "C:\Temp"
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param (
        [String]$ModuleRoot
    )

    $ScriptBlock = {
        Param (
            [String]$ModuleRoot
        )
        $moduleManifest = (Import-PowerShellDataFile -Path "$((Get-ChildItem -Path $ModuleRoot -Filter *.psd1).Fullname)")
        $moduleFileName = $moduleManifest.RootModule
        $moduleName = $ModuleFileName.Substring(0, $ModuleFileName.IndexOf("."))
        $script:ModuleVersion = $moduleManifest.ModuleVersion -as [version]

        $GalleryModule = Find-Module -Name $ModuleName -Repository PSGallery
        if ( $script:ModuleVersion -lt $GalleryModule.version ) {
            $bt = New-BTButton -Content "Get Update" -Arguments "$($moduleManifest.PrivateData.PSData.ProjectUri)#installation"
            New-BurntToastNotification -Text "$ModuleName Update found", 'There is a new version of this module available.' -Button $bt
        }
    }

    # Create Runspace, set maximum threads
    $pool = [RunspaceFactory]::CreateRunspacePool(1, 1)
    $pool.ApartmentState = "MTA"
    $pool.Open()

    $runspace = [PowerShell]::Create()
    $runspace.Runspace.Name = "$ModuleName.Update"
    $null = $runspace.AddScript( $ScriptBlock )
    $null = $runspace.AddArgument( $ModuleRoot )
    $runspace.RunspacePool = $pool

    [PSCustomObject]@{
        Pipe   = $runspace
        Status = $runspace.BeginInvoke()
        Pool   = $pool
    }
}

Function Stop-ModuleUpdate {
    <#
    .SYNOPSIS
    Function to stop checking for updates on this module and clear runspaces.
     
    .DESCRIPTION
    Function to stop checking for updates on this module and clear runspaces.
     
    .PARAMETER RunspaceData
    Runspace data retrieved from intial Start-ModuleUpdate function.
 
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
     
    .EXAMPLE
    PS C:\> Stop-ModuleUpdate -RunspaceData $data
    Runs the function to stop checking for update on this module and clear runspaces.
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param(
        $RunspaceData
    )
    # Receive Results and cleanup
    $null = $RunspaceData.Pipe.EndInvoke($RunspaceData.Status)
    $RunspaceData.Pipe.Dispose()

    # Cleanup Runspace Pool
    $RunspaceData.pool.Close()
    $RunspaceData.pool.Dispose()
}

Function Start-IBTool {
    <#
    .SYNOPSIS
    Function to start the 'Information Barriers' tool.
     
    .DESCRIPTION
    Function to start the 'Information Barriers' tool.
     
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
 
    .EXAMPLE
    PS C:\> Start-IBTool
    This command will launch the 'Information Barriers' GUI tool.
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    param (
        # Parameters
    )
    # check for updates
    $runspaceData = Start-ModuleUpdate -ModuleRoot $script:ModuleRoot

    # Check current connection status, and connect if needed
    $ServicesToConnect = Assert-ServiceConnection
    # Connect to services if ArrayList is not empty
    if ( $ServicesToConnect.Count ) { Connect-OnlineServices -Services $ServicesToConnect }

    function GenerateForm {
        #region Import the Assemblies
        Add-Type -AssemblyName System.Windows.Forms
        Add-Type -AssemblyName System.Drawing
        Add-Type -AssemblyName Microsoft.VisualBasic
        [System.Windows.Forms.Application]::EnableVisualStyles()
        #endregion Import the Assemblies

        #region Creating required Forms Objects
        $MainForm = New-Object System.Windows.Forms.Form
        $statusBar = New-Object System.Windows.Forms.StatusStrip
        $statusBarLabel = New-Object System.Windows.Forms.ToolStripStatusLabel
        $labelTenantInfo = New-Object System.Windows.Forms.Label
        $labelAuditLogStatus = New-Object System.Windows.Forms.Label
        $labelAuditLogStatusValue = New-Object System.Windows.Forms.Label
        $labelABPStatus = New-Object System.Windows.Forms.Label
        $labelABPStatusValue = New-Object System.Windows.Forms.Label
        $labelIBServicePrincipal = New-Object System.Windows.Forms.Label
        $labelIBServicePrincipalValue = New-Object System.Windows.Forms.Label
        $HorizontalLine1 = New-Object System.Windows.Forms.Label
        $LabelGettingInfo = New-Object System.Windows.Forms.Label
        $buttonGetSegments = New-Object System.Windows.Forms.Button
        $buttonGetIBPolicies = New-Object System.Windows.Forms.Button
        $buttonGetIBPoliciesAppStatus = New-Object System.Windows.Forms.Button
        $HorizontalLine2 = New-Object System.Windows.Forms.Label
        $LabelGetOrgSegmentMemberTitle = New-Object System.Windows.Forms.Label
        $textBoxOrgSegment = New-Object System.Windows.Forms.TextBox
        $buttonGetSegmentMembers = New-Object System.Windows.Forms.Button
        $HorizontalLine3 = New-Object System.Windows.Forms.Label
        $LabelGetIBRecipientStatusTitle = New-Object System.Windows.Forms.Label
        $textBoxUser1 = New-Object System.Windows.Forms.TextBox
        $labelCompareWith = New-Object System.Windows.Forms.Label
        $textBoxUser2 = New-Object System.Windows.Forms.TextBox
        $buttonCompareIdentities = New-Object System.Windows.Forms.Button
        $HorizontalLine4 = New-Object System.Windows.Forms.Label
        $labelNewSegmentTitle = New-Object System.Windows.Forms.Label
        $labelNewSegmentHelp = New-Object System.Windows.Forms.Label
        $labelNewSegmentName = New-Object System.Windows.Forms.Label
        $textNewSegmentName = New-Object System.Windows.Forms.TextBox
        $labelUserGroupFilter = New-Object System.Windows.Forms.Label
        $comboBoxAttributelist = New-Object System.Windows.Forms.ComboBox
        $comboBoxComparison = New-Object System.Windows.Forms.ComboBox
        $textAttributeValue = New-Object System.Windows.Forms.TextBox
        $buttonCreateSegment = New-Object System.Windows.Forms.Button
        $HorizontalLine5 = New-Object System.Windows.Forms.Label
        $labelNewIBPolicyTitle = New-Object System.Windows.Forms.Label
        $labelNewIBPolicyName = New-Object System.Windows.Forms.Label
        $textNewIBPolicyName = New-Object System.Windows.Forms.TextBox
        $labelAssignSegment = New-Object System.Windows.Forms.Label
        $textAssignedSegment = New-Object System.Windows.Forms.TextBox
        $comboBoxSegmentAorB = New-Object System.Windows.Forms.ComboBox
        $textAorBSegment = New-Object System.Windows.Forms.TextBox
        $buttonCreateIBpolicy = New-Object System.Windows.Forms.Button
        $buttonStartIBPolicyApplication = New-Object System.Windows.Forms.Button
        $HorizontalLine6 = New-Object System.Windows.Forms.Label
        $labelRemoveIBPolicyTitle = New-Object System.Windows.Forms.Label
        $labelRemoveIBPolicyName = New-Object System.Windows.Forms.Label
        $textRemoveIBPolicyName = New-Object System.Windows.Forms.TextBox
        $buttonRemoveSegment = New-Object System.Windows.Forms.Button
        $buttonRemoveIBpolicy = New-Object System.Windows.Forms.Button
        $HorizontalLine7 = New-Object System.Windows.Forms.Label
        $labelSearchLogTitle = New-Object System.Windows.Forms.Label
        $labFromDate = New-Object System.Windows.Forms.Label
        $FromDatePicker = New-Object System.Windows.Forms.DateTimePicker
        $labToDate = New-Object System.Windows.Forms.Label
        $ToDatePicker = New-Object System.Windows.Forms.DateTimePicker
        $labelSearchAppLog = New-Object System.Windows.Forms.Label
        $textSeaarchAppLog = New-Object System.Windows.Forms.TextBox
        $buttonSearchAppLog = New-Object System.Windows.Forms.Button
        
        $dataGrid = New-Object System.Windows.Forms.DataGridView
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        #endregion Creating required Forms Objects

        #region Internal scriptblocks
        $OnLoadMainWindow_StateCorrection = { #Correct the initial state of the form to prevent the .Net maximized form issue
            $MainForm.WindowState = $InitialFormWindowState
        }

        $labelNewSegmentHelp_Click = {
            [Microsoft.VisualBasic.Interaction]::MsgBox("This option is to create or edit a simple Organization Segment. If you need to create a more complex segment with more attributes and combinations, please do them with powershell.
 
If you are trying to create a new Organization Segment with the same name as an existing one, we will overwrite the current one with the new settings.
 
More info at: https://docs.microsoft.com/en-us/microsoft-365/compliance/information-barriers-policies?view=o365-worldwide#part-1-segment-users
 
Press CTRL + C to copy this message to clipboard."
, [Microsoft.VisualBasic.MsgBoxStyle]::Okonly, "Information Message")
        }

        #endregion Internal scriptblocks

        #region Generated Form Code
        #
        # Main Form
        #
        $null = $statusBar.Items.Add($statusBarLabel)
        $statusBar.Name = "statusBar"
        $statusBarLabel.Text = "Ready..."
        $MainForm.Controls.Add($statusBar)
        $MainForm.ClientSize = New-Object System.Drawing.Size(1100, 920)
        $MainForm.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $MainForm.Name = "Main Form"
        $MainForm.Text = "Manage Information Barriers"
        $MainForm.StartPosition = "CenterScreen"
        $MainForm.KeyPreview = $True
        $MainForm.Add_KeyDown({
                if ( $_.KeyCode -eq "Escape" ) { $MainForm.Close() }
            })
        #
        # Label Tenant Info
        #
        $labelTenantInfo.Location = New-Object System.Drawing.Point(10, 10)
        $labelTenantInfo.Size = New-Object System.Drawing.Size(125, 20)
        $labelTenantInfo.Name = "labelTenantInfo"
        $labelTenantInfo.Text = "Tenant Info"
        $labelTenantInfo.Font = New-Object System.Drawing.Font("Arial", 8, [System.Drawing.FontStyle]::Bold)
        $MainForm.Controls.Add($labelTenantInfo)
        #
        # Button Change AzContext
        #
        if ( $ServicesToConnect -notcontains "AzAccount") {
            $buttonChangeAzContext = New-Object System.Windows.Forms.Button
            $buttonChangeAzContext.DataBindings.DefaultDataSourceUpdateMode = 0
            $buttonChangeAzContext.ForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
            $buttonChangeAzContext.Location = New-Object System.Drawing.Point(150,8)
            $buttonChangeAzContext.Size = New-Object System.Drawing.Size(250,25)
            $buttonChangeAzContext.Name = "ChangeAzContext"
            $buttonChangeAzContext.Text = "Change AzContext Account"
            $buttonChangeAzContext.UseVisualStyleBackColor = $True
            $buttonChangeAzContext.add_Click({Connect-AzAccount -ErrorAction Stop})
            $MainForm.Controls.Add($buttonChangeAzContext)
        }
        #
        # Label Audit Logging Status
        #
        $labelAuditLogStatus.Location = New-Object System.Drawing.Point(10, ($labelTenantInfo.Location.Y + 25))
        $labelAuditLogStatus.Size = New-Object System.Drawing.Size(125, 20)
        $labelAuditLogStatus.Name = "labelAuditLogStatus"
        $labelAuditLogStatus.Text = "Audit Logging Enabled:"
        $MainForm.Controls.Add($labelAuditLogStatus)
        #
        # Label Audit Logging Status Value
        #
        $labelAuditLogStatusValue.Location = New-Object System.Drawing.Point(155, ($labelTenantInfo.Location.Y + 25))
        $labelAuditLogStatusValue.Size = New-Object System.Drawing.Size(35, 20)
        $labelAuditLogStatusValue.Name = "labelAuditLogStatusValue"
        Get-AuditLogStatus
        $MainForm.Controls.Add($labelAuditLogStatusValue)
        #
        # Label Exchange Address Book Policy Status
        #
        $labelABPStatus.Location = New-Object System.Drawing.Point(10, ($labelAuditLogStatus.Location.Y + 25))
        $labelABPStatus.Size = New-Object System.Drawing.Size(145, 20)
        $labelABPStatus.Name = "labelABPStatus"
        $labelABPStatus.Text = "No Exchange ABP applied:"
        $MainForm.Controls.Add($labelABPStatus)
        #
        # Label Exchange Address Book Policy Status Value
        #
        $labelABPStatusValue.Location = New-Object System.Drawing.Point(155, ($labelAuditLogStatus.Location.Y + 25))
        $labelABPStatusValue.Size = New-Object System.Drawing.Size(35, 20)
        $labelABPStatusValue.Name = "labelABPStatusValue"
        Get-ExchangeABPStatus
        $MainForm.Controls.Add($labelABPStatusValue)
        #
        # Label Information Barrier Service Principal
        #
        $labelIBServicePrincipal.Location = New-Object System.Drawing.Point(10, ($labelABPStatus.Location.Y + 25))
        $labelIBServicePrincipal.Size = New-Object System.Drawing.Size(220, 20)
        $labelIBServicePrincipal.Name = "labelIBServicePrincipal"
        $labelIBServicePrincipal.Text = "Information Barrier Service Principal found:"
        $MainForm.Controls.Add($labelIBServicePrincipal)
        #
        # Label Information Barrier Service Principal Status
        #
        $labelIBServicePrincipalValue.Location = New-Object System.Drawing.Point(230, ($labelABPStatus.Location.Y + 25))
        $labelIBServicePrincipalValue.Size = New-Object System.Drawing.Size(35, 20)
        $labelIBServicePrincipalValue.Name = "labelIBServicePrincipalStatus"
        Get-IBServicePrincipal
        $MainForm.Controls.Add($labelIBServicePrincipalValue)
        #
        # Horizontal Line 1
        #
        $HorizontalLine1.Location = New-Object System.Drawing.Point(5, ($labelIBServicePrincipal.Location.Y + 25))
        $HorizontalLine1.Size = New-Object System.Drawing.Size(1090, 2)
        $HorizontalLine1.Name = "HorizontalLine1"
        $HorizontalLine1.Text = $null
        $HorizontalLine1.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
        $MainForm.Controls.Add($HorizontalLine1)
        #
        # Label Getting Info
        #
        $LabelGettingInfo.Location = New-Object System.Drawing.Point(10, ($HorizontalLine1.Location.Y + 10))
        $LabelGettingInfo.Size = New-Object System.Drawing.Size(250, 20)
        $LabelGettingInfo.Name = "LabelGettingInfo"
        $LabelGettingInfo.Text = "Get general Information Barrier Info"
        $LabelGettingInfo.Font = New-Object System.Drawing.Font("Arial", 8, [System.Drawing.FontStyle]::Bold)
        $MainForm.Controls.Add($LabelGettingInfo)
        #
        # Button Get Organization Segments
        #
        $buttonGetSegments.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonGetSegments.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonGetSegments.Location = New-Object System.Drawing.Point(10, ($LabelGettingInfo.Location.Y + 25))
        $buttonGetSegments.Size = New-Object System.Drawing.Size(200, 25)
        $buttonGetSegments.TabIndex = 17
        $buttonGetSegments.Name = "GetSegments"
        $buttonGetSegments.Text = "Get Organization Segments"
        $buttonGetSegments.UseVisualStyleBackColor = $True
        $buttonGetSegments.add_Click({
                $Segments = Get-OrgSegments -ShowOutputLine
                Add-ArrayToDataGrid -ArrayData $Segments -DataGrid $dataGrid -Form $MainForm
            })
        $MainForm.Controls.Add($buttonGetSegments)
        #
        # Button Get Information Barriers Policies
        #
        $buttonGetIBPolicies.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonGetIBPolicies.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonGetIBPolicies.Location = New-Object System.Drawing.Point(220, ($LabelGettingInfo.Location.Y + 25))
        $buttonGetIBPolicies.Size = New-Object System.Drawing.Size(250, 25)
        $buttonGetIBPolicies.TabIndex = 17
        $buttonGetIBPolicies.Name = "GetIBPolicies"
        $buttonGetIBPolicies.Text = "Get Information Barriers Policies"
        $buttonGetIBPolicies.UseVisualStyleBackColor = $True
        $buttonGetIBPolicies.add_Click({
                $IBPolicies = Get-IBPolicies -ShowOutputLine
                Add-ArrayToDataGrid -ArrayData $IBPolicies -DataGrid $dataGrid -Form $MainForm
            })
        $MainForm.Controls.Add($buttonGetIBPolicies)
        #
        # Button Get Information Barriers Policies Application Status
        #
        $buttonGetIBPoliciesAppStatus.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonGetIBPoliciesAppStatus.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonGetIBPoliciesAppStatus.Location = New-Object System.Drawing.Point(480, ($LabelGettingInfo.Location.Y + 25))
        $buttonGetIBPoliciesAppStatus.Size = New-Object System.Drawing.Size(300, 25)
        $buttonGetIBPoliciesAppStatus.TabIndex = 17
        $buttonGetIBPoliciesAppStatus.Name = "GetIBPoliciesAppStatus"
        $buttonGetIBPoliciesAppStatus.Text = "Get IB Policies Application Status"
        $buttonGetIBPoliciesAppStatus.UseVisualStyleBackColor = $True
        $buttonGetIBPoliciesAppStatus.add_Click({
                $IBPoliciesAppStatus = Get-IBPoliciesAppStatus -ShowOutputLine
                Add-ArrayToDataGrid -ArrayData $IBPoliciesAppStatus -DataGrid $dataGrid -Form $MainForm
            })
        $MainForm.Controls.Add($buttonGetIBPoliciesAppStatus)
        #
        # Horizontal Line 2
        #
        $HorizontalLine2.Location = New-Object System.Drawing.Point(5, ($buttonGetSegments.Location.Y + 40))
        $HorizontalLine2.Size = New-Object System.Drawing.Size(1090, 2)
        $HorizontalLine2.Name = "HorizontalLine2"
        $HorizontalLine2.Text = $null
        $HorizontalLine2.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
        $MainForm.Controls.Add($HorizontalLine2)
        #
        # Label Get Org Segment Member title
        #
        $LabelGetOrgSegmentMemberTitle.Location = New-Object System.Drawing.Point(10, ($HorizontalLine2.Location.Y + 10))
        $LabelGetOrgSegmentMemberTitle.Size = New-Object System.Drawing.Size(250, 20)
        $LabelGetOrgSegmentMemberTitle.Name = "LabelGetOrgSegmentMemberTitle"
        $LabelGetOrgSegmentMemberTitle.Text = "Get Organization Segment members"
        $LabelGetOrgSegmentMemberTitle.Font = New-Object System.Drawing.Font("Arial", 8, [System.Drawing.FontStyle]::Bold)
        $MainForm.Controls.Add($LabelGetOrgSegmentMemberTitle)
        #
        # Text Box Organization Segment Name
        #
        $textBoxOrgSegment.Location = New-Object System.Drawing.Point(10, ($LabelGetOrgSegmentMemberTitle.Location.Y + 28))
        $textBoxOrgSegment.Size = New-Object System.Drawing.Size(200, 20)
        $textBoxOrgSegment.Name = "textBoxOrgSegment"
        $textBoxOrgSegment.Text = "Sample Organization Segment"
        $MainForm.Controls.Add($textBoxOrgSegment)
        #
        # Button Get Organization Segment Members
        #
        $buttonGetSegmentMembers.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonGetSegmentMembers.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonGetSegmentMembers.Location = New-Object System.Drawing.Point(220, ($LabelGetOrgSegmentMemberTitle.Location.Y + 25))
        $buttonGetSegmentMembers.Size = New-Object System.Drawing.Size(250, 25)
        $buttonGetSegmentMembers.TabIndex = 17
        $buttonGetSegmentMembers.Name = "GetSegmentMembers"
        $buttonGetSegmentMembers.Text = "Get Segment Members"
        $buttonGetSegmentMembers.UseVisualStyleBackColor = $True
        $buttonGetSegmentMembers.add_Click({
                $members = Get-SegmentMembers -SegmentName $textBoxOrgSegment.Text.ToString() -ShowOutputLine
                Add-ArrayToDataGrid -ArrayData $members -DataGrid $dataGrid -Form $MainForm
            })
        $MainForm.Controls.Add($buttonGetSegmentMembers)
        #
        # Horizontal Line 3
        #
        $HorizontalLine3.Location = New-Object System.Drawing.Point(5, ($textBoxOrgSegment.Location.Y + 40))
        $HorizontalLine3.Size = New-Object System.Drawing.Size(1090, 2)
        $HorizontalLine3.Name = "HorizontalLine3"
        $HorizontalLine3.Text = $null
        $HorizontalLine3.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
        $MainForm.Controls.Add($HorizontalLine3)
        #
        # Label Get Org Recipient Status
        #
        $LabelGetIBRecipientStatusTitle.Location = New-Object System.Drawing.Point(10, ($HorizontalLine3.Location.Y + 10))
        $LabelGetIBRecipientStatusTitle.Size = New-Object System.Drawing.Size(250, 20)
        $LabelGetIBRecipientStatusTitle.Name = "LabelGetIBRecipientStatusTitle"
        $LabelGetIBRecipientStatusTitle.Text = "Get Information Barrier Recipient Status"
        $LabelGetIBRecipientStatusTitle.Font = New-Object System.Drawing.Font("Arial", 8, [System.Drawing.FontStyle]::Bold)
        $MainForm.Controls.Add($LabelGetIBRecipientStatusTitle)
        #
        # Text Box for user1
        #
        $textBoxUser1.Location = New-Object System.Drawing.Point(10, ($LabelGetIBRecipientStatusTitle.Location.Y + 25))
        $textBoxUser1.Size = New-Object System.Drawing.Size(150, 20)
        $textBoxUser1.Name = "textBoxUser1"
        $textBoxUser1.Text = "Sample User1@domain.com"
        $MainForm.Controls.Add($textBoxUser1)
        #
        # Label Compare with
        #
        $labelCompareWith.Location = New-Object System.Drawing.Point(170, ($LabelGetIBRecipientStatusTitle.Location.Y + 28))
        $labelCompareWith.Size = New-Object System.Drawing.Size(80, 20)
        $labelCompareWith.Name = "labelABPStatusValue"
        $labelCompareWith.Text = "compare with:"
        $MainForm.Controls.Add($labelCompareWith)
        #
        # Text Box for user2
        #
        $textBoxUser2.Location = New-Object System.Drawing.Point(250, ($LabelGetIBRecipientStatusTitle.Location.Y + 25))
        $textBoxUser2.Size = New-Object System.Drawing.Size(150, 20)
        $textBoxUser2.Name = "textBoxUser2"
        $textBoxUser2.Text = "Sample User2@domain.com"
        $MainForm.Controls.Add($textBoxUser2)
        #
        # Button to Compare both identities
        #
        $buttonCompareIdentities.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonCompareIdentities.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonCompareIdentities.Location = New-Object System.Drawing.Point(410, ($LabelGetIBRecipientStatusTitle.Location.Y + 23))
        $buttonCompareIdentities.Size = New-Object System.Drawing.Size(150, 25)
        $buttonCompareIdentities.TabIndex = 17
        $buttonCompareIdentities.Name = "CompareIdentities"
        $buttonCompareIdentities.Text = "Compare Users"
        $buttonCompareIdentities.UseVisualStyleBackColor = $True
        $buttonCompareIdentities.add_Click({
                $RecipientStatus = @(Get-IBPoliciesRecipientStatus -User1 $textBoxUser1.Text.toString() -User2 $textBoxUser2.Text.toString() -ShowOutputLine)
                Add-ArrayToDataGrid -ArrayData $RecipientStatus -DataGrid $dataGrid -Form $MainForm
            })
        $MainForm.Controls.Add($buttonCompareIdentities)
        #
        # Horizontal Line 4
        #
        $HorizontalLine4.Location = New-Object System.Drawing.Point(5, ($textBoxUser1.Location.Y + 40))
        $HorizontalLine4.Size = New-Object System.Drawing.Size(1090, 2)
        $HorizontalLine4.Name = "HorizontalLine4"
        $HorizontalLine4.Text = $null
        $HorizontalLine4.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
        $MainForm.Controls.Add($HorizontalLine4)
        #
        # Label New Segment Name Title
        #
        $labelNewSegmentTitle.Location = New-Object System.Drawing.Point(10, ($HorizontalLine4.Location.Y + 10))
        $labelNewSegmentTitle.Size = New-Object System.Drawing.Size(220, 20)
        $labelNewSegmentTitle.Name = "labelNewSegmentTitle"
        $labelNewSegmentTitle.Text = "Create or Edit an Organization Segment"
        $labelNewSegmentTitle.Font = New-Object System.Drawing.Font("Arial", 8, [System.Drawing.FontStyle]::Bold)
        $MainForm.Controls.Add($labelNewSegmentTitle)
        #
        # Label New Segment Title Help
        #
        $labelNewSegmentHelp.Location = New-Object System.Drawing.Point(240, ($HorizontalLine4.Location.Y + 10))
        $labelNewSegmentHelp.Size = New-Object System.Drawing.Size(30, 20)
        $labelNewSegmentHelp.Name = "labelNewSegmentHelp"
        $labelNewSegmentHelp.ForeColor = "Blue"
        $labelNewSegmentHelp.Text = "help"
        $labelNewSegmentHelp.add_Click($labelNewSegmentHelp_Click)
        $MainForm.Controls.Add($labelNewSegmentHelp)
        #
        # Label New Segment Name
        #
        $labelNewSegmentName.Location = New-Object System.Drawing.Point(10, ($labelNewSegmentTitle.Location.Y + 28))
        $labelNewSegmentName.Size = New-Object System.Drawing.Size(40, 20)
        $labelNewSegmentName.Name = "labelNewSegmentName"
        $labelNewSegmentName.Text = "Name:"
        $MainForm.Controls.Add($labelNewSegmentName)
        #
        # Text New Segment Name
        #
        $textNewSegmentName.Location = New-Object System.Drawing.Point(55, ($labelNewSegmentTitle.Location.Y + 25))
        $textNewSegmentName.Size = New-Object System.Drawing.Size(150, 20)
        $textNewSegmentName.Name = "textNewSegmentName"
        $textNewSegmentName.Text = "Sample Organization Segment"
        $MainForm.Controls.Add($textNewSegmentName)
        #
        # Label user Group Filter
        #
        $labelUserGroupFilter.Location = New-Object System.Drawing.Point(210, ($labelNewSegmentTitle.Location.Y + 28))
        $labelUserGroupFilter.Size = New-Object System.Drawing.Size(90, 20)
        $labelUserGroupFilter.Name = "labelUserGroupFilter"
        $labelUserGroupFilter.Text = "-UserGroupFilter"
        $MainForm.Controls.Add($labelUserGroupFilter)
        #
        # Combobox Attribute lists
        #
        $comboBoxAttributelist.DataBindings.DefaultDataSourceUpdateMode = 0
        $comboBoxAttributelist.FormattingEnabled = $True
        $comboBoxAttributelist.Location = New-Object System.Drawing.Point(305, ($labelNewSegmentTitle.Location.Y + 25))
        $comboBoxAttributelist.Size = New-Object System.Drawing.Size(200, 23)
        $comboBoxAttributelist.Items.Add("Co") | Out-Null
        $comboBoxAttributelist.Items.Add("Company") | Out-Null
        $comboBoxAttributelist.Items.Add("Department") | Out-Null
        1..15 | ForEach-Object { $comboBoxAttributelist.Items.Add("CustomAttribute$_") | Out-Null }
        1..5  | ForEach-Object { $comboBoxAttributelist.Items.Add("ExtensionCustomAttribute$_") | Out-Null }
        $comboBoxAttributelist.Items.Add("Alias") | Out-Null
        $comboBoxAttributelist.Items.Add("Office") | Out-Null
        $comboBoxAttributelist.Items.Add("PostalCode") | Out-Null
        $comboBoxAttributelist.Items.Add("EmailAddresses") | Out-Null
        $comboBoxAttributelist.Items.Add("StreetAddress") | Out-Null
        $comboBoxAttributelist.Items.Add("ExternalEmailAddress") | Out-Null
        $comboBoxAttributelist.Items.Add("UsageLocation") | Out-Null
        $comboBoxAttributelist.Items.Add("UserPrincipalName") | Out-Null
        $comboBoxAttributelist.Items.Add("WindowsEmailAddress") | Out-Null
        $comboBoxAttributelist.Items.Add("Description") | Out-Null
        $comboBoxAttributelist.Items.Add("MemberOfGroup") | Out-Null
        $comboBoxAttributelist.Name = "comboBoxAttributelist"
        $MainForm.Controls.Add($comboBoxAttributelist)
        #
        # Combobox Comparison
        #
        $comboBoxComparison.DataBindings.DefaultDataSourceUpdateMode = 0
        $comboBoxComparison.FormattingEnabled = $True
        $comboBoxComparison.Location = New-Object System.Drawing.Point(510, ($labelNewSegmentTitle.Location.Y + 25))
        $comboBoxComparison.Size = New-Object System.Drawing.Size(70, 23)
        $comboBoxComparison.Items.Add("Equals") | Out-Null
        $comboBoxComparison.Items.Add("Not Equals") | Out-Null
        $comboBoxComparison.Name = "comboBoxComparison"
        $MainForm.Controls.Add($comboBoxComparison)
        #
        # Text Attribute Value
        #
        $textAttributeValue.Location = New-Object System.Drawing.Point(588, ($labelNewSegmentTitle.Location.Y + 25))
        $textAttributeValue.Size = New-Object System.Drawing.Size(200, 20)
        $textAttributeValue.Name = "textAttributeValue"
        $textAttributeValue.Text = "Sample Attribute Value"
        $MainForm.Controls.Add($textAttributeValue)
        #
        # Button to create Organization Segment
        #
        $buttonCreateSegment.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonCreateSegment.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonCreateSegment.Location = New-Object System.Drawing.Point(795, ($labelNewSegmentTitle.Location.Y + 23))
        $buttonCreateSegment.Size = New-Object System.Drawing.Size(100, 25)
        $buttonCreateSegment.TabIndex = 17
        $buttonCreateSegment.Name = "buttonCreateSegment"
        $buttonCreateSegment.Text = "Create / Set"
        $buttonCreateSegment.UseVisualStyleBackColor = $True
        $buttonCreateSegment.add_Click({
                New-OrgSegment -Name $textNewSegmentName.Text.toString() -GroupFilter $comboBoxAttributelist.SelectedItem.ToString() -Comparison $comboBoxComparison.SelectedItem.ToString() -AttributeValue $textAttributeValue.Text.ToString()
            })
        $MainForm.Controls.Add($buttonCreateSegment)
        #
        # Horizontal Line 5
        #
        $HorizontalLine5.Location = New-Object System.Drawing.Point(5, ($labelNewSegmentName.Location.Y + 40))
        $HorizontalLine5.Size = New-Object System.Drawing.Size(1090, 2)
        $HorizontalLine5.Name = "HorizontalLine5"
        $HorizontalLine5.Text = $null
        $HorizontalLine5.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
        $MainForm.Controls.Add($HorizontalLine5)
        #
        # Label New IB Policy Title
        #
        $labelNewIBPolicyTitle.Location = New-Object System.Drawing.Point(10, ($HorizontalLine5.Location.Y + 10))
        $labelNewIBPolicyTitle.Size = New-Object System.Drawing.Size(250, 20)
        $labelNewIBPolicyTitle.Name = "labelNewIBPolicyTitle"
        $labelNewIBPolicyTitle.Text = "Create a new Information Barrier Policy"
        $labelNewIBPolicyTitle.Font = New-Object System.Drawing.Font("Arial", 8, [System.Drawing.FontStyle]::Bold)
        $MainForm.Controls.Add($labelNewIBPolicyTitle)
        #
        # Label New IB Policy Name
        #
        $labelNewIBPolicyName.Location = New-Object System.Drawing.Point(10, ($labelNewIBPolicyTitle.Location.Y + 28))
        $labelNewIBPolicyName.Size = New-Object System.Drawing.Size(40, 20)
        $labelNewIBPolicyName.Name = "labelNewIBPolicyName"
        $labelNewIBPolicyName.Text = "Name:"
        $MainForm.Controls.Add($labelNewIBPolicyName)
        #
        # Text New IB Policy Name
        #
        $textNewIBPolicyName.Location = New-Object System.Drawing.Point(55, ($labelNewIBPolicyTitle.Location.Y + 25))
        $textNewIBPolicyName.Size = New-Object System.Drawing.Size(150, 20)
        $textNewIBPolicyName.Name = "textNewIBPolicyName"
        $textNewIBPolicyName.Text = "Sample IB Policy"
        $MainForm.Controls.Add($textNewIBPolicyName)
        #
        # Label Assign Segment
        #
        $labelAssignSegment.Location = New-Object System.Drawing.Point(210, ($labelNewIBPolicyTitle.Location.Y + 28))
        $labelAssignSegment.Size = New-Object System.Drawing.Size(90, 20)
        $labelAssignSegment.Name = "labelAssignSegment"
        $labelAssignSegment.Text = "Assign Segment:"
        $MainForm.Controls.Add($labelAssignSegment)
        #
        # Text Assign Segment name
        #
        $textAssignedSegment.Location = New-Object System.Drawing.Point(305, ($labelNewIBPolicyTitle.Location.Y + 25))
        $textAssignedSegment.Size = New-Object System.Drawing.Size(150, 20)
        $textAssignedSegment.Name = "textAssignedSegment"
        $textAssignedSegment.Text = "Sample Segment 1"
        $MainForm.Controls.Add($textAssignedSegment)
        #
        # Combobox Segment allowedBlock
        #
        $comboBoxSegmentAorB.DataBindings.DefaultDataSourceUpdateMode = 0
        $comboBoxSegmentAorB.FormattingEnabled = $True
        $comboBoxSegmentAorB.Location = New-Object System.Drawing.Point(460, ($labelNewIBPolicyTitle.Location.Y + 25))
        $comboBoxSegmentAorB.Size = New-Object System.Drawing.Size(110, 23)
        $comboBoxSegmentAorB.Items.Add("SegmentsAllowed") | Out-Null
        $comboBoxSegmentAorB.Items.Add("SegmentsBlocked") | Out-Null
        $comboBoxSegmentAorB.Name = "comboBoxSegmentAorB"
        $MainForm.Controls.Add($comboBoxSegmentAorB)
        # Arrow label
        $ArrowLabel = New-Object System.Windows.Forms.Label
        $ArrowLabel.Location = New-Object System.Drawing.Point(571, ($labelNewIBPolicyTitle.Location.Y + 28))
        $ArrowLabel.Size = New-Object System.Drawing.Size(16, 20)
        $ArrowLabel.Name = "ArrowLabel"
        $ArrowLabel.Text = "->"
        $MainForm.Controls.Add($ArrowLabel)
        #
        # Textbox Segments names
        #
        $textAorBSegment.Location = New-Object System.Drawing.Point(588, ($labelNewIBPolicyTitle.Location.Y + 25))
        $textAorBSegment.Size = New-Object System.Drawing.Size(200, 20)
        $textAorBSegment.Name = "textAorBSegment"
        $textAorBSegment.Text = "'Sample Segment 1', 'Sample Segment 2'"
        $MainForm.Controls.Add($textAorBSegment)
        #
        # Button to create IB policy
        #
        $buttonCreateIBpolicy.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonCreateIBpolicy.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonCreateIBpolicy.Location = New-Object System.Drawing.Point(795, ($labelNewIBPolicyTitle.Location.Y + 23))
        $buttonCreateIBpolicy.Size = New-Object System.Drawing.Size(100, 25)
        $buttonCreateIBpolicy.TabIndex = 17
        $buttonCreateIBpolicy.Name = "buttonCreateIBpolicy"
        $buttonCreateIBpolicy.Text = "Create"
        $buttonCreateIBpolicy.UseVisualStyleBackColor = $True
        $buttonCreateIBpolicy.add_Click({
                New-IBPolicy -PolicyName $textNewIBPolicyName.text.ToString() -AssignedSegment $textAssignedSegment.Text.ToString() -AssignedAction $comboBoxSegmentAorB.SelectedItem.ToString() -AorBSegments $textAorBSegment.Text.ToString()
            })
        $MainForm.Controls.Add($buttonCreateIBpolicy)
        #
        # Button to Start IB policy Application
        #
        $buttonStartIBPolicyApplication.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonStartIBPolicyApplication.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonStartIBPolicyApplication.Location = New-Object System.Drawing.Point(900, ($labelNewIBPolicyTitle.Location.Y + 23))
        $buttonStartIBPolicyApplication.Size = New-Object System.Drawing.Size(150, 25)
        $buttonStartIBPolicyApplication.TabIndex = 17
        $buttonStartIBPolicyApplication.Name = "buttonStartIBPolicyApplication"
        $buttonStartIBPolicyApplication.Text = "Start IB Policy Application"
        $buttonStartIBPolicyApplication.UseVisualStyleBackColor = $True
        $buttonStartIBPolicyApplication.add_Click({
                Start-IBPolicyApp
            })
        $MainForm.Controls.Add($buttonStartIBPolicyApplication)
        #
        # Horizontal Line 6
        #
        $HorizontalLine6.Location = New-Object System.Drawing.Point(5, ($buttonStartIBPolicyApplication.Location.Y + 40))
        $HorizontalLine6.Size = New-Object System.Drawing.Size(1090, 2)
        $HorizontalLine6.Name = "HorizontalLine6"
        $HorizontalLine6.Text = $null
        $HorizontalLine6.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
        $MainForm.Controls.Add($HorizontalLine6)
        #
        # Label Remove Segment/Policy Title
        #
        $labelRemoveIBPolicyTitle.Location = New-Object System.Drawing.Point(10, ($HorizontalLine6.Location.Y + 10))
        $labelRemoveIBPolicyTitle.Size = New-Object System.Drawing.Size(350, 20)
        $labelRemoveIBPolicyTitle.Name = "labelRemoveIBPolicyTitle"
        $labelRemoveIBPolicyTitle.Text = "Remove Organization Segment or Information Barrier Policy"
        $labelRemoveIBPolicyTitle.Font = New-Object System.Drawing.Font("Arial", 8, [System.Drawing.FontStyle]::Bold)
        $MainForm.Controls.Add($labelRemoveIBPolicyTitle)
        #
        # Label Remove Policy Name
        #
        $labelRemoveIBPolicyName.Location = New-Object System.Drawing.Point(10, ($labelRemoveIBPolicyTitle.Location.Y + 28))
        $labelRemoveIBPolicyName.Size = New-Object System.Drawing.Size(40, 20)
        $labelRemoveIBPolicyName.Name = "labelRemoveIBPolicyName"
        $labelRemoveIBPolicyName.Text = "Name:"
        $MainForm.Controls.Add($labelRemoveIBPolicyName)
        #
        # Textbox Remove names
        #
        $textRemoveIBPolicyName.Location = New-Object System.Drawing.Point(55, ($labelRemoveIBPolicyTitle.Location.Y + 25))
        $textRemoveIBPolicyName.Size = New-Object System.Drawing.Size(200, 20)
        $textRemoveIBPolicyName.Name = "textRemoveIBPolicyName"
        $textRemoveIBPolicyName.Text = "Organization Segment or IB Policy name"
        $MainForm.Controls.Add($textRemoveIBPolicyName)
        #
        # Button to Remove OrganizationSegment
        #
        $buttonRemoveSegment.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonRemoveSegment.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonRemoveSegment.Location = New-Object System.Drawing.Point(300, ($labelRemoveIBPolicyTitle.Location.Y + 23))
        $buttonRemoveSegment.Size = New-Object System.Drawing.Size(150, 25)
        $buttonRemoveSegment.TabIndex = 17
        $buttonRemoveSegment.Name = "buttonRemoveSegment"
        $buttonRemoveSegment.Text = "Remove Org Segment"
        $buttonRemoveSegment.UseVisualStyleBackColor = $True
        $buttonRemoveSegment.add_Click({
                Remove-OrgSegment -Identity $textRemoveIBPolicyName.Text
            })
        $MainForm.Controls.Add($buttonRemoveSegment)
        #
        # Button to Remove OrganizationSegment
        #
        $buttonRemoveIBpolicy.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonRemoveIBpolicy.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonRemoveIBpolicy.Location = New-Object System.Drawing.Point(470, ($labelRemoveIBPolicyTitle.Location.Y + 23))
        $buttonRemoveIBpolicy.Size = New-Object System.Drawing.Size(150, 25)
        $buttonRemoveIBpolicy.TabIndex = 17
        $buttonRemoveIBpolicy.Name = "buttonRemoveIBpolicy"
        $buttonRemoveIBpolicy.Text = "Remove IB Policy"
        $buttonRemoveIBpolicy.UseVisualStyleBackColor = $True
        $buttonRemoveIBpolicy.add_Click({
                Remove-IBPolicy -Identity $textRemoveIBPolicyName.Text
            })
        $MainForm.Controls.Add($buttonRemoveIBpolicy)
        #
        # Horizontal Line 7
        #
        $HorizontalLine7.Location = New-Object System.Drawing.Point(5, ($buttonRemoveIBpolicy.Location.Y + 40))
        $HorizontalLine7.Size = New-Object System.Drawing.Size(1090, 2)
        $HorizontalLine7.Name = "HorizontalLine7"
        $HorizontalLine7.Text = $null
        $HorizontalLine7.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
        $MainForm.Controls.Add($HorizontalLine7)
        #
        # Label Remove Segment/Policy Title
        #
        $labelSearchLogTitle.Location = New-Object System.Drawing.Point(10, ($HorizontalLine7.Location.Y + 10))
        $labelSearchLogTitle.Size = New-Object System.Drawing.Size(350, 20)
        $labelSearchLogTitle.Name = "labelSearchLogTitle"
        $labelSearchLogTitle.Text = "Search Unified Audit Logs"
        $labelSearchLogTitle.Font = New-Object System.Drawing.Font("Arial", 8, [System.Drawing.FontStyle]::Bold)
        $MainForm.Controls.Add($labelSearchLogTitle)
        #
        #Label FromDate
        #
        $labFromDate.Location = New-Object System.Drawing.Point(10, ($labelSearchLogTitle.Location.Y + 28))
        $labFromDate.Size = New-Object System.Drawing.Size(80, 35)
        $labFromDate.Name = "FromDate"
        $labFromDate.Text = "From or greater than"
        $MainForm.Controls.Add($labFromDate)
        #
        # FromDate Date Picker
        #
        $FromDatePicker.DataBindings.DefaultDataSourceUpdateMode = 0
        $FromDatePicker.Location = New-Object System.Drawing.Point(90, ($labelSearchLogTitle.Location.Y + 28))
        $FromDatePicker.Name = "FromDatePicker"
        $FromDatePicker.Value = (Get-date).AddDays(-30)
        $MainForm.Controls.Add($FromDatePicker)
        #
        # Label ToDate
        #
        $labToDate.Location = New-Object System.Drawing.Point(300, ($labelSearchLogTitle.Location.Y + 30))
        $labToDate.Size = New-Object System.Drawing.Size(80, 40)
        $labToDate.Name = "ToDate"
        $labToDate.Text = "To or less than"
        $MainForm.Controls.Add($labToDate)
        #
        # ToDate Date Picker
        #
        $ToDatePicker.DataBindings.DefaultDataSourceUpdateMode = 0
        $ToDatePicker.Location = New-Object System.Drawing.Point(390, ($labelSearchLogTitle.Location.Y + 28))
        $ToDatePicker.Name = "ToDatePicker"
        $ToDatePicker.Value = (Get-date).AddDays(1)
        $MainForm.Controls.Add($ToDatePicker)
        #
        # Label Identity App Status
        #
        $labelSearchAppLog.Location = New-Object System.Drawing.Point(600, ($labelSearchLogTitle.Location.Y + 30))
        $labelSearchAppLog.Size = New-Object System.Drawing.Size(80, 40)
        $labelSearchAppLog.Name = "labelSearchAppLog"
        $labelSearchAppLog.Text = "App Status ID:"
        $MainForm.Controls.Add($labelSearchAppLog)
        #
        # Textbox Search App ID
        #
        $textSeaarchAppLog.Location = New-Object System.Drawing.Point(680, ($labelSearchLogTitle.Location.Y + 28))
        $textSeaarchAppLog.Size = New-Object System.Drawing.Size(200, 20)
        $textSeaarchAppLog.Name = "textSeaarchAppLog"
        $textSeaarchAppLog.Text = "IB Policy Application Status Id"
        $MainForm.Controls.Add($textSeaarchAppLog)
        #
        # Button to Remove OrganizationSegment
        #
        $buttonSearchAppLog.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonSearchAppLog.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonSearchAppLog.Location = New-Object System.Drawing.Point(900, ($labelSearchLogTitle.Location.Y + 28))
        $buttonSearchAppLog.Size = New-Object System.Drawing.Size(150, 25)
        $buttonSearchAppLog.Name = "buttonSearchAppLog"
        $buttonSearchAppLog.Text = "Get Unfied Logs"
        $buttonSearchAppLog.UseVisualStyleBackColor = $True
        $buttonSearchAppLog.add_Click({
            $Records = @(Get-UnifiedLog -StartDate $FromDatePicker.Value -EndDate $ToDatePicker.Value -AppId $textSeaarchAppLog.Text)
            Add-ArrayToDataGrid -ArrayData $Records -DataGrid $dataGrid -Form $MainForm
        })
        $MainForm.Controls.Add($buttonSearchAppLog)
        #
        # Data Grid outputs
        #
        $dataGrid.Anchor = 15
        $dataGrid.DataBindings.DefaultDataSourceUpdateMode = 0
        $dataGrid.DataMember = ""
        $dataGrid.Location = New-Object System.Drawing.Point(5, 650)
        $dataGrid.Size = New-Object System.Drawing.Size(1090, 240)
        $dataGrid.Name = "dataGrid"
        $dataGrid.ReadOnly = $True
        $dataGrid.RowHeadersVisible = $False
        $dataGrid.Visible = $True
        $dataGrid.AllowUserToOrderColumns = $True
        $dataGrid.AllowUserToResizeColumns = $True
        $MainForm.Controls.Add($dataGrid)

        #endregion Generated Form Code

        # Show Form
        #Save the initial state of the form
        $InitialFormWindowState = $MainForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $MainForm.add_Load($OnLoadMainWindow_StateCorrection)
        $MainForm.Add_Shown({ $MainForm.Activate() })
        $MainForm.ShowDialog() | Out-Null
    } #End Function

    #Call the Function
    try {
        GenerateForm
    }
    finally {
        Stop-ModuleUpdate -RunspaceData $runspaceData
    }
}

<#
This is an example configuration file
 
By default, it is enough to have a single one of them,
however if you have enough configuration settings to justify having multiple copies of it,
feel totally free to split them into multiple files.
#>


<#
# Example Configuration
Set-PSFConfig -Module 'IBTool' -Name 'Example.Setting' -Value 10 -Initialize -Validation 'integer' -Handler { } -Description "Example configuration setting. Your module can then use the setting using 'Get-PSFConfigValue'"
#>


Set-PSFConfig -Module 'IBTool' -Name 'Import.DoDotSource' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be dotsourced on import. By default, the files of this module are read as string value and invoked, which is faster but worse on debugging."
Set-PSFConfig -Module 'IBTool' -Name 'Import.IndividualFiles' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be imported individually. During the module build, all module code is compiled into few files, which are imported instead by default. Loading the compiled versions is faster, using the individual files is easier for debugging and testing out adjustments."

<#
Stored scriptblocks are available in [PsfValidateScript()] attributes.
This makes it easier to centrally provide the same scriptblock multiple times,
without having to maintain it in separate locations.
 
It also prevents lengthy validation scriptblocks from making your parameter block
hard to read.
 
Set-PSFScriptblock -Name 'IBTool.ScriptBlockName' -Scriptblock {
     
}
#>


<#
# Example:
Register-PSFTeppScriptblock -Name "IBTool.alcohol" -ScriptBlock { 'Beer','Mead','Whiskey','Wine','Vodka','Rum (3y)', 'Rum (5y)', 'Rum (7y)' }
#>


<#
# Example:
Register-PSFTeppArgumentCompleter -Command Get-Alcohol -Parameter Type -Name IBTool.alcohol
#>


New-PSFLicense -Product 'IBTool' -Manufacturer 'agallego' -ProductVersion $script:ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date "2020-10-27") -Text @"
Copyright (c) 2020 agallego
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"@

#endregion Load compiled code