Harden-Sysvol/Private/FileHandlers.psm1
2024-11-18 11:50:01 +01:00

1187 lines
47 KiB
PowerShell

# FileHandlers.psm1
#region FonctionDetect
function Get-OthersContent {
param (
[string]$filepath,
[string[]]$patterns
)
$results = @()
try {
$findmatch = Select-String -Path $filepath -Pattern $patterns -AllMatches
foreach ($match in $findmatch) {
$patternMatch = $match.pattern -replace '\\b',''
[string]$word= $match.line.Replace($patternMatch,'')
if (-not([string]::IsNullOrEmpty(($word -replace '^[\s=:"]+').Trim()))){
switch ($patternMatch) {
'(?:[0-9]{1,3}\.){3}[0-9]{1,3}' { $patternMatch = 'IPv4' }
'[a-fA-F0-9]{32}' { $patternMatch = 'MD5' }
'[a-fA-F0-9]{40}' { $patternMatch = 'SHA-1' }
'[a-fA-F0-9]{64}' { $patternMatch = 'SHA-256' }
default {
switch -Wildcard ($patternMatch) {
'net *' { $patternMatch = 'Commande Net User' }
default { $patternMatch = $patternMatch }
}
}
}
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = $patternMatch
Reason = $match.Line
}
$results += $result
}
}
} catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'error'
Reason = $_.Exception.Message
}
$results = $result
}
return $results
}
function Get-DocxContent {
param (
[string]$filepath,
[string[]]$patterns
)
$results = @()
Import-Module PSWriteOffice
try {
$document = Get-OfficeWord -FilePath $filepath -ReadOnly
$n = 0
foreach ($pattern in $patterns) {
$pattern = $pattern -replace '\\b', ''
[string]$findtext = $document.Find($pattern) | Select-Object text -First 2
if ($findtext) {
if ($n -le '1') {
foreach ($text in $findtext) {
$n++
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = $pattern
Reason = $text
}
$results += $result
}
} elseif ($n -gt '1') {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = $pattern
Reason = "at least " + $n + " characters found"
}
$results += $result
break }
}
}
Close-OfficeWord -Document $document
}
catch { $result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'error'
Reason = $_
}
$results = $result
}
$results
}
function Get-XlsxContent {
param (
[string]$filepath,
[string[]]$patterns
)
$results = @()
Import-Module PSWriteOffice
try {
$excel = Get-OfficeExcel -FilePath $filepath
$n = 0
foreach ($pattern in $patterns) {
$pattern = $pattern -replace '\\b', ''
[string]$findtext = $excel.Search($pattern, [System.Globalization.CompareOptions]::IgnoreCase, $false) | Select-Object value -First 2
if ($findtext) {
if ($n -le '2') {
foreach ($text in $findtext) {
$n++
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = $pattern
Reason = $text
}
$results += $result
}
} else {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = $pattern
Reason = "at least " + $n + " characters found"
}
$results += $result
break }
}
}
$excel.Dispose()
}
catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'error'
Reason = $_
}
$results = $result
}
$results
}
function Get-DocContent {
param (
[string]$filepath,
[string[]]$patterns,
[string]$wordinstalled
)
$results = @()
if ($wordinstalled -eq $false) {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'requires_check'
Reason = 'Word is not installed'
}
$results += $result
} else {
$wordApp = New-Object -ComObject Word.Application
$wordApp.Visible = $false
try {
$document = $wordApp.Documents.Open($filepath, [ref]$null, [ref]$true)
$n = 0
foreach ($pattern in $patterns) {
$pattern = $pattern -replace '\\b', ''
$find = $document.Content.Find | Select-Object -First 1
$find.Text = $pattern
$find.Forward = $true
$find.Wrap = 1 # wdFindContinue
$find.Execute() | Out-Null
if ($find.Found) {
if ($n -le '2') {
$n++
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = $pattern
Reason = "at least " + $n + " characters found"
}
$results = $result
} else { break }
}
}
$document.Close([ref]$false)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($document) | Out-Null
} catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'error'
Reason = $_.Exception.Message
}
$results = $result
} finally {
$wordApp.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($wordApp) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
}
$results
}
function Get-XlsContent {
param (
[string]$filePath,
[string[]]$patterns,
[string]$excelInstalled
)
$results = @()
if ($excelInstalled -eq $false) {
$result = [PSCustomObject]@{
FilePath = $filePath
pattern = 'requires_check'
Reason = 'Excel is not installed'
}
$results += $result
} else {
$excelApp = New-Object -ComObject Excel.Application
$excelApp.Visible = $false
try {
$workbook = $excelApp.Workbooks.Open($filePath, [ref]$null, [ref]$true)
$n = 0
foreach ($pattern in $patterns) {
$pattern = $pattern -replace '\\b', ''
foreach ($sheet in $workbook.Sheets) {
$cells = $sheet.Cells.Find($pattern)
if ($null -ne $cells) {
if ($n -le '2') {
$n++
$result = [PSCustomObject]@{
FilePath = $filePath
pattern = $pattern
Reason = "at least " + $n + " characters found"
}
$results = $result
} else { break }
}
}
}
$workbook.Close([ref]$false)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
} catch {
$result = [PSCustomObject]@{
FilePath = $filePath
pattern = 'error'
Reason = $_.Exception.Message
}
$results = $result
} finally {
$excelApp.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excelApp) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
}
$results
}
function Get-PPTContent {
param (
[string]$filepath,
[string[]]$patterns,
[string]$wordinstalled
)
$results = @()
if ($wordinstalled -eq $false) {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'requires_check'
Reason = 'Office is not installed'
}
$results += $result
}
else {
try {
$MSPPT = New-Object -ComObject powerpoint.application
$PRES = $MSPPT.Presentations.Open($filepath, $true, $true, $false)
$n = 0
foreach($Slide in $PRES.Slides) {
foreach ($Shape in $Slide.Shapes) {
if ($Shape.HasTextFrame -eq "-1") {
$text = $Shape.TextFrame.TextRange.Text
foreach ($pattern in $patterns) {
$pattern = $pattern -replace '\\b', ''
if ($text -match $pattern) {
if ($n -le '2') {
$n++
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = $pattern
Reason = "at least " + $n + " characters found"
}
$results = $result
} else { break }
}
}
}
}
}
$MSPPT.PresentationClose
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($MSPPT) | Out-Null
} catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'error'
Reason = $_.Exception.Message
}
$results = $result
} finally {
$MSPPT.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($MSPPT) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
}
$results
}
function Get-OdsContent {
param (
[string]$filePath,
[string[]]$patterns
)
$results = @()
# Open ODS file
Add-Type -AssemblyName System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead($filePath)
# Extract contenant
$contentXmlEntry = $zip.Entries | Where-Object { $_.FullName -eq "content.xml" }
$reader = [System.IO.StreamReader]::new($contentXmlEntry.Open())
$contentXml = $reader.ReadToEnd()
$reader.Close()
$zip.Dispose()
# Analys file XML
[xml]$xmlContent = $contentXml
# Read text XML
$textContent = $xmlContent.'document-content'.InnerText
$n = 0
foreach ($pattern in $patterns) {
$pattern = $pattern -replace '\\b', ''
if ($textContent -match $pattern) {
if ($n -le '2') {
$n++
$result = [PSCustomObject]@{
FilePath = $filePath
Pattern = $pattern
Reason = "at least " + $n + " characters found"
}
$results = $result
}
}
}
$results
}
function Get-Pdfcontent {
param (
[string]$filepath,
[string[]]$patterns
)
$results = @()
Import-Module PSWritePDF
try {
$text = (Convert-PDFToText -FilePath $filepath) -join "`n"
$n = 0
foreach ($pattern in $passwordPatterns) {
if ($text -match $pattern) {
if ($n -le '2') {
$n++
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = $pattern
Reason = "at least " + $n + " characters found"
}
$results = $result
} else { break }
}
}
}
catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'error'
Reason = $_.Exception.Message
}
$results = $result
}
$results
}
function Get-Xmlcontent {
param (
[string]$filepath,
[string[]]$patterns
)
$results = @()
$xmlContent = Get-Content -Path $filepath -Raw
if ($xmlContent -match 'cpassword') {
$xml = [xml]$xmlContent
# Check for cpassword
$cpasswords = @()
if ($xml.Groups.User) {
$cpasswords = $xml | Select-Xml "/Groups/User/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.NTServices.NTService) {
$cpasswords = $xml | Select-Xml "/NTServices/NTService/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.ScheduledTasks.Task) {
$cpasswords = $xml | Select-Xml "/ScheduledTasks/Task/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.DataSources.DataSource) {
$cpasswords = $xml | Select-Xml "/DataSources/DataSource/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.Printers.SharedPrinter) {
$cpasswords = $xml | Select-Xml "/Printers/SharedPrinter/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.Drives.Drive) {
$cpasswords = $xml | Select-Xml "/Drives/Drive/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
}
if ($cpasswords) {
$result = [PSCustomObject]@{
FilePath = $filepath
Pattern = 'cpassword'
Reason = $cpasswords
}
$results += $result
}
}
elseif ($xmlContent -match 'DefaultUserName') {
$xml = [xml]$xmlContent
# Check for AutoLogon
$userName = ""
$password = ""
foreach ($registry in $xml.RegistrySettings.Registry) {
if ($registry.Properties.name -eq "DefaultUserName") {
$userName = $registry.Properties.value
}
if ($registry.Properties.name -eq "DefaultPassword") {
$password = $registry.Properties.value
}
}
$result = [PSCustomObject]@{
FilePath = $filepath
Pattern = 'AutoLogon'
Reason = "$userName : $password"
}
$results += $result
}
else {
$xml = [xml]$xmlContent
foreach ($pattern in $patterns) {
$findmatches = $xmlContent | Select-String -Pattern $pattern
foreach ($match in $findmatches) {
switch ($pattern) {
'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b' { $pattern = 'IPv4' }
'\b[a-fA-F0-9]{32}\b' { $pattern = 'MD5' }
'\b[a-fA-F0-9]{40}\b' { $pattern = 'SHA-1' }
'\b[a-fA-F0-9]{64}\b' { $pattern = 'SHA-256' }
default {
switch -Wildcard ($pattern) {
'net *' { $pattern = 'Commande Net User' }
default { $pattern = $pattern }
}
}
}
$result = [PSCustomObject]@{
FilePath = $filepath
Pattern = $pattern
Reason = $match.Matches.Value
}
$results += $result
}
}
}
$results
}
function Get-Executablescontent {
param (
[string]$filepath
)
$results = @()
if ($filepath -notlike '*.jar') {
$signature = Get-AuthenticodeSignature -FilePath $filepath
if ($signature.Status -ne 'Valid') {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = "NotSigned"
Reason = 'File is Not Signed'
}
$results = $result
}
} else {
$isSigned = $false
try {
$zip = [System.IO.Compression.ZipFile]::OpenRead($filepath)
foreach ($entry in $zip.Entries) {
if ($entry.FullName -like "META-INF/*.SF") {
$isSigned = $true
break
}
}
$zip.Dispose()
} catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'error'
Reason = $_.Exception.Message
}
$results = $result
}
if (!$isSigned) {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = "NotSigned"
Reason = "Jar file not signed"
}
$results = $result
}
}
$results
}
function Get-Zipprotectedbypass {
param (
[string]$filepath,
[string]$zipinstalled
)
$extension = [System.IO.Path]::GetExtension($filePath).TrimStart('.')
if ($extension -eq "zip" ) {
try {
$zip = [System.IO.Compression.ZipFile]::OpenRead($filepath)
foreach ($entry in $zip.Entries) {
$stream = $entry.Open()
[byte[]]$buffer = New-Object byte[] 10
$stream.Read($buffer, 0, $buffer.Length) | Out-Null
$stream.Close()
break
}
$zip.Dispose()
return $null
}
catch {
if ($_.Exception.Message -match "(Read|Block|Password|Encrypted)") {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Zip protected'
Reason = 'File protected by password'
}
return $result
} else {
Write-Host "Erreur inattendue : $_"
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Zip check error'
Reason = 'Error to read zip : $_'
}
return $result
}
}
} elseif ($zipinstalled) {
$sevenZipPath = $zipinstalled + "7z.exe"
$output = & "$sevenZipPath" t "$filepath" -pBadPasswordConf 2>&1
if ($output -match "Wrong password") {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Zip protected'
Reason = 'File protected by password'
}
return $result
}
}
}
function Get-Requiredcheckcontent {
param (
[string]$filepath
)
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'check required'
Reason = 'Binary does not match'
}
return $result
}
function Get-CertifsContent {
param (
[string]$filePath
)
$results = @()
try {
# Try to load certificat with class .NET X509Certificate2
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($filePath)
if (!$cert.Thumbprint) { $result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Certificate Empty'
Reason = 'Certificate without Thumbprint'
}
$results = $result }
if ($cert.PrivateKey) { $result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Certificate private key'
Reason = 'certificate with exportable private key'
}
$results += $result }
$cert.Dispose()
}
catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Protected Certificate'
Reason = ($_.Exception.Message).split(":").split("`n")[1].Trim()
}
$results = $result
}
return $results
}
function Get-P7bCertContent {
param (
[string]$filePath
)
$results = @()
try {
# Create certificate collection contenant P7B ou P7C
$certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$certCollection.Import($filePath)
# browse all certificate present in P7B/P7C
foreach ($cert in $certCollection) {
if (!$cert.Thumbprint) {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Certificate Empty'
Reason = 'Certificate without Thumbprint'
}
$results += $result
}
if ($cert.PrivateKey) {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Certificate private key'
Reason = 'certificate with exportable private key'
}
$results += $result
}
$cert.Dispose()
}
}
catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Protected Certificate'
Reason = $_.Exception.Message
}
$results = $result
}
return $results
}
function Get-HiddenFilesInImage {
param (
[string]$filePath
)
$fileInfo = Get-Item $filePath
$fileSizeMB = [math]::Round($fileInfo.Length / 1MB, 2)
# Skip file more than 4 Mo
if ($fileSizeMB -gt 4) {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Large size'
Reason = "File ignored: (size: $fileSizeMB MB)"
}
return $result
}
try {
# read binary and convert file to Hexa
$fileBytes = [System.IO.File]::ReadAllBytes($filePath)
$fileHex = [BitConverter]::ToString($fileBytes) -replace '-'
$magicNumbers = [ordered]@{
"MSI" = "D0CF11E0A1B11AE1" # MSI or office
"RAR" = "526172211A0700"; # RAR file
"ZIP" = "504B0304"; # ZIP file
"7z" = "377ABCAF271C"; # 7z file
"EXE" = "4D5A"; # EXE file (MZ header)
}
foreach ($key in $magicNumbers.Keys) {
$magicNumber = $magicNumbers[$key]
$currentIndex = 0
if ($fileHex -match $magicNumber) {
if ($key -eq "EXE") {
while ($fileHex.IndexOf($magicNumber, $currentIndex) -ne -1) {
$startIndex = $fileHex.IndexOf($magicNumber, $currentIndex)
# Extract the part after the Magic Number (limited to 400 bytes after)
$remainingHex = $fileHex.Substring($startIndex + $magicNumber.Length, [Math]::Min(200 * 2, $fileHex.Length - ($startIndex + $magicNumber.Length)))
# Check for the presence of the special string "0000004000" in this range
if ($remainingHex -match "0000004000") {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Suspicious Image'
Reason = "EXE file with '0000004000' string detected"
}
return $result
}
# Continue the search from the next index
$currentIndex = $startIndex + $magicNumber.Length
}
}
elseif ($key -eq "ZIP") {
# Find the index where the ZIP file starts
$startIndex = $fileHex.IndexOf($magicNumber, $currentIndex) / 2 # Divide by 2 because each hexadecimal represents 2 characters
# Extract the ZIP bytes starting from this index
$zipBytes = $fileBytes[$startIndex..($fileBytes.Length - 1)]
$tempDir = [System.IO.Path]::GetTempPath()
$fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($filePath)
$tempZipPath = [System.IO.Path]::Combine($tempDir, "$fileNameWithoutExtension.zip")
[System.IO.File]::WriteAllBytes($tempZipPath, $zipBytes)
# Read the ZIP file and list the files
Add-Type -AssemblyName System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead($tempZipPath)
# List the files inside the ZIP
$fileNames = $zip.Entries | Select-Object -ExpandProperty FullName
$fileNames | ForEach-Object { Write-Host "File in ZIP: $_" }
$zip.Dispose()
# Delete the temporary file
Remove-Item $tempZipPath
# Return the result
$result = [PSCustomObject]@{
FilePath = $filePath
Pattern = 'Suspicious Image'
Reason = "ZIP detected in pictures. Containing: $($fileNames -join ', ')"
}
return $result
}
else {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Suspicious Image'
Reason = "File $key detected in the image"
}
return $result
}
}
}
}
catch {
$result = [PSCustomObject]@{
FilePath = $filepath
pattern = 'Error'
Reason = "Details : $_"
}
return $result
}
}
#endregion FonctionDetect
# Add other functions for different file types...
function Get-CompressedFileType {
param (
[string]$filePath,
[object[]]$detectedType
)
# More check fot DOCX, XLSX, ODT, ODS ou JAR PPTX zip
if ($detectedType -contains "docx" -or $detectedType -contains "jar") {
try {
Add-Type -AssemblyName System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead($filePath)
$fileNames = $zip.Entries | Select-Object -ExpandProperty FullName
if ($fileNames -contains "word/document.xml") {
$detectedType = "docx"
}
elseif ($fileNames -contains "xl/workbook.xml") {
$detectedType = "xlsx"
}
elseif ($fileNames -contains "ppt/presentation.xml") {
$detectedType = "pptx"
}
elseif ($fileNames -contains "visio/document.xml") {
$detectedType = "vsdx"
}
elseif ($fileNames -contains "content.xml") {
$mimetypeEntry = $zip.Entries | Where-Object { $_.FullName -eq "mimetype" }
if ($mimetypeEntry -ne $null) {
$reader = [System.IO.StreamReader]::new($mimetypeEntry.Open())
$mimetype = $reader.ReadToEnd()
$reader.Close()
switch ($mimetype) {
"application/vnd.oasis.opendocument.spreadsheet" {
$detectedType = "ods"
}
"application/vnd.oasis.opendocument.text" {
$detectedType = "odt"
}
"application/vnd.oasis.opendocument.presentation" {
$detectedType = "odp"
}
"application/vnd.oasis.opendocument.text-template" {
$detectedType = "ott"
}
}
}
}
elseif ($fileNames -contains "META-INF/MANIFEST.MF") {
$detectedType = "jar"
}
else { $detectedType = "others" }
$zip.Dispose()
}
catch {
$detectedType = "requires_check"
}
}
elseif ($detectedType -contains "doc") {
$a = [System.IO.File]::ReadAllBytes($filePath)
$content = [System.Text.Encoding]::ASCII.GetString($a)
if ($content.Contains("Word.Document")) {
$detectedType = "doc"
} elseif ($content.Contains("MSI") -or $content.Contains("Installer")) {
$detectedType = "msi"
} elseif ($content.Contains("Excel") ) {
$detectedType = "xls"
} elseif ($content.Contains("PowerPoint")) {
$detectedType = "ppt"
} elseif ($content.Contains("Microsoft Visio")) {
$detectedType = "vsd"
} else {
#check for db files
$offsetBytes = [System.IO.File]::ReadAllBytes($filePath)[1024..1050]
$offsetAscii = [System.Text.Encoding]::ASCII.GetString($offsetBytes).Trim()
$filteredAscii = ($offsetAscii -split '').Where{ $_ -match '[A-Za-z ]' } -join ''
if ($filteredAscii -replace '\s+', ' ' -eq "Root Entry") {
$detectedType = "db"
}
else {
$detectedType = "others"
}
}
}
return $detectedType
}
function Get-FileType {
param (
[string]$filePath,
[object]$jsonContent
)
$detectedType = "others"
$extension = [System.IO.Path]::GetExtension($filePath).TrimStart('.')
$fileHeaderHex = [System.IO.File]::ReadAllBytes($filePath)[0..16] | ForEach-Object { "{0:X2}" -f $_ }
$fileHeaderHex = ($fileHeaderHex -join '').Trim()
if ($fileHeaderHex.Length -eq 0) {
return "empty"
}
$matchFound = $false
foreach ($entry in $jsonContent.magic_numbers) {
if ($matchFound) { break }
foreach ($expectedMagic in $entry.magic) {
if ($matchFound) { break }
if ($expectedMagic.Length -le $fileHeaderHex.Length) {
$difference = Compare-Object -ReferenceObject $expectedMagic -DifferenceObject ($fileHeaderHex.Substring(0, $expectedMagic.Length)) -SyncWindow 0
if ($difference.Count -eq 0) {
if ($entry.offset) {
foreach ($offsetItem in $entry.offset) {
$offsetPosition = $expectedOffsetValue = $null
$offsetPosition = $offsetItem[0]
$expectedOffsetValue = $offsetItem[1]
$lastpostition = $offsetPosition + ($expectedOffsetValue.Length/2)-1
$CustomfileHeaderHex = [System.IO.File]::ReadAllBytes($filePath)[$offsetPosition..$lastpostition] | ForEach-Object { "{0:X2}" -f $_ }
$specificBytes = ($CustomfileHeaderHex -join '').Trim()
if ($specificBytes -eq $expectedOffsetValue) {
if ($extension -notin $entry.extensions) {
$detectedType = 'requires_check'
} else {
$detectedType = $extension
}
$matchFound = $true
break
}
}
}
else {
if ($extension -notin $entry.extensions) {
$detectedType = 'requires_check'
}
else {
if ($entry.extensions -contains "docx" -or $entry.extensions -contains "doc") {
$detectedType = Get-CompressedFileType -filePath $filePath -detectedType $entry.extensions
}
if ($detectedType -eq "others" -and $extension -in $entry.extensions) {
$detectedType = $extension
} elseif ($detectedType -ne $extension -and $detectedType -ne "others") {
$detectedType = 'requires_check'
}
}
$matchFound = $true
break
}
}
}
}
}
if ($detectedType -eq 'others' -and $extension -in $jsonContent.magic_numbers.extensions) {
$detectedType = 'requires_check'
}
if ($detectedType -eq "others") {
$firstLine = Get-Content -Path $filePath -TotalCount 1
if ($firstLine -match '^<\?xml') {
$detectedType = "xml"
}
}
return $detectedType
}
# SIG # Begin signature block
# MIImVgYJKoZIhvcNAQcCoIImRzCCJkMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCC8KZNcKCzMj87C
# Xm3TUdHfsYDelwrkLm78Scnqq3gb1qCCH+wwggWNMIIEdaADAgECAhAOmxiO+dAt
# 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa
# Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD
# ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E
# MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy
# unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF
# xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1
# 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB
# MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR
# WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6
# nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB
# YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S
# UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x
# q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB
# NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP
# TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC
# AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
# Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0
# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB
# LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc
# Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov
# Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy
# oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW
# juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF
# mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z
# twGpn1eqXijiuZQwggYoMIIEEKADAgECAhBrxlWg9go45bxtH9Zi+WCgMA0GCSqG
# SIb3DQEBCwUAMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBT
# eXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNpZ25pbmcgMjAyMSBD
# QTAeFw0yNDExMDYwOTQ0MjlaFw0yNTExMDYwOTQ0MjhaME4xCzAJBgNVBAYTAkZS
# MQ8wDQYDVQQHDAZUb3Vsb24xFjAUBgNVBAoMDU1laGRpIERha2hhbWExFjAUBgNV
# BAMMDU1laGRpIERha2hhbWEwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIB
# gQCsFc3e5PwEJuycVRR54Qp8hFEckVwj7u1hMc7fejXKC/oR+uixlujLAHA9NcGX
# jcQIXNP3GmezLF3Tj6Jvcs/kNT/a5zqjI5HEfIap7EHwf03f5060+Rc21v1UDjzj
# DZzi9xFFum8eeGLc4pTzUB3wP3+M+mY7d5QlTjIxZSNnMBisJE8ASqG9JtRcQmIz
# HACI70xRCQVV8ZjJ8J+Shr6wkNdDy/IjR+Y9VkMRIJozWR+pqbKuQOIDBSxQYVHg
# bT+gsLOfvHkBPJN0ZQe7eJdG7J78Z1nzNH9yXhZ0HHdPB80tUwM0HC1n4LO3kki/
# IBmg4Qq/UyMMQd826fJk3ylbAlf8w7N80INQcLLBGVECmWI21d9f3l5usvWDa+mJ
# ma57c6GUDY05Jg5owLgNREZsyRt5rOlg68NLmz9tuEkJA1D4ntpKq0KZc3HJv04x
# XTcfTEqbKYr7vZ//ENsell5UdUQxL6rGJzazhsK02ZcmasICiHNLfG/tBaolCbeM
# 8ekCAwEAAaOCAXgwggF0MAwGA1UdEwEB/wQCMAAwPQYDVR0fBDYwNDAyoDCgLoYs
# aHR0cDovL2Njc2NhMjAyMS5jcmwuY2VydHVtLnBsL2Njc2NhMjAyMS5jcmwwcwYI
# KwYBBQUHAQEEZzBlMCwGCCsGAQUFBzABhiBodHRwOi8vY2NzY2EyMDIxLm9jc3At
# Y2VydHVtLmNvbTA1BggrBgEFBQcwAoYpaHR0cDovL3JlcG9zaXRvcnkuY2VydHVt
# LnBsL2Njc2NhMjAyMS5jZXIwHwYDVR0jBBgwFoAU3XRdTADbe5+gdMqxbvc8wDLA
# cM0wHQYDVR0OBBYEFAG3sIcT8bRm7QyFu8699Gpkr5NmMEsGA1UdIAREMEIwCAYG
# Z4EMAQQBMDYGCyqEaAGG9ncCBQEEMCcwJQYIKwYBBQUHAgEWGWh0dHBzOi8vd3d3
# LmNlcnR1bS5wbC9DUFMwEwYDVR0lBAwwCgYIKwYBBQUHAwMwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQCJ58BnchFNGzLksJ9oHFEWTs643G+PKOHr
# 9RmrKSB/4MtPriG5iez+MFsGqYwkYd5QzqOIYg24ctfbWXJWG8Xj+YMfp1r+hkYq
# O0Abpv26sZ1ZjNGgGUbb3z7KqhY+IdVpZf2aG/Rycl5dE2LbhWqp9h24WfQCIS/e
# XxH7HmM9SEBHYbfOqlEA+RF/gRGYCQOg0ui2j0ZzIOrQGj3Njn/5rzP9OmPmLt4h
# DsixjFWgu598XmRKj5KW1MShFIjUuUzSmOWDgKA16lJi6LggdFAB/MImiDH48v8N
# /9R9En24pUGGj2XOgBX5SZ4kj+VN1YaY1vYPFp3wLu85zpgRZgZQC+WurX8s1tRn
# iCIj/+ajUB4G4TcbTz6k16X1Yz9ba1y7p/hJB92uDW7esMGgqzEv+Osd11bVoNmv
# CE8Twsz0cuFJqBtVZIycCkgw/AVyJIsNS6RADi94PvbOf8rty8HV3bHmm6O4wJVc
# 5ch50bL7JVyYTPN5OTzXSDx62wKi5ePZvEF7RX3cQlTQMYticde91khs2n2FZ06K
# Uin5DtQgxy0Q1ufFIDZthsk5AaSWiZzFgAgJt8JaQGPyGAYl2Sr8a/gMLpcBsPwI
# zdlDUOJwyHPxlR9ZiraUzF/1SSN7CgjqFSDAAZ+i4i8gZsPpU38GtBSLrw/CrnUB
# /KGcFNMvszCCBq4wggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJKoZIhvcN
# AQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG
# A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3Rl
# ZCBSb290IEc0MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVowYzELMAkG
# A1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdp
# Q2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklRVcclA8Ty
# kTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54PMx9QEwsm
# c5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupRPfDWVtTn
# KC3r07G1decfBmWNlCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvohGS0UvJ2
# R/dhgxndX7RUCyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV5huowWR0
# QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYVVSZwmCZ/
# oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6ic/rnH1ps
# lPJSlRErWHRAKKtzQ87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/CiPMpC3BhI
# fxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5K6jzRWC8
# I41Y99xh3pP+OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oiqMEmCPkU
# EBIDfV8ju2TjY+Cm4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuldyF4wEr1G
# nrXTdrnSDmuZDNIztM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEA
# MB0GA1UdDgQWBBS6FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAWgBTs1+OC
# 0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYB
# BQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k
# aWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSG
# Mmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQu
# Y3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0B
# AQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvHUF3iSyn7
# cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0MCIKoFr2p
# Vs8Vc40BIiXOlWk/R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCKrOX9jLxk
# Jodskr2dfNBwCnzvqLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rAJ4JErpkn
# G6skHibBt94q6/aesXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZxhOACcS2
# n82HhyS7T6NJuXdmkfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScsPT9rp/Fm
# w0HNT7ZAmyEhQNC3EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1MrfvElXvt
# Cl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXseGYs2uJPU
# 5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWYMbRiCQ8K
# vYHZE/6/pNHzV9m8BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYphwlHK+Z/
# GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPwwgga5MIIE
# oaADAgECAhEAmaOACiZVO2Wr3G6EprPqOTANBgkqhkiG9w0BAQwFADCBgDELMAkG
# A1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAl
# BgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMb
# Q2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMB4XDTIxMDUxOTA1MzIxOFoXDTM2
# MDUxODA1MzIxOFowVjELMAkGA1UEBhMCUEwxITAfBgNVBAoTGEFzc2VjbyBEYXRh
# IFN5c3RlbXMgUy5BLjEkMCIGA1UEAxMbQ2VydHVtIENvZGUgU2lnbmluZyAyMDIx
# IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnSPPBDAjO8FGLOcz
# cz5jXXp1ur5cTbq96y34vuTmflN4mSAfgLKTvggv24/rWiVGzGxT9YEASVMw1Aj8
# ewTS4IndU8s7VS5+djSoMcbvIKck6+hI1shsylP4JyLvmxwLHtSworV9wmjhNd62
# 7h27a8RdrT1PH9ud0IF+njvMk2xqbNTIPsnWtw3E7DmDoUmDQiYi/ucJ42fcHqBk
# bbxYDB7SYOouu9Tj1yHIohzuC8KNqfcYf7Z4/iZgkBJ+UFNDcc6zokZ2uJIxWgPW
# XMEmhu1gMXgv8aGUsRdaCtVD2bSlbfsq7BiqljjaCun+RJgTgFRCtsuAEw0pG9+F
# A+yQN9n/kZtMLK+Wo837Q4QOZgYqVWQ4x6cM7/G0yswg1ElLlJj6NYKLw9EcBXE7
# TF3HybZtYvj9lDV2nT8mFSkcSkAExzd4prHwYjUXTeZIlVXqj+eaYqoMTpMrfh5M
# CAOIG5knN4Q/JHuurfTI5XDYO962WZayx7ACFf5ydJpoEowSP07YaBiQ8nXpDkNr
# UA9g7qf/rCkKbWpQ5boufUnq1UiYPIAHlezf4muJqxqIns/kqld6JVX8cixbd6Pz
# kDpwZo4SlADaCi2JSplKShBSND36E/ENVv8urPS0yOnpG4tIoBGxVCARPCg1BnyM
# J4rBJAcOSnAWd18Jx5n858JSqPECAwEAAaOCAVUwggFRMA8GA1UdEwEB/wQFMAMB
# Af8wHQYDVR0OBBYEFN10XUwA23ufoHTKsW73PMAywHDNMB8GA1UdIwQYMBaAFLah
# VDkCw6A/joq8+tT4HKbROg79MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggr
# BgEFBQcDAzAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmNlcnR1bS5wbC9j
# dG5jYTIuY3JsMGwGCCsGAQUFBwEBBGAwXjAoBggrBgEFBQcwAYYcaHR0cDovL3N1
# YmNhLm9jc3AtY2VydHVtLmNvbTAyBggrBgEFBQcwAoYmaHR0cDovL3JlcG9zaXRv
# cnkuY2VydHVtLnBsL2N0bmNhMi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYI
# KwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQwF
# AAOCAgEAdYhYD+WPUCiaU58Q7EP89DttyZqGYn2XRDhJkL6P+/T0IPZyxfxiXumY
# lARMgwRzLRUStJl490L94C9LGF3vjzzH8Jq3iR74BRlkO18J3zIdmCKQa5LyZ48I
# fICJTZVJeChDUyuQy6rGDxLUUAsO0eqeLNhLVsgw6/zOfImNlARKn1FP7o0fTbj8
# ipNGxHBIutiRsWrhWM2f8pXdd3x2mbJCKKtl2s42g9KUJHEIiLni9ByoqIUul4Gb
# lLQigO0ugh7bWRLDm0CdY9rNLqyA3ahe8WlxVWkxyrQLjH8ItI17RdySaYayX3Ph
# RSC4Am1/7mATwZWwSD+B7eMcZNhpn8zJ+6MTyE6YoEBSRVrs0zFFIHUR08Wk0ikS
# f+lIe5Iv6RY3/bFAEloMU+vUBfSouCReZwSLo8WdrDlPXtR0gicDnytO7eZ5827N
# S2x7gCBibESYkOh1/w1tVxTpV2Na3PR7nxYVlPu1JPoRZCbH86gc96UTvuWiOruW
# myOEMLOGGniR+x+zPF/2DaGgK2W1eEJfo2qyrBNPvF7wuAyQfiFXLwvWHamoYtPZ
# o0LHuH8X3n9C+xN4YaNjt2ywzOr+tKyEVAotnyU9vyEVOaIYMk3IeBrmFnn0gbKe
# TTyYeEEUz/Qwt4HOUBCrW602NCmvO1nm+/80nLy5r0AZvCQxaQ4wgga8MIIEpKAD
# AgECAhALrma8Wrp/lYfG+ekE4zMEMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYT
# AlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQg
# VHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjQw
# OTI2MDAwMDAwWhcNMzUxMTI1MjM1OTU5WjBCMQswCQYDVQQGEwJVUzERMA8GA1UE
# ChMIRGlnaUNlcnQxIDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDI0MIIC
# IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvmpzn/aVIauWMLpbbeZZo7Xo
# /ZEfGMSIO2qZ46XB/QowIEMSvgjEdEZ3v4vrrTHleW1JWGErrjOL0J4L0HqVR1cz
# SzvUQ5xF7z4IQmn7dHY7yijvoQ7ujm0u6yXF2v1CrzZopykD07/9fpAT4BxpT9vJ
# oJqAsP8YuhRvflJ9YeHjes4fduksTHulntq9WelRWY++TFPxzZrbILRYynyEy7rS
# 1lHQKFpXvo2GePfsMRhNf1F41nyEg5h7iOXv+vjX0K8RhUisfqw3TTLHj1uhS66Y
# X2LZPxS4oaf33rp9HlfqSBePejlYeEdU740GKQM7SaVSH3TbBL8R6HwX9QVpGnXP
# lKdE4fBIn5BBFnV+KwPxRNUNK6lYk2y1WSKour4hJN0SMkoaNV8hyyADiX1xuTxK
# aXN12HgR+8WulU2d6zhzXomJ2PleI9V2yfmfXSPGYanGgxzqI+ShoOGLomMd3mJt
# 92nm7Mheng/TBeSA2z4I78JpwGpTRHiT7yHqBiV2ngUIyCtd0pZ8zg3S7bk4QC4R
# rcnKJ3FbjyPAGogmoiZ33c1HG93Vp6lJ415ERcC7bFQMRbxqrMVANiav1k425zYy
# FMyLNyE1QulQSgDpW9rtvVcIH7WvG9sqYup9j8z9J1XqbBZPJ5XLln8mS8wWmdDL
# nBHXgYly/p1DhoQo5fkCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNV
# HRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYG
# Z4EMAQQCMAsGCWCGSAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGog
# j57IbzAdBgNVHQ4EFgQUn1csA3cOKBWQZqVjXu5Pkh92oFswWgYDVR0fBFMwUTBP
# oE2gS4ZJaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0
# UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMw
# gYAwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEF
# BQcwAoZMaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3Rl
# ZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsF
# AAOCAgEAPa0eH3aZW+M4hBJH2UOR9hHbm04IHdEoT8/T3HuBSyZeq3jSi5GXeWP7
# xCKhVireKCnCs+8GZl2uVYFvQe+pPTScVJeCZSsMo1JCoZN2mMew/L4tpqVNbSpW
# O9QGFwfMEy60HofN6V51sMLMXNTLfhVqs+e8haupWiArSozyAmGH/6oMQAh078qR
# h6wvJNU6gnh5OruCP1QUAvVSu4kqVOcJVozZR5RRb/zPd++PGE3qF1P3xWvYViUJ
# Lsxtvge/mzA75oBfFZSbdakHJe2BVDGIGVNVjOp8sNt70+kEoMF+T6tptMUNlehS
# R7vM+C13v9+9ZOUKzfRUAYSyyEmYtsnpltD/GWX8eM70ls1V6QG/ZOB6b6Yum1Hv
# IiulqJ1Elesj5TMHq8CWT/xrW7twipXTJ5/i5pkU5E16RSBAdOp12aw8IQhhA/vE
# bFkEiF2abhuFixUDobZaA0VhqAsMHOmaT3XThZDNi5U2zHKhUs5uHHdG6BoQau75
# KiNbh0c+hatSF+02kULkftARjsyEpHKsF7u5zKRbt5oK5YGwFvgc4pEVUNytmB3B
# pIiowOIIuDgP5M9WArHYSAR16gc0dP2XdkMEP5eBsX7bf/MGN4K3HP50v/01ZHo/
# Z5lGLvNwQ7XHBx1yomzLP8lx4Q1zZKDyHcp4VQJLu2kWTsKsOqQxggXAMIIFvAIB
# ATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1z
# IFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNpZ25pbmcgMjAyMSBDQQIQa8ZV
# oPYKOOW8bR/WYvlgoDANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQow
# CKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC
# AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCDRDzs2Ytj0Dqx5LB+l
# pxX4cE0yDiFZ7vG8rNTLXz+KKzANBgkqhkiG9w0BAQEFAASCAYAmmXOJQfsI38xT
# YThT8Zio6kQKcmRUHLHq0J2JLdGFflBy76meillnESCwNczrmd1kdGRpiyxegDt3
# 1afBoTZ5tq+3ZXW1TebagwAhp6pxoav+AVdCgvKBrzKiEisDuPQppyNGQfhTZ3sR
# SxQLrXtPGaODfgABeYfe0xHzGKre2eEP07TY0IEFC1Ncn6k0cgP4+B4gXwRfkoHM
# Rk2iRB1WHYzX1/BXUkp7ET+w2X5hJZYxLn8/Th9RkCxuzk8ctQVbfbuV4r6hC6Zs
# TWorfMPF6JPMtrxAEfoDcB241xm9OnN7PnI7en7+Jq6otGwDr3k13YbxBphySY1s
# DkNVGVQr1qaVExefm4dRO/PenInWMlduwWWSzkmdB0m0GpuxwsmXsixYyR77SU7O
# jJ8/sTTsGNqIgS6+Mv+RLBGsHvAAedD4kPzfJMSg5yE+tFdd50sTpAgi1exuFKrW
# c99a+xhSBMmt/oss228cbQF+2/VrwdFi3yJUWZVcfoaAdFFy092hggMgMIIDHAYJ
# KoZIhvcNAQkGMYIDDTCCAwkCAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO
# RGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNB
# NDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBAhALrma8Wrp/lYfG+ekE4zMEMA0G
# CWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG
# 9w0BCQUxDxcNMjQxMTEzMjMzOTE2WjAvBgkqhkiG9w0BCQQxIgQgu+gdumT7pwD4
# cDnOysQNtr2j8VfIX4zHfQPV4WwSmT4wDQYJKoZIhvcNAQEBBQAEggIAB0FkcEJO
# h2KNBz+gTFA1lq4o1Fy+2LFOvsxjNQPyimcQ0Ft4I3MmnsT3HNGuGK0Q14ojZk8j
# 27sDCmwwG5N1nryWWxLcul2qWrPhN2dxgp22ikuCHhTU6VFFXvKpnEd4AsghbuaD
# gAGXYglB3JKwFrPm2trD0zN4VA/RhzH/O6dvTQSdFXkOAESCvv4mG8n9BwpSSkha
# DxHvu+lDfhIogAIjviMgq3Sbpd0R9Y9XWepr4aRbcqmwo6FVyqs4/ToSMZxcNb8g
# yu6z9U9ioJeghEUhJPWe1m1JcgTFdValtHkG/v1j+JXBiyDziCrrKGoAZadJ83Yl
# wHjF63hk3f4RC+xfY4IzcVnYBaaoSFvQdLbmRHJcxWho/Te7acX0K/Tr/vFVW4IW
# DXWlqpkKTGxjHeLZrrQkURE6FPBk0UaJRYwaXpofkfvfO7/BAbf0h7s8sGku2JA1
# wa6ck7wKCSHW9UDi9u+Q2+3GlB7vstcCO6nZ8WmswNtg87v9bU/Rd8nXAy4yYIUp
# af1LEMEk310zN8/RJCq2ZYfZ1/XQShBFCJk97D1IeeMz64TAUdyTxquiz3V8KeqQ
# nFm9woD/YYzv/RSU0/iSYZRAMKUCQbSZm31M1UUuKTW6bxUiRXAuEP5ltnLeGugd
# iFgJIrU+wyu+iggEVWDsCtH4OnfLWt0iLXM=
# SIG # End signature block