I have a PowerShell script which takes a YAML input and converts it to a JSON template.
I am struggling to return the raw values of a variable in my output. They always reformat to System.Collections.Hashtable and make the JSON output invalid for the system i need to import it into. How do I keep the raw values of the variable without them changing to Systems.Collection.Hashtable.
Here is the Conversion script:
$global:convert = ""
function ConvertSentinelRuleFrom-Yaml {
[CmdletBinding()]
param (
[System.IO.FileInfo] $Path = "C:\Users\Liam.Jones\Downloads\Hunting Queries",
[Parameter(Mandatory = $false)]
[System.IO.FileInfo]$OutputFolder = "C:\Output"
)
if (Get-Module -ListAvailable -Name powershell-yaml) {
Write-Host "Module already installed"
}
else {
Write-Host "Installing PowerShell-YAML module"
try {
Install-Module powershell-yaml -AllowClobber -Force -ErrorAction Stop
Import-Module powershell-yaml
}
catch {
Write-Error $_.Exception.Message
break
}
}
<#
If OutPut folder defined then test if exists otherwise create folder
#>
if ($OutputFolder) {
if (Test-Path $OutputFolder) {
$expPath = (Get-Item $OutputFolder).FullName
}
else {
try {
$script:expPath = (New-Item -Path $OutputFolder -ItemType Directory -Force).FullName
}
catch {
Write-Error $_.Exception.Message
break
}
}
}
<#
Test if path exists and extract the data from folder or file
#>
if ($Path.Extension -in '.yaml', '.yml') {
Write-Host "Singel YAML file selected"
try {
$content = Get-Item -Path $Path -ErrorAction Stop
}
catch {
Write-Error $_.Exception.Message
}
}
elseif ($Path.Extension -in '') {
Write-Host "Folder defined"
try {
$content = Get-ChildItem -Path $Path -Filter *.yaml -Recurse -ErrorAction Stop
}
catch {
Write-Error $_.Exception.Message
}
}
else {
Write-Error 'Wrong Path please see example'
}
<#
If any YAML file found starte lopp to process all the files
#>
if ($content) {
Write-Host "'$($content.count)' templates found to convert"
$content | ForEach-Object {
<#
Define JSON template format
#>
$template = [PSCustomObject]@{
'$schema' = "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#"
contentVersion = "1.0.0.0"
Parameters = @{
Workspace = @{
type = "string"
}
}
variables = @{
"description" = ""
"tactics" = ""
"displayName" = ""
"query" = ""
"id" = ""
}
resources = @(
[PSCustomObject]@{
type = "Microsoft.OperationalInsights/workspaces/savedSearches"
apiVersion = "2020-08-01"
name = "[parameters('Workspace'), '/', variables('id')]"
properties = [PSCustomObject]@{
"etag" = "*"
"Category" = "Hunting Queries"
"DisplayName" = "[variables('displayName')]"
"Query" = "[variables('query')]"
"Tags" = @(
@{Name="description"; Value="[variables('description')]";}
@{Name="tactics"; Value="[variables('tactics')]";}
)
}
}
)
}
# Update the template format with the data from YAML file
$global:convert = $_ | Get-Content -Raw
$convert = ConvertFrom-Yaml $global:convert
$displayName = $convert["name"]
$query = $convert["query"]
$id = $convert["id"]
$tactics = $convert["tactics"]
Write-Host $tactics
$description = $convert["description"]
#Write-Verbose $displayName, $query, $id, $description
($template.variables).tactics = $tactics
($template.variables).description = $description
($template.variables).displayName = $displayName
($template.variables).query = $query
($template.variables).id = $id
#Based of output path variable export files to the right folder
if ($null -ne $expPath) {
$outputFile = $expPath + "/" + $($_.BaseName) + ".json"
}
else {
$outputFile = $($_.DirectoryName) + "/" + $($_.BaseName) + ".json"
}
#Export to JSON
try {
$template | ConvertTo-Json -Depth 4 | Out-File $outputFile -ErrorAction Stop
}
catch {
Write-Error $_.Exception.Message
}
}
}
else {
Write-Error "No YAML templates found"
break
}
}
ConvertSentinelRuleFrom-Yaml
Here is the yaml file I am trying to convert:
name: Anomalies on users tagged as VIP
description: |
'Shows all users tagged as VIP in the VIP users watchlist that had anomalies with a score greater than 0.'
requiredDataConnectors:
- connectorId: BehaviorAnalytics
dataTypes:
- BehaviorAnalytics
tactics:
relevantTechniques:
query: |
BehaviorAnalytics
| where UsersInsights.IsVIPUser == True
| where InvestigationPriority > 0
| extend AadUserId = UsersInsights.AccountObjectID
entityMappings:
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: AadUserId
I need the output to be in this format:
{
"Name": "description",
"Value": "Demo"
},
{
"Name": "tactics",
"Value": "[parameters('tactics')]"
}
]
but my script returns this:
"Tags": [
"System.Collections.Hashtable",
"System.Collections.Hashtable"
]