commands.ps1

function Add-MitreCheckboxes {

<#
    .SYNOPSIS
    Populates all the MITRE ATT&CK checkboxes.
 
    .DESCRIPTION
    Populates all the MITRE ATT&CK checkboxes in the EventList GUI. Used for initial creation of the checkboxes and the CheckedListBoxes
 
    .EXAMPLE
    Add-MitreCheckboxes
 
    Populates all the MITRE ATT&CK checkboxes.
 
#>

    
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]
    param ()

    $query = "select id, area_name from mitre_areas;"

    $Script:areas = Invoke-SqliteQuery -Query $Query -DataSource $Database

    $Script:CheckBox = [ordered]@{}
    $Script:CheckBoxArea = [ordered]@{}


    $i=1
    $j = 0

    $width = 350
    $height = 200
    $x = 10
    $y = 20 + 60

    foreach ($area in $areas) {

        $x = $x +2
        $CheckBoxArea[$area.area_name]                       = New-Object system.Windows.Forms.CheckBox
        $CheckBoxArea[$area.area_name].text                  = $area.area_name
        $CheckBoxArea[$area.area_name].AutoSize              = $false
        $CheckBoxArea[$area.area_name].width                 = 300
        $CheckBoxArea[$area.area_name].height                = 20
        $CheckBoxArea[$area.area_name].location              = New-Object System.Drawing.Point($x,$y)
        $CheckBoxArea[$area.area_name].Font                  = 'Microsoft Sans Serif,12'
        $CheckBoxArea[$area.area_name].Tag                   = @{AreaName = $area.area_name}
        $CheckBoxArea[$area.area_name].Add_Click({
            param($Senderinfo)
            & Select-AllCheckboxesFromOneArea -AreaName $($Senderinfo.Tag.AreaName)
         })
        $x = $x -2
        $y = $y + 25

        $Form.controls.AddRange(@($CheckBoxArea[$area.area_name]))

        $tmp = New-Object system.Windows.Forms.CheckedListBox

        $tmp.AutoSize = $false
        $tmp.width = $width
        $tmp.height = $height
        $tmp.CheckOnClick = $true
        $tmp.location = New-Object System.Drawing.Point($x,$y)
        $tmp.Font = 'Microsoft Sans Serif,10'

        $query = "select distinct ma.area_name, mt.technique_id, mt.technique_name from mitre_events me, events_main em, mitre_techniques mt, mitre_areas ma where me.technique_id = mt.id and me.event_id = em.id and me.area_id = ma.id and ma.id = '" + $area.id + "' order by technique_name;"

        $techniques = Invoke-SqliteQuery -Query $query -DataSource $Database

        foreach ($technique in $techniques) {
            $tmp.Items.Add($technique.technique_id + " " + $technique.technique_name,$false) | Out-Null
        }

        $y = $y - 25

        $i++

        if ($x -gt 750){
            $x = 10
            $y = $y + 225
            $i = 1
        }

        $CheckBox.add( $area.area_name, $tmp )

        if ($i -ne 1) {
            $x = $x + 380
        }

        $j = $j + 1

    }

        foreach ($key in $CheckBox.keys) {
            $Form.controls.AddRange($CheckBox[$key])
        }

}

function Close-Form {

<#
    .SYNOPSIS
    Closes the Form.
 
    .DESCRIPTION
    Closes the Form, that was passed by the -Form Parameter. Nothing to see here, move on! ;-)
 
    .PARAMETER Form
    A Windows form that should be closed: [system.Windows.Forms.Form]
 
    .EXAMPLE
    Close-Form -Form $Form
 
    Closes the Form.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [object]$Form
    )
    $Form.close()
}

function ConvertFrom-PSSQLString {

<#
    .SYNOPSIS
    Converts a text string from a database into output text.
 
    .DESCRIPTION
    Converts a text string from a database into output text, which was earlier parsed by the ConvertTo-PSSQLString function.
 
    .PARAMETER Text
    The String to parse for Output.
 
    .EXAMPLE
    ConvertFrom-PSSQLString -Text $queryString
 
    Converts a text string from a database into output text.
 
#>


    [CmdletBinding()]
    [OutputType([String])]
    param (
        [string]$Text
    )
    $Text = $Text.Replace("&quot;", '"')
    $Text = $Text.Replace("&apos;", "'")
    $Text = $Text.Replace("&x00;", "\x00")
    $Text = $Text.Replace("&n;", "\n")
    $Text = $Text.Replace("&r;", "\r")
    $Text = $Text.Replace("&bsol;", "\")
    $Text = $Text.Replace("&x1a;", "\x1a")
    $Text = $Text.Replace("&#59;", ";")

    return $Text
 }

function ConvertFrom-PSSQLStringArray {

<#
    .SYNOPSIS
    Converts a text string from a database into output text.
 
    .DESCRIPTION
    Converts a text string from a database into output text, which was earlier parsed by the ConvertTo-PSSQLString function.
 
    .PARAMETER Text
    The String to parse for Output.
 
    .EXAMPLE
    ConvertFrom-PSSQLStringArray -Text $queryString
 
    Converts a text string from a database into output text.
 
#>


    [CmdletBinding()]
    [OutputType([String])]
    param (
        [string[]]$Text
    )
    $Text = $Text.Replace("&quot;", '"')
    $Text = $Text.Replace("&apos;", "'")
    $Text = $Text.Replace("&x00;", "\x00")
    $Text = $Text.Replace("&n;", "\n")
    $Text = $Text.Replace("&r;", "\r")
    $Text = $Text.Replace("&bsol;", "\")
    $Text = $Text.Replace("&x1a;", "\x1a")
    $Text = $Text.Replace("&#59;", ";")

    return $Text
 }

function ConvertTo-PSSQLString {

<#
    .SYNOPSIS
    Converts a string into a format that can be inserted into a PSSQL database.
 
    .DESCRIPTION
    Converts a string into a format that can be inserted into a PSSQL database without the risk of common SQL injections.
 
    .PARAMETER Text
    The String to parse for the database.
 
    .EXAMPLE
    ConvertTo-PSSQLString -Text $queryString
 
    Converts a string into a format that can be inserted into a PSSQL database.
#>


    [CmdletBinding()]
    [OutputType([String])]
    param (
        [string]$Text
    )
    $Text = $Text.Replace('"', "&quot;")
    $Text = $Text.Replace("'", "&apos;")
    $Text = $Text.Replace("\x00", "&x00;")
    $Text = $Text.Replace("\n", "&n;")
    $Text = $Text.Replace("\r", "&r;")
    $Text = $Text.Replace("\", "&bsol;")
    $Text = $Text.Replace("\x1a", "&x1a;")
    $Text = $Text.Replace(";", "&#59;")

    return $Text
 }

function ConvertTo-PSSQLStringArray {

<#
    .SYNOPSIS
    Converts a string into a format that can be inserted into a PSSQL database.
 
    .DESCRIPTION
    Converts a string into a format that can be inserted into a PSSQL database without the risk of common SQL injections.
 
    .PARAMETER Text
    The String to parse for the database.
 
    .EXAMPLE
    ConvertTo-PSSQLStringArray -Text $queryString
 
    Converts a string into a format that can be inserted into a PSSQL database.
#>


    [CmdletBinding()]
    [OutputType([String])]
    param (
        [string[]]$Text
    )
    $Text = $Text.Replace('"', "&quot;")
    $Text = $Text.Replace("'", "&apos;")
    $Text = $Text.Replace("\x00", "&x00;")
    $Text = $Text.Replace("\n", "&n;")
    $Text = $Text.Replace("\r", "&r;")
    $Text = $Text.Replace("\", "&bsol;")
    $Text = $Text.Replace("\x1a", "&x1a;")
    $Text = $Text.Replace(";", "&#59;")

    return $Text
 }


function Get-AgentConfigSelect {

<#
    .SYNOPSIS
    Displays the form to select and display the Agent config of your choice.
 
    .DESCRIPTION
    Displays the form to select and display the Agent config of your choice. All Agent Forwarders are pulled out of the database and are being supported by Sigma.
 
    .EXAMPLE
    Get-AgentConfigSelect
 
    Displays the form to select and display the Agent config of your choice.
 
#>

    [CmdletBinding()]
    param ()

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

    $Form = New-Object System.Windows.Forms.Form
    $Form.width = 700
    $Form.height = 550
    $Form.Text = "Generate Agent Config"

    $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10)
    $Form.Font = $Font

    $MyGroupBox = New-Object System.Windows.Forms.GroupBox
    $MyGroupBox.Location = '40,40'
    $MyGroupBox.size = '600,350'
    $MyGroupBox.text = "For which forwarder agent would you like to generate a configuration snippet?"


    $ComboBox2                       = New-Object system.Windows.Forms.ComboBox
    $query = "select name from agent_forwarder_syntax order by name;"
    $agentFwdNames = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty name

    if ([string]::IsNullOrEmpty($agentFwdNames)) {
        $ComboBox2.text = "No Agent Forwarder implemented"
    }
    else {
        $ComboBox2.text = "Select an option..."
    }


    $ComboBox2.width                 = 580
    $ComboBox2.height                = 40

    $agentFwdNames | ForEach-Object {[void] $ComboBox2.Items.Add($_)}
    $ComboBox2.location              = New-Object System.Drawing.Point(50,85)
    $ComboBox2.Font                  = 'Microsoft Sans Serif,11'
    $ComboBox2.Add_SelectedValueChanged({
        If ((!([string]::IsNullOrEmpty($ComboBox2.Text))) -and ($ComboBox2.Text -in $agentFwdNames)) {
            Get-AgentConfigString -ForwarderName $ComboBox2.Text
        }
    })

    $Script:agentSnippetBox = New-Object System.Windows.Forms.TextBox
    $agentSnippetBox.Multiline = $True;
    $agentSnippetBox.Location = New-Object System.Drawing.Size(50,130)
    $agentSnippetBox.Size = New-Object System.Drawing.Size(580,250)
    $agentSnippetBox.Scrollbars = "Vertical"
    $form.Controls.Add($agentSnippetBox)

    $OKButton = new-object System.Windows.Forms.Button
    $OKButton.Location = '230,425'
    $OKButton.Size = '100,40'
    $OKButton.Text = 'OK'
    $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK

    $CancelButton = new-object System.Windows.Forms.Button
    $CancelButton.Location = '355,425'
    $CancelButton.Size = '100,40'
    $CancelButton.Text = "Cancel"
    $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel

    $Form.controls.AddRange(@($ComboBox2))
    $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton))

    $form.AcceptButton = $OKButton
    $form.CancelButton = $CancelButton

    $form.Add_Shown({$form.Activate()})

    $form.ShowDialog()
}

function Get-CheckedMitreAreas {

<#
    .SYNOPSIS
    Gets all Mitre Areas that were checked.
 
    .DESCRIPTION
    Gets all Mitre Areas that were checked.
 
    .EXAMPLE
    Get-CheckedMitreAreas
 
    Gets all Mitre Areas that were checked.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]
    param ()

    foreach ($key in $CheckBoxArea.keys) {
        if (![string]::IsNullOrEmpty($CheckBoxArea[$key].checkedItems)) {
            foreach ($item in ($CheckBoxArea[$key].checkedItems.Split(" "))) {
                if (![string]::IsNullOrEmpty($item)) {
                    if ([string]::IsNullOrEmpty($tmpStr)) {
                        $tmpStr = "'$item'"
                    }
                    else {
                        $tmpStr = "$tmpStr, '$item'"
                    }

                }
            }
        }
    }

    return $tmpStr
}

function Get-CheckedMitreTechniques {

<#
    .SYNOPSIS
    Gets all Mitre Techniques that were checked.
 
    .DESCRIPTION
    Gets all Mitre Techniques that were checked.
 
    .EXAMPLE
    Get-CheckedMitreTechniques
 
    Gets all Mitre Techniques that were checked.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]
    param ()

    foreach ($key in $CheckBox.keys) {

        if (![string]::IsNullOrEmpty($CheckBox[$key].checkedItems)) {
            foreach ($item in ($CheckBox[$key].checkedItems.Split(" ") | Select-String -Pattern 'T[0-9][0-9][0-9][0-9]' -CaseSensitive)) {
                if (![string]::IsNullOrEmpty($item)) {
                    if ([string]::IsNullOrEmpty($tmpStr)) {
                        $tmpStr = "'$item'"
                    }
                    else {
                        $tmpStr = "$tmpStr, '$item'"
                    }

                }
            }
        }
    }

    return $tmpStr

}

function Get-DeleteBaselineSelect {

<#
    .SYNOPSIS
    Shows a pop-up in which the deletion options are being displayed.
 
    .DESCRIPTION
    Shows a pop-up in which the deletion options are being displayed: Delete the selected baseline or Delete all baselines
 
    .EXAMPLE
    Get-DeleteBaselineSelect
 
    Shows a pop-up in which the deletion options are being displayed.
 
#>

    [CmdletBinding()]
    param ()

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

    $Form = New-Object System.Windows.Forms.Form
    $Form.width = 700
    $Form.height = 350
    $Form.Text = "Delete Baseline"

    $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10)
    $Form.Font = $Font

    $MyGroupBox = New-Object System.Windows.Forms.GroupBox
    $MyGroupBox.Location = '40,40'
    $MyGroupBox.size = '600,150'
    $MyGroupBox.text = "Would you prefer to..."

    $RadioButton1 = New-Object System.Windows.Forms.RadioButton
    $RadioButton1.Location = '20,50'
    $RadioButton1.size = '450,30'
    $RadioButton1.Checked = $true
    $RadioButton1.Text = "Delete the selected baseline"

    $RadioButton2 = New-Object System.Windows.Forms.RadioButton
    $RadioButton2.Location = '20,85'
    $RadioButton2.size = '450,30'
    $RadioButton2.Checked = $false
    $RadioButton2.Text = "Delete all baselines"

    $OKButton = new-object System.Windows.Forms.Button
    $OKButton.Location = '230,200'
    $OKButton.Size = '100,40'
    $OKButton.Text = 'OK'
    $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK

    $CancelButton = new-object System.Windows.Forms.Button
    $CancelButton.Location = '355,200'
    $CancelButton.Size = '100,40'
    $CancelButton.Text = "Cancel"
    $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel

    $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton))

    $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$RadioButton3))

    $form.AcceptButton = $OKButton
    $form.CancelButton = $CancelButton

    $form.Add_Shown({$form.Activate()})

    $dialogResult = $form.ShowDialog()

    if ($dialogResult -eq "OK"){

        if ($RadioButton1.Checked){
            Remove-OneBaseline -BaselineName $ComboBox1Value
            Reset-MitreCheckboxes
            $baselineNames = Get-BaselineNameFromDB
            Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames
        }
        elseif ($RadioButton2.Checked){
            Remove-AllBaselines
            Reset-MitreCheckboxes
            $baselineNames = Get-BaselineNameFromDB
            Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames
        }
    }
}

function Get-EventListConfigSelect {

<#
    .SYNOPSIS
    Shows a pop-up in which the EventList configuration options are being displayed.
 
    .DESCRIPTION
    Shows a pop-up in which the EventList configuration options are being displayed.
 
    .EXAMPLE
    Get-EventListConfigSelect
 
    Shows a pop-up in which the EventList configuration options are being displayed.
 
#>

    [CmdletBinding()]
    param ()

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

    $Form = New-Object System.Windows.Forms.Form
    $Form.width = 700
    $Form.height = 400
    $Form.Text = "Configure EventList"

    $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10)
    $Form.Font = $Font

    $MyGroupBox = New-Object System.Windows.Forms.GroupBox
    $MyGroupBox.Location = '40,40'
    $MyGroupBox.size = '600,200'
    $MyGroupBox.text = "Configure EventList"

    $Checkbox1 = New-Object System.Windows.Forms.Checkbox
    $Checkbox1.Location = '20,50'
    $Checkbox1.size = '500,90'
    $sigmaPath = Get-SigmaPath
    if ($sigmaPath) {
        $Checkbox1.Checked = $true
        $Checkbox1.Text = "Sigma Path configured: $sigmaPath"
    }
    else {
        $Checkbox1.Checked = $false
        $Checkbox1.Text = "Configure Sigma Path"
    }

    $Checkbox1.Add_Click({
        if ($Checkbox1.checked) {
            $sigmaPath = Start-FilePicker -description "Please select where the sigmac file is located"
            if ($sigmaPath) {
                Add-EventListConfiguration -sigmaPath $sigmaPath
                $Checkbox1.Text = "Sigma Path configured: $sigmaPath"
            }
        }
        else {
            Remove-EventListConfiguration -sigmaPath
            $Checkbox1.Text = "Configure Sigma Path"
        }
     })

    $OKButton = new-object System.Windows.Forms.Button
    $OKButton.Location = '230,250'
    $OKButton.Size = '100,40'
    $OKButton.Text = 'OK'
    $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK

    $CancelButton = new-object System.Windows.Forms.Button
    $CancelButton.Location = '355,250'
    $CancelButton.Size = '100,40'
    $CancelButton.Text = "Cancel"
    $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel

    $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton))

    $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$Checkbox1,$Checkbox2))

    $form.AcceptButton = $OKButton
    $form.CancelButton = $CancelButton

    $form.Add_Shown({$form.Activate()})

    $form.ShowDialog()
}

function Get-EventListSelect {

<#
    .SYNOPSIS
    Shows a pop-up in which the EventList generation options are being displayed.
 
    .DESCRIPTION
    Shows a pop-up in which the EventList generation options are being displayed.
 
    .EXAMPLE
    Get-EventListSelect
 
    Shows a pop-up in which the EventList generation options are being displayed.
 
#>

    [CmdletBinding()]
    param ()

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

    $Form = New-Object System.Windows.Forms.Form
    $Form.width = 700
    $Form.height = 400
    $Form.Text = "EventList"

    $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10)
    $Form.Font = $Font

    $MyGroupBox = New-Object System.Windows.Forms.GroupBox
    $MyGroupBox.Location = '40,40'
    $MyGroupBox.size = '600,200'
    $MyGroupBox.text = "Which Events would you like to process?"

    $RadioButton1 = New-Object System.Windows.Forms.RadioButton
    $RadioButton1.Location = '20,50'
    $RadioButton1.size = '450,30'
    $RadioButton1.Checked = $true
    $RadioButton1.Text = "Baseline Events only"

    $RadioButton2 = New-Object System.Windows.Forms.RadioButton
    $RadioButton2.Location = '20,85'
    $RadioButton2.size = '450,30'
    $RadioButton2.Checked = $false
    $RadioButton2.Text = "All MITRE ATT&&CK Events"

    $Checkbox1 = New-Object System.Windows.Forms.Checkbox
    $Checkbox1.Location = '50,130'
    $Checkbox1.size = '350,30'
    $Checkbox1.Checked = $false
    $Checkbox1.Text = "Export as CSV"
    $Checkbox1.Add_Click({
        $Script:ExportFolder = Start-FilePicker -description "Please select where to store your Excel file"
     })

    $OKButton = new-object System.Windows.Forms.Button
    $OKButton.Location = '230,250'
    $OKButton.Size = '100,40'
    $OKButton.Text = 'OK'
    $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK

    $CancelButton = new-object System.Windows.Forms.Button
    $CancelButton.Location = '355,250'
    $CancelButton.Size = '100,40'
    $CancelButton.Text = "Cancel"
    $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel

    $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton))

    $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$Checkbox1))

    $form.AcceptButton = $OKButton
    $form.CancelButton = $CancelButton

    $form.Add_Shown({$form.Activate()})

    $dialogResult = $form.ShowDialog()

    if ($dialogResult -eq "OK"){
        if ($RadioButton1.Checked){
            Get-BaselineEventList -generateExcelYsn $Checkbox1.Checked
        }
        elseif ($RadioButton2.Checked){
            Get-MitreEventList -generateExcelYsn $Checkbox1.Checked
        }
    }
}

function Get-ImportSelect {

<#
    .SYNOPSIS
    Shows a pop-up in which the baseline import options are being displayed.
 
    .DESCRIPTION
    Shows a pop-up in which the baseline import options are being displayed.
 
    .EXAMPLE
    Get-ImportSelect
 
    Shows a pop-up in which the baseline import options are being displayed.
 
#>


    [CmdletBinding()]
    param ()

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

    $Form = New-Object System.Windows.Forms.Form
    $Form.width = 700
    $Form.height = 350
    $Form.Text = "Import Baseline"

    $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10)
    $Form.Font = $Font

    $MyGroupBox = New-Object System.Windows.Forms.GroupBox
    $MyGroupBox.Location = '40,40'
    $MyGroupBox.size = '600,150'
    $MyGroupBox.text = "What kind of baseline would you like to import?"

    $RadioButton1 = New-Object System.Windows.Forms.RadioButton
    $RadioButton1.Location = '20,50'
    $RadioButton1.size = '450,30'
    $RadioButton1.Checked = $true
    $RadioButton1.Text = "Import a Microsoft Security Baseline or a backed-up GPO"

    $OKButton = new-object System.Windows.Forms.Button
    $OKButton.Location = '230,200'
    $OKButton.Size = '100,40'
    $OKButton.Text = 'OK'
    $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK

    $CancelButton = new-object System.Windows.Forms.Button
    $CancelButton.Location = '355,200'
    $CancelButton.Size = '100,40'
    $CancelButton.Text = "Cancel"
    $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel

    $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton))

    $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2))

    $form.AcceptButton = $OKButton
    $form.CancelButton = $CancelButton

    $form.Add_Shown({$form.Activate()})

    $dialogResult = $form.ShowDialog()

    if ($dialogResult -eq "OK"){

        if ($RadioButton1.Checked){
           $baselineFolder = Start-FilePicker -description "Select a file or directory where the Baselines are located"
           if (![string]::IsNullOrEmpty($baselineFolder)) {
               Import-BaselineFromFolder -Path "$baselineFolder"
               $baselineNames = Get-BaselineNameFromDB
               Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames
           }
           else {
               $wshell = New-Object -ComObject Wscript.Shell
               $wshell.Popup("No Baseline was selected.",0,"Done",0x1)
           }
        }
    }
}

function Get-IsMitreAreaYsn {

    <#
        .SYNOPSIS
        Returns if a string is a MitreArea.
     
        .DESCRIPTION
        Returns if a string is a MitreArea.
 
        .PARAMETER AreaName
        Prompts you for the Area Name which should be checked.
     
        .EXAMPLE
        Get-IsMitreAreaYsn -BaselineName "MSFT Windows Server 2019 - Domain Controller"
     
        Returns all Mitre Techniques that would be covered by the specified baseline.
     
    #>

        [CmdletBinding()]
        [OutputType([Bool])]
        param (
            [Parameter(Mandatory = $true)]
            [string]$AreaName
        )
    
        $query = "select area_name from mitre_areas where area_name = ' + $AreaName + ';"
    
        if (Invoke-SqliteQuery -Query $query -DataSource $database) {
            return $true
        }
        else {
            return $false
        }

        
    
    }

function Get-MitreEvents {

<#
    .SYNOPSIS
    Returns all events for the selected Mitre techniques.
 
    .DESCRIPTION
    Returns all events for the selected Mitre techniques.
 
    .PARAMETER MitreTechniques
    Lets you specify the Mitre ATT&CK techniques that should be used.
 
    .PARAMETER AdvancedAudit
    If set, only events which will be set from the Advanced Audit options will be taken into account.
 
    .PARAMETER EventIds
    If set, only Event Ids will be returned from this function.
 
    .EXAMPLE
    Get-MitreEvents
 
    Returns all events for the selected Mitre techniques.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$True)]
        [string]$MitreTechniques,
        [switch]$AdvancedAudit,
        [switch]$EventIds
    )

    if (![string]::IsNullOrEmpty($MitreTechniques)) {

        if ($AdvancedAudit){
            # if success_failure_id >= 3 it's always s+f / 1 = s / 2 = f
            $query = "select subcategory_name, guid, sum(success_failure_id) as sf_sum from ( select distinct eaas.subcategory_name, eaas.guid, m.success_failure_id from mitre_techniques t, mitre_events e left join events_main m on e.event_id = m.id left join events_source so on m.so_id = so.id left join events_audit_subcategory eas on m.id = eas.event_id left join events_advanced_audit_subcategories eaas on eas.audit_subc_id = eaas.id where t.technique_id in ($MitreTechniques) and t.id = e.technique_id and e.event_id is not null and so.source_name = 'Advanced Audit Logs' and e.event_id <> '-1' ) group by subcategory_name, guid order by subcategory_name"
        }
        elseif ($EventIds) {
            $query = "select distinct e.event_id from mitre_techniques t, mitre_events e left join events_main m on e.event_id = m.id left join events_source so on m.so_id = so.id left join events_security_recommendation sr on m.sr_id = sr.id where t.technique_id in ($MitreTechniques) and t.id = e.technique_id and e.event_id is not null order by e.event_id"
        }
        else {
            $query = "select t.technique_id, t.technique_name, e.event_id, m.event_name, m.link_text, so.source_name, sr.sec_rec_name from mitre_techniques t, mitre_events e left join events_main m on e.event_id = m.id left join events_source so on m.so_id = so.id left join events_security_recommendation sr on m.sr_id = sr.id where t.technique_id in ($MitreTechniques) and t.id = e.technique_id and e.event_id is not null order by e.event_id"
        }

        $resultStr = Invoke-SqliteQuery -Query $query -DataSource $database
    }

    return $resultStr
}

function Get-MitreTechniquesFromBaseline {

    <#
        .SYNOPSIS
        Returns a list of MitreTechniques that would be covered by a specific baseline.
     
        .DESCRIPTION
        Returns a list of MitreTechniques that would be covered by a specific baseline.
 
        .PARAMETER BaselineName
        Prompts you for the Baseline Name that should be used to generate the Mitre Techniques list from.
     
        .EXAMPLE
        Get-MitreTechniquesFromBaseline -BaselineName "MSFT Windows Server 2019 - Domain Controller"
     
        Returns all Mitre Techniques that would be covered by the specified baseline.
     
    #>

        [CmdletBinding()]
        [OutputType([String])]
        param (
            [Parameter(Mandatory = $true)]
            [string]$BaselineName
        )
    
        $query = "select distinct a.technique_id as technique_id from ( select * from v_mitre_matches_baseline ) a left join ( select * from v_mitre_matches_baseline where baseline_name = '$BaselineName' ) b on a.technique_id = b.technique_id where b.baseline_name is not null order by a.area_id, a.technique_name;"
    
        $MitreTechniques = "'" + ((Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty technique_id) -join "', '") + "'"

        return $MitreTechniques
    
    }

function Get-Queries {

<#
    .SYNOPSIS
    Returns queries for the selected MITRE ATT&CK Techniques & areas.
 
    .DESCRIPTION
    Returns queries for the selected MITRE ATT&CK Techniques & areas.
 
    .PARAMETER TechniqueIds
    Prompts you for the TechniqueIds which should be used to generate the queries.
 
    .PARAMETER AreaNames
        Prompts you for the Area Names which should be used to generate the queries.
 
    .EXAMPLE
    Get-Queries -TechniqueIds "'T1086', 'T1039', 'T1090'" -AreaNames ""
 
    Returns queries for the selected MITRE ATT&CK Techniques & areas.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$True)]
        [string]$TechniqueIds,
        [string]$AreaNames
    )

    $query = "select distinct
                ma.area_name, mt.technique_id, mt.technique_name, qm.title, qm.description, qm.status, qm.date, qm.author, qm.raw_yaml, qm.level, qm.filename
            from mitre_events me, mitre_techniques mt, mitre_areas ma,
            queries_data_yaml_tags qt,
            queries_data_yaml_main qm
            where me.technique_id = mt.id
            and qt.mitre_technique_id = mt.id
            and qt.m_id = qm.id
            and me.area_id = ma.id
            and (
                    (mt.technique_id in ($TechniqueIds) )
                    or (ma.area_name in ($AreaNames))
                )
            order by area_id, technique_name;"



    $result = Invoke-SqliteQuery -Query $query -DataSource $database

    return $result
}

function Get-QueriesSelect {

<#
    .SYNOPSIS
    Shows a pop-up in which the query creation options are being displayed.
 
    .DESCRIPTION
    Shows a pop-up in which the query creation options are being displayed.
 
    .EXAMPLE
    Get-QueriesSelect
 
    Shows a pop-up in which the query creation options are being displayed.
 
#>


    [CmdletBinding()]
    param ()

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

    $Form = New-Object System.Windows.Forms.Form
    $Form.width = 700
    $Form.height = 400
    $Form.Text = "Generate Queries"

    $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10)
    $Form.Font = $Font

    $MyGroupBox = New-Object System.Windows.Forms.GroupBox
    $MyGroupBox.Location = '40,40'
    $MyGroupBox.size = '600,200'
    $MyGroupBox.text = "How would you like to create your queries?"

    $RadioButton1 = New-Object System.Windows.Forms.RadioButton
    $RadioButton1.Location = '20,50'
    $RadioButton1.size = '450,30'
    $RadioButton1.Checked = $true
    $RadioButton1.Text = "Please generate SIGMA queries for:"

    $ComboSiemBox                       = New-Object system.Windows.Forms.ComboBox
    $supportedSiem = Get-SigmaSupportedSiemFromDb
    if ([string]::IsNullOrEmpty($supportedSiem)) {
        $ComboSiemBox.text = "No supported Siem solution imported"
    }
    else {
        $ComboSiemBox.text = "Select Siem solution"
    }


    $ComboSiemBox.width                 = 200
    $ComboSiemBox.height                = 40

    $supportedSiem | ForEach-Object {[void] $ComboSiemBox.Items.Add($_)}
    $ComboSiemBox.location              = New-Object System.Drawing.Point(76,120)
    $ComboSiemBox.Font                  = 'Microsoft Sans Serif,11'

    $ComboSiemBox.Add_SelectedValueChanged({
        $Script:SelectedComboSiemBox = $ComboSiemBox.Text
    })

    $Form.controls.AddRange(@($ComboSiemBox))

    $RadioButton2 = New-Object System.Windows.Forms.RadioButton
    $RadioButton2.Location = '20,115'
    $RadioButton2.size = '450,30'
    $RadioButton2.Checked = $false
    $RadioButton2.Text = "Generate Queries in YAML format"

    $OKButton = new-object System.Windows.Forms.Button
    $OKButton.Location = '230,250'
    $OKButton.Size = '100,40'
    $OKButton.Text = 'OK'
    $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK

    $CancelButton = new-object System.Windows.Forms.Button
    $CancelButton.Location = '355,250'
    $CancelButton.Size = '100,40'
    $CancelButton.Text = "Cancel"
    $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel

    $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton))

    $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$Checkbox1))

    $form.AcceptButton = $OKButton
    $form.CancelButton = $CancelButton

    $form.Add_Shown({$form.Activate()})

    $dialogResult = $form.ShowDialog()

    if ($dialogResult -eq "OK"){
        if ($ExportFolder = Start-FilePicker -description "Where do you want to save your Queries?") {
            if ($RadioButton1.Checked){
                Get-SigmaQueries -Path $ExportFolder -siemName $SelectedComboSiemBox
            }
            elseif ($RadioButton2.Checked){
                Get-SigmaQueries -Path $ExportFolder -siemName $SelectedComboSiemBox -yamlOnly
            }
        }
    }
}

function Get-YamlAdminSelect {

<#
    .SYNOPSIS
    Shows a pop-up in which the YAML admin options are being displayed.
 
    .DESCRIPTION
    Shows a pop-up in which the YAML admin options are being displayed.
 
    .EXAMPLE
    Get-YamlAdminSelect
 
    Shows a pop-up in which the YAML admin options are being displayed.
 
#>


    [CmdletBinding()]
    param ()

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

    $Form = New-Object System.Windows.Forms.Form
    $Form.width = 700
    $Form.height = 350
    $Form.Text = "Delete Baseline"

    $Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10)
    $Form.Font = $Font

    $MyGroupBox = New-Object System.Windows.Forms.GroupBox
    $MyGroupBox.Location = '40,40'
    $MyGroupBox.size = '600,150'
    $MyGroupBox.text = "Would you prefer to..."

    $RadioButton1 = New-Object System.Windows.Forms.RadioButton
    $RadioButton1.Location = '20,50'
    $RadioButton1.size = '450,30'
    $RadioButton1.Checked = $true
    $RadioButton1.Text = "Import YAML Configuration Files"

    $RadioButton2 = New-Object System.Windows.Forms.RadioButton
    $RadioButton2.Location = '20,85'
    $RadioButton2.size = '450,30'
    $RadioButton2.Checked = $false
    $RadioButton2.Text = "Remove existing YAML Configuration"

    $OKButton = new-object System.Windows.Forms.Button
    $OKButton.Location = '230,200'
    $OKButton.Size = '100,40'
    $OKButton.Text = 'OK'
    $OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK

    $CancelButton = new-object System.Windows.Forms.Button
    $CancelButton.Location = '355,200'
    $CancelButton.Size = '100,40'
    $CancelButton.Text = "Cancel"
    $CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel

    $form.Controls.AddRange(@($MyGroupBox,$OKButton,$CancelButton))

    $MyGroupBox.Controls.AddRange(@($Radiobutton1,$RadioButton2,$RadioButton3))

    $form.AcceptButton = $OKButton
    $form.CancelButton = $CancelButton

    $form.Add_Shown({$form.Activate()})

    $dialogResult = $form.ShowDialog()

    if ($dialogResult -eq "OK"){

        if ($RadioButton1.Checked){
            Import-YamlCofigurationFiles
        }
        elseif ($RadioButton2.Checked){
            Remove-AllYamlConfigurations
        }
    }
}

function Import-BaselineIntoDb {

<#
    .SYNOPSIS
    Imports one policy into the database, if not existant yet.
 
    .DESCRIPTION
    Imports one policy into the database, if not existant yet.
 
    .PARAMETER Path
    Defines the path where the baseline is located.
 
    .PARAMETER PolicyName
    Name of the baseline which should be imported.
 
    .EXAMPLE
    Import-BaselineIntoDb -Path $item.FullName -PolicyName $auditPolicyNameStr
 
    Imports one policy into the database, if not existant yet.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [cmdletbinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path,
        [Parameter(Mandatory = $true)]
        [string]$PolicyName
    )

    $PolicyName = ConvertTo-PSSQLString($PolicyName)

    $Query = "select name from baseline_main where name = '$PolicyName';"

    if (!(Invoke-SqliteQuery -Query $Query -DataSource $Database)){
        $settings = Import-Csv -Path $Path

        if ($settings) {
            $Query = "insert into baseline_main (name) values ('$PolicyName');SELECT last_insert_rowid();"
            $b_id = Invoke-SqliteQuery -Query $Query -DataSource $Database | Select-Object -ExpandProperty "last_insert_rowid()"

            ForEach ($setting in $settings){
                $policy_target = $PolicyName = ConvertTo-PSSQLString($($setting."Policy Target"))
                $subcategory = ConvertTo-PSSQLString($($setting."Subcategory"))
                $subcategory_guid = ConvertTo-PSSQLString($($setting."Subcategory GUID"))
                $inclusion_setting = ConvertTo-PSSQLString($($setting."Inclusion Setting"))
                $exclusion_setting = ConvertTo-PSSQLString($($setting."Exclusion Setting"))
                $setting_value = ConvertTo-PSSQLString($($setting."Setting Value"))

                $Query = "insert into baseline_data (policy_target,subcategory,subcategory_guid,inclusion_setting,exclusion_setting,setting_value,b_id) values ('$policy_target','$subcategory','$subcategory_guid','$inclusion_setting','$exclusion_setting','$setting_value','$b_id');"
                Invoke-SqliteQuery -Query $Query -DataSource $Database
            }
        }
    }
    else {
        $PolicyName = ConvertFrom-PSSQLString($PolicyName)
        $resultStr = "Baseline $PolicyName was already imported"
        if ($Script:openFromGui) {
            $wshell = New-Object -ComObject Wscript.Shell
            $wshell.Popup($resultStr,0,"Done",0x1)
        }
        else {
            write-host $resultStr
        }
    }




}

function Import-YamlCofigurationFiles {

<#
    .SYNOPSIS
    Imports one or more YAML configuration file(s) from a folder into the database.
 
    .DESCRIPTION
    Imports one or more YAML configuration file(s) from a folder into the database. YAML configurations can be found in the sigma GitHub repository.
 
    .EXAMPLE
    Import-YamlCofigurationFiles
 
    Imports one or more YAML configuration file(s) from a folder into the database.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]
    param ()

    $configFolder = Start-FilePicker -description "Select the directory where the YAML configuration files are located"
    if (![string]::IsNullOrEmpty($configFolder)) {
        Import-YamlCofigurationFromFolder -Path $configFolder
    }
    else {
        $wshell = New-Object -ComObject Wscript.Shell
        $wshell.Popup("No Folder was selected.",0,"Done",0x1)
    }

}

function Remove-OneBaseline {

    <#
    .SYNOPSIS
    Removes one imported baseline from the database.
 
    .DESCRIPTION
    Removes one imported baseline from the database.
 
    .PARAMETER BaselineName
    Defines the name of the baseline.
 
    .PARAMETER Confirm
    Prompts you for confirmation before executing the command.
 
    .PARAMETER WhatIf
    Displays a message that describes the effect of the command, instead of executing the command.
 
    .EXAMPLE
    Remove-OneBaseline -BaselineName "SCM Windows 10 - Computer"
 
    Removes one imported baseline from the database.
 
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [CmdletBinding(SupportsShouldProcess)]
    Param (
        [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
        [string]$BaselineName
    )

    process {

        $valuesFromDb = Get-BaselineNameFromDB

        if (($BaselineName -eq "No Baselines imported") -or ($BaselineName -eq "Select Baseline") -or [string]::IsNullOrEmpty($BaselineName)) {
            $returnStr = "No Baseline was selected."
        
            if ($Script:openFromGui) {
                $wshell = New-Object -ComObject Wscript.Shell
                $wshell.Popup($returnStr, 0, "Delete selected baseline", 0x1)
            }
            Write-Host $returnStr
        }
        else {
            If ($BaselineName -in $valuesFromDb) {
                $query = "select id from baseline_main where name like '$BaselineName' ;"
                $id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty id

                $query = "delete from baseline_data where b_id = $id ; delete from baseline_main where id = $id ;"
                Invoke-SqliteQuery -Query $query -DataSource $database

                $returnStr = "Baseline $BaselineName was deleted successfully."

                if ($Script:openFromGui) {
                    $wshell = New-Object -ComObject Wscript.Shell
                    $wshell.Popup($returnStr, 0, "Delete selected baseline", 0x1)
                }
            }
        }
    }
}

function Reset-MitreCheckboxes {

<#
    .SYNOPSIS
    Unchecks all checked MITRE ATT&CK technique & area checkboxes.
 
    .DESCRIPTION
    Unchecks all checked MITRE ATT&CK technique & area checkboxes. Also resets the baseline combobox selection.
 
    .PARAMETER Confirm
    Prompts you for confirmation before executing the command.
 
    .PARAMETER WhatIf
    Displays a message that describes the effect of the command, instead of executing the command.
 
    .EXAMPLE
    Reset-MitreCheckboxes
 
    Unchecks all checked MITRE ATT&CK technique & area checkboxes.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")]
    [CmdletBinding(SupportsShouldProcess)]
    param ()

    foreach ($key in $CheckBox.keys) {
        for ($i=0; $i -lt $CheckBox[$key].Items.count; $i++) {
            $CheckBox[$key].SetItemChecked($i, $false)
        }
    }

    foreach ($key in $CheckBoxArea.keys) {
        $($CheckBoxArea[$key]).checked = $false
    }

    $ComboBox1Value = ""
    $ComboBox1.text = "Select Baseline"
}

function Select-AllCheckboxesFromOneArea {

<#
    .SYNOPSIS
    Selects all Checkboxes of the techniques mapped to an area.
 
    .DESCRIPTION
    Selects all Checkboxes of the techniques mapped to an area.
 
    .PARAMETER AreaName
    The name of the area.
 
    .EXAMPLE
    Select-AllCheckboxesFromOneArea -AreaName "Initial Access"
 
    Selects all Checkboxes of the techniques mapped to an area.
 
#>

    [CmdletBinding()]
    param (
        [string]$AreaName
    )

        if ($CheckBoxArea[$AreaName].checked) {
            $isChecked = $true
        }
        else {
            $isChecked = $false
        }

        for ($i=0; $i -lt $CheckBox[$AreaName].Items.count; $i++) {
            $CheckBox[$AreaName].SetItemChecked($i, $isChecked)
        }

}

Function Start-FilePicker{

<#
    .SYNOPSIS
    Lets the user select a folder and returns the path.
 
    .DESCRIPTION
    Lets the user select a folder and returns the path.
 
    .PARAMETER description
    Specifies the description dialog which is shown to the user
 
    .PARAMETER Confirm
    Prompts you for confirmation before executing the command.
 
    .PARAMETER WhatIf
    Displays a message that describes the effect of the command, instead of executing the command.
 
    .EXAMPLE
    Start-FilePicker -description "Select a file or directory"
 
    Lets the user select a folder and returns the path. and displays the description "Select a file or directory"
 
#>

    [CmdletBinding(SupportsShouldProcess)]
param(
    [string]$description = "Select a file or directory"
)

    $browse = New-Object System.Windows.Forms.FolderBrowserDialog
    $browse.SelectedPath = "$ENV:UserProfile\Downloads"
    $browse.Description = $description

    $show = $browse.ShowDialog()

    if ($show -eq "OK") {
        $test = $browse.SelectedPath | Out-String
        $test = $test -replace "`n|`r"
        return $test
    }
}

function Sync-ComboBox
{
<#
    .SYNOPSIS
        This functions helps you load baselines into a ComboBox.
 
    .DESCRIPTION
        Use this function to dynamically load baselines into the ComboBox control.
 
    .PARAMETER ComboBox
        The ComboBox control you want to add items to.
 
    .PARAMETER Items
        The object or objects you wish to load into the ComboBox's Items collection.
 
    .PARAMETER DisplayMember
        Indicates the property to display for the items in this control.
 
    .PARAMETER Append
        Adds the item(s) to the ComboBox without clearing the Items collection.
 
    .EXAMPLE
        Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames
 
        Loads baselines into a ComboBox.
 
#>

    [CmdletBinding()]
    Param (
            [ValidateNotNull()]
            [Parameter(Mandatory=$true)]
            [System.Windows.Forms.ComboBox]$ComboBox,
            $Items,
            [string]$DisplayMember,
            [switch]$Append
        )

   if(-not$Append)
    {
        $ComboBox.Items.Clear()
        $ComboBox.text = "No Baselines imported"
    }

    if($Items-is [Object[]])
    {
        $ComboBox.Items.AddRange($Items)
        $ComboBox.text = "Select Baseline"
    }
    elseif ($Items-is [Array])
    {
        $ComboBox.BeginUpdate()
        foreach($obj in $Items)
        {
            $ComboBox.Items.Add($obj)
            $ComboBox.text = "Select Baseline"
        }
        $ComboBox.EndUpdate()
    }
    elseif (![string]::IsNullOrEmpty($Items))
    {
        $ComboBox.Items.Add($Items)
        $ComboBox.text = "Select Baseline"
    }

    $ComboBox.DisplayMember =$DisplayMember
}

function Sync-MitreCheckboxes {

<#
    .SYNOPSIS
    Syncs all Mitre Checkboxes according to the selected baseline.
 
    .DESCRIPTION
    Syncs all Mitre Checkboxes according to the selected baseline.
 
    .PARAMETER BaselineName
    Defines the baseline for which the MITRE ATT&CK Checkboxes should be synced.
 
    .EXAMPLE
    Sync-MitreCheckboxes -BaselineName "SCM Windows 10 - Computer"
 
    Syncs all Mitre Checkboxes according to the selected baseline.
 
#>

    
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]
    param (
        [string]$BaselineName
    )

    if (![string]::IsNullOrEmpty($BaselineName)) {

        $query = "select distinct a.area_name as area_name, a.area_id as area_id, a.technique_name as technique_name, a.technique_id as technique_id, b.baseline_name as baseline_name from ( select * from v_mitre_matches_baseline ) a left join ( select * from v_mitre_matches_baseline where baseline_name = '" + $BaselineName + "' ) b on a.technique_id = b.technique_id order by a.area_id, a.technique_name;"
        $results = Invoke-SqliteQuery -Query $Query -DataSource $Database

            $i=0

            foreach ($result in $results) {

                if (($old_area_name) -and ($old_area_name -ne $result.area_name)) {
                    if ($i -eq $cntChecked) {
                        $CheckBoxArea[$old_area_name].checked = $true
                    }
                    else {
                        $CheckBoxArea[$old_area_name].checked = $false
                    }

                    $i = 0
                    $cntChecked = 0
                }

                if (![string]::IsNullOrEmpty($result.baseline_name)) {
                    $CheckBox[$result.area_name].SetItemChecked($i, $true)
                    $cntChecked = $cntChecked + 1
                }
                else {
                    $CheckBox[$result.area_name].SetItemChecked($i, $false)
                }
                $old_area_name = $result.area_name


                $i = $i + 1
            }

    }
}

function Add-EventListConfiguration {

<#
    .SYNOPSIS
    Writes an EventList configuration to the database.
 
    .DESCRIPTION
    Writes an EventList configuration to the database. Important: Specify the sigma\tools folder!
 
    Configurable options:
      - Path where Sigma is located to automatically parse the desired queries.
      - Default Output Path: Avoid clicking 1000 times to specify a default output location.
 
    .PARAMETER sigmaPath
    Path where Sigma is located to automatically parse the desired queries.
 
    .PARAMETER defaultOutputPath
    Default Output Path: Avoid clicking 1000 times to specify a default output location.
 
    .EXAMPLE
    Add-EventListConfiguration -sigmaPath "C:\tmp\sigma\tools"
 
    Writes the configuration for the Sigma Path to the database.
 
#>

    [CmdletBinding()]
    param(
        [string]$sigmaPath
    )

    if ($sigmaPath) {
        $query = "Update EventList_configuration set sigma_path='" + $sigmaPath + "' where id=1;"
    }

    if ($query) {
        Invoke-SqliteQuery -Query $query -DataSource $database
    }
}

function Get-AgentConfigString {

<#
    .SYNOPSIS
    Gets all the event ids that you need to monitor the selected MITRE Techniques & areas.
 
    .DESCRIPTION
    Gets all the event ids that you need to monitor the selected MITRE Techniques & areas and matches it to the selected event forwarder syntax.
     
    .PARAMETER Identity
    Prompts you for the Identity that should be used to generate an Agent Configuration from. You can either use a baseline name or one or multiple Mitre Technique IDs.
 
    .PARAMETER ForwarderName
    Specifies the name of the Agent Forwarder for which the config should be queried:
    - splunk
    - xpath
    - mdatp
 
    .EXAMPLE
    Get-AgentConfigString -ForwarderName splunk
 
    Gets all the event ids for the Splunk Universal Forwarder that you need to monitor the selected MITRE Techniques & areas.
 
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('BaselineName', 'TechniqueId')]
        [string]$Identity,
        [Parameter(Mandatory=$True)]
        [string]$ForwarderName
    )

    process {

        if ($Script:openFromGui) {
            $MitreTechniques = $(Get-CheckedMitreTechniques)
        }
        else {
            if ($identity) {
                if (Get-BaselineNameFromDB -BaselineName $Identity){
                    $MitreTechniques = Get-MitreTechniquesFromBaseline -BaselineName $Identity
                }
                elseif ($Identity -match "^T\d{4}$") {
                    $MitreTechniques = $("'" + $Identity + "'")
                }
                elseif ( ($Identity -match "^['T\d{4}$]") -or ($Identity -match "^T\d{4}$") ) {
                    $MitreTechniques = $Identity
                }
            }
        }

        if ($MitreTechniques) {
            if ($Script:openFromGui) {
                $query = "select * from agent_forwarder_syntax where name = '" + (ConvertTo-PSSQLString($ForwarderName)) + "';"
            }
            else {
                $query = "select * from agent_forwarder_syntax where short_name = '" + (ConvertTo-PSSQLString($ForwarderName)) + "';"
            }
            
            $results = Invoke-SqliteQuery -Query $query -DataSource $database
        
            foreach ($result in $results) {
                $eventStr = Get-MitreEvents -MitreTechniques $MitreTechniques -EventIds | Select-Object -ExpandProperty event_id -Unique | foreach-Object { $result.single_event_syntax -replace ("{{SINGLE_EVENTID}}", $_) }
                
                $eventStr = [string]$eventStr -replace(" ", ($result.event_separator + " "))
                $eventStr = [string]$eventStr -replace(($result.event_separator + " -1"), "")
        
                if ($result.single_event_syntax -eq "{{SINGLE_EVENTID}}") {
                    $eventStr = [string]$eventStr -replace("-1", "")
                }
                else {
                    $SingleEventSyntaxReplaced = $result.single_event_syntax -replace ("{{SINGLE_EVENTID}}", "")
                    $eventStr = [string]$eventStr -replace(($SingleEventSyntaxReplaced + "-1" + $result.event_separator), "")
                }
        
                $syntaxStr = $result.syntax -replace ("{{EVENTIDS}}", $eventStr) -replace "`n", "`r`n"
        
                $syntaxStr = $syntaxStr -replace(("= " + $result.event_separator), "=")

                if ($Script:openFromGui) {
                    $agentSnippetBox.Text = $syntaxStr
                }
                else {
                    write-host $syntaxStr
                }
                
            }
        }
        else {
            write-host "No MITRE ATT&CK techniques were selected."
        }
    }

}

function Get-BaselineEventList {

<#
    .SYNOPSIS
    Gets an EventList for the selected Baseline.
 
    .DESCRIPTION
    Gets an EventList for the Baseline which was selected from the Combobox in the GUI.
 
    .PARAMETER BaselineName
    Prompts you for the Baseline Name that should be used to generate an EventList from.
 
    .PARAMETER generateExcelYsn
    Defines if an Excel document will be generated. When checked, one can define where the document should be stored.
 
    .EXAMPLE
    Get-BaselineEventList -generateExcelYsn $true
 
    Gets an EventList for the selected Baseline.
 
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline=$True)]
        [string]$BaselineName,
        [boolean]$generateExcelYsn = $false
    )

    process {

        if ($Script:openFromGui) {
            $BaselineName = $ComboBox1Value
        }

        if (($BaselineName -eq "No Baselines imported") -or ($BaselineName -eq "Select Baseline") -or [string]::IsNullOrEmpty($BaselineName)){
            $returnStr = "No Baseline was selected."
            if ($Script:openFromGui) {
                    $wshell = New-Object -ComObject Wscript.Shell
                    $wshell.Popup($returnStr,0,"Generate EventList",0x1)
            }
            else {
                Write-Host $returnStr
            }
        }
        else {
            $BaselineName = ConvertTo-PSSQLString($BaselineName)
            $query = "select eaac.category_name as Category, d.subcategory as Subcategory, em.id as 'Event ID', em.event_name as 'Event Description', em.link_text as 'Event Link', d.inclusion_setting as 'Audit Recommendation', d.setting_value 'Audit Recommendation Number', sf.success_failure_name as 'Event S/F', d.policy_target as 'Policy Target', sr.sec_rec_name as Recommendation from baseline_main m, baseline_data d, events_main em, events_source so, events_success_failure sf, events_security_recommendation sr, events_audit_subcategory eas, events_advanced_audit_categories eaac, events_advanced_audit_subcategories eaas where m.id = d.b_id and d.subcategory = eaas.subcategory_name and em.so_id = so.id and em.success_failure_id = sf.id and em.sr_id = sr.id and em.id = eas.event_id and eas.audit_subc_id = eaas.id and eaas.c_id = eaac.id and m.name = '$BaselineName';"
            $results = Invoke-SqliteQuery -Query $query -DataSource $database
            if ($generateExcelYsn) {
                $tmp = get-date -f yyyyMMddHHmmss
                $results | Export-Csv -Path $ExportFolder\$tmp"EventList.csv"
            }
            else {
                if ($Script:openFromGui) {
                    $BaselineName = ConvertFrom-PSSQLString($BaselineName)
                    $results | Out-GridView -Title "EventList for: $BaselineName"
                }
                else {
                    return $results
                }
            }

        }

    }

}



function Get-BaselineNameFromDB {

<#
    .SYNOPSIS
    Gets all the names of the baselines, stored in the database.
 
    .DESCRIPTION
    Gets all the names of the baselines, stored in the database.
 
    .PARAMETER BaselineName
    Prompts you for the Baseline Name that should be checked against the database.
 
    .EXAMPLE
    Get-BaselineNameFromDB
 
    Gets all the names of the baselines, stored in the database.
 
#>


    [CmdletBinding()]
    param (
        [string]$BaselineName
    )

    if ($BaselineName){
        $tmpStr = " where name = '" + (ConvertTo-PSSQLStringArray($BaselineName)) + "'"
    }

    $query = "select name from baseline_main" + $tmpStr + ";"

    $baselineNames = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty name

    if ($baselineNames) {
        $baselineNames = ConvertFrom-PSSQLStringArray -Text $baselineNames
    }
    
    return $baselineNames
}

function Get-GroupPolicyFromMitreTechniques {

    <#
    .SYNOPSIS
    Creates a group policy out of the selected events.
 
    .DESCRIPTION
    Creates a group policy out of the selected events which are mapped to the MITRE ATT&CK Techniques.
 
    .PARAMETER Identity
    Prompts you for the Identity that should be used to generate an Group Policy from. You can either use a baseline name or one or multiple Mitre Technique IDs.
     
    .PARAMETER Path
    Lets you specify the destination output path: where should the GPO be stored?
 
    .EXAMPLE
    Get-GroupPolicyFromMitreTechniques
 
    Creates a group policy out of the selected events.
 
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseOutputTypeCorrectly", "")]
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('BaselineName', 'TechniqueId')]
        [string]$Identity,
        [string]$Path
    )

    process {

        if ($Path) {
            $destFolder = $Path
        }
        else {
            if ($Script:openFromGui) {
                $destFolder = Start-FilePicker -description "Select a directory where the GPO should be saved"
            }
            else {
                write-host "Provide the path where the GPO should be saved: Get-GroupPolicyFromMitreTechniques -Path 'C:\tmp' -Identity 'T1039'"
            }
        }

        if ($destFolder) {
            $GpoTmpl = "$ModuleRoot\internal\data\GPO\*"

            if ($Script:openFromGui) {
                $MitreTechniques = Get-CheckedMitreTechniques
            }
            else {
                if ($identity) {
                    if (Get-BaselineNameFromDB -BaselineName $Identity) {
                        $MitreTechniques = Get-MitreTechniquesFromBaseline -BaselineName $Identity
                    }
                    elseif ($Identity -match "^T\d{4}$") {
                        $MitreTechniques = $("'" + $Identity + "'")
                    }
                    elseif ( ($Identity -match "^['T\d{4}$]") -or ($Identity -match "^T\d{4}$") ) {
                        $MitreTechniques = $Identity
                    }
                }
            }
        
            $tmp = Get-MitreEvents  -MitreTechniques $MitreTechniques -advancedAudit
        
            if ($tmp) {
                $auditCsvString = "Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting,Setting Value"
        
                foreach ($item in $tmp) {
                    $subcategory_name = $item | Select-Object -ExpandProperty subcategory_name
                    $guid = $item | Select-Object -ExpandProperty guid
                    $sf_sum = $item | Select-Object -ExpandProperty sf_sum
        
                    switch ($sf_sum) {
                        # if success_failure_id >= 3 it's always s+f / 1 = s / 2 = f
                        0 { "" }
                        1 {
                            $sf_string = "Success"
                            $sf_number = $sf_sum
                        }
                        2 {
                            $sf_string = "Failure"
                            $sf_number = $sf_sum
                        }
                        default {
                            $sf_string = "Success and Failure"
                            $sf_number = 3
                        }
                    }
        
                    $auditCsvString = $auditCsvString + "`r`n,System,$subcategory_name,$guid,$sf_string,,$sf_number"
                }
        
                $GPOFolder = $("{$(New-Guid)}").ToUpper()
        
                New-Item -ItemType directory -Path "$destFolder\$GPOFolder"
                Copy-Item "$GpoTmpl" -Destination "$destFolder\$GPOFolder" -Recurse
        
                New-Item -ItemType directory -Path "$destFolder\$GPOFolder\Machine\Microsoft\Windows NT\Audit\"
        
                New-Item -ItemType directory -Path "$destFolder\$GPOFolder\Machine\Scripts\Shutdown\"
                New-Item -ItemType directory -Path "$destFolder\$GPOFolder\Machine\Scripts\Startup\"
                New-Item -ItemType directory -Path "$destFolder\$GPOFolder\User\"
        
                Set-Content -Path "$destFolder\$GPOFolder\Machine\Microsoft\Windows NT\Audit\audit.csv" -Value $auditCsvString
            }
        
        }
    }

}

function Get-MitreEventList {

    <#
    .SYNOPSIS
    Gets an EventList for the selected MITRE ATT&CK techniques.
 
    .DESCRIPTION
    Gets an EventList for the MITRE ATT&CK techniques which were selected from the checkboxes in the GUI.
 
    .PARAMETER Identity
    Defines which MITRE ATT&CK Techniques or which Microsoft Security Baseline should be used as Input to generate a Mitre EventList.
 
    .PARAMETER generateExcelYsn
    Defines if an Excel document will be generated. When checked, one can define where the document should be stored.
 
    .EXAMPLE
    Get-MitreEventList -generateExcelYsn $true
 
    Gets an EventList for the selected MITRE ATT&CK techniques.
 
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('BaselineName', 'TechniqueId')]
        [string]
        $Identity,
        [boolean]$generateExcelYsn = $false
    )

    process {

        if ($Script:openFromGui) {
            $results = Get-MitreEvents -MitreTechniques $(Get-CheckedMitreTechniques)
        }
        else {
            if ($identity) {
                if (Get-BaselineNameFromDB -BaselineName $Identity) {
                    $tmpStr = Get-MitreTechniquesFromBaseline -BaselineName $Identity
                    if ($tmpStr) {
                        $results = Get-MitreEvents -MitreTechniques $tmpStr
                    }
                }
                elseif ($Identity -match "^T\d{4}$") {
                    $results = Get-MitreEvents -MitreTechniques $("'" + $Identity + "'")
                }
                elseif ( ($Identity -match "^['T\d{4}$]") -or ($Identity -match "^T\d{4}$") ) {
                    $results = Get-MitreEvents -MitreTechniques $Identity
                }
            }
        }
        
        if (![string]::IsNullOrEmpty($results)) {
            if ($generateExcelYsn) {
                $tmp = get-date -f yyyyMMddHHmmss
                $results | Export-Csv -Path $ExportFolder\$tmp"EventList.csv"
            }
            else {
                if ($Script:openFromGui) {
                    $results | Out-GridView -Title "EventList for: $ComboBox1Value"
                }
                else {
                    $results
                }
            }

        }
        else {
            $returnStr = "No MITRE ATT&CK techniques were selected."
            if ($Script:openFromGui) {
                $wshell = New-Object -ComObject Wscript.Shell
                $wshell.Popup($returnStr, 0, "Done", 0x1)
            }
            else {
                Write-Host $returnStr
            }
        }
    }

}

function Get-SigmaPath {

<#
    .SYNOPSIS
    Returns the path to the location where sigmac is located.
 
    .DESCRIPTION
    Returns the path to the location where sigmac is located. The path is configured by the user.
 
    .EXAMPLE
    Get-SigmaPath
 
    Returns the path to the location where sigmac is located.
 
#>

    [CmdletBinding()]
    [OutputType([String])]
    param ()

    $query = "select sigma_path from EventList_configuration;"

    $sigmaPath = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty sigma_path

    $sigmaPath = $sigmaPath

    if (!(Test-Path -Path "$sigmaPath\sigmac" -PathType Leaf)) {
        return ""
    }
    else {
        return "$sigmaPath\sigmac"
    }

}

function Get-SigmaQueries {

    <#
    .SYNOPSIS
    Returns the queries for the desired target system.
 
    .DESCRIPTION
    Returns the queries for the desired target system. Either as YAML, sigma command or already converted by sigma.
 
    .PARAMETER Identity
    Prompts you for the Identity that should be used to generate the Sigma queries from. You can either use a baseline name or one or multiple Mitre Technique IDs.
 
    .PARAMETER Path
    Defines where the Output should be stored.
 
    .PARAMETER siemName
    Defines the target SIEM system. Must be supported by Sigma.
 
    .PARAMETER yamlOnly
    If set, the configuration will be generated in YAML only
 
    .EXAMPLE
    Get-SigmaQueries -Path $ExportFolder -siemName $SelectedComboSiemBox
 
    Returns the queries for the desired target system.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]

    param (
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('TechniqueId', 'BaselineName')]
        [string]$Identity,
        [Parameter(Mandatory = $True)]
        [string]$Path,
        [Parameter(Mandatory = $True)]
        [string]$siemName,
        [switch]$yamlOnly
    )

    process {

        $query = "select target from sigma_supportedSiem where name = '" + $siemName + "' COLLATE NOCASE;"
        $target = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty target

        if ($Script:openFromGui) {
            $MitreTechniques = Get-CheckedMitreTechniques
            $MitreAreas = Get-CheckedMitreAreas
        }
        else {
            if ($identity) {
                if (Get-BaselineNameFromDB -BaselineName $Identity) {
                    $MitreTechniques = Get-MitreTechniquesFromBaseline -BaselineName $Identity
                }
                elseif ($Identity -match "^T\d{4}$") {
                    $MitreTechniques = $("'" + $Identity + "'")
                }
                elseif ( ($Identity -match "^['T\d{4}$]") -or ($Identity -match "^T\d{4}$") ) {
                    $MitreTechniques = $Identity
                }
            }


            if ($MitreTechniques) {
                $tmpStr = $tmpStr + " -TechniqueIds $MitreTechniques"
            }
            if ($MitreAreas) {
                $tmpStr = $tmpStr + " -AreaNames $MitreAreas"
            }
        }

        if ($MitreTechniques) {
            $queryObj = Get-Queries -TechniqueIds $MitreTechniques
        }
        elseif ($MitreAreas) {
            $queryObj = Get-Queries -AreaNames $MitreAreas
        }
        elseif (($MitreTechniques) -and ($MitreAreas)) {
            $queryObj = Get-Queries -TechniqueIds $MitreTechniques -AreaNames $MitreAreas
        }

        if ($queryObj) {

            $tmp = get-date -f yyyyMMddHHmmss
    
            $yamlPath = $Path + "\" + $tmp + "_EventList-Queries\yaml\"
            New-Item -ItemType directory -Path $Path\$tmp"_EventList-Queries"
            New-Item -ItemType directory -Path $yamlPath
    
            foreach ($item in $queryObj) {
                $addQuery = $false
                $tmpStr = ""
                $sigmaLocation = Get-SigmaPath
                if ($sigmaLocation) {
                    $sigmaIsInstalled = $true
                }
                else {
                    $sigmaIsInstalled = $false
                }
    
                $area_name = ConvertFrom-PSSQLString -Text $item.area_name
                $technique_id = ConvertFrom-PSSQLString -Text $item.technique_id
                $technique_name = ConvertFrom-PSSQLString -Text $item.technique_name
                $title = ConvertFrom-PSSQLString -Text $item.title
                $description = ConvertFrom-PSSQLString -Text $item.description
                $status = ConvertFrom-PSSQLString -Text $item.status
                $date = ConvertFrom-PSSQLString -Text $item.date
                $author = ConvertFrom-PSSQLString -Text $item.author
                $raw_yaml = ConvertFrom-PSSQLString -Text $item.raw_yaml
                $level = ConvertFrom-PSSQLString -Text $item.level
                $filename = ConvertFrom-PSSQLString -Text $item.filename
    
                $yamlFile = ".\yaml\" + $filename
                Set-Content -Path ($yamlPath + $filename) -Value $raw_yaml
    
    
    
                if ($old_areaName -ne $area_name) {
                    if ($old_areaName) {
                        $tmpStr = $tmpStr + "`r`n"
                    }
    
                    $tmpStr = $tmpStr + "# " + $area_name + "`r`n"
                }
    
                if ($old_techniqueName -ne $technique_name) {
                    $tmpStr = $tmpStr + "`r`n"
                    $tmpStr = $tmpStr + "## " + $technique_id + " " + $technique_name + "`r`n"
                }
    
                $tmpStr = $tmpStr + "`r`n"
                $tmpStr = $tmpStr + "### " + $title + "`r`n"
    
                if ($sigmaIsInstalled) {
                    "Processing " + $title + "`r`n" >> $Path\$tmp"_EventList-Queries\SigmaLog.txt"
                }
    
                $tmpStr = $tmpStr + "* Author: " + $author + "`r`n"
                $tmpStr = $tmpStr + "* Date: " + $date + "`r`n"
                $tmpStr = $tmpStr + "* Query Status: " + $status + "`r`n"
                $tmpStr = $tmpStr + "* Level: " + $level + "`r`n"
    
                $tmpStr = $tmpStr + "*" + $description + "*`r`n"
    
                if ($yamlOnly) {
                    $tmpStr = $tmpStr + "#### Yaml:`r`n"
                    $tmpStr = $tmpStr + $raw_yaml
                    $addQuery = $true
                }
                else {
                    if ($sigmaIsInstalled) {
                        $sigmaConfigPath = Join-Path -Path $sigmaLocation -ChildPath "..\config\generic\windows-audit.yml" -Resolve
                        $sigmaquery = python.exe $sigmaLocation -t $target ($yamlPath + $filename) -c $sigmaConfigPath 2>>$Path\$tmp"_EventList-Queries\SigmaLog.txt"

                        if ($sigmaquery) {
                            $addQuery = $true
                        }
    
                        $tmpStr = $tmpStr + " " + $sigmaquery + "`r`n"
                        if ($addQuery) {
                            $scriptStr = $scriptStr + $sigmaquery + "`r`n`r`n"
                        }
                    }
                    else {
                        $tmpStr = $tmpStr + " python.exe tools/sigmac -t $target $yamlFile -c config\generic\windows-audit.yml `r`n"
                        $addQuery = $true
                        $scriptStr = $scriptStr + "python.exe tools/sigmac -t $target $yamlFile -c config\generic\windows-audit.yml `r`n`r`n"
                    }
                }
    
                if ($addQuery) {
                    $outputStr = $outputStr + $tmpStr
                }
    
                $old_areaName = $area_name
                $old_techniqueName = $technique_name
            }
    
            Set-Content -Path $Path\$tmp"_EventList-Queries\EventList-Queries.md" -Value $outputStr

            if ($scriptStr) {
                Set-Content -Path $Path\$tmp"_EventList-Queries\EventList-Queries.txt" -Value $scriptStr
            }
        }
    
    }

}

function Get-SigmaSupportedSiemFromDb {

<#
    .SYNOPSIS
    Returns all SIEM systems which are supported by sigma.
 
    .DESCRIPTION
    Returns all SIEM systems which are supported by sigma.
 
    .EXAMPLE
    Get-SigmaSupportedSiemFromDb
 
    Returns all SIEM systems which are supported by sigma.
 
#>

    [CmdletBinding()]
    param ()

    $query = "select name from sigma_supportedSiem order by name;"

    $siemNames = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty name

    return $siemNames
}

function Import-BaselineFromFolder {

<#
    .SYNOPSIS
    Imports one or multiple baselines from a folder into the database.
 
    .DESCRIPTION
    Imports one or multiple baselines from a folder into the database.
 
    .PARAMETER Path
    Path where the baseline(s) is/are located.
 
    .EXAMPLE
    Import-BaselineFromFolder -Path "C:\tmp\"
 
    Imports one or multiple baselines from "C:\tmp" into the database.
 
#>


    [cmdletbinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path
    )

    $test = Get-ChildItem -LiteralPath $Path -Filter audit.csv -Recurse -ErrorAction SilentlyContinue -Force | Group-Object path

    foreach ($item in $test.Group) {
        if (![string]::IsNullOrEmpty($item.FullName)) {
            if ($item.Directory -match "GPO") {
                $gpReportXmlPathStr = $item.Directory -Replace("DomainSysvol\\GPO\\Machine\\microsoft\\windows nt\\Audit", "gpreport.xml")
                [xml]$xml = Get-Content -Path $gpReportXmlPathStr
                $auditPolicyNameStr = $xml.GPO.Name
                Import-BaselineIntoDb -Path $item.FullName -PolicyName $auditPolicyNameStr
            }
        }
    }
}

function Import-YamlCofigurationFromFolder {

<#
    .SYNOPSIS
    Imports one or more YAML configuration file(s) into the database.
 
    .DESCRIPTION
    Imports one or more YAML configuration file(s) into the database. YAML configurations can be found in the sigma GitHub repository.
 
    .PARAMETER Path
    Defines the path where the YAML configuration files are located.
 
    .PARAMETER Force
    If set, overwrites queries, that were already imported in the database.
 
    .EXAMPLE
    Import-YamlCofigurationFromFolder -Path "C:\tmp"
 
    Imports one or more YAML configuration file(s) from "C:\tmp" into the database.
 
#>


    [cmdletbinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path,
        [switch]$Force
     )

    $YamlConfigFiles = Get-ChildItem -LiteralPath $Path -Recurse -ErrorAction SilentlyContinue -Force | Group-Object path


    foreach ($item in $YamlConfigFiles.Group) {
        if (![string]::IsNullOrEmpty($item.FullName)) {

            if ($item.Extension -match ".yml") {
                $rawYaml = get-content -raw $item.FullName
                $yamlObj = [pscustomobject](convertfrom-yaml $rawYaml)

                $delQuery = ""
                $tmpStr = ""
                $sqlStr = ""

                $query = "select * from queries_data_yaml_main where title = '" + (ConvertTo-PSSQLString -Text $yamlObj.title) + "';"

                if ($Force) {
                    $m_id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty "id"

                    if ($m_id -gt 0) {
                        $delQuery = "delete from queries_data_yaml_tags where m_id = '$m_id'; "
                    }

                    $delQuery = $delQuery + "delete from queries_data_yaml_main where title = '" + (ConvertTo-PSSQLString -Text $yamlObj.title) + "';"
                    Invoke-SqliteQuery -Query $delQuery -DataSource $database
                }

                if (!(Invoke-SqliteQuery -Query $query -DataSource $database)) {
                    $sqlStr = "insert into queries_data_yaml_main (title, description, status, date, author, raw_yaml, level, filename) values ('" + (ConvertTo-PSSQLString -Text $yamlObj.title) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.description) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.status) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.date) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.author) + "', '" + (ConvertTo-PSSQLString -Text $rawYaml) + "', '" + (ConvertTo-PSSQLString -Text $yamlObj.level) + "', '" + (ConvertTo-PSSQLString -Text $item.name) + "'); select last_insert_rowid();"
                    $m_id = Invoke-SqliteQuery -Query $sqlStr -DataSource $database | Select-Object -ExpandProperty "last_insert_rowid()"

                    foreach ($item in $yamlObj.tags) {
                        $technique_id = 0
                        $area_id = 0
                        $tag_category = ($item.split("."))[0]
                        $tag_name = ($item.split("."))[1] -replace "_", " "

                        if ($tag_category -eq "attack") {
                            if ($tag_name.SubString(0,1) -eq "t") {
                                $query = "SELECT * FROM mitre_techniques WHERE technique_id = '$tag_name' COLLATE NOCASE;"
                                $technique_id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty "id"
                            }
                            else {
                                $query = "SELECT * FROM mitre_areas WHERE area_name = '$tag_name' COLLATE NOCASE;"
                                $area_id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty "id"

                                if (!($technique_id) -or ($technique_id -eq 0)) {
                                    $query = "SELECT * FROM mitre_techniques WHERE technique_name = '$tag_name' COLLATE NOCASE;"
                                    $technique_id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty "id"
                                }
                            }
                        }

                        if (!$technique_id) {
                            $technique_id = 0
                        }

                        if (!$area_id) {
                            $area_id = 0
                        }

                        $tmpStr = "insert into queries_data_yaml_tags (tag_name, m_id, full_tag_name, category, mitre_area_id, mitre_technique_id) values ('$tag_name', '$m_id', '$item', '$tag_category', '$area_id', '$technique_id');"

                        if (![string]::IsNullOrEmpty(($tmpStr))) {
                            Invoke-SqliteQuery -Query $tmpStr -DataSource $database
                        }
                    }
                }

            }
        }
    }

}

function Open-EventListGUI {

<#
    .SYNOPSIS
    Opens the EventList GUI.
 
    .DESCRIPTION
    Opens the EventList GUI.
 
    .EXAMPLE
    Open-EventListGUI
 
    Opens the EventList GUI.
 
#>


    $Script:openFromGui = $true

    $GuiWidth = 1535
    $GuiHeight = 1000

    $ButtonWidth = 200
    $ButtonHeight = 30
    $ButtonXDistance = 215
    $ButtonYDistance = 40

    $ButtonPanelDistance = 1305

    $ComboboxWidth = 420

    $x = 10
    $y = 20 + 60

    Add-Type -AssemblyName System.Windows.Forms
    [System.Windows.Forms.Application]::EnableVisualStyles()


    $Form                            = New-Object system.Windows.Forms.Form
    $Form.ClientSize                 = "$GuiWidth,$GuiHeight"
    $Form.text                       = "EventList"
    $Form.TopMost                    = $false

    #Panel oben mit Baseline Auswahl
    $Panel1                          = New-Object system.Windows.Forms.Panel
    $Panel1.height                   = 50
    $Panel1.width                    = 2000
    $Panel1.BackColor                = "#9b9b9b"
    $Panel1.location                 = New-Object System.Drawing.Point(0,0)

    #Panel an der Seite mit Buttons
    $Panel2                          = New-Object system.Windows.Forms.Panel
    $Panel2.height                   = 2000
    $Panel2.width                    = 235
    $Panel2.BackColor                = "#9b9b9b"
    $Panel2.location                 = New-Object System.Drawing.Point($ButtonPanelDistance,0)

    Add-MitreCheckboxes

    $x = $ButtonPanelDistance + 10
    $y = 60

    $ButtonShowEvts                         = New-Object system.Windows.Forms.Button
    $ButtonShowEvts.BackColor               = "#d5d8d7"
    $ButtonShowEvts.text                    = "Generate Event List"
    $ButtonShowEvts.width                   = $ButtonWidth
    $ButtonShowEvts.height                  = $ButtonHeight
    $ButtonShowEvts.location                = New-Object System.Drawing.Point($x,$y)
    $ButtonShowEvts.Font                    = 'Microsoft Sans Serif,11'
    $Form.controls.AddRange(@($ButtonShowEvts))
    $ButtonShowEvts.Add_Click({
        Get-EventListSelect
     })

    $y = $y + $ButtonYDistance

    $ButtonAgentCfg                         = New-Object system.Windows.Forms.Button
    $ButtonAgentCfg.BackColor               = "#d5d8d7"
    $ButtonAgentCfg.text                    = "Generate Agent Config"
    $ButtonAgentCfg.width                   = $ButtonWidth
    $ButtonAgentCfg.height                  = $ButtonHeight
    $ButtonAgentCfg.location                = New-Object System.Drawing.Point($x,$y)
    $ButtonAgentCfg.Font                    = 'Microsoft Sans Serif,11'
    $Form.controls.AddRange(@($ButtonAgentCfg))
    $ButtonAgentCfg.Add_Click({ Get-AgentConfigSelect })

    $y = $y + $ButtonYDistance

    $ButtonExportQueries                         = New-Object system.Windows.Forms.Button
    $ButtonExportQueries.BackColor               = "#d5d8d7"
    $ButtonExportQueries.text                    = "Generate Queries"
    $ButtonExportQueries.width                   = $ButtonWidth
    $ButtonExportQueries.height                  = $ButtonHeight
    $ButtonExportQueries.location                = New-Object System.Drawing.Point($x,$y)
    $ButtonExportQueries.Font                    = 'Microsoft Sans Serif,11'
    $Form.controls.AddRange(@($ButtonExportQueries))
    $ButtonExportQueries.Add_Click({
        Get-QueriesSelect
    })

    $y = $y + $ButtonYDistance

    $ButtonExportGPO                         = New-Object system.Windows.Forms.Button
    $ButtonExportGPO.BackColor               = "#d5d8d7"
    $ButtonExportGPO.text                    = "Generate GPO"
    $ButtonExportGPO.width                   = $ButtonWidth
    $ButtonExportGPO.height                  = $ButtonHeight
    $ButtonExportGPO.location                = New-Object System.Drawing.Point($x,$y)
    $ButtonExportGPO.Font                    = 'Microsoft Sans Serif,11'
    $Form.controls.AddRange(@($ButtonExportGPO))
    $ButtonExportGPO.Add_Click({ Get-GroupPolicyFromMitreTechniques })

    $y = $GuiHeight - 50

    $ButtonExit                         = New-Object system.Windows.Forms.Button
    $ButtonExit.BackColor               = "#C0C0C0"
    $ButtonExit.text                    = "Close"
    $ButtonExit.width                   = $ButtonWidth
    $ButtonExit.height                  = $ButtonHeight
    $ButtonExit.location                = New-Object System.Drawing.Point($x,$y)
    $ButtonExit.Font                    = [System.Drawing.Font]::new("Microsoft Sans Serif", 11, [System.Drawing.FontStyle]::Bold)
    $Form.controls.AddRange(@($ButtonExit))
    $ButtonExit.Add_Click({ Close-Form -Form $Form })

    $Script:ComboBox1                       = New-Object system.Windows.Forms.ComboBox
    $baselineNames = Get-BaselineNameFromDB
    if ([string]::IsNullOrEmpty($baselineNames)) {
        $ComboBox1.text = "No Baselines imported"
    }
    else {
        $ComboBox1.text = "Select Baseline"
    }


    $ComboBox1.width                 = $ComboboxWidth
    $ComboBox1.height                = 40

    $x = 20
    $y = 10

    Get-BaselineNameFromDB | ForEach-Object {[void] $ComboBox1.Items.Add($_)}
    $ComboBox1.location              = New-Object System.Drawing.Point($x,($y+2))
    $ComboBox1.Font                  = 'Microsoft Sans Serif,11'

    $ComboBox1.Add_SelectedValueChanged({
        $Script:ComboBox1Value = $ComboBox1.Text
        Sync-MitreCheckboxes -BaselineName $ComboBox1Value
    })

    $Form.controls.AddRange(@($ComboBox1))

    $x = $x + $ComboboxWidth + 15

    $ButtonImportBsl                         = New-Object system.Windows.Forms.Button
    $ButtonImportBsl.BackColor               = "#d5d8d7"
    $ButtonImportBsl.text                    = "Import Baseline(s)"
    $ButtonImportBsl.width                   = $ButtonWidth
    $ButtonImportBsl.height                  = $ButtonHeight
    $ButtonImportBsl.location                = New-Object System.Drawing.Point($x,$y)
    $ButtonImportBsl.Font                    = 'Microsoft Sans Serif,11'
    $Form.controls.AddRange(@($ButtonImportBsl))
    $ButtonImportBsl.Add_Click({
        Get-ImportSelect
    })

    $x = $x + $ButtonXDistance

    $ButtonDelOneBaseline                         = New-Object system.Windows.Forms.Button
    $ButtonDelOneBaseline.BackColor               = "#d5d8d7"
    $ButtonDelOneBaseline.text                    = "Delete baseline(s)"
    $ButtonDelOneBaseline.width                   = $ButtonWidth
    $ButtonDelOneBaseline.height                  = $ButtonHeight
    $ButtonDelOneBaseline.location                = New-Object System.Drawing.Point($x,$y)
    $ButtonDelOneBaseline.Font                    = 'Microsoft Sans Serif,11'
    $Form.controls.AddRange(@($ButtonDelOneBaseline))
    $ButtonDelOneBaseline.Add_Click({
        Get-DeleteBaselineSelect
     })

     $x = $x + $ButtonXDistance

     $ButtonResetCheckboxes                         = New-Object system.Windows.Forms.Button
     $ButtonResetCheckboxes.BackColor               = "#d5d8d7"
     $ButtonResetCheckboxes.text                    = "Reset Checkboxes"
     $ButtonResetCheckboxes.width                   = $ButtonWidth
     $ButtonResetCheckboxes.height                  = $ButtonHeight
     $ButtonResetCheckboxes.location                = New-Object System.Drawing.Point($x,$y)
     $ButtonResetCheckboxes.Font                    = 'Microsoft Sans Serif,11'
     $Form.controls.AddRange(@($ButtonResetCheckboxes))
     $ButtonResetCheckboxes.Add_Click({
         Reset-MitreCheckboxes
     })

     $x = $x + $ButtonXDistance

     $ButtonImportYaml                         = New-Object system.Windows.Forms.Button
     $ButtonImportYaml.BackColor               = "#d5d8d7"
     $ButtonImportYaml.text                    = "YAML Admin"
     $ButtonImportYaml.width                   = $ButtonWidth
     $ButtonImportYaml.height                  = $ButtonHeight
     $ButtonImportYaml.location                = New-Object System.Drawing.Point($x,$y)
     $ButtonImportYaml.Font                    = 'Microsoft Sans Serif,11'
     $Form.controls.AddRange(@($ButtonImportYaml))
     $ButtonImportYaml.Add_Click({
        Get-YamlAdminSelect
     })

     $x = $x + $ButtonXDistance

     $ButtonConfig                         = New-Object system.Windows.Forms.Button
     $ButtonConfig.BackColor               = "#C0C0C0"
     $ButtonConfig.text                    = "Configure EventList"
     $ButtonConfig.width                   = $ButtonWidth
     $ButtonConfig.height                  = $ButtonHeight
     $ButtonConfig.location                = New-Object System.Drawing.Point($x,$y)
     $ButtonConfig.Font                    = [System.Drawing.Font]::new("Microsoft Sans Serif", 11, [System.Drawing.FontStyle]::Bold)
     $Form.controls.AddRange(@($ButtonConfig))
     $ButtonConfig.Add_Click({
        Get-EventListConfigSelect
     })

    Sync-ComboBox -ComboBox $ComboBox1 -Items $baselineNames

    $Form.controls.AddRange(@($Panel1,$Panel2))

    [void]$Form.ShowDialog()

}

function Remove-AllBaselines {

<#
    .SYNOPSIS
    Deletes all imported baselines from the database.
 
    .DESCRIPTION
    Deletes all imported baselines from the database.
 
    .PARAMETER Confirm
    Prompts you for confirmation before executing the command.
 
    .PARAMETER WhatIf
    Displays a message that describes the effect of the command, instead of executing the command.
 
    .EXAMPLE
    Remove-AllBaselines
 
    Deletes all imported baselines from the database.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')]
    [CmdletBinding(SupportsShouldProcess)]
    param ()

    $Query = "delete from baseline_data; delete from baseline_main;"

    Invoke-SqliteQuery -Query $Query -DataSource $Database

    $returnStr = "All baselines were successfully deleted."

    if ($Script:openFromGui) {
        $wshell = New-Object -ComObject Wscript.Shell
        $wshell.Popup($returnStr,0,"Done",0x1)
    }
    

}

function Remove-AllYamlConfigurations {

<#
    .SYNOPSIS
    Deletes all imported YAML configuration files from the database.
 
    .DESCRIPTION
    Deletes all imported YAML configuration files from the database.
 
    .PARAMETER Confirm
    Prompts you for confirmation before executing the command.
 
    .PARAMETER WhatIf
    Displays a message that describes the effect of the command, instead of executing the command.
 
    .EXAMPLE
    Remove-AllYamlConfigurations
 
    Deletes all imported YAML configuration files from the database.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding(SupportsShouldProcess)]
    param ()

    $Query = "delete from queries_data_yaml_main; delete from queries_data_yaml_tags;"

    Invoke-SqliteQuery -Query $Query -DataSource $Database

    if ($Script:openFromGui) {
        $wshell = New-Object -ComObject Wscript.Shell
        $wshell.Popup("All YAML configurations were successfully deleted.",0,"Done",0x1)
    }
}

function Remove-EventListConfiguration {

<#
    .SYNOPSIS
    Deletes all existent EventList configurations from the database.
 
    .DESCRIPTION
    Deletes all existent EventList configurations from the database.
 
    .PARAMETER sigmaPath
    Defines the path where sigmac is located.
 
    .PARAMETER Confirm
    Prompts you for confirmation before executing the command.
 
    .PARAMETER WhatIf
    Displays a message that describes the effect of the command, instead of executing the command.
 
    .EXAMPLE
    Remove-EventListConfiguration -sigmaPath
 
    Deletes all existent EventList configurations from the database.
 
#>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [switch]$sigmaPath
    )

    if ($sigmaPath) {
        $query = "Update EventList_configuration set sigma_path='' where id=1;"
    }

    if ($query) {
        Invoke-SqliteQuery -Query $query -DataSource $database
    }
}

function Remove-OneBaseline {

    <#
    .SYNOPSIS
    Removes one imported baseline from the database.
 
    .DESCRIPTION
    Removes one imported baseline from the database.
 
    .PARAMETER BaselineName
    Defines the name of the baseline.
 
    .PARAMETER Confirm
    Prompts you for confirmation before executing the command.
 
    .PARAMETER WhatIf
    Displays a message that describes the effect of the command, instead of executing the command.
 
    .EXAMPLE
    Remove-OneBaseline -BaselineName "SCM Windows 10 - Computer"
 
    Removes one imported baseline from the database.
 
#>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [CmdletBinding(SupportsShouldProcess)]
    Param (
        [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
        [string]$BaselineName
    )

    process {

        $valuesFromDb = Get-BaselineNameFromDB

        if (($BaselineName -eq "No Baselines imported") -or ($BaselineName -eq "Select Baseline") -or [string]::IsNullOrEmpty($BaselineName)) {
            $returnStr = "No Baseline was selected."
        
            if ($Script:openFromGui) {
                $wshell = New-Object -ComObject Wscript.Shell
                $wshell.Popup($returnStr, 0, "Delete selected baseline", 0x1)
            }
            Write-Host $returnStr
        }
        else {
            If ($BaselineName -in $valuesFromDb) {
                $query = "select id from baseline_main where name like '$BaselineName' ;"
                $id = Invoke-SqliteQuery -Query $query -DataSource $database | Select-Object -ExpandProperty id

                $query = "delete from baseline_data where b_id = $id ; delete from baseline_main where id = $id ;"
                Invoke-SqliteQuery -Query $query -DataSource $database

                $returnStr = "Baseline $BaselineName was deleted successfully."

                if ($Script:openFromGui) {
                    $wshell = New-Object -ComObject Wscript.Shell
                    $wshell.Popup($returnStr, 0, "Delete selected baseline", 0x1)
                }
            }
        }
    }
}