From a6666f4603d6f13668e8d7731c3b447d614f6fbd Mon Sep 17 00:00:00 2001 From: Chris Arceneaux Date: Tue, 6 Dec 2022 15:50:22 -0500 Subject: [PATCH 1/6] Adding JSON Plugin * Added JSON plugin files * Added JSON plugin unit tests * Added JSON plugin help documentation * Updated README with JSON plugin example info --- ExampleJsonOutput.png | Bin 0 -> 64847 bytes PScriboExample.json | 2346 +++++++++++++++++ README.md | 6 + Src/Plugins/Json/Get-JsonTableCaption.ps1 | 23 + Src/Plugins/Json/New-PScriboJsonOption.ps1 | 26 + Src/Plugins/Json/Out-JsonDocument.ps1 | 123 + Src/Plugins/Json/Out-JsonHeaderFooter.ps1 | 63 + Src/Plugins/Json/Out-JsonParagraph.ps1 | 37 + Src/Plugins/Json/Out-JsonSection.ps1 | 66 + Src/Plugins/Json/Out-JsonTOC.ps1 | 25 + Src/Plugins/Json/Out-JsonTable.ps1 | 30 + Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 | 51 + .../Plugins/Json/Out-JsonParagraph.Tests.ps1 | 66 + Tests/Plugins/Json/Out-JsonSection.Tests.ps1 | 55 + Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 | 30 + Tests/Plugins/Json/Out-JsonTable.Tests.ps1 | 50 + en-US/about_HtmlPlugin.help.txt | 1 + en-US/about_JsonPlugin.help.txt | 37 + en-US/about_PScriboPlugins.help.txt | 3 +- en-US/about_TextPlugin.help.txt | 1 + en-US/about_WordPlugin.help.txt | 1 + 21 files changed, 3039 insertions(+), 1 deletion(-) create mode 100644 ExampleJsonOutput.png create mode 100644 PScriboExample.json create mode 100644 Src/Plugins/Json/Get-JsonTableCaption.ps1 create mode 100644 Src/Plugins/Json/New-PScriboJsonOption.ps1 create mode 100644 Src/Plugins/Json/Out-JsonDocument.ps1 create mode 100644 Src/Plugins/Json/Out-JsonHeaderFooter.ps1 create mode 100644 Src/Plugins/Json/Out-JsonParagraph.ps1 create mode 100644 Src/Plugins/Json/Out-JsonSection.ps1 create mode 100644 Src/Plugins/Json/Out-JsonTOC.ps1 create mode 100644 Src/Plugins/Json/Out-JsonTable.ps1 create mode 100644 Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 create mode 100644 Tests/Plugins/Json/Out-JsonParagraph.Tests.ps1 create mode 100644 Tests/Plugins/Json/Out-JsonSection.Tests.ps1 create mode 100644 Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 create mode 100644 Tests/Plugins/Json/Out-JsonTable.Tests.ps1 create mode 100644 en-US/about_JsonPlugin.help.txt diff --git a/ExampleJsonOutput.png b/ExampleJsonOutput.png new file mode 100644 index 0000000000000000000000000000000000000000..c16417b23e24b307957b3cc7b09d91746d9bf4c1 GIT binary patch literal 64847 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 C0k<;% literal 0 HcmV?d00001 diff --git a/PScriboExample.json b/PScriboExample.json new file mode 100644 index 0000000..0892f72 --- /dev/null +++ b/PScriboExample.json @@ -0,0 +1,2346 @@ +{ + "paragraph1": "This is Heading 1", + "paragraph2": "This is Heading 2", + "paragraph3": "This is Heading 3", + "paragraph4": "This is a regular line of text indented 0 tab stops", + "paragraph5": "This is a regular line of text indented 1 tab stops. This text should not be displayed as a hanging indent, e.g. not just the first line of the paragraph indented.", + "paragraph6": "This is a regular line of text indented 2 tab stops", + "paragraph7": "This is a regular line of text indented 3 tab stops", + "paragraph8": "This is a regular line of text in the default font in italics", + "paragraph9": "This is a regular line of text in the default font in bold", + "paragraph10": "This is a regular line of text in the default font in bold italics", + "paragraph11": "This is a regular line of text in the default font in 14 point", + "paragraph12": "This is a regular line of text in Courier New font", + "paragraph13": "This is a regular line of text indented 0 tab stops with the computer name as data: OFFICEPC", + "paragraph14": "This is a regular line of text indented 0 tab stops with the computer name as data in bold: OFFICEPC", + "paragraph15": "This is a regular line of text indented 0 tab stops with the computer name as data in bold italics: OFFICEPC", + "paragraph16": "This is a regular line of text indented 0 tab stops with the computer name as data in 14 point bold italics: OFFICEPC", + "paragraph17": "This is a regular line of text indented 0 tab stops with the computer name as data in 8 point Courier New bold italics: OFFICEPC", + "1": { + "name": "Standard-Style Tables", + "1.1": { + "name": "Autofit Width Autofit Cell No Highlighting", + "paragraph1": "Example of an autofit table width, autofit contents and no cell highlighting.", + "paragraph2": "Services (231 Services found):", + "table1": [ + { + "Display Name": "ActiveX Installer (AxInstSV)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "AllJoyn Router Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "App Readiness", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Application Identity", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Application Information", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Application Layer Gateway Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Application Management", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "AppX Deployment Service (AppXSVC)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Auto Time Zone Updater", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "AVCTP service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Background Intelligent Transfer Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Background Tasks Infrastructure Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Base Filtering Engine", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Bluetooth Audio Gateway Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Bluetooth Support Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Capability Access Manager Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "CaptureService_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Certificate Propagation", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Client License Service (ClipSVC)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Clipboard User Service_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "CNG Key Isolation", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "COM+ Event System", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "COM+ System Application", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Connected Devices Platform Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Connected Devices Platform User Service_78880d92", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Connected User Experiences and Telemetry", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "ConsentUX_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Contact Data_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "CoreMessaging", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Credential Manager", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Cryptographic Services", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Data Sharing Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "DCOM Server Process Launcher", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Delivery Optimization", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Association Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Install Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Management Enrollment Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Management Wireless Application Protocol (WAP) Push message Routing Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Setup Manager", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "DevicePicker_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "DevicesFlow_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "DevQuery Background Discovery Broker", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "DHCP Client", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Diagnostic Policy Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Diagnostic Service Host", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Diagnostic System Host", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Distributed Link Tracking Client", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Distributed Transaction Coordinator", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "DNS Client", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Downloaded Maps Manager", + "Status": "Stopped", + "Startup Type": "Auto" + }, + { + "Display Name": "Embedded Mode", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Encrypting File System (EFS)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Enterprise App Management Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Extensible Authentication Protocol", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Function Discovery Provider Host", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Function Discovery Resource Publication", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Geolocation Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "GISvc", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Google Chrome Elevation Service (GoogleChromeElevationService)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Google Update Service (gupdate)", + "Status": "Stopped", + "Startup Type": "Auto" + }, + { + "Display Name": "Google Update Service (gupdatem)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "GraphicsPerfSvc", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Group Policy Client", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Human Interface Device Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "HV Host Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Data Exchange Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Guest Service Interface", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Guest Shutdown Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Heartbeat Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V PowerShell Direct Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Remote Desktop Virtualization Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Time Synchronization Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Volume Shadow Copy Requestor", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "IKE and AuthIP IPsec Keying Modules", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Internet Connection Sharing (ICS)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "IP Helper", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "IPsec Policy Agent", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "KDC Proxy Server service (KPS)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "KtmRm for Distributed Transaction Coordinator", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Link-Layer Topology Discovery Mapper", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Local Session Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Microsoft (R) Diagnostics Hub Standard Collector Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Account Sign-in Assistant", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft App-V Client", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "Microsoft iSCSI Initiator Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Microsoft Passport", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Passport Container", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Software Shadow Copy Provider", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Storage Spaces SMP", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Store Install Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Net.Tcp Port Sharing Service", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "Netlogon", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Network Connection Broker", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Network Connections", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Network Connectivity Assistant", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Network List Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Network Location Awareness", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Network Setup Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Network Store Interface Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Offline Files", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "OpenSSH Authentication Agent", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "OpenSSH SSH Server", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Optimize drives", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Payments and NFC/SE Manager", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Performance Counter DLL Host", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Performance Logs \u0026 Alerts", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Phone Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Plug and Play", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Portable Device Enumerator Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Power", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Print Spooler", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Printer Extensions and Notifications", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "PrintWorkflow_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Problem Reports and Solutions Control Panel Support", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Program Compatibility Assistant Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Quality Windows Audio Video Experience", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Radio Management Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Access Auto Connection Manager", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Access Connection Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Remote Desktop Configuration", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Desktop Services", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Desktop Services UserMode Port Redirector", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Procedure Call (RPC)", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Remote Procedure Call (RPC) Locator", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Registry", + "Status": "Stopped", + "Startup Type": "Auto" + }, + { + "Display Name": "Resultant Set of Policy Provider", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Routing and Remote Access", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "RPC Endpoint Mapper", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Secondary Logon", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Secure Socket Tunneling Protocol Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Security Accounts Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Sensor Data Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Sensor Monitoring Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Sensor Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Server", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Shared PC Account Manager", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "Shell Hardware Detection", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Smart Card", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Smart Card Device Enumeration Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Smart Card Removal Policy", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "SNMP Trap", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Software Protection", + "Status": "Stopped", + "Startup Type": "Auto" + }, + { + "Display Name": "Special Administration Console Helper", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Spot Verifier", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "SSDP Discovery", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "State Repository Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Still Image Acquisition Events", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Storage Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Storage Tiers Management", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "SysMain", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "System Event Notification Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "System Events Broker", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "System Guard Runtime Monitor Broker", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Task Scheduler", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "TCP/IP NetBIOS Helper", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Telephony", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Themes", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Time Broker", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Touch Keyboard and Handwriting Panel Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Update Orchestrator Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "UPnP Device Host", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "User Access Logging Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "User Data Access_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "User Data Storage_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "User Experience Virtualization Service", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "User Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "User Profile Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam AWS Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Azure Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Backup Server RESTful API Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Backup Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Backup VSS Integration Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Broker Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam CDP Coordinator Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Cloud Connect Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Data Mover Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Distribution Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Explorers Recovery Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Guest Catalog Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Installer Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Management Agent Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Mount Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam ONE Agent", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam vPower NFS Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam VSS Hardware Provider Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Virtual Disk", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "VMware Alias Manager and Ticket Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "VMware Snapshot Provider", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "VMware SVGA Helper Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "VMware Tools", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Volume Shadow Copy", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "WalletService", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "WarpJITSvc", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Web Account Manager", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Audio", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Audio Endpoint Builder", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Biometric Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Camera Frame Server", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Connection Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Defender Advanced Threat Protection Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Defender Antivirus Network Inspection Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Defender Antivirus Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Defender Firewall", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Encryption Provider Host Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Error Reporting Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Event Collector", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Event Log", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Font Cache Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Image Acquisition (WIA)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Insider Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Installer", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows License Manager Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Licensing Monitoring Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Management Instrumentation", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Media Player Network Sharing Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Mobile Hotspot Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Modules Installer", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Push Notifications System Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Push Notifications User Service_78880d92", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows PushToInstall Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Remote Management (WS-Management)", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Search", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "Windows Security Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Time", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Update", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Update Medic Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "WinHTTP Web Proxy Auto-Discovery Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Wired AutoConfig", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "WMI Performance Adapter", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Workstation", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Zabbix Agent", + "Status": "Running", + "Startup Type": "Auto" + } + ] + } + }, + "2": { + "name": "Full Width Autofit Cell Highlighting", + "paragraph1": "Example of a full width table with autofit columns and individual cell highlighting.", + "paragraph2": "Services (231 Services found):", + "table1": [ + { + "Display Name": "ActiveX Installer (AxInstSV)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "AllJoyn Router Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "App Readiness", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Application Identity", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Application Information", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Application Layer Gateway Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Application Management", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "AppX Deployment Service (AppXSVC)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Auto Time Zone Updater", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "AVCTP service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Background Intelligent Transfer Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Background Tasks Infrastructure Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Base Filtering Engine", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Bluetooth Audio Gateway Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Bluetooth Support Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Capability Access Manager Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "CaptureService_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Certificate Propagation", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Client License Service (ClipSVC)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Clipboard User Service_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "CNG Key Isolation", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "COM+ Event System", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "COM+ System Application", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Connected Devices Platform Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Connected Devices Platform User Service_78880d92", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Connected User Experiences and Telemetry", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "ConsentUX_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Contact Data_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "CoreMessaging", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Credential Manager", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Cryptographic Services", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Data Sharing Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "DCOM Server Process Launcher", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Delivery Optimization", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Association Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Install Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Management Enrollment Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Management Wireless Application Protocol (WAP) Push message Routing Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Device Setup Manager", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "DevicePicker_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "DevicesFlow_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "DevQuery Background Discovery Broker", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "DHCP Client", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Diagnostic Policy Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Diagnostic Service Host", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Diagnostic System Host", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Distributed Link Tracking Client", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Distributed Transaction Coordinator", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "DNS Client", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Downloaded Maps Manager", + "Status": "Stopped", + "Startup Type": "Auto" + }, + { + "Display Name": "Embedded Mode", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Encrypting File System (EFS)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Enterprise App Management Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Extensible Authentication Protocol", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Function Discovery Provider Host", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Function Discovery Resource Publication", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Geolocation Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "GISvc", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Google Chrome Elevation Service (GoogleChromeElevationService)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Google Update Service (gupdate)", + "Status": "Stopped", + "Startup Type": "Auto" + }, + { + "Display Name": "Google Update Service (gupdatem)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "GraphicsPerfSvc", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Group Policy Client", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Human Interface Device Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "HV Host Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Data Exchange Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Guest Service Interface", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Guest Shutdown Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Heartbeat Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V PowerShell Direct Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Remote Desktop Virtualization Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Time Synchronization Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Hyper-V Volume Shadow Copy Requestor", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "IKE and AuthIP IPsec Keying Modules", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Internet Connection Sharing (ICS)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "IP Helper", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "IPsec Policy Agent", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "KDC Proxy Server service (KPS)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "KtmRm for Distributed Transaction Coordinator", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Link-Layer Topology Discovery Mapper", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Local Session Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Microsoft (R) Diagnostics Hub Standard Collector Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Account Sign-in Assistant", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft App-V Client", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "Microsoft iSCSI Initiator Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Microsoft Passport", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Passport Container", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Software Shadow Copy Provider", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Storage Spaces SMP", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Microsoft Store Install Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Net.Tcp Port Sharing Service", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "Netlogon", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Network Connection Broker", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Network Connections", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Network Connectivity Assistant", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Network List Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Network Location Awareness", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Network Setup Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Network Store Interface Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Offline Files", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "OpenSSH Authentication Agent", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "OpenSSH SSH Server", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Optimize drives", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Payments and NFC/SE Manager", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Performance Counter DLL Host", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Performance Logs \u0026 Alerts", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Phone Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Plug and Play", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Portable Device Enumerator Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Power", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Print Spooler", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Printer Extensions and Notifications", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "PrintWorkflow_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Problem Reports and Solutions Control Panel Support", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Program Compatibility Assistant Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Quality Windows Audio Video Experience", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Radio Management Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Access Auto Connection Manager", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Access Connection Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Remote Desktop Configuration", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Desktop Services", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Desktop Services UserMode Port Redirector", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Procedure Call (RPC)", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Remote Procedure Call (RPC) Locator", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Remote Registry", + "Status": "Stopped", + "Startup Type": "Auto" + }, + { + "Display Name": "Resultant Set of Policy Provider", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Routing and Remote Access", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "RPC Endpoint Mapper", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Secondary Logon", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Secure Socket Tunneling Protocol Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Security Accounts Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Sensor Data Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Sensor Monitoring Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Sensor Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Server", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Shared PC Account Manager", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "Shell Hardware Detection", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Smart Card", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Smart Card Device Enumeration Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Smart Card Removal Policy", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "SNMP Trap", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Software Protection", + "Status": "Stopped", + "Startup Type": "Auto" + }, + { + "Display Name": "Special Administration Console Helper", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Spot Verifier", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "SSDP Discovery", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "State Repository Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Still Image Acquisition Events", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Storage Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Storage Tiers Management", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "SysMain", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "System Event Notification Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "System Events Broker", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "System Guard Runtime Monitor Broker", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Task Scheduler", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "TCP/IP NetBIOS Helper", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Telephony", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Themes", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Time Broker", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Touch Keyboard and Handwriting Panel Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Update Orchestrator Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "UPnP Device Host", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "User Access Logging Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "User Data Access_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "User Data Storage_78880d92", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "User Experience Virtualization Service", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "User Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "User Profile Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam AWS Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Azure Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Backup Server RESTful API Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Backup Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Backup VSS Integration Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Broker Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam CDP Coordinator Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Cloud Connect Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Data Mover Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Distribution Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Explorers Recovery Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Guest Catalog Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Installer Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Management Agent Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam Mount Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam ONE Agent", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam vPower NFS Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Veeam VSS Hardware Provider Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Virtual Disk", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "VMware Alias Manager and Ticket Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "VMware Snapshot Provider", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "VMware SVGA Helper Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "VMware Tools", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Volume Shadow Copy", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "WalletService", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "WarpJITSvc", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Web Account Manager", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Audio", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Audio Endpoint Builder", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Biometric Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Camera Frame Server", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Connection Manager", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Defender Advanced Threat Protection Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Defender Antivirus Network Inspection Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Defender Antivirus Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Defender Firewall", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Encryption Provider Host Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Error Reporting Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Event Collector", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Event Log", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Font Cache Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Image Acquisition (WIA)", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Insider Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Installer", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows License Manager Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Licensing Monitoring Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Management Instrumentation", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Media Player Network Sharing Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Mobile Hotspot Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Modules Installer", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Push Notifications System Service", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Push Notifications User Service_78880d92", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows PushToInstall Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Remote Management (WS-Management)", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Search", + "Status": "Stopped", + "Startup Type": "Disabled" + }, + { + "Display Name": "Windows Security Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Time", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Windows Update", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Windows Update Medic Service", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "WinHTTP Web Proxy Auto-Discovery Service", + "Status": "Running", + "Startup Type": "Manual" + }, + { + "Display Name": "Wired AutoConfig", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "WMI Performance Adapter", + "Status": "Stopped", + "Startup Type": "Manual" + }, + { + "Display Name": "Workstation", + "Status": "Running", + "Startup Type": "Auto" + }, + { + "Display Name": "Zabbix Agent", + "Status": "Running", + "Startup Type": "Auto" + } + ] + } +} \ No newline at end of file diff --git a/README.md b/README.md index 9e5eadf..f8807b2 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,12 @@ PScribo can export documentation in a variety of formats and currently supports [Example text Document Download](https://raw.githubusercontent.com/iainbrighton/PScribo/dev/PScriboExample.txt) +### Example Json Output ### + +![](./ExampleJsonOutput.png) + +[Example Json Document Download](https://raw.githubusercontent.com/iainbrighton/PScribo/dev/PScriboExample.json) + If you find it useful, unearth any bugs or have any suggestions for improvements, feel free to add an [issue](https://github.com/iainbrighton/PScribo/issues) or place a comment at the project home page. diff --git a/Src/Plugins/Json/Get-JsonTableCaption.ps1 b/Src/Plugins/Json/Get-JsonTableCaption.ps1 new file mode 100644 index 0000000..dab2acf --- /dev/null +++ b/Src/Plugins/Json/Get-JsonTableCaption.ps1 @@ -0,0 +1,23 @@ +function Get-JsonTableCaption +{ +<# + .SYNOPSIS + Generates caption from a PScribo.Table object. +#> + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter(Mandatory, ValueFromPipeline)] + [ValidateNotNull()] + [System.Management.Automation.PSObject] $Table + ) + process + { + $tableStyle = Get-PScriboDocumentStyle -TableStyle $Table.Style + + return [PSCustomObject] @{ + Caption = ('{0} {1} {2}' -f $tableStyle.CaptionPrefix, $Table.CaptionNumber, $Table.Caption) + } + } +} diff --git a/Src/Plugins/Json/New-PScriboJsonOption.ps1 b/Src/Plugins/Json/New-PScriboJsonOption.ps1 new file mode 100644 index 0000000..f2aeba1 --- /dev/null +++ b/Src/Plugins/Json/New-PScriboJsonOption.ps1 @@ -0,0 +1,26 @@ +function New-PScriboJsonOption +{ +<# + .SYNOPSIS + Sets the Json plugin specific formatting/output options. + + .NOTES + All plugin options should be prefixed with the plugin name. +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions','')] + [OutputType([System.Collections.Hashtable])] + param + ( + ## Text encoding + [Parameter(ValueFromPipelineByPropertyName)] + [ValidateSet('ASCII','Unicode','UTF7','UTF8')] + [System.String] $Encoding = 'ASCII' + ) + process + { + return @{ + Encoding = $Encoding + } + } +} diff --git a/Src/Plugins/Json/Out-JsonDocument.ps1 b/Src/Plugins/Json/Out-JsonDocument.ps1 new file mode 100644 index 0000000..a9f990e --- /dev/null +++ b/Src/Plugins/Json/Out-JsonDocument.ps1 @@ -0,0 +1,123 @@ +function Out-JsonDocument +{ +<# + .SYNOPSIS + Json output plugin for PScribo. + + .DESCRIPTION + Outputs a Json file representation of a PScribo document object. +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments','pluginName')] + param + ( + ## ThePScribo document object to convert to a Json document + [Parameter(Mandatory, ValueFromPipeline)] + [System.Management.Automation.PSObject] $Document, + + ## Output directory path for the .json file + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNull()] + [System.String] $Path, + + ### Hashtable of all plugin supported options + [Parameter()] + [AllowNull()] + [System.Collections.Hashtable] $Options + ) + process + { + $pluginName = 'Json' + $stopwatch = [Diagnostics.Stopwatch]::StartNew() + Write-PScriboMessage -Message ($localized.DocumentProcessingStarted -f $Document.Name) + + ## Merge the document, plugin default and specified/specific plugin options + $mergePScriboPluginOptionParams = @{ + DefaultPluginOptions = New-PScriboJsonOption + DocumentOptions = $Document.Options + PluginOptions = $Options + } + $Options = Merge-PScriboPluginOption @mergePScriboPluginOptionParams + $script:currentPageNumber = 1 + + ## Initializing JSON object + $jsonBuilder = [ordered]@{} + + ## Initializing paragraph counter + [int]$paragraph = 1 + + ## Initializing table counter + [int]$table = 1 + + ## Generating header + $header = Out-JsonHeaderFooter -Header -FirstPage + if ($null -ne $header) { + [ref] $null = $jsonBuilder.Add("header", $header) + [ref] $null = $header + } + + foreach ($subSection in $Document.Sections.GetEnumerator()) + { + # Write-Host "Type: $($subSection.Type)" + switch ($subSection.Type) + { + 'PScribo.Section' + { + ## Corrects behavior where NOTOC* heading is used + if (("" -eq $subSection.Number)) + { + [ref] $null = $jsonBuilder.Add($subSection.Name, (Out-JsonSection -Section $subSection)) + } + else + { + [ref] $null = $jsonBuilder.Add($subSection.Number, (Out-JsonSection -Section $subSection)) + } + } + 'PScribo.Paragraph' + { + [ref] $null = $jsonBuilder.Add("paragraph$($paragraph)", (Out-JsonParagraph -Paragraph $subSection)) + $paragraph++ + } + 'PScribo.Table' + { + [ref] $null = $jsonBuilder.Add("table$($table)", (Out-JsonTable -Table $subSection)) + $table++ + } + 'PScribo.TOC' + { + [ref] $null = $jsonBuilder.Add("toc", (Out-JsonTOC -TOC $subSection)) + } + Default + { + Write-PScriboMessage -Message ($localized.PluginUnsupportedSection -f $subSection.Type) -IsWarning + } + } + } + + ## Generating footer + $footer = Out-JsonHeaderFooter -Footer + if ($null -ne $footer) { + [ref] $null = $jsonBuilder.Add("footer", $footer) + [ref] $null = $footer + } + + $stopwatch.Stop() + Write-PScriboMessage -Message ($localized.DocumentProcessingCompleted -f $Document.Name) + $destinationPath = Join-Path -Path $Path ('{0}.json' -f $Document.Name) + Write-PScriboMessage -Message ($localized.SavingFile -f $destinationPath) + $jsonBuilder | ConvertTo-Json -Depth 100 | Set-Content -Path $destinationPath -Encoding $Options.Encoding + [ref] $null = $jsonBuilder + + if ($stopwatch.Elapsed.TotalSeconds -gt 90) + { + Write-PScriboMessage -Message ($localized.TotalProcessingTimeMinutes -f $stopwatch.Elapsed.TotalMinutes) + } + else + { + Write-PScriboMessage -Message ($localized.TotalProcessingTimeSeconds -f $stopwatch.Elapsed.TotalSeconds) + } + + ## Return the file reference to the pipeline + Write-Output (Get-Item -Path $destinationPath) + } +} diff --git a/Src/Plugins/Json/Out-JsonHeaderFooter.ps1 b/Src/Plugins/Json/Out-JsonHeaderFooter.ps1 new file mode 100644 index 0000000..260be0c --- /dev/null +++ b/Src/Plugins/Json/Out-JsonHeaderFooter.ps1 @@ -0,0 +1,63 @@ +function Out-JsonHeaderFooter +{ +<# + .SYNOPSIS + Output formatted header/footer. +#> + [CmdletBinding()] + param + ( + [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'DefaultHeader')] + [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'FirstPageHeader')] + [System.Management.Automation.SwitchParameter] $Header, + + [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'DefaultFooter')] + [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'FirstPageFooter')] + [System.Management.Automation.SwitchParameter] $Footer, + + [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'FirstPageHeader')] + [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'FirstPageFooter')] + [System.Management.Automation.SwitchParameter] $FirstPage + ) + begin + { + ## Initializing header/footer object + $hfBuilder = [ordered]@{} + + ## Initializing paragraph counter + [int]$paragraph = 1 + + ## Initializing table counter + [int]$table = 1 + } + process + { + $headerFooter = Get-PScriboHeaderFooter @PSBoundParameters + if ($null -ne $headerFooter) + { + foreach ($subSection in $headerFooter.Sections.GetEnumerator()) + { + ## When replacing tokens (by reference), the tokens are removed + $cloneSubSection = Copy-Object -InputObject $subSection + switch ($cloneSubSection.Type) + { + 'PScribo.Paragraph' + { + [ref] $null = $hfBuilder.Add("paragraph$($paragraph)", (Out-JsonParagraph -Paragraph $cloneSubSection)) + $paragraph++ + } + 'PScribo.Table' + { + [ref] $null = $hfBuilder.Add("table$($table)", (Out-JsonTable -Table $cloneSubSection)) + $table++ + } + } + } + + return $hfBuilder + } + else { + return $null + } + } +} diff --git a/Src/Plugins/Json/Out-JsonParagraph.ps1 b/Src/Plugins/Json/Out-JsonParagraph.ps1 new file mode 100644 index 0000000..814e300 --- /dev/null +++ b/Src/Plugins/Json/Out-JsonParagraph.ps1 @@ -0,0 +1,37 @@ +function Out-JsonParagraph +{ +<# + .SYNOPSIS + Output formatted paragraph run. +#> + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter(Mandatory, ValueFromPipeline)] + [ValidateNotNull()] + [System.Management.Automation.PSObject] $Paragraph + ) + begin + { + ## Initializing string object + [System.Text.StringBuilder] $paragraphBuilder = New-Object -TypeName 'System.Text.StringBuilder' + } + process + { + foreach ($paragraphRun in $Paragraph.Sections) + { + $text = Resolve-PScriboToken -InputObject $paragraphRun.Text + [ref] $null = $paragraphBuilder.Append($text) + + if (($paragraphRun.IsParagraphRunEnd -eq $false) -and + ($paragraphRun.NoSpace -eq $false)) + { + [ref] $null = $paragraphBuilder.Append(' ') + } + } + + + return $paragraphBuilder.ToString() + } +} diff --git a/Src/Plugins/Json/Out-JsonSection.ps1 b/Src/Plugins/Json/Out-JsonSection.ps1 new file mode 100644 index 0000000..35b172c --- /dev/null +++ b/Src/Plugins/Json/Out-JsonSection.ps1 @@ -0,0 +1,66 @@ +function Out-JsonSection +{ +<# + .SYNOPSIS + Output formatted Json section. +#> + [CmdletBinding()] + param + ( + ## Section to output + [Parameter(Mandatory, ValueFromPipeline)] + [System.Management.Automation.PSObject] $Section + ) + begin + { + ## Initializing section object + $sectionBuilder = [ordered]@{} + + ## Initializing paragraph counter + [int]$paragraph = 1 + + ## Initializing table counter + [int]$table = 1 + } + process + { + $sectionBuilder.Add("name", $Section.Name) + + foreach ($subSection in $Section.Sections.GetEnumerator()) + { + # Write-Host "Section Type: $($subSection.Type)" + switch ($subSection.Type) + { + 'PScribo.Section' + { + ## Corrects behavior where NOTOC* heading is used + if (("" -eq $subSection.Number)) + { + [ref] $null = $sectionBuilder.Add($subSection.Name, (Out-JsonSection -Section $subSection)) + } + else + { + [ref] $null = $sectionBuilder.Add($subSection.Number, (Out-JsonSection -Section $subSection)) + } + } + 'PScribo.Paragraph' + { + [ref] $null = $sectionBuilder.Add("paragraph$($paragraph)", (Out-JsonParagraph -Paragraph $subSection)) + $paragraph++ + } + 'PScribo.Table' + { + [ref] $null = $sectionBuilder.Add("table$($table)", (Out-JsonTable -Table $subSection)) + $table++ + } + Default + { + Write-PScriboMessage -Message ($localized.PluginUnsupportedSection -f $subSection.Type) -IsWarning + } + } + } + + + return $sectionBuilder + } +} diff --git a/Src/Plugins/Json/Out-JsonTOC.ps1 b/Src/Plugins/Json/Out-JsonTOC.ps1 new file mode 100644 index 0000000..c3c8cc1 --- /dev/null +++ b/Src/Plugins/Json/Out-JsonTOC.ps1 @@ -0,0 +1,25 @@ +function Out-JsonTOC { + <# + .SYNOPSIS + Output formatted Table of Contents +#> + [CmdletBinding()] + param + ( + [Parameter(Mandatory, ValueFromPipeline)] + [System.Management.Automation.PSObject] $TOC + ) + begin { + ## Initializing TOC object + $tocBuilder = [ordered]@{} + } + process { + ## Populating TOC + ## Disregarding section numbering as its highly beneficial when parsing JSON after the fact + foreach ($tocEntry in $Document.TOC) { + [ref] $null = $tocBuilder.Add($tocEntry.Number, $tocEntry.Name) + } + + return ($tocBuilder) + } +} diff --git a/Src/Plugins/Json/Out-JsonTable.ps1 b/Src/Plugins/Json/Out-JsonTable.ps1 new file mode 100644 index 0000000..0910e74 --- /dev/null +++ b/Src/Plugins/Json/Out-JsonTable.ps1 @@ -0,0 +1,30 @@ +function Out-JsonTable +{ +<# + .SYNOPSIS + Output formatted Json table. +#> + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter(Mandatory, ValueFromPipeline)] + [System.Management.Automation.PSObject] $Table + ) + begin + { + ## Initializing table object + $tableBuilder = [System.Collections.ArrayList]::new() + } + process + { + if ($Table.HasCaption) + { + [ref] $null = $tableBuilder.Add((Get-JsonTableCaption -Table $Table)) + } + + [ref] $null = $tableBuilder.Add(($Table.Rows | Select-Object -Property * -ExcludeProperty '*__Style')) + + return $tableBuilder + } +} diff --git a/Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 b/Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 new file mode 100644 index 0000000..a4a686b --- /dev/null +++ b/Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 @@ -0,0 +1,51 @@ +$here = Split-Path -Path $MyInvocation.MyCommand.Path -Parent; +$pluginRoot = Split-Path -Path $here -Parent; +$testRoot = Split-Path -Path $pluginRoot -Parent; +$moduleRoot = Split-Path -Path $testRoot -Parent; +Import-Module "$moduleRoot\PScribo.psm1" -Force; + +InModuleScope 'PScribo' { + + $isNix = $false + if (($PSVersionTable['PSEdition'] -eq 'Core') -and (-not $IsWindows)) + { + $isNix = $true + } + + Describe 'Plugins\Json\Out-JsonDocument' { + + $path = (Get-PSDrive -Name TestDrive).Root; + + It 'calls Out-JsonSection' { + Mock -CommandName Out-JsonSection + + Document -Name 'TestDocument' -ScriptBlock { Section -Name 'TestSection' -ScriptBlock { } } | Out-JsonDocument -Path $path + + Assert-MockCalled -CommandName Out-JsonSection -Exactly 1 + } + + It 'calls Out-JsonParagraph' { + Mock -CommandName Out-JsonParagraph + + Document -Name 'TestDocument' -ScriptBlock { Paragraph 'TestParagraph' } | Out-JsonDocument -Path $path + + Assert-MockCalled -CommandName Out-JsonParagraph -Exactly 1 + } + + It 'calls Out-JsonTable' { + Mock -CommandName Out-JsonTable + + Document -Name 'TestDocument' -ScriptBlock { Get-Process | Select-Object -First 1 | Table 'TestTable' } | Out-JsonDocument -Path $path + + Assert-MockCalled -CommandName Out-JsonTable -Exactly 1 + } + + It 'calls Out-JsonTOC' { + Mock -CommandName Out-JsonTOC + + Document -Name 'TestDocument' -ScriptBlock { TOC -Name 'TestTOC'; } | Out-JsonDocument -Path $path + + Assert-MockCalled -CommandName Out-JsonTOC -Exactly 1 + } + } +} diff --git a/Tests/Plugins/Json/Out-JsonParagraph.Tests.ps1 b/Tests/Plugins/Json/Out-JsonParagraph.Tests.ps1 new file mode 100644 index 0000000..41694d0 --- /dev/null +++ b/Tests/Plugins/Json/Out-JsonParagraph.Tests.ps1 @@ -0,0 +1,66 @@ +$here = Split-Path -Path $MyInvocation.MyCommand.Path -Parent; +$pluginRoot = Split-Path -Path $here -Parent; +$testRoot = Split-Path -Path $pluginRoot -Parent; +$moduleRoot = Split-Path -Path $testRoot -Parent; +Import-Module "$moduleRoot\PScribo.psm1" -Force; + +InModuleScope 'PScribo' { + + Describe 'Plugins\Json\Out-JsonParagraph' { + + ## Scaffold document options + $Document = Document -Name 'TestDocument' -ScriptBlock {} + $script:currentPageNumber = 1 + $pscriboDocument = $Document + $Options = New-PScriboJsonOption + + Context 'By pipeline' { + + It 'Paragraph outputs text' { + $testParagraph = 'Test paragraph.' + $expected = 'Test paragraph.' + + $p = Paragraph $testParagraph | Out-JsonParagraph + + $p | Should BeExactly $expected + } + + It 'adds spaces between text runs (by default)' { + $testParagraph = { + Text 'Test' + Text 'paragraph' + } + $expected = 'Test paragraph' + + $p = Paragraph $testParagraph | Out-JsonParagraph + + $p | Should BeExactly $expected + } + + It 'does not add spaces between text runs (when specified)' { + $testParagraph = { + Text 'Test' -NoSpace + Text 'paragraph' + } + $expected = 'Testparagraph' + + $p = Paragraph $testParagraph | Out-JsonParagraph + + $p | Should BeExactly $expected + } + } + + Context 'By named -Paragraph parameter' { + + It 'By named -Paragraph parameter' { + $testParagraph = 'Test paragraph.' + $expected = 'Test paragraph.' + + $p = Out-JsonParagraph -Paragraph (Paragraph $testParagraph) + + $p | Should BeExactly $expected + } + + } + } +} diff --git a/Tests/Plugins/Json/Out-JsonSection.Tests.ps1 b/Tests/Plugins/Json/Out-JsonSection.Tests.ps1 new file mode 100644 index 0000000..76dd88b --- /dev/null +++ b/Tests/Plugins/Json/Out-JsonSection.Tests.ps1 @@ -0,0 +1,55 @@ +$here = Split-Path -Path $MyInvocation.MyCommand.Path -Parent; +$pluginRoot = Split-Path -Path $here -Parent; +$testRoot = Split-Path -Path $pluginRoot -Parent; +$moduleRoot = Split-Path -Path $testRoot -Parent; +Import-Module "$moduleRoot\PScribo.psm1" -Force; + +InModuleScope 'PScribo' { + + Describe 'Plugins\Json\Out-JsonSection' { + + $Document = Document -Name 'TestDocument' -ScriptBlock { } + $pscriboDocument = $Document + + It 'calls Out-JsonParagraph' { + Mock -CommandName Out-JsonParagraph + + Section -Name TestSection -ScriptBlock { Paragraph 'TestParagraph' } | Out-JsonSection + + Assert-MockCalled -CommandName Out-JsonParagraph -Exactly 1 + } + + It 'calls Out-JsonParagraph twice' { + Mock -CommandName Out-JsonParagraph + + Section -Name TestSection -ScriptBlock { Paragraph 'TestParagraph'; Paragraph 'TestParagraph'; } | Out-JsonSection + + Assert-MockCalled -CommandName Out-JsonParagraph -Exactly 3 + } + + It 'calls Out-JsonTable' { + Mock -CommandName Out-JsonTable + + Section -Name TestSection -ScriptBlock { Get-Process | Select-Object -First 3 | Table TestTable } | Out-JsonSection + + Assert-MockCalled -CommandName Out-JsonTable -Exactly 1 + } + + It 'warns on call Out-JsonTOC' { + Mock -CommandName Out-JsonTOC + + Section -Name TestSection -ScriptBlock { TOC 'TestTOC' } | Out-JsonSection -WarningAction SilentlyContinue + + Assert-MockCalled Out-JsonTOC -Exactly 0 + } + + It 'calls nested Out-JsonSection' { + ## Note this must be called last in the Describe script block as the Out-XmlSection gets mocked! + Mock -CommandName Out-JsonSection + + Section -Name TestSection -ScriptBlock { Section -Name SubSection { } } | Out-JsonSection + + Assert-MockCalled -CommandName Out-JsonSection -Exactly 1 + } + } +} diff --git a/Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 b/Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 new file mode 100644 index 0000000..653ec90 --- /dev/null +++ b/Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 @@ -0,0 +1,30 @@ +$here = Split-Path -Path $MyInvocation.MyCommand.Path -Parent; +$pluginRoot = Split-Path -Path $here -Parent; +$testRoot = Split-Path -Path $pluginRoot -Parent; +$moduleRoot = Split-Path -Path $testRoot -Parent; +Import-Module "$moduleRoot\PScribo.psm1" -Force; + +InModuleScope 'PScribo' { + + Describe 'Plugins\Json\Out-JsonTOC' { + + ## Section numbering is ignored and used regardless + + It 'outputs TOC' { + $tocName = 'Table of contents' + $heading1 = 'Heading 1' + $heading2 = 'Heading 2' + $Document = Document -Name 'TestDocument' -ScriptBlock { + TOC -Name $tocName + Section $heading1 -Style Heading1 { + Section $heading2 -Style Heading2 { } + } + } + $expected = '{{.*"{0}".*"{1}"}}' -f $heading1, $heading2 + + $result = Out-JsonTOC -TOC $Document.Sections[0] | ConvertTo-Json -Depth 100 -Compress + + $result | Should MatchExactly $expected + } + } +} diff --git a/Tests/Plugins/Json/Out-JsonTable.Tests.ps1 b/Tests/Plugins/Json/Out-JsonTable.Tests.ps1 new file mode 100644 index 0000000..5234d08 --- /dev/null +++ b/Tests/Plugins/Json/Out-JsonTable.Tests.ps1 @@ -0,0 +1,50 @@ +$here = Split-Path -Path $MyInvocation.MyCommand.Path -Parent; +$pluginRoot = Split-Path -Path $here -Parent; +$testRoot = Split-Path -Path $pluginRoot -Parent; +$moduleRoot = Split-Path -Path $testRoot -Parent; +Import-Module "$moduleRoot\PScribo.psm1" -Force; + +InModuleScope 'PScribo' { + + Describe 'Plugins\Json\Out-JsonTable' { + + $isNix = (($PSVersionTable['PSEdition'] -eq 'Core') -and (-not $IsWindows)) + + ## Scaffold document options + $Document = Document -Name 'TestDocument' -ScriptBlock {} + $script:currentPageNumber = 1 + $pscriboDocument = $Document + + ## Context (list vs table) doesn't make a difference as they are treated the same + + $services = @( + [Ordered] @{ Name = 'TestService1'; 'Service Name' = 'Test 1'; 'Display Name' = 'Test Service 1'; } + [Ordered] @{ Name = 'TestService3'; 'Service Name' = 'Test 3'; 'Display Name' = 'Test Service 3'; } + [Ordered] @{ Name = 'TestService2'; 'Service Name' = 'Test 2'; 'Display Name' = 'Test Service 2'; } + ) + + It 'Input matches output' { + $expected = 3 + + $table = Table -Hashtable $services 'Test Table' | Out-JsonTable + + $table.Count | Should Be $expected + } + + It 'Caption present' { + $expected = $true + + $table = Table -Hashtable $services 'Test Table' -Caption 'Test' | Out-JsonTable + + $table[0].Caption | Should Be $expected + } + + It 'Input matches output with caption present' { + $expected = 3 + + $table = Table -Hashtable $services 'Test Table' -Caption 'Test' | Out-JsonTable + + $table[1].Count | Should Be $expected + } + } +} diff --git a/en-US/about_HtmlPlugin.help.txt b/en-US/about_HtmlPlugin.help.txt index 2303847..e86ce17 100644 --- a/en-US/about_HtmlPlugin.help.txt +++ b/en-US/about_HtmlPlugin.help.txt @@ -27,4 +27,5 @@ PLUGIN OPTIONS SEE ALSO about_PscriboPlugins about_TextPlugin + about_JsonPlugin about_WordPlugin diff --git a/en-US/about_JsonPlugin.help.txt b/en-US/about_JsonPlugin.help.txt new file mode 100644 index 0000000..88fb22c --- /dev/null +++ b/en-US/about_JsonPlugin.help.txt @@ -0,0 +1,37 @@ +TOPIC + Json Plugin + +SYNOPSIS + PScribo supports outputting JSON-formatted text (.json) documents. + +DESCRIPTION + PScribo can output JSON-formatted text documents with multiple file encodings. The benefit of JSON is it can be consumed by 3rd party tools after the fact to ingest the information contained in the report. + +KNOWN LIMITATIONS + There are some restrictions which means that some PScribo functionality cannot either be partially or fully implemented: + + - PScribo style elements are ignored + - This includes section numbering as it better ensures each section is unique which facilitates easier parsing. + - The following PScribo types are not supported as there is no provision for them in JSON: + - Image + - PageBreak + - LineBreak + - BlankLine + - Headers and footers are only shown once at the beginning/end of the generated document + - Sections at the same hierarchical level using the NOTOC* header cannot have the same name. This is a PowerShell Dictionary limitation. + +PLUGIN OPTIONS + The Text plugin accepts the following output customisation options: + + Encoding [string] : Specifies the file encoding to use. Supported values are 'ASCII', 'Unicode', + 'UTF7' and 'UTF8'. If not specified, defaults to 'ASCII'. + + Output customisations are passed to the Export-Document cmdlet as a hashtable, e.g. + + PS> $document | Export-Document -Format Text -Options @{ Encoding = 'ASCII' } + +SEE ALSO + about_PscriboPlugins + about_HtmlPlugin + about_WordPlugin + about_TextPlugin diff --git a/en-US/about_PScriboPlugins.help.txt b/en-US/about_PScriboPlugins.help.txt index 1f259f6..5d6da51 100644 --- a/en-US/about_PScriboPlugins.help.txt +++ b/en-US/about_PScriboPlugins.help.txt @@ -5,10 +5,11 @@ SYNOPSIS PScribo supports outputting to multiple document formats. DESCRIPTION - PScribo can output plain text, Html (web) and Microsoft Word documents via plugins. Each format may or may not + PScribo can output plain text, Json, Html (web) and Microsoft Word documents via plugins. Each format may or may not support various PScribo document options. Refer to each specific plugin help topic for more information. SEE ALSO about_HtmlPlugin about_TextPlugin + about_JsonPlugin about_WordPlugin diff --git a/en-US/about_TextPlugin.help.txt b/en-US/about_TextPlugin.help.txt index 84b4da4..ac38e8f 100644 --- a/en-US/about_TextPlugin.help.txt +++ b/en-US/about_TextPlugin.help.txt @@ -38,4 +38,5 @@ PLUGIN OPTIONS SEE ALSO about_PscriboPlugins about_HtmlPlugin + about_JsonPlugin about_WordPlugin diff --git a/en-US/about_WordPlugin.help.txt b/en-US/about_WordPlugin.help.txt index bd977f8..ce53c2d 100644 --- a/en-US/about_WordPlugin.help.txt +++ b/en-US/about_WordPlugin.help.txt @@ -28,3 +28,4 @@ SEE ALSO about_PscriboPlugins about_HtmlPlugin about_TextPlugin + about_JsonPlugin From 53c78265bd1ae15483eacf84e8f4580b6f9f9bd1 Mon Sep 17 00:00:00 2001 From: Chris Arceneaux Date: Tue, 6 Dec 2022 16:09:58 -0500 Subject: [PATCH 2/6] Resolving AppVeyor issues - removing trailing whitespace - ensured PScriboExample.json ended with a newline Signed-off-by: Chris Arceneaux --- PScriboExample.json | 2 +- Src/Plugins/Json/Out-JsonParagraph.ps1 | 2 +- Src/Plugins/Json/Out-JsonSection.ps1 | 2 +- Src/Plugins/Json/Out-JsonTable.ps1 | 2 +- en-US/about_JsonPlugin.help.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/PScriboExample.json b/PScriboExample.json index 0892f72..128adb2 100644 --- a/PScriboExample.json +++ b/PScriboExample.json @@ -2343,4 +2343,4 @@ } ] } -} \ No newline at end of file +} diff --git a/Src/Plugins/Json/Out-JsonParagraph.ps1 b/Src/Plugins/Json/Out-JsonParagraph.ps1 index 814e300..14c20eb 100644 --- a/Src/Plugins/Json/Out-JsonParagraph.ps1 +++ b/Src/Plugins/Json/Out-JsonParagraph.ps1 @@ -31,7 +31,7 @@ function Out-JsonParagraph } } - + return $paragraphBuilder.ToString() } } diff --git a/Src/Plugins/Json/Out-JsonSection.ps1 b/Src/Plugins/Json/Out-JsonSection.ps1 index 35b172c..a31cda8 100644 --- a/Src/Plugins/Json/Out-JsonSection.ps1 +++ b/Src/Plugins/Json/Out-JsonSection.ps1 @@ -25,7 +25,7 @@ function Out-JsonSection process { $sectionBuilder.Add("name", $Section.Name) - + foreach ($subSection in $Section.Sections.GetEnumerator()) { # Write-Host "Section Type: $($subSection.Type)" diff --git a/Src/Plugins/Json/Out-JsonTable.ps1 b/Src/Plugins/Json/Out-JsonTable.ps1 index 0910e74..e591317 100644 --- a/Src/Plugins/Json/Out-JsonTable.ps1 +++ b/Src/Plugins/Json/Out-JsonTable.ps1 @@ -24,7 +24,7 @@ function Out-JsonTable } [ref] $null = $tableBuilder.Add(($Table.Rows | Select-Object -Property * -ExcludeProperty '*__Style')) - + return $tableBuilder } } diff --git a/en-US/about_JsonPlugin.help.txt b/en-US/about_JsonPlugin.help.txt index 88fb22c..23af307 100644 --- a/en-US/about_JsonPlugin.help.txt +++ b/en-US/about_JsonPlugin.help.txt @@ -9,7 +9,7 @@ DESCRIPTION KNOWN LIMITATIONS There are some restrictions which means that some PScribo functionality cannot either be partially or fully implemented: - + - PScribo style elements are ignored - This includes section numbering as it better ensures each section is unique which facilitates easier parsing. - The following PScribo types are not supported as there is no provision for them in JSON: From b2fb7459dd33e06207b643309eec4a3e84c09d25 Mon Sep 17 00:00:00 2001 From: Chris Arceneaux Date: Tue, 6 Dec 2022 16:19:59 -0500 Subject: [PATCH 3/6] Removing unused parameter AppVeyor identified an unused parameter. Updating corresponding files to resolve the issue. Signed-off-by: Chris Arceneaux --- Src/Plugins/Json/Out-JsonDocument.ps1 | 2 +- Src/Plugins/Json/Out-JsonTOC.ps1 | 6 ------ Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Src/Plugins/Json/Out-JsonDocument.ps1 b/Src/Plugins/Json/Out-JsonDocument.ps1 index a9f990e..b172d47 100644 --- a/Src/Plugins/Json/Out-JsonDocument.ps1 +++ b/Src/Plugins/Json/Out-JsonDocument.ps1 @@ -85,7 +85,7 @@ function Out-JsonDocument } 'PScribo.TOC' { - [ref] $null = $jsonBuilder.Add("toc", (Out-JsonTOC -TOC $subSection)) + [ref] $null = $jsonBuilder.Add("toc", (Out-JsonTOC)) } Default { diff --git a/Src/Plugins/Json/Out-JsonTOC.ps1 b/Src/Plugins/Json/Out-JsonTOC.ps1 index c3c8cc1..77c7785 100644 --- a/Src/Plugins/Json/Out-JsonTOC.ps1 +++ b/Src/Plugins/Json/Out-JsonTOC.ps1 @@ -3,12 +3,6 @@ function Out-JsonTOC { .SYNOPSIS Output formatted Table of Contents #> - [CmdletBinding()] - param - ( - [Parameter(Mandatory, ValueFromPipeline)] - [System.Management.Automation.PSObject] $TOC - ) begin { ## Initializing TOC object $tocBuilder = [ordered]@{} diff --git a/Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 b/Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 index 653ec90..afe36ba 100644 --- a/Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 +++ b/Tests/Plugins/Json/Out-JsonTOC.Tests.ps1 @@ -22,7 +22,7 @@ InModuleScope 'PScribo' { } $expected = '{{.*"{0}".*"{1}"}}' -f $heading1, $heading2 - $result = Out-JsonTOC -TOC $Document.Sections[0] | ConvertTo-Json -Depth 100 -Compress + $result = Out-JsonTOC | ConvertTo-Json -Depth 100 -Compress $result | Should MatchExactly $expected } From 7794e9ae6a9ee7fe99a5b014bd74be2bf5ecae2c Mon Sep 17 00:00:00 2001 From: Chris Arceneaux Date: Wed, 7 Dec 2022 08:44:44 -0500 Subject: [PATCH 4/6] Limiting PSScriptAnalyzer version Applied workaround until new rule can be resolved appropriately. - Version 1.21.0 introduces a rule that breaks AppVeyor builds - New rule: AvoidMultipleTypeAttributes - Limited version to 1.20 Signed-off-by: Chris Arceneaux --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6a1e188..055b88c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,7 +14,8 @@ environment: install: - ps: Write-Verbose -Message "PowerShell version $($PSVersionTable.PSVersion)" -Verbose - ps: Install-Module -Name Pester -MaximumVersion 4.99 -Scope CurrentUser -Force -AllowClobber -Verbose - - ps: Install-Module -Name PSSCriptAnalyzer, PSake, VirtualEngine.Build -Scope CurrentUser -Force -AllowClobber -Verbose + - ps: Install-Module -Name PSScriptAnalyzer -MaximumVersion 1.20.0 -Scope CurrentUser -Force -AllowClobber -Verbose + - ps: Install-Module -Name PSake, VirtualEngine.Build -Scope CurrentUser -Force -AllowClobber -Verbose - ps: $null = Invoke-Expression ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) build: false From 52220591d159ca061ef9f5bdf264dedbeff7b50f Mon Sep 17 00:00:00 2001 From: Chris Arceneaux Date: Fri, 20 Jan 2023 13:39:35 -0500 Subject: [PATCH 5/6] Reverting change as its fixed in #125 Signed-off-by: Chris Arceneaux --- appveyor.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 055b88c..6a1e188 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,8 +14,7 @@ environment: install: - ps: Write-Verbose -Message "PowerShell version $($PSVersionTable.PSVersion)" -Verbose - ps: Install-Module -Name Pester -MaximumVersion 4.99 -Scope CurrentUser -Force -AllowClobber -Verbose - - ps: Install-Module -Name PSScriptAnalyzer -MaximumVersion 1.20.0 -Scope CurrentUser -Force -AllowClobber -Verbose - - ps: Install-Module -Name PSake, VirtualEngine.Build -Scope CurrentUser -Force -AllowClobber -Verbose + - ps: Install-Module -Name PSSCriptAnalyzer, PSake, VirtualEngine.Build -Scope CurrentUser -Force -AllowClobber -Verbose - ps: $null = Invoke-Expression ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) build: false From 5d8af8bf0207d58edcb8d95a32be4f9bdc9a2cc2 Mon Sep 17 00:00:00 2001 From: Chris Arceneaux Date: Fri, 20 Jan 2023 14:01:05 -0500 Subject: [PATCH 6/6] Improving unit tests - removed $isNix check as it was not needed - PowerShell vs PowerShell Core didn't change the expected responses Signed-off-by: Chris Arceneaux --- Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 | 6 ------ Tests/Plugins/Json/Out-JsonTable.Tests.ps1 | 2 -- 2 files changed, 8 deletions(-) diff --git a/Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 b/Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 index a4a686b..aca4086 100644 --- a/Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 +++ b/Tests/Plugins/Json/Out-JsonDocument.Tests.ps1 @@ -6,12 +6,6 @@ Import-Module "$moduleRoot\PScribo.psm1" -Force; InModuleScope 'PScribo' { - $isNix = $false - if (($PSVersionTable['PSEdition'] -eq 'Core') -and (-not $IsWindows)) - { - $isNix = $true - } - Describe 'Plugins\Json\Out-JsonDocument' { $path = (Get-PSDrive -Name TestDrive).Root; diff --git a/Tests/Plugins/Json/Out-JsonTable.Tests.ps1 b/Tests/Plugins/Json/Out-JsonTable.Tests.ps1 index 5234d08..d2960e4 100644 --- a/Tests/Plugins/Json/Out-JsonTable.Tests.ps1 +++ b/Tests/Plugins/Json/Out-JsonTable.Tests.ps1 @@ -8,8 +8,6 @@ InModuleScope 'PScribo' { Describe 'Plugins\Json\Out-JsonTable' { - $isNix = (($PSVersionTable['PSEdition'] -eq 'Core') -and (-not $IsWindows)) - ## Scaffold document options $Document = Document -Name 'TestDocument' -ScriptBlock {} $script:currentPageNumber = 1