0

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"
]
LiamWBA
  • 53
  • 7

0 Answers0