# Documentation Output Provider for Word #https://docs.microsoft.com/en-us/office/vba/api/overview/word function Get-ModuleVersion { '1.7.0' } function Invoke-InitializeModule { if(!("Microsoft.Office.Interop.Word.Application" -as [Type])) { $loaded = $false try { Add-Type -AssemblyName Microsoft.Office.Interop.Word $loaded = $true } catch { } try { $wordFile = Get-ChildItem -path "$($env:windir)\assembly\GAC_MSIL" -Filter "Microsoft.Office.Interop.Word.dll" -Recurse if($wordFile -and $wordFile.Exists) { Add-Type -Path $wordFile.FullName $loaded = $true } } catch { Write-LogError "Failed to add Word Interop type. Cannot create word documents. Verify that Word is installed properly." $_.Exception return } if(-not $loaded) { Write-LogError "Word Interop type not found. Cannot create word documents. Verify that Word is installed properly." $_.Exception return } } Add-OutputType ([PSCustomObject]@{ Name="Word" Value="word" OutputOptions = (Add-WordOptionsControl) Activate = { Invoke-WordActivate @args } PreProcess = { Invoke-WordPreProcessItems @args } NewObjectGroup = { Invoke-WordNewObjectGroup @args } NewObjectType = { Invoke-WordNewObjectType @args } Process = { Invoke-WordProcessItem @args } PostProcess = { Invoke-WordPostProcessItems @args } ProcessAllObjects = { Invoke-WordProcessAllObjects @args } }) } function Add-WordOptionsControl { $script:wordForm = Get-XamlObject ($global:AppRootFolder + "\Xaml\DocumentationWordOptions.xaml") -AddVariables $global:cbWordDocumentationProperties.ItemsSource = ("[ { Name: `"Simple (Name and Value)`",Value: `"simple`" }, { Name: `"Extended`",Value: `"extended`" }, { Name: `"Custom`",Value: `"custom`" }]" | ConvertFrom-Json) $global:cbWordDocumentationProperties.SelectedValue = (Get-Setting "Documentation" "WordExportProperties" "simple") $global:txtWordCustomProperties.Text = (Get-Setting "Documentation" "WordCustomDisplayProperties" "Name,Value,Category,SubCategory") $global:spWordCustomProperties.Visibility = (?: ($global:cbWordDocumentationProperties.SelectedValue -ne "custom") "Collapsed" "Visible") $global:txtWordCustomProperties.Visibility = (?: ($global:cbWordDocumentationProperties.SelectedValue -ne "custom") "Collapsed" "Visible") $global:cbWordDocumentationFormat.ItemsSource = ("[ { Name: `"Docx`",Value: `"docx`" }, { Name: `"PDF`",Value: `"pdf`" }]" | ConvertFrom-Json) $global:cbWordDocumentationFormat.SelectedValue = (Get-Setting "Documentation" "WordDocumentFormat" "docx") $global:cbWordDocumentationLevel.ItemsSource = ("[ { Name: `"Full`",Value: `"full`" }, { Name: `"Limited`",Value: `"limited`" }, { Name: `"Basic`",Value: `"basic`" }]" | ConvertFrom-Json) $global:cbWordDocumentationLevel.SelectedValue = (Get-Setting "Documentation" "WordDocumentationLevel" "full") $global:gdWordDocumentationLimitOptions.Visibility = (?: ($global:cbWordDocumentationLevel.SelectedValue -ne "limited") "Collapsed" "Visible") $global:txtWordDocumentationLimitMaxLength.Text = Get-Setting "Documentation" "WordDocumentationLimitMaxLength" "" $global:txtWordDocumentationLimitTruncateLength.Text = Get-Setting "Documentation" "WordDocumentationLimitTruncateLength" "" $global:chkWordDocumentationLimitAttach.IsChecked = ((Get-Setting "Documentation" "WordDocumentationLimitAttatch" "true") -ne "false") $global:txtWordDocumentTemplate.Text = Get-Setting "Documentation" "WordDocumentTemplate" "" $global:txtWordDocumentName.Text = (Get-Setting "Documentation" "WordDocumentName" "%MyDocuments%\%Organization%-%Date%.docx") $global:chkWordAddCategories.IsChecked = ((Get-Setting "Documentation" "WordAddCategories" "true") -ne "false") $global:chkWordAddSubCategories.IsChecked = ((Get-Setting "Documentation" "WordAddSubCategories" "true") -ne "false") $global:txtWordHeader1Style.Text = Get-Setting "Documentation" "WordHeader1Style" "Heading 1" $global:txtWordHeader2Style.Text = Get-Setting "Documentation" "WordHeader2Style" "Heading 2" $global:txtWordHeader3Style.Text = Get-Setting "Documentation" "WordHeader3Style" "Heading 3" $global:txtWordTableStyle.Text = Get-Setting "Documentation" "WordTableStyle" "Grid table 4 - Accent 3" $global:txtWordTableHeaderStyle.Text = Get-Setting "Documentation" "WordTableHeaderStyle" "" $global:txtWordCategoryHeaderStyle.Text = Get-Setting "Documentation" "WordCategoryHeaderStyle" "" $global:txtWordSubCategoryHeaderStyle.Text = Get-Setting "Documentation" "WordSubCategoryHeaderStyle" "" $global:txtWordTableTextStyle.Text = Get-Setting "Documentation" "WordTableTextStyle" "" $global:cbWordTableCaptionPosition.ItemsSource = ("[ { Name: `"Above`",Value: `"above`" }, { Name: `"Below`",Value: `"below`" }]" | ConvertFrom-Json) $global:cbWordTableCaptionPosition.SelectedValue = (Get-Setting "Documentation" "WordTableCaptionPosition" "below") $global:txtWordContentControls.Text = Get-Setting "Documentation" "WordContentControls" "Year=;Address=" $global:txtWordTitleProperty.Text = Get-Setting "Documentation" "WordTitleProperty" "Intune documentation" $global:txtWordSubjectProperty.Text = Get-Setting "Documentation" "WordSubjectProperty" "Intune documentation" $global:chkWordAttachJsonFile.IsChecked = ((Get-Setting "Documentation" "WordAttatchJsonFile" "false") -ne "false") $global:txtWordScriptTableStyle.Text = Get-Setting "Documentation" "WordScriptTableStyle" "" $global:txtWordScriptStyle.Text = Get-Setting "Documentation" "WordScriptStyle" $global:chkWordOpenDocument.IsChecked = ((Get-Setting "Documentation" "WordOpenDocument" "true") -ne "false") Add-XamlEvent $script:wordForm "browseWordDocumentTemplate" "add_click" { $of = [System.Windows.Forms.OpenFileDialog]::new() $of.Multiselect = $false $of.Filter = "Word Templates (*.dotx)|*.dotx" if($of.ShowDialog()) { Set-XamlProperty $script:wordForm "txtWordDocumentTemplate" "Text" $of.FileName Save-Setting "Documentation" "WordDocumentTemplate" $of.FileName } } Add-XamlEvent $script:wordForm "cbWordDocumentationProperties" "add_selectionChanged" { $global:spWordCustomProperties.Visibility = (?: ($this.SelectedValue -ne "custom") "Collapsed" "Visible") $global:txtWordCustomProperties.Visibility = (?: ($this.SelectedValue -ne "custom") "Collapsed" "Visible") } Add-XamlEvent $script:wordForm "cbWordDocumentationLevel" "add_selectionChanged" { $global:gdWordDocumentationLimitOptions.Visibility = (?: ($this.SelectedValue -ne "limited") "Collapsed" "Visible") } $script:wordForm } function Invoke-WordActivate { #$global:chkWordAddCompanyName.IsChecked = (Get-SettingValue "AddCompanyName") } function Invoke-WordPreProcessItems { Save-Setting "Documentation" "WordExportProperties" $global:cbWordDocumentationProperties.SelectedValue Save-Setting "Documentation" "WordCustomDisplayProperties" $global:txtWordCustomProperties.Text Save-Setting "Documentation" "WordDocumentFormat" $global:cbWordDocumentationFormat.SelectedValue Save-Setting "Documentation" "WordDocumentTemplate" $global:txtWordDocumentTemplate.Text Save-Setting "Documentation" "WordDocumentName" $global:txtWordDocumentName.Text Save-Setting "Documentation" "WordDocumentationLevel" $global:cbWordDocumentationLevel.SelectedValue Save-Setting "Documentation" "WordDocumentationLimitMaxLength" $global:txtWordDocumentationLimitMaxLength.Text Save-Setting "Documentation" "WordDocumentationLimitTruncateLength" $global:txtWordDocumentationLimitTruncateLength.Text Save-Setting "Documentation" "WordDocumentationLimitAttatch" $global:chkWordDocumentationLimitAttach.IsChecked Save-Setting "Documentation" "WordAddCategories" $global:chkWordAddCategories.IsChecked Save-Setting "Documentation" "WordAddSubCategories" $global:chkWordAddSubCategories.IsChecked Save-Setting "Documentation" "WordOpenDocument" $global:chkWordOpenDocument.IsChecked Save-Setting "Documentation" "WordHeader1Style" $global:txtWordHeader1Style.Text Save-Setting "Documentation" "WordHeader2Style" $global:txtWordHeader2Style.Text Save-Setting "Documentation" "WordHeader3Style" $global:txtWordHeader3Style.Text Save-Setting "Documentation" "WordTableStyle" $global:txtWordTableStyle.Text Save-Setting "Documentation" "WordTableHeaderStyle" $global:txtWordTableHeaderStyle.Text Save-Setting "Documentation" "WordCategoryHeaderStyle" $global:txtWordCategoryHeaderStyle.Text Save-Setting "Documentation" "WordSubCategoryHeaderStyle" $global:txtWordSubCategoryHeaderStyle.Text Save-Setting "Documentation" "WordTableTextStyle" $global:txtWordTableTextStyle.Text Save-Setting "Documentation" "WordTableCaptionPosition" $global:cbWordTableCaptionPosition.SelectedValue Save-Setting "Documentation" "WordContentControls" $global:txtWordContentControls.Text Save-Setting "Documentation" "WordTitleProperty" $global:txtWordTitleProperty.Text Save-Setting "Documentation" "WordSubjectProperty" $global:txtWordSubjectProperty.Text Save-Setting "Documentation" "WordAttatchJsonFile" $global:chkWordAttachJsonFile.IsChecked Save-Setting "Documentation" "WordScriptTableStyle" $global:txtWordScriptTableStyle.Text Save-Setting "Documentation" "WordScriptStyle" $global:txtWordScriptStyle.Text $script:limitMaxValue = 100 $script:truncateValueLength = $script:limitMaxValue if($global:cbWordDocumentationLevel.SelectedValue -eq "limited") { if($global:txtWordDocumentationLimitMaxLength.Text) { try { $script:limitMaxValue = [int]::Parse($global:txtWordDocumentationLimitMaxLength.Text) } catch { Write-LogError "Failed to parse $($global:txtWordDocumentationLimitMaxLength.Text) to int. Max value length will be set to 100." $_.Exception } } if($global:txtWordDocumentationLimitTruncateLength.Text) { try { $script:truncateValueLength = [int]::Parse($global:txtWordDocumentationLimitTruncateLength.Text) } catch { Write-LogError "Failed to parse $($global:txtWordDocumentationLimitTruncateLength.Text) to int. Truncat length will be set to $script:limitMaxValue." $_.Exception } } if($script:limitMaxValue -lt 20) { Write-Log "Max value length must be 20 or more. Changed to 20" 2 $script:limitMaxValue = 0 } if($script:truncateValueLength -lt 0) { Write-Log "Truncate length must be 0 or more. Changed to 0" 2 $script:truncateValueLength = 0 } elseif($script:truncateValueLength -gt $script:limitMaxValue) { Write-Log "Truncate length cannot be larger than Max value length. Canged to: $($script:limitMaxValue)" 2 $script:truncateValueLength = $script:limitMaxValue } } try { $script:wordApp = New-Object -ComObject Word.Application } catch { Write-LogError "Failed to create Word App object. Word documentation aborted..." $_.Exception return $false } #$wordApp.Visible = $true if($global:txtWordDocumentTemplate.Text) { try { $script:doc = $script:wordApp.Documents.Add($global:txtWordDocumentTemplate.Text) } catch { Write-LogError "Failed to create document based on template: $($global:txtWordDocumentTemplate.Text)" $_.Exception } } else { $script:doc = $script:wordApp.Documents.Add() } #Get BuiltIn properties $script:builtInProps = @() $script:doc.BuiltInDocumentProperties | foreach-object { $name = [System.__ComObject].invokemember("name",[System.Reflection.BindingFlags]::GetProperty,$null,$_,$null) try { $value = [System.__ComObject].invokemember("value",[System.Reflection.BindingFlags]::GetProperty,$null,$_,$null) } catch{} if($name) { $script:builtInProps += [PSCustomObject]@{ Name = $name Value = $value } } } #Get Custom properties $script:customProps = @() $script:doc.CustomDocumentProperties | foreach-object { $name = [System.__ComObject].invokemember("name",[System.Reflection.BindingFlags]::GetProperty,$null,$_,$null) try { $value = [System.__ComObject].invokemember("value",[System.Reflection.BindingFlags]::GetProperty,$null,$_,$null) } catch{} if($name) { $script:customProps += [PSCustomObject]@{ Name = $name Value = $value } } } $script:wordStyles = @() $script:doc.Styles | foreach { $script:wordStyles += [PSCUstomObject]@{ Name=$_.NameLocal Type=$_.Type Style=$_ } } $script:builtinStyles = [Enum]::GetNames([Microsoft.Office.Interop.Word.wdBuiltinStyle]) if(-not $global:txtWordDocumentTemplate.Text) { $script:doc.Application.Templates.LoadBuildingBlocks() $BuildingBlocks = $script:doc.Application.Templates | Where {$_.name -eq 'Built-In Building Blocks.dotx'} if($BuildingBlocks) { $coverPageName = ?? $global:txtWordCoverPage.Text 'Ion (Dark)' try { $blocks = @() for($i = 1;$i -le $BuildingBlocks.BuildingBlockEntries.Count;$i++) { $blocks += $BuildingBlocks.BuildingBlockEntries.Item($i) } $coverPages = (($blocks | Where { $_.Type.Index -eq 2 } | Select Name) | Sort -Property Name).Name if(($coverPages | measure).Count -gt 0) { if($coverPageName -notin $coverPages) { Write-Log "$coverPageName not found in available Cover Page list. Using: $($coverPages[0])" Write-Log "Available Cover Pages: $(($coverPages -join ","))" $coverPageName = $coverPages[0] } else { Write-Log "Add Cover Page: $coverPageName" } } $coverPage = $BuildingBlocks.BuildingBlockEntries.Item($coverPageName) $coverPage.Insert($script:wordApp.Selection.Range,$true) | Out-Null $script:wordApp.Selection.InsertNewPage() } catch { Write-LogError "Failed to create Cover Page" $_.Exception } try { $coverPageProps = $script:doc.CustomXMLParts | where { $_.NamespaceURI -match "coverPageProps$" } if($coverPageProps) { Write-Log "Available Cover Page properties for $($coverPageName): $(((([xml]$coverPageProps.DocumentElement.XML).ChildNodes[0].ChildNodes).Name -join ","))" } } catch{} try { $script:doc.TablesOfContents.Add($script:wordApp.Selection.Range) | out-null $script:wordApp.Selection.InsertNewPage() } catch { Write-LogError "Failed to create Table of Contents" $_.Exception } } } else { if(($script:doc.TablesOfContents | measure).Count -eq 0) { # Where should it be added? # $script:doc.TablesOfContents.Add($script:wordApp.Selection.Range) | out-null } Invoke-DocGoToEnd $script:wordApp.Selection.InsertNewPage() } } function Invoke-WordPostProcessItems { $userName = $global:me.displayName if($global:me.givenName -and $global:me.surname) { $userName = ($global:me.givenName + " " + $global:me.surname) } #Add properties - ToDo: This is static... Set-WordDocBuiltInProperty "wdPropertyTitle" (?? $global:txtWordTitleProperty.Text "Intune documentation") Set-WordDocBuiltInProperty "wdPropertySubject" (?? $global:txtWordSubjectProperty.Text "Intune documentation") Set-WordDocBuiltInProperty "wdPropertyAuthor" $userName Set-WordDocBuiltInProperty "wdPropertyCompany" $global:Organization.displayName Set-WordDocBuiltInProperty "wdPropertyKeywords" "Intune,Endpoint Manager,MEM" try { # ToDo: Add support for custom properties # Add: https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.core.documentproperties.add?view=office-pia # Types: https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.core.msodocproperties?view=office-pia #$coverPageProps = $script:doc.CustomXMLParts | where { $_.NamespaceURI -match "coverPageProps$" } #[System.__ComObject].InvokeMember("add",[System.Reflection.BindingFlags]::InvokeMethod,$null,$script:doc.CustomDocumentProperties,([array]("PropName", $false, 4, "PropValue"))) $ContentControlProperties = $global:txtWordContentControls.Text #"Year=;Address=TestAddress" foreach($ccObj in $ContentControlProperties.Split(';')) { $ccName,$ccVal = $ccObj.Split('=') Set-WordContentControlText $ccName $ccVal } } catch {} #update fields, ToC etc. $script:doc.Fields | ForEach-Object -Process { $_.Update() | Out-Null } $script:doc.TablesOfContents | ForEach-Object -Process { $_.Update() | Out-Null } $script:doc.TablesOfFigures | ForEach-Object -Process { $_.Update() | Out-Null } $script:doc.TablesOfAuthorities | ForEach-Object -Process { $_.Update() | Out-Null } if($global:cbWordDocumentationFormat.SelectedValue -eq "pdf") { $format = [Microsoft.Office.Interop.Word.WdSaveFormat]::wdFormatPDF } else { $format = [Microsoft.Office.Interop.Word.WdSaveFormat]::wdFormatDocumentDefault } $fileName = $global:txtWordDocumentName.Text if(-not $fileName) { $fileName = "%MyDocuments%\%Organization%-%Date%.docx" } $fileName = Expand-FileName $fileName if($format -eq [Microsoft.Office.Interop.Word.WdSaveFormat]::wdFormatPDF -and $fileName -notlike "*.pdf") { $fileName = [IO.Path]::ChangeExtension($fileName, ".pdf") } try { $script:doc.SaveAs2([ref]$fileName,[ref]$format) Write-Log "Document $fileName saved successfully" } catch { Write-LogError "Failed to save file $fileName" $_.Excption } if($global:chkWordOpenDocument.IsChecked -eq $true -and $global:hideUI -ne $true) { $script:wordApp.Visible = $true $script:wordApp.WindowState = [Microsoft.Office.Interop.Word.WdWindowState]::wdWindowStateMaximize $script:wordApp.Activate() [Console.Window]::SetForegroundWindow($script:wordApp.ActiveWindow.Hwnd) | Out-Null } else { $script:doc.Close([Microsoft.Office.Interop.Word.WdSaveOptions]::wdDoNotSaveChanges) $script:wordApp.Quit() } } function Set-WordContentControlText { param($controlName, $value) if(-not $controlName) { return } try { $ctrl = $script:doc.SelectContentControlsByTitle($controlName) if($ctrl) { Write-LogDebug "Update ContentControl $controlName (Type: $($ctrl[1].Type))" if($ctrl[1].Type -eq 6) { if($ctrl[1].DateDisplayFormat) { $ctrl[1].Range.Text = (Get-Date).ToString($ctrl[1].DateDisplayFormat) } else { $ctrl[1].Range.Text = (Get-Date).ToShortDateString() } } else { if(-not $value) { return } $ctrl[1].Range.Text = $value } } else { #Write-Log "No ContentControl found with name $controlName" 2 } } catch { Write-LogError "Failed to set ContentControl $controlName" $_.Exception } } function Invoke-WordNewObjectGroup { param($groupId) $objectTypeString = Get-ObjectTypeString -ObjectType $groupId Add-DocText $objectTypeString $global:txtWordHeader1Style.Text } function Invoke-WordNewObjectType { param($objectTypeName) $script:objectHeaderLevel = 2 Add-DocText $objectTypeName (Get-ObjectLevelHeader) $script:objectHeaderLevel = 3 } function local:Get-ObjectLevelHeader { if($script:objectHeaderLevel -eq 3 -and $global:txtWordHeader3Style.Text) { return $global:txtWordHeader3Style.Text } return $global:txtWordHeader2Style.Text } function Invoke-WordProcessItem { param($obj, $objectType, $documentedObj) if(!$documentedObj -or !$obj -or !$objectType) { return } $objName = Get-GraphObjectName $obj $objectType Add-DocText $objName (Get-ObjectLevelHeader) $script:doc.Application.Selection.TypeParagraph() try { #TableHeaders.value #Inputs.displayNameLabel foreach($tableType in @("BasicInfo","FilteredSettings")) { if($tableType -eq "BasicInfo") { $properties = @("Name","Value") } elseif($global:cbWordDocumentationProperties.SelectedValue -eq 'extended' -and $documentedObj.DisplayProperties) { $properties = @("Name","Value","Description") } elseif($global:cbWordDocumentationProperties.SelectedValue -eq 'custom' -and $global:txtWordCustomProperties.Text) { $properties = @() foreach($prop in $global:txtWordCustomProperties.Text.Split(",")) { # This will add language support for custom columns (or replacing existing header) $propInfo = $prop.Split('=') if(($propInfo | measure).Count -gt 1) { $properties += $propInfo[0] Set-DocColumnHeaderLanguageId $propInfo[0] $propInfo[1] } else { $properties += $prop } } } else { $properties = (?? $documentedObj.DefaultDocumentationProperties (@("Name","Value"))) } if($global:cbWordDocumentationLevel.SelectedValue -eq "basic" -and $tableType -ne "BasicInfo") { continue } $lngId = ?: ($tableType -eq "BasicInfo") "SettingDetails.basics" "TableHeaders.settings" -AddCategories if(($documentedObj.$tableType).Count -gt 0) { Add-DocTableItems $obj $objectType ($documentedObj.$tableType) $properties $lngId ` -AddCategories:($global:chkWordAddCategories.IsChecked -eq $true) ` -AddSubcategories:($global:chkWordAddSubCategories.IsChecked -eq $true) ` -ForceFullValue:($tableType -eq "BasicInfo") } } if($global:cbWordDocumentationLevel.SelectedValue -ne "basic") { if(($documentedObj.ComplianceActions | measure).Count -gt 0) { $properties = @("Action","Schedule","MessageTemplate","EmailCC") Add-DocTableItems $obj $objectType $documentedObj.ComplianceActions $properties "Category.complianceActionsLabel" } if(($documentedObj.ApplicabilityRules | measure).Count -gt 0) { $properties = @("Rule","Property","Value") Add-DocTableItems $obj $objectType $documentedObj.ApplicabilityRules $properties "SettingDetails.applicabilityRules" } Add-DocObjectSettings $obj $objectType $documentedObj foreach($customTable in ($documentedObj.CustomTables | Sort-Object -Property Order)) { Add-DocTableItems $obj $objectType $customTable.Values $customTable.Columns $customTable.LanguageId -AddCategories -AddSubcategories } } if(($documentedObj.Assignments | measure).Count -gt 0) { $params = @{} $settingProps = $null if($documentedObj.Assignments[0].RawIntent) { $properties = @("GroupMode","Group","Filter","FilterMode") $settingProps = @("Filter","FilterMode") $settingsObj = $documentedObj.Assignments | Where { $_.Settings -ne $null } | Select -First 1 if($settingsObj) { foreach($objProp in $settingsObj.Settings.Keys) { if($objProp -in $properties) { continue } if($objProp -in @("Category","RawIntent")) { continue } $settingProps += ("Settings." + $objProp) } } $params.Add("AddCategories", $true) } else { $isFilterAssignment = $false foreach($assignment in $documentedObj.Assignments) { if(($assignment.PSObject.Properties | Where Name -eq "FilterMode")) { $isFilterAssignment = $true break } } $properties = @("Group") if($isFilterAssignment) { $properties += @("Filter","FilterMode") } $params.Add("AddCategories", $true) } # Creates a standard assignments table Add-DocTableItems $obj $objectType $documentedObj.Assignments $properties "TableHeaders.assignments" @params if($null -ne $settingProps) { # Adds additional values to the assignments table for Apps assignments Set-DocTableSettingsItems $obj $objectType $documentedObj.Assignments $settingProps 3 } } if($global:chkWordAttachJsonFile.IsChecked -eq $true) { $fileName = Export-GraphObject $obj $objectType ([IO.Path]::GetTempPath()) -IsFullObject -PassThru -SkipAddID if($fileName) { $fi = [IO.FileInfo]$fileName if($fi.Exists) { $script:doc.Application.Selection.InlineShapes.AddOLEObject("",$fi.FullName,$false,$true,"$($env:WinDir)\System32\Notepad.exe",0,$fi.Name) $script:doc.Application.Selection.TypeParagraph() try { $fi.Delete() } catch {} # Cleanup } } } } catch { Write-LogError "Failed to process object $objName" $_.Exception } } function Set-DocTableSettingsItems { param($obj, $objectType, $items, $properties, $firstColumn) $secondColumn = $firstColumn + 1 $script:docTable.Cell(1, $firstColumn).Range.Text = (Invoke-DocTranslateColumnHeader "Settings") $script:docTable.Cell(1, $secondColumn).Range.Text = "" $row = 2 foreach($itemObj in $items) { #if($script:docTable.Rows($row).Cells.Count -eq 1) { $row++;continue } # Category / Sub-category while($script:docTable.Cell($row,1).Next.RowIndex -gt $row) { # Category / Sub-category $row++; } $script:docTable.Cell($row, $firstColumn).Range.Text = "" $script:docTable.Cell($row, $secondColumn).Range.Text = "" $script:docTable.Cell($row, $firstColumn).Split($properties.Count,1) $script:docTable.Cell($row, $secondColumn).Split($properties.Count,1) $cellRow = $row foreach($settingProp in $properties) { if([String]::IsNullOrEmpty($settingProp)) { continue } $script:docTable.Cell($cellRow, $firstColumn).Range.Text = (Invoke-DocTranslateColumnHeader ($settingProp.Split('.')[-1])) $propArr = $settingProp.Split('.') $tmpObj = $itemObj $propName = $propArr[-1] for($x = 0; $x -lt ($propArr.Count - 1);$x++) { $tmpObj = $tmpObj."$($propArr[$x])" } $script:docTable.Cell($cellRow, $secondColumn).Range.Text = "$($tmpObj.$propName)" $cellRow++ } $row = $row + $properties.Count } } function Invoke-WordProcessAllObjects { param($allObjectTypeObjects) if(($allObjectTypeObjects | measure).Count -eq 0) { return } $tmpObj = $allObjectTypeObjects | Select -First 1 if(-not $tmpObj) { return } $objectType = $tmpObj.Object.ObjectType if($objectType.Id -eq "ScopeTags") { $objTypeName = Get-LanguageString "SettingDetails.scopeTags" Add-DocText $objTypeName (Get-ObjectLevelHeader) $script:doc.Application.Selection.TypeParagraph() $items = @() $nameLabel = Get-LanguageString "Inputs.displayNameLabel" $descriptionLable = Get-LanguageString "TableHeaders.description" foreach($obj in $allObjectTypeObjects.Object.Object) { $items += [PSCustomObject]@{ $nameLabel = $obj.displayName ID = $obj.Id $descriptionLable = $obj.Description Object = $obj } } $items = $items | Sort -Property $nameLabel $properties = @($nameLabel,"id",$descriptionLable) Add-DocTableItems $tmpObj.Object.Object $tmpObj.Object.ObjectType $items $properties -captionOverride (Get-LanguageString "SettingDetails.scopeTags") } } function Invoke-WordCustomProcessItems { param($obj, $documentedObj) } function Add-DocTableItems { param($obj, $objectType, $items, $properties, $lngId, [switch]$AddCategories, [switch]$AddSubcategories, $captionOverride, [switch]$forceFullValue) if(($items | measure).Count -eq 0) { return } $tblHeaderStyle = $global:txtWordTableHeaderStyle.Text $tblCategoryStyle = $global:txtWordCategoryHeaderStyle.Text $tblSubCategoryStyle = $global:txtWordSubCategoryHeaderStyle.Text $tblTextStyle = $global:txtWordTableTextStyle.Text $txtTableCaptionPosition = $global:cbWordTableCaptionPosition.SelectedValue $range = $script:doc.application.selection.range $script:docTable = $script:doc.Tables.Add($range, (($items | measure).Count + 1), $properties.Count, [Microsoft.Office.Interop.Word.WdDefaultTableBehavior]::wdWord9TableBehavior, [Microsoft.Office.Interop.Word.WdAutoFitBehavior]::wdAutoFitWindow) $script:docTable.ApplyStyleHeadingRows = $true Set-DocObjectStyle $script:docTable $global:txtWordTableStyle.Text | Out-null if($captionOverride) { $caption = $captionOverride } elseif($lngId) { $caption = "$((Get-LanguageString $lngId)) - $((Get-GraphObjectName $obj $objectType))" } else { $caption = "$((Get-GraphObjectName $obj $objectType)) ($($objectType.Title))" } $i = 1 foreach($prop in $properties) { if([String]::IsNullOrEmpty($prop)) { continue } $script:docTable.Cell(1, $i).Range.Text = (Invoke-DocTranslateColumnHeader ($prop.Split(".")[-1])) $i++ } if(!(Set-DocObjectStyle $script:docTable.Rows(1).Range $tblHeaderStyle)) { $script:docTable.Rows(1).Range.Font.Size += 2 $script:docTable.Rows(1).Range.Font.Bold = $true } $curCategory = "" $curSubCategory = "" $row = 2 $curentPropertyIndex = 0 foreach($itemObj in $items) { try { if(($itemObj.Category -and $curCategory -ne $itemObj.Category -and $AddCategories -eq $true) -or ($itemObj.SubCategory -and $curSubCategory -ne $itemObj.SubCategory -and $AddSubcategories -eq $true)) { $curentPropertyIndex = 0 } if($itemObj.PropertyIndex -is [int] -and $itemObj.PropertyIndex -gt 0 -and $itemObj.PropertyIndex -eq 1) { $curentPropertyIndex = $itemObj.PropertyIndex # !!! ToDo: Set style for new property } $i = 1 foreach($prop in $properties) { try { # This adds support for properties like Settings.PropName $propArr = $prop.Split('.') $tmpObj = $itemObj $propName = $propArr[-1] for($x = 0; $x -lt ($propArr.Count - 1);$x++) { $tmpObj = $tmpObj."$($propArr[$x])" } $propValue = "$($tmpObj.$propName)" $propValueFull = $null if($forceFullValue -ne $true -and $global:cbWordDocumentationLevel.SelectedValue -eq "limited" -and $propValue.Length -gt $script:limitMaxValue) { $propValueFull = $propValue if($script:truncateValueLength -gt 0) { $propValue = ($propValue.Substring(0, $script:truncateValueLength) + "...") if($global:chkWordDocumentationLimitAttach.IsChecked -eq $true) { $propValue = ("`r`n" + $propValue) } } else { $propValue = $null } } $levelExtra = "" if($i -eq 1 -and $itemObj.Level) { try { $level = ([int]$itemObj.Level) # - 1 if($level -lt 0) { $level = 0 } if($level -gt 0) { $levelExtra = [String]::new(" ", ($level * 2)) #Should probably use tab stops instead } } catch{} } if($null -ne $propValue) { $script:docTable.Cell($row, $i).Range.Text = "$levelExtra$propValue" } if($propValueFull -and $global:chkWordDocumentationLimitAttach.IsChecked -eq $true) { if($null -ne $propValue) { #$script:doc.Application.Selection.TypeParagraph() } $tmpName = "$((Get-GraphObjectName $obj $objectType))-$propName" $tmpFile = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "$($tmpName).txt") $tmpFile = Remove-InvalidFileNameChars $tmpFile $propValueFull | Out-File -LiteralPath $tmpFile -Force $fi = [IO.FileInfo]$tmpFile [void]$script:docTable.Cell($row, $i).Range.InlineShapes.AddOLEObject("",$fi.FullName,$false,$true,"$($env:WinDir)\System32\Notepad.exe",0,"Full value") try { $fi.Delete() } catch {} } } catch { Write-LogError "Failed to add property value for $prop" $_.Exception } $i++ } Set-DocObjectStyle $script:docTable.Rows($row).Range $tblTextStyle | Out-Null if($itemObj.Category -and $curCategory -ne $itemObj.Category -and $AddCategories -eq $true) { # Insert row for the Category above the new row $script:docTable.Rows.Add($script:docTable.Rows.Item($row)) | Out-Null $script:docTable.Rows.Item($row).Cells.Merge() $script:docTable.Cell($row, 1).Range.Text = $itemObj.Category if(!(Set-DocObjectStyle $script:docTable.Rows($row).Range $tblCategoryStyle)) { $script:docTable.Rows($row).Range.Font.Size += 2 $script:docTable.Rows($row).Range.Font.Italic = $true } $row++ $curCategory = $itemObj.Category $curSubCategory = "" } if($itemObj.SubCategory -and $curSubCategory -ne $itemObj.SubCategory -and $AddSubcategories -eq $true) { # Insert row for the SubCategory above the new row $script:docTable.Rows.Add($script:docTable.Rows.Item($row)) | Out-Null $script:docTable.Rows.Item($row).Cells.Merge() $script:docTable.Cell($row, 1).Range.Text = $itemObj.SubCategory if(!(Set-DocObjectStyle $script:docTable.Rows($row).Range $tblSubCategoryStyle)) { $script:docTable.Rows($row).Range.Font.Italic = $true } $row++ $curSubCategory = $itemObj.SubCategory } } catch { Write-Log "Failed to process property" 2 } $row++ } # -2 = Table caption, 1 = Below / 0 = Above if($txtTableCaptionPosition -eq "above") { $capPos = 0 } else { $capPos = 1 } $script:docTable.Application.Selection.InsertCaption(-2, ". $caption", $null, $capPos) Invoke-DocGoToEnd # Add new row after the table #$script:doc.Application.Selection.InsertParagraphAfter() $script:doc.Application.Selection.TypeParagraph() } function Add-DocTableScript { param($caption, $header, $script) if(-not $script) { return } $tblScriptStyle = (?? $global:txtWordScriptTableStyle.Text $global:txtWordTableStyle.Text) $range = $script:doc.application.selection.range $scriptTable = $script:doc.Tables.Add($range, 2, 1, [Microsoft.Office.Interop.Word.WdDefaultTableBehavior]::wdWord9TableBehavior, [Microsoft.Office.Interop.Word.WdAutoFitBehavior]::wdAutoFitWindow) $scriptTable.ApplyStyleHeadingRows = $true Set-DocObjectStyle $scriptTable $tblScriptStyle | Out-Null if($header) { $scriptTable.Cell(1, 1).Range.Text = $header } $scriptTable.Cell(2,1).Range.Font.Bold = $false $scriptTable.Cell(2, 1).Range.Text = $script if($global:txtWordScriptStyle.Text) { Set-DocObjectStyle $scriptTable.Rows(2).Range $global:txtWordScriptStyle.Text | Out-Null } else { $tmp = $script:wordStyles | Where Name -like "HTML Code" if($tmp) { $scriptTable.Cell(2,1).Range.Font = $tmp.Style.Font } $scriptTable.Cell(2,1).Range.Font.Bold = $false } $scriptTable.Cell(2,1).Range.NoProofing = $true # -2 = Table, 1 = Below $scriptTable.Application.Selection.InsertCaption(-2, ". $caption", $null, 1) # Add new row after the table $script:doc.Application.Selection.TypeParagraph() } function Get-DocStyle { param($styleName) $tmpStyle = ($script:wordStyles | Where Name -like $styleName).Style # BuiltIn Styles #[Enum]::GetNames([Microsoft.Office.Interop.Word.wdBuiltinStyle]) if(!$tmpStyle) { Write-Log "Style $styleName not found" } $tmpStyle } function Add-DocText { param($text, $style, [switch]$SkipAddParagraph) Set-DocObjectStyle $script:doc.application.selection $style | Out-Null $script:doc.Application.Selection.TypeText($text) if($SkipAddParagraph -ne $true) { # Add new paragraph by default $script:doc.Application.Selection.TypeParagraph() } } function Invoke-DocGoToEnd { $script:doc.Application.Selection.goto([Microsoft.Office.Interop.Word.WdGoToItem]::wdGoToBookmark, $null, $null, '\EndOfDoc') | Out-Null } function Set-WordDocBuiltInProperty { param($propertyName, $value) try { $script:doc.BuiltInDocumentProperties([Microsoft.Office.Interop.Word.WdBuiltInProperty]$propertyName) = $value } catch { Write-LogError "Failed to set built in property $propertyName to $value" $_.Exception } } function Set-DocObjectStyle { param($docObj, $objStyle) $styleSet = $false if($docObj -and $objStyle) { try { if(($script:builtinStyles | Where { $_ -eq $objStyle })) { $docObj.style = [Microsoft.Office.Interop.Word.wdBuiltinStyle]$objStyle } else { $docObj.style = $objStyle } $styleSet = $true } catch { Write-Log "Failed to set style: $objStyle" 3 } } $styleSet } function Add-DocObjectSettings { param($obj, $objectType, $documentedObj) foreach($objectScript in $documentedObj.Scripts) { if(-not $objectScript.ScriptContent -or -not $objectScript.Caption) { continue } Add-DocTableScript $objectScript.Caption $objectScript.Header $objectScript.ScriptContent } }