Files
2026-05-12 19:39:29 +10:00

266 lines
10 KiB
PowerShell

function Get-ModuleVersion
{
'1.0.0'
}
function Invoke-InitializeModule
{
Add-OutputType ([PSCustomObject]@{
Name = "Json"
Value = "json"
OutputOptions = (Add-JsonOptionsControl)
PreProcess = { Invoke-JsonPreProcessItems @args }
NewObjectGroup = { Invoke-JsonNewObjectGroup @args }
NewObjectType = { Invoke-JsonNewObjectType @args }
Process = { Invoke-JsonProcessItem @args }
PostProcess = { Invoke-JsonPostProcessItems @args }
})
}
function Add-JsonOptionsControl
{
$script:jsonForm = Get-XamlObject ($global:AppRootFolder + "\Xaml\DocumentationJsonOptions.xaml") -AddVariables
Set-XamlProperty $script:jsonForm "txtJsonFileName" "Text" (Get-Setting "Documentation" "JsonDocumentName" "")
Set-XamlProperty $script:jsonForm "chkJsonOpenDocument" "IsChecked" (Get-Setting "Documentation" "JsonOpenFile" $true)
$outputFileTypes = '[ { "Name": "Single file", "Value": "Full" }, { "Name": "One file per object type", "Value": "ObjectType" } ]' | ConvertFrom-Json
Set-XamlProperty $script:jsonForm "cbJsonOutputFile" "ItemsSource" $outputFileTypes
Set-XamlProperty $script:jsonForm "cbJsonOutputFile" "SelectedValue" (Get-Setting "Documentation" "JsonOutputFileType" "Full")
Add-XamlEvent $script:jsonForm "browseJsonFileName" "add_click" {
$sf = [System.Windows.Forms.SaveFileDialog]::new()
$sf.DefaultExt = "json"
$sf.Filter = "Json (*.json)|*.json|All files (*.*)|*.*"
if ($sf.ShowDialog() -eq "OK")
{
Set-XamlProperty $script:jsonForm "txtJsonFileName" "Text" $sf.FileName
Save-Setting "Documentation" "JsonDocumentName" $sf.FileName
}
}
$script:jsonForm
}
function Invoke-JsonPreProcessItems
{
$script:jsonAllObjects = [System.Collections.Generic.List[object]]::new()
$script:jsonCurrentTypeObjects = [System.Collections.Generic.List[object]]::new()
$script:jsonCurrentTypeName = $null
$script:jsonOutputType = Get-XamlProperty $script:jsonForm "cbJsonOutputFile" "SelectedValue" "Full"
$jsonFileName = Get-XamlProperty $script:jsonForm "txtJsonFileName" "Text" ""
Save-Setting "Documentation" "JsonDocumentName" $jsonFileName
Save-Setting "Documentation" "JsonOpenFile" (Get-XamlProperty $script:jsonForm "chkJsonOpenDocument" "IsChecked")
Save-Setting "Documentation" "JsonOutputFileType" $script:jsonOutputType
$script:jsonOutFile = Expand-FileName (?? $jsonFileName "%MyDocuments%\%Organization%-%Date%.json")
$script:jsonDocumentPath = [IO.Path]::GetDirectoryName($script:jsonOutFile)
}
function Invoke-JsonNewObjectGroup
{
param($groupId)
# Groups are not used in flat Json output
}
function Invoke-JsonNewObjectType
{
param($objectTypeName)
if ($script:jsonOutputType -eq "ObjectType" -and
$script:jsonCurrentTypeName -and
$script:jsonCurrentTypeObjects.Count -gt 0)
{
Save-JsonTypeFile $script:jsonCurrentTypeName $script:jsonCurrentTypeObjects
}
$script:jsonCurrentTypeName = $objectTypeName
$script:jsonCurrentTypeObjects = [System.Collections.Generic.List[object]]::new()
}
function Invoke-JsonProcessItem
{
param($obj, $objectType, $documentedObj)
if (-not $documentedObj -or -not $obj -or -not $objectType) { return }
$objName = Get-GraphObjectName $obj $objectType
try
{
$jsonObj = [ordered]@{
objectType = $objectType.Title
name = $objName
}
# BasicInfo as a flat key/value object
if ($documentedObj.BasicInfo.Count -gt 0)
{
$basicInfo = [ordered]@{}
foreach ($item in $documentedObj.BasicInfo)
{
if ($item.Name) { $basicInfo[$item.Name] = $item.Value }
}
$jsonObj.basicInfo = $basicInfo
}
# Detailed settings as an array
if ($documentedObj.FilteredSettings.Count -gt 0)
{
$settings = [System.Collections.Generic.List[object]]::new()
foreach ($item in $documentedObj.FilteredSettings)
{
$setting = [ordered]@{ name = $item.Name; value = $item.Value }
if ($item.Category) { $setting.category = $item.Category }
if ($item.SubCategory) { $setting.subCategory = $item.SubCategory }
$settings.Add($setting)
}
$jsonObj.settings = $settings
}
# Compliance actions
if (($documentedObj.ComplianceActions | Measure-Object).Count -gt 0)
{
$actions = [System.Collections.Generic.List[object]]::new()
foreach ($item in $documentedObj.ComplianceActions)
{
$actions.Add([ordered]@{
action = $item.Action
schedule = $item.Schedule
messageTemplate = $item.MessageTemplate
emailCC = $item.EmailCC
})
}
$jsonObj.complianceActions = $actions
}
# Applicability rules
if (($documentedObj.ApplicabilityRules | Measure-Object).Count -gt 0)
{
$rules = [System.Collections.Generic.List[object]]::new()
foreach ($item in $documentedObj.ApplicabilityRules)
{
$rules.Add([ordered]@{
rule = $item.Rule
property = $item.Property
value = $item.Value
})
}
$jsonObj.applicabilityRules = $rules
}
# Custom tables — each becomes a top-level array keyed by the last segment of the language ID
foreach ($customTable in ($documentedObj.CustomTables | Sort-Object -Property Order))
{
if (-not $customTable.Values -or ($customTable.Values | Measure-Object).Count -eq 0) { continue }
$tableKey = if ($customTable.LanguageId) { $customTable.LanguageId.Split('.')[-1] } else { "customTable" }
$tableArr = [System.Collections.Generic.List[object]]::new()
foreach ($item in $customTable.Values)
{
$tableObj = [ordered]@{}
foreach ($col in $customTable.Columns)
{
$colName = $col.Split('.')[-1]
$tableObj[$colName] = "$($item.$colName)"
}
$tableArr.Add($tableObj)
}
$jsonObj[$tableKey] = $tableArr
}
# Assignments
if (($documentedObj.Assignments | Measure-Object).Count -gt 0)
{
$assignments = [System.Collections.Generic.List[object]]::new()
$hasRawIntent = $null -ne $documentedObj.Assignments[0].RawIntent
foreach ($item in $documentedObj.Assignments)
{
if ($hasRawIntent)
{
$assignObj = [ordered]@{
groupMode = $item.GroupMode
group = $item.Group
}
if ($null -ne $item.Filter) { $assignObj.filter = $item.Filter }
if ($null -ne $item.FilterMode) { $assignObj.filterMode = $item.FilterMode }
if ($item.Settings)
{
$settingsObj = [ordered]@{}
foreach ($key in $item.Settings.Keys)
{
if ($key -in @("Category","RawIntent")) { continue }
$settingsObj[$key] = $item.Settings[$key]
}
$assignObj.settings = $settingsObj
}
}
else
{
$assignObj = [ordered]@{ group = $item.Group }
if ($item.PSObject.Properties.Name -contains "Filter") { $assignObj.filter = $item.Filter }
if ($item.PSObject.Properties.Name -contains "FilterMode") { $assignObj.filterMode = $item.FilterMode }
}
$assignments.Add($assignObj)
}
$jsonObj.assignments = $assignments
}
# Scripts — included when "Document scripts" is checked in the documentation form
if ($global:chkIncludeScripts.IsChecked -and ($documentedObj.Scripts | Measure-Object).Count -gt 0)
{
$scripts = [System.Collections.Generic.List[object]]::new()
foreach ($scriptItem in $documentedObj.Scripts)
{
if (-not $scriptItem.ScriptContent) { continue }
$scripts.Add([ordered]@{
caption = $scriptItem.Caption
content = $scriptItem.ScriptContent
})
}
if ($scripts.Count -gt 0) { $jsonObj.scripts = $scripts }
}
$script:jsonCurrentTypeObjects.Add($jsonObj)
if ($script:jsonOutputType -ne "ObjectType") { $script:jsonAllObjects.Add($jsonObj) }
}
catch
{
Write-LogError "Failed to process object $objName" $_.Exception
}
}
function Invoke-JsonPostProcessItems
{
$openFile = (Get-XamlProperty $script:jsonForm "chkJsonOpenDocument" "IsChecked") -eq $true
if ($script:jsonOutputType -eq "ObjectType")
{
if ($script:jsonCurrentTypeName -and $script:jsonCurrentTypeObjects.Count -gt 0)
{
Save-JsonTypeFile $script:jsonCurrentTypeName $script:jsonCurrentTypeObjects
}
Write-Log "Json documentation saved to folder: $($script:jsonDocumentPath)"
}
else
{
$jsonContent = ConvertTo-Json -InputObject @($script:jsonAllObjects) -Depth 20
Save-DocumentationFile $jsonContent $script:jsonOutFile -OpenFile:$openFile
}
}
function Save-JsonTypeFile
{
param($typeName, $objects)
$safeTypeName = Remove-InvalidFileNameChars ($typeName.Replace(" ", "_"))
$typeFileName = [IO.Path]::Combine($script:jsonDocumentPath, "$safeTypeName.json")
$jsonContent = ConvertTo-Json -InputObject @($objects) -Depth 20
Save-DocumentationFile $jsonContent $typeFileName
Write-Log "Saved $($objects.Count) objects to $typeFileName"
}