src/Get-ObjectSchemaAsHash.ps1

Function Get-ObjectSchemaAsHash
{
  <#
    .SYNOPSIS
    Gets the schema of the object as hash table with column-names and their type (strin, boolean, dynamic, etc.)
 
    .DESCRIPTION
    Used to validate the data structure - and give insight of any potential data manipulation
    Support to return in both LogAnalytics table-format and DCR-format
 
    .VERSION
    1.0
 
    .AUTHOR
    Morten Knudsen, Microsoft MVP - https://mortenknudsen.net
 
    .LINK
    https://github.com/KnudsenMorten/AzLogDcrIngestPS
 
    .PARAMETER Data
    Object to modify
 
    .PARAMETER ReturnType
    Object to modify
 
    .INPUTS
    None. You cannot pipe objects
 
    .OUTPUTS
    Updated object with CollectionTime
 
    .EXAMPLE
    $verbose = $true
 
    $TenantId = "xxxxx"
    $LogIngestAppId = "xxxxx"
    $LogIngestAppSecret = "xxxxx"
 
    $TableName = 'InvClientComputerOSInfoV2' # must not contain _CL
    $DcrName = "dcr-" + $AzDcrPrefixClient + "-" + $TableName + "_CL"
 
    $DceName = "dce-log-platform-management-client-demo1-p"
    $LogAnalyticsWorkspaceResourceId = "/subscriptions/xxxxxx/resourceGroups/rg-logworkspaces/providers/Microsoft.OperationalInsights/workspaces/log-platform-management-client-demo1-p"
    $AzDcrPrefixClient = "clt1"
 
    $AzDcrSetLogIngestApiAppPermissionsDcrLevel = $false
    $AzDcrLogIngestServicePrincipalObjectId = "xxxxxx"
 
    #-------------------------------------------------------------------------------------------
    # Collecting data (in)
    #-------------------------------------------------------------------------------------------
             
    Write-Output ""
    Write-Output "Collecting OS information ... Please Wait !"
 
    $DataVariable = Get-CimInstance -ClassName Win32_OperatingSystem
 
    #-------------------------------------------------------------------------------------------
    # Preparing data structure
    #-------------------------------------------------------------------------------------------
 
    # convert CIM array to PSCustomObject and remove CIM class information
    $DataVariable = Convert-CimArrayToObjectFixStructure -data $DataVariable -Verbose:$Verbose
     
    # add CollectionTime to existing array
    $DataVariable = Add-CollectionTimeToAllEntriesInArray -Data $DataVariable -Verbose:$Verbose
 
    # add Computer & UserLoggedOn info to existing array
    $DataVariable = Add-ColumnDataToAllEntriesInArray -Data $DataVariable -Column1Name Computer -Column1Data $Env:ComputerName -Column2Name UserLoggedOn -Column2Data $UserLoggedOn
 
    # Validating/fixing schema data structure of source data
    $DataVariable = ValidateFix-AzLogAnalyticsTableSchemaColumnNames -Data $DataVariable -Verbose:$Verbose
 
    # Aligning data structure with schema (requirement for DCR)
    $DataVariable = Build-DataArrayToAlignWithSchema -Data $DataVariable -Verbose:$Verbose
 
    # build schema to be used for LogAnalytics Table
    $Schema = Get-ObjectSchemaAsHash -Data $DataVariable -ReturnType Table -Verbose:$Verbose
    $Schema
 
    #-------------------------------------------------------------------------------------------
    # Output
    #-------------------------------------------------------------------------------------------
    PS $Schema = Get-ObjectSchemaAsHash -Data $DataVariable -ReturnType Table -Verbose:$Verbose
        $Schema
 
    Name Value
    ---- -----
    description
    name TimeGenerated
    type datetime
    description
    name BootDevice
    type string
    description
    name BuildNumber
    type string
    description
    name BuildType
    type string
    description
    name Caption
    type string
    description
    name CodeSet
    type string
    description
    name CollectionTime
    type datetime
    description
    name Computer
    type string
    description
    name CountryCode
    type string
    description
    name CreationClassName
    type string
    description
    name CSCreationClassName
    type string
    description
    name CSDVersion
    type dynamic
    description
    name CSName
    type string
    description
    name CurrentTimeZone
    type int
    description
    name DataExecutionPrevention_32BitApplications
    type boolean
    description
    name DataExecutionPrevention_Available
    type boolean
    description
    name DataExecutionPrevention_Drivers
    type boolean
    description
    name DataExecutionPrevention_SupportPolicy
    type int
    description
    name Debug
    type boolean
    description
    name Description
    type string
    description
    name Distributed
    type boolean
    description
    name EncryptionLevel
    type int
    description
    name ForegroundApplicationBoost
    type int
    description
    name FreePhysicalMemory
    type int
    description
    name FreeSpaceInPagingFiles
    type int
    description
    name FreeVirtualMemory
    type int
    description
    name InstallDate
    type datetime
    description
    name LargeSystemCache
    type dynamic
    description
    name LastBootUpTime
    type datetime
    description
    name LocalDateTime
    type datetime
    description
    name Locale
    type string
    description
    name Manufacturer
    type string
    description
    name MaxNumberOfProcesses
    type long
    description
    name MaxProcessMemorySize
    type long
    description
    name MUILanguages
    type dynamic
    description
    name Name
    type string
    description
    name NumberOfLicensedUsers
    type int
    description
    name NumberOfProcesses
    type int
    description
    name NumberOfUsers
    type int
    description
    name OperatingSystemSKU
    type int
    description
    name Organization
    type dynamic
    description
    name OSArchitecture
    type string
    description
    name OSLanguage
    type int
    description
    name OSProductSuite
    type int
    description
    name OSType
    type int
    description
    name OtherTypeDescription
    type dynamic
    description
    name PAEEnabled
    type dynamic
    description
    name PlusProductID
    type dynamic
    description
    name PlusVersionNumber
    type dynamic
    description
    name PortableOperatingSystem
    type boolean
    description
    name Primary
    type boolean
    description
    name ProductType
    type int
    description
    name PSComputerName
    type dynamic
    description
    name RegisteredUser
    type string
    description
    name SerialNumber
    type string
    description
    name ServicePackMajorVersion
    type int
    description
    name ServicePackMinorVersion
    type int
    description
    name SizeStoredInPagingFiles
    type int
    description
    name Status
    type string
    description
    name SuiteMask
    type int
    description
    name SystemDevice
    type string
    description
    name SystemDirectory
    type string
    description
    name SystemDrive
    type string
    description
    name TotalSwapSpaceSize
    type dynamic
    description
    name TotalVirtualMemorySize
    type int
    description
    name TotalVisibleMemorySize
    type int
    description
    name UserLoggedOn
    type string
    description
    name Version
    type string
    description
    name WindowsDirectory
    type string
 
    # build schema to be used for DCR
    $Schema = Get-ObjectSchemaAsHash -Data $DataVariable -ReturnType DCR -Verbose:$verbose
    $Schema
 
    $Schema = Get-ObjectSchemaAsHash -Data $DataVariable -ReturnType DCR -Verbose:$verbose
    $Schema
    #-------------------------------------------------------------------------------------------
    # Output
    #-------------------------------------------------------------------------------------------
 
    Name Value
    ---- -----
    name BootDevice
    type string
    name BuildNumber
    type string
    name BuildType
    type string
    name Caption
    type string
    name CodeSet
    type string
    name CollectionTime
    type datetime
    name Computer
    type string
    name CountryCode
    type string
    name CreationClassName
    type string
    name CSCreationClassName
    type string
    name CSDVersion
    type dynamic
    name CSName
    type string
    name CurrentTimeZone
    type int
    name DataExecutionPrevention_32BitApplications
    type boolean
    name DataExecutionPrevention_Available
    type boolean
    name DataExecutionPrevention_Drivers
    type boolean
    name DataExecutionPrevention_SupportPolicy
    type int
    name Debug
    type boolean
    name Description
    type string
    name Distributed
    type boolean
    name EncryptionLevel
    type int
    name ForegroundApplicationBoost
    type int
    name FreePhysicalMemory
    type int
    name FreeSpaceInPagingFiles
    type int
    name FreeVirtualMemory
    type int
    name InstallDate
    type datetime
    name LargeSystemCache
    type dynamic
    name LastBootUpTime
    type datetime
    name LocalDateTime
    type datetime
    name Locale
    type string
    name Manufacturer
    type string
    name MaxNumberOfProcesses
    type long
    name MaxProcessMemorySize
    type long
    name MUILanguages
    type dynamic
    name Name
    type string
    name NumberOfLicensedUsers
    type int
    name NumberOfProcesses
    type int
    name NumberOfUsers
    type int
    name OperatingSystemSKU
    type int
    name Organization
    type dynamic
    name OSArchitecture
    type string
    name OSLanguage
    type int
    name OSProductSuite
    type int
    name OSType
    type int
    name OtherTypeDescription
    type dynamic
    name PAEEnabled
    type dynamic
    name PlusProductID
    type dynamic
    name PlusVersionNumber
    type dynamic
    name PortableOperatingSystem
    type boolean
    name Primary
    type boolean
    name ProductType
    type int
    name PSComputerName
    type dynamic
    name RegisteredUser
    type string
    name SerialNumber
    type string
    name ServicePackMajorVersion
    type int
    name ServicePackMinorVersion
    type int
    name SizeStoredInPagingFiles
    type int
    name Status
    type string
    name SuiteMask
    type int
    name SystemDevice
    type string
    name SystemDirectory
    type string
    name SystemDrive
    type string
    name TotalSwapSpaceSize
    type dynamic
    name TotalVirtualMemorySize
    type int
    name TotalVisibleMemorySize
    type int
    name UserLoggedOn
    type string
    name Version
    type string
    name WindowsDirectory
    type string
  #>


    [CmdletBinding()]
    param(
            [Parameter(mandatory)]
                [Array]$Data,
            [Parameter(mandatory)]
                [ValidateSet("Table", "DCR")]
                [string[]]$ReturnType
         )


        $SchemaArrayLogAnalyticsTableFormat = @()
        $SchemaArrayDcrFormat = @()
        $SchemaArrayLogAnalyticsTableFormatHash = @()
        $SchemaArrayDcrFormatHash = @()

        # Requirement - Add TimeGenerated to array
        $SchemaArrayLogAnalyticsTableFormatHash += @{
                                                     name        = "TimeGenerated"
                                                     type        = "datetime"
                                                     description = ""
                                                    }

        $SchemaArrayLogAnalyticsTableFormat += [PSCustomObject]@{
                                                     name        = "TimeGenerated"
                                                     type        = "datetime"
                                                     description = ""
                                               }

        # Loop source object and build hash for table schema
        ForEach ($Entry in $Data)
            {
                $ObjColumns = $Entry | ConvertTo-Json -Depth 100 | ConvertFrom-Json | Get-Member -MemberType NoteProperty
                ForEach ($Column in $ObjColumns)
                    {
                        $ObjDefinitionStr = $Column.Definition
                                If ($ObjDefinitionStr -like "int*")                                            { $ObjType = "int" }
                            ElseIf ($ObjDefinitionStr -like "real*")                                           { $ObjType = "int" }
                            ElseIf ($ObjDefinitionStr -like "long*")                                           { $ObjType = "long" }
                            ElseIf ($ObjDefinitionStr -like "guid*")                                           { $ObjType = "dynamic" }
                            ElseIf ($ObjDefinitionStr -like "string*")                                         { $ObjType = "string" }
                            ElseIf ($ObjDefinitionStr -like "datetime*")                                       { $ObjType = "datetime" }
                            ElseIf ($ObjDefinitionStr -like "bool*")                                           { $ObjType = "boolean" }
                            ElseIf ($ObjDefinitionStr -like "object*")                                         { $ObjType = "dynamic" }
                            ElseIf ($ObjDefinitionStr -like "System.Management.Automation.PSCustomObject*")    { $ObjType = "dynamic" }

                        # build for array check
                        $SchemaLogAnalyticsTableFormatObjHash = @{
                                                                   name        = $Column.Name
                                                                   type        = $ObjType
                                                                   description = ""
                                                                 }

                        $SchemaLogAnalyticsTableFormatObj     = [PSCustomObject]@{
                                                                   name        = $Column.Name
                                                                   type        = $ObjType
                                                                   description = ""
                                                                }
                        $SchemaDcrFormatObjHash = @{
                                                      name        = $Column.Name
                                                      type        = $ObjType
                                                   }

                        $SchemaDcrFormatObj     = [PSCustomObject]@{
                                                      name        = $Column.Name
                                                      type        = $ObjType
                                                  }


                        If ($Column.Name -notin $SchemaArrayLogAnalyticsTableFormat.name)
                            {
                                $SchemaArrayLogAnalyticsTableFormat       += $SchemaLogAnalyticsTableFormatObj
                                $SchemaArrayDcrFormat                     += $SchemaDcrFormatObj

                                $SchemaArrayLogAnalyticsTableFormatHash   += $SchemaLogAnalyticsTableFormatObjHash
                                $SchemaArrayDcrFormatHash                 += $SchemaDcrFormatObjHash
                            }
                    }
            }

            If ($ReturnType -eq "Table")
            {
                # Return schema format for Table
                $SchemaArrayLogAnalyticsTableFormatHash
            }
        ElseIf ($ReturnType -eq "DCR")
            {
                # Return schema format for DCR
                $SchemaArrayDcrFormatHash
            }
        
        Return
}