Modules/DSCParser.psm1
function ConvertTo-DSCObject { [CmdletBinding()] param ( [Parameter(Mandatory = $true,Position = 1)] [string] $Path ) #region Variables $ParsedResults = @() #endregion # Define components we wish to filter out $noisyTypes = @("NewLine", "StatementSeparator", "Command", "CommandArgument", "CommandParameter", "Comment") $noisyParts = @("in", "if", "node", "localconfigurationmanager", "for", "foreach", "when", "configuration", "Where", "_") $noisyOperators = (".",",", "") # Tokenize the file's content to break it down into its various components; $parsedData = [System.Management.Automation.PSParser]::Tokenize((Get-Content $Path), [ref]$null) [array]$componentsArray = @() $currentValues = @() $nodeKeyWordEncountered = $false $ObjectsToClose = 0 for ($i = 0; $i -lt $parsedData.Count; $i++) { if ($nodeKeyWordEncountered) { if ($parsedData[$i].Type -eq "GroupStart" -or $parsedData[$i].Content -eq '{') { $ObjectsToClose++ } elseif (($parsedData[$i].Type -eq "GroupEnd" -or $parsedData[$i].Content -eq '}') -and $ObjectsToClose -gt 0) { $ObjectsToClose-- } if ($parsedData[$i].Type -notin $noisyTypes -and $parsedData[$i].Content -notin $noisyParts) { $currentValues += $parsedData[$i] if($parsedData[$i].Type -eq "GroupEnd" -and $parsedData[$i].Content -eq '}' -and $ObjectsToClose -eq 0) { $componentsArray += ,$currentValues $currentValues = @() $ObjectsToClose = 0 } } elseif (($parsedData[$i].Type -eq "GroupEnd" -and $parsedData[$i-2].Content -ne 'parameter' -and $parsedData[$i].Content -ne '}') -or ($parsedData[$i].Type -eq "GroupStart" -and $parsedData[$i-1].Content -ne 'parameter' -and $parsedData[$i].Content -ne '{')) { $currentValues += $parsedData[$i] } } elseif ($parsedData[$i].Content -eq 'node') { $nodeKeyWordEncountered = $true $newIndexPosition = $i+1 while ($parsedData[$newIndexPosition].Type -ne 'Keyword') { $i++ $newIndexPosition = $i+1 } } } $ParsedResults = Get-HashtableFromGroup -Groups $componentsArray return $ParsedResults } function Get-HashtableFromGroup { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param( [Parameter(Mandatory = $true)] [System.Array] $Groups, [Parameter()] [System.Boolean] $IsSubGroup = $false ) # Loop through all the Resources identified within our configuration $currentIndex = 1 $result = @() $ParsedResults = @() foreach ($group in $Groups) { $keywordFound = $false if (-not $IsSubGroup -and $currentIndex -le $Groups.Count-2) { Write-Progress -PercentComplete ($currentIndex / ($Groups.Count-2) * 100) -Activity "Parsing $($resource.Content) [$($currentIndex)/$($Groups.Count-2)]" } $currentPropertyIndex = 0 $currentProperty = '' while ($currentPropertyIndex -lt $group.Count) { $component = $group[$currentPropertyIndex] if ($component.Type -eq "Keyword" -and -not $keywordFound) { $result = @{ ResourceName = $component.Content } $keywordFound = $true } elseif ($keywordFound) { # If the next component is a keyword and we've already identified a keyword for this group, that means that we are # looking at a CIMInstance property; if ($component.Type -eq "Keyword") { $currentGroupEndFound = $false $currentPosition = $currentPropertyIndex + 1 $subGroup = @($component) $ObjectsToClose = 0 $allSubGroups = @() [Array]$subResult = @() while (!$currentGroupEndFound) { $currentSubComponent = $group[$currentPosition] if ($currentSubComponent.Type -eq 'GroupStart' -or $currentSubComponent.Content -eq '{') { $ObjectsToClose++ } elseif ($currentSubComponent.Type -eq 'GroupEnd' -or $currentSubComponent.Content -eq '}') { $ObjectsToClose-- } $subGroup += $group[$currentPosition] if ($ObjectsToClose -eq 0 -and $group[$currentPosition+1].Type -ne 'Keyword' -and ` $group[$currentPosition].Type -ne 'Keyword') { $currentGroupEndFound = $true } if ($ObjectsToClose -eq 0 -and $group[$currentPosition].Type -ne 'Keyword') { $allSubGroups += ,$subGroup $subGroup = @() } $currentPosition++ } $currentPropertyIndex = $currentPosition $subResult = Get-HashtableFromGroup -Groups $allSubGroups -IsSubGroup $true $allSubGroups = @() $subGroup = @() $result.$currentProperty = $subResult } # If the next component is not an operator, that means that the current member is part of the previous property's # value; elseif ($group[$currentPropertyIndex + 1].Type -ne "Operator" -and $component.Content -ne "=" -and ` $component.Content -ne '{' -and $component.Content -ne '}' -and $group[$currentPropertyIndex + 1].Type -ne 'Keyword') { switch ($component.Type) { {$_ -in @("String","Number")} { $result.$currentProperty += $component.Content } {$_ -in @("Variable")} { $result.$currentProperty += "`$" + $component.Content } {$_ -in @("Member")} { $result.$currentProperty += "." + $component.Content } {$_ -in @("GroupStart")} { $result.$currentProperty += "@(" do { if ($group[$currentPropertyIndex].Content -notin @("@(", ")")) { $result.$currentProperty += "`"" + $group[$currentPropertyIndex].Content + "`",`"" } $currentPropertyIndex++ } while ($group[$currentPropertyIndex].Type -ne 'GroupEnd') if (($result.$currentProperty).EndsWith(",")) { $result.$currentProperty = ($result.$CurrentProperty).Substring(0, ($result.$CurrentProperty).Length -1) + ")" } else { $result.$currentProperty += ')' } } } } elseif ($component.Content -notin $noisyOperators) { switch ($component.Type) { "Member" { $currentProperty = $component.Content.ToString() if(!$result.Contains($currentProperty)) { $result.Add($currentProperty, $null) } } } } } $currentPropertyIndex++ } if($keywordFound) { $ParsedResults += $result } $currentIndex++ } return $ParsedResults } |