functions/Import-FindingsFromCSV.ps1

<#
.SYNOPSIS
Convert and import a set of findings from a external CSV file.
  
.DESCRIPTION
Used to import findings from a 3rd party CSV file. Data must match the format dictated by /sample_csv_import.csv located in the module root folder.
  
.EXAMPLE
Import-FindingsFromCSV <MyCSV File> <name of tool or team> <target project> <output directory for file>
Import-FindingsFromCSV .\myfile.csv "Red Team Delta" "my project" "c:\temp\"
 
#>

Function Import-FindingsFromCSV
{
    [cmdletbinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$SourceScanFilepath,
        [Parameter(Mandatory=$true)]
        [string]$SourceToolName,
        [Parameter(Mandatory=$true)]
        [string]$TargetProject,
        [Parameter(Mandatory=$true)]
        [string]$OutputDir
    )
    
    #Setup variables
    $CDate = Get-Date -format "yyyy-MM-dd-HHmmss"
    $OutputFilePath = $OutputDir.Trim("""") + "\CSV2CDX - " + $CDate + ".xml"
    
    # Enable for Debugging
    #
    #$SourceScanFilepath = "sample_csv_import.csv"
    #$OutputFilePath = "C:\Users\aacuna\Documents\repos\powershell\Code Dx\CSV2CDX -" + $CDate + ".xml"
    
    $SourceScanFile = $SourceScanFilepath.Trim("""")
    $description
    $ToolName = $SourceToolName

    #Setup Code Dx output doc
    [xml]$doc = New-Object System.Xml.XmlDocument
    $dec = $doc.CreateXmlDeclaration("1.0","UTF-8",$null)
    $updateXML= $doc.AppendChild($dec)

    $reportComment = "CSV to Code Dx - Generated $CDate"
    $updateXML= $doc.AppendChild($doc.CreateComment($reportComment))

    $root = $doc.CreateNode("element","report",$null)
    
    #read source file and create custom PSO
    $SourceScanData = Get-Content -Raw -Path $SourceScanFile | ConvertFrom-CSV

    #pull report date attributes and reformat for Code Dx file
    $reportDate = $CDate

    #Set Root attributes
    $root.SetAttribute("date",$reportDate)
    $root.SetAttribute("tool",$ToolName)

    #create findings Element
    $fds = $doc.CreateNode("element","findings",$null)

    #Get parent array of results
    $Results = $SourceScanData

    #drill into each vulnerability
    $Results | ForEach-Object{
    
            #Create Code Dx elements
            $fd = $doc.CreateNode("element","finding",$null)
            $desc = $doc.CreateNode("element","description",$null)
            $tl = $doc.CreateNode("element","tool",$null)
            $loc = $doc.CreateNode("element","location",$null)
            $cwe = $doc.CreateNode("element","cwe",$null)
            $ln = $doc.CreateNode("element","line",$null)
            
            #Set Custom Tool Code
            $code = $_."toolcode"

            $resDesc = $_.description

            #Set finding severity value
            $sev = $_."severity".ToLower()

            #Set scan type
            $scantype = $_.scan_type

            #Set finding "fd" attributes
            $fd.SetAttribute("severity", $sev)
            $fd.SetAttribute("type",$scantype)

            #Set CWE attributes
            If($_.cwe.length -gt 0){
                $cweID = $_."cwe"
                $cwe.SetAttribute("id", $cweID)
                $updateXML= $fd.AppendChild($cwe)
            }
            

            #Set Tool attributes
            $tl.SetAttribute("name",$ToolName)
            $tl.SetAttribute("category","Security")
            $tl.SetAttribute("code", $code)

            #build location node and attributes
            $loc.SetAttribute("type",$_.resource_type)
            $loc.SetAttribute("path",$_.resource_location)

            #set line attributes
            If($_.resource_type -eq "file"){
                $fileinfo = $_.resource_location.split(":")
                $line = $fileinfo[1]
                $ln.SetAttribute("end", $line)
                $ln.SetAttribute("start", $line)
                $updateXML= $loc.AppendChild($ln)
            }

            #Set description attributes
            $desc.SetAttribute("format", "plain-text")
            $desc.InnerText = $resDesc

            #Determine and set CVE attributes, if needed
            If($_.cve.length -gt 0){
                    If($_.cve.substring(0,3) -ceq "CVE"){
                    $cves = $doc.CreateNode("element","cves",$null)
                    $cve = $doc.CreateNode("element","cve",$null)
                    $cveArr = $_.cve.split("-")
                    $cve.SetAttribute("sequence-number",$cveArr[2])
                    $cve.SetAttribute("year",$cveArr[1])
                    $updateXML= $cves.AppendChild($cve)
                    $updateXML= $fd.AppendChild($cves)
                }
            }

            #append remaining children to finding
            $updateXML= $fd.AppendChild($tl)
            $updateXML= $fd.AppendChild($loc)
            $updateXML= $fd.AppendChild($desc)


            #append finding to findings
            $updateXML= $fds.AppendChild($fd)
        }

    $updateXML= $root.AppendChild($fds)
    $updateXML= $doc.AppendChild($root) | Out-Null
    
    Write-Host "Outputing file to: $OutputFilePath"
    $doc.Save($OutputFilePath)

    Write-Host "Uploading to Project: $TargetProject"
 
    $ProjID = Get-ProjectID $TargetProject

    If ($ProjID.length -gt 0) {
        Invoke-Analysis $OutputFilePath $ProjID
    }
    else {
        Write-Host "Unable to find project ID for Project: $TargetProject" -ForegroundColor Red
        Write-Host "Please upload your results manually."
    }
}