DimCryGarage.psm1
# MIT License # # Copyright (c) 2020 DimCry's Garage (Cristian Dimofte) # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # Description: ### This module contains common useful functions # Author: ### DimCry (Cristian Dimofte) ##################################### # Common space for Global variables # ##################################### #region "Global variables" ### TheWorkingDirectory (Global: Script) variable is used to list the exact value for the Working Directory $Global:TheWorkingDirectory = $null [System.Collections.ArrayList]$Global:LogObject = @() [string]$Global:LogPath = "$Env:Temp\DimCryGarage\Log.log" [string]$Global:HTMLLogPath = "$Env:Temp\DimCryGarage\Log.html" [string]$GLobal:LogEntry = $null $Global:HTMLLogEntry = New-Object PSObject $Global:HTMLLogEntry | Add-Member -NotePropertyName Date -TypeName string -NotePropertyValue "" $Global:HTMLLogEntry | Add-Member -NotePropertyName Type -TypeName string -NotePropertyValue "" $Global:HTMLLogEntry | Add-Member -NotePropertyName Description -TypeName string -NotePropertyValue "" #endregion "Global variables" ##################################### # Common space for Functions # ##################################### #region "Functions" <# .SYNOPSIS Function to export content from a String or TableStructure to HTML report .DESCRIPTION Function "Export-ReportToHTML" is used to export content from a String or TableStructure to HTML report. It can create the HTML report using different themes (for the moment just the "Blue" / default one is defined). .EXAMPLE Export-ReportToHTML -FilePath $FilePath -PageTitle $PageTitle -ReportTitle $ReportTitle -TheObjectToConvertToHTML $TheObjectToConvertToHTML Description ----------- This example is exporting the information into the $FilePath HTML report .NOTES This function can be used to convert any correctly formatted PowerShell content to an HTML report. #> function Export-ReportToHTML { param( [Parameter(Mandatory=$true)] [string]$FilePath, [Parameter(Mandatory=$false)] [string]$PageTitle, [Parameter(Mandatory=$false)] [string]$ReportTitle, [Parameter(Mandatory=$true)] [System.Collections.ArrayList]$TheObjectToConvertToHTML, [Parameter(Mandatory=$false)] [ValidateSet("Blue")] [string]$Theme = "Blue" ) ### Create header of the HTML file if ($Theme -eq "Blue") { $HTMLBeginning = @" <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="description" content="DimCry's Garage"> <meta name="keywords" content="PowerShell, HTML, Report, DimCry, Garage"> <meta name="author" content="Cristian Dimofte"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>$PageTitle</title> <link rel="titlebar icon" href="data:image/png;base64,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" /> <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/css/fabric.min.css" /> <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/css/fabric.components.min.css" /> <script src="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/js/fabric.min.js"></script> <style type="text/css"> html { box-sizing: border-box; font-family: FabricMDL2Icons; } *, *:before, *:after { box-sizing: inherit; } .ms-font-su { font-family:FabricMDL2Icons; -webkit-font-smoothing:antialiased; font-weight:100 } .ms-fontColor-themePrimary,.ms-fontColor-themePrimary--hover:hover{ color:#0078d7 } @font-face{ font-family:FabricMDL2Icons; src:url(https://spoprod-a.akamaihd.net/files/fabric/assets/icons/fabricmdl2icons.woff) format('woff'),url(https://spoprod-a.akamaihd.net/files/fabric/assets/icons/fabricmdl2icons.ttf) format('truetype'); font-weight:400; font-style:normal } body { padding: 10px; font-family: FabricMDL2Icons; background: #f6f6f6; } a { color: #06c; } h1 { margin: 0 0 1.5em; font-weight: 600; font-size: 1.5em; } h2 { color: #1a0e0e; font-size: 20px; font-weight: 700; margin: 0; line-height: normal; text-transform:uppercase; margin-block-start: 0.3em; margin-block-end: 0.3em; text-indent: 0px; margin-left: 0px; } h2 span { display: block; padding: 0; font-size: 18px; opacity: 0.7; margin-top: 5px; text-transform:uppercase; } h3 { color: #000000; font-size: 17px; font-weight: 300; margin-left: 10px; font-family: FabricMDL2Icons; } h3 span { color: #000000; font-size: 17px; font-weight: 300; margin-left: 10px; font-family: FabricMDL2Icons; } h5 { display: block; padding: 0; margin: 5px 0px 0px 0px; font-size: 42px; font-weight: 100; font-family: FabricMDL2Icons; } p { margin: 0 0 1em; padding: 10px; font-family: FabricMDL2Icons; } .ms-icon--description:before { font-family: FabricMDL2Icons; content: "\EA16"; color: #0078d7; margin-right: 5px; font-style: normal; font-size: 20px; } .ms-icon--emojineutral:before { font-family: FabricMDL2Icons; content: "\EA87"; margin-left: 25px; margin-right: -15px; font-style: normal; } .ms-icon--emojihappy:before { font-family: FabricMDL2Icons; content: "\E76E"; margin-left: 25px; margin-right: -15px; font-style: normal; } .ms-icon--emojidisappointed:before { font-family: FabricMDL2Icons; content: "\EA88"; margin-left: 25px; margin-right: -15px; font-style: normal; } .label { width: 100%; height: 80px; background-color: #0078d7; color: #ffffff; font-size: 46px; display: inline-block; } .label1 { width: 100%; height: 80px; background-color: #f6f6f6; color: #0078d7; font-size: 46px; display: inline-block; box-sizing: border-box; } .body-panel { font-size: 14px; padding: 15px; margin-bottom: 5px; margin-top: 5px; box-shadow: 0 1px 2px 0 rgba(0,0,0,.1); overflow-x: auto; box-sizing: border-box; background-color: #fff; color: #333; -webkit-tap-highlight-color: rgba(0,0,0,0); padding-top: 15px; font-family: FabricMDL2Icons; } .accordion { margin-bottom: 1em; } .accordion p:last-child { margin-bottom: 0; } .accordion > input[name="collapse"] { display: none; } .accordion > input[name="collapse"]:checked ~ .content { height: auto; transition: height 0.5s; } .accordion label, .accordion .content { max-width: 3200px; width: 99%; } .accordion .content { background: #fff; overflow: hidden; overflow-x: auto; height: 0; transition: 0.5s; box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.3); } .accordion label { display: block; } .accordion > input[name="collapse"]:checked ~ .content { border-top: 0; transition: 0.3s; } .accordion .handle { margin: 0; font-size: 16px; } .accordion label { color: #0078d7; cursor: pointer; font-weight: 300; padding: 10px; background: #e6f3ff; user-select: none; } .accordion label:hover, .accordion label:focus { background: #cce6ff; color: #0000ff; } .accordion .handle label:before { font-family: FabricMDL2Icons; content: "\E972"; display: inline-block; margin-right: -20px; font-size: 1em; line-height: 1.556em; vertical-align: middle; transition: 0.4s; } .accordion > input[name="collapse"]:checked ~ .handle label:before { transform: rotate(180deg); transform-origin: center; transition: 0.4s; } section { float: left; width: 100%; } .container{ max-width: 3200px; width:99%; margin: 0 auto; } table { font-size: 14px; font-weight: 800; border: 1px solid #0078d7; border-collapse: collapse; font-family: FabricMDL2Icons; margin-left: 10px; margin-bottom: 10px; margin-right: 10px; text-align: center; } td { padding: 4px; margin: 0px; border: 1px solid #0078d7; border-collapse: collapse; } th { color: #0078d7; font-family: FabricMDL2Icons; text-transform: uppercase; padding: 10px 5px; vertical-align: middle; border: 1px solid #0078d7; border-collapse: collapse; } tbody tr:nth-child(odd) { background: #f0f0f2; } #output { color: #004377; font-size: 14px; } @media screen and (max-width:639px){ h2 { color: #1a0e0e; font-size: 16px; font-weight: 700; margin: 0; line-height: normal; text-transform:uppercase; text-indent: 0px; margin-left: 0px; } h5 { margin: 5px 0px 0px 0px; font-size: 8vw; font-weight: 100; font-family: FabricMDL2Icons; } .accordion label, .accordion .content { max-width: 3200px; width: 99%; } .accordion .content { background: #fff; overflow: hidden; overflow-x: auto; height: 0; transition: 0.5s; box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.3); } .accordion > input[name="collapse"]:checked ~ .content { height: auto; } } @media (max-device-width:480px) and (orientation:landscape) { .body-panel { max-height:200px } } /* For Desktop */ @media only screen and (min-width: 620px) { .accordion > input[name="collapse"]:checked ~ .content { height: auto; } } .ms-icon--HTMLReport:before { font-family: FabricMDL2Icons; content: "\E9D9"; font-size: 120px; color: #0078d7; font-style: normal; } </style> </head> <body class="ms-Fabric" dir="ltr"> <header> <div class="label1"> <a href="https://github.com/dimcry/DimCry-Garage" target="_blank"> <img src="data:image/png;base64,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" alt="DimCry's Garage" width="auto" height="110%" style="float: left; margin-right: 5px"> </a> <div style="width: 100%; height: 100%; "> <h5 class="ms-font-su ms-fontColor-themePrimary" style="font-weight: 350; "> $ReportTitle </h5> </div> </div> </header> <div class="body-panel" style="margin: 30px 0px 0px 0px; display: block;"> "@ $HTMLEnd = @" </div> <div class="ms-font-su ms-fontColor-themePrimary" style="font-size: 15px; margin-left: 10px; text-align: right;"> <ul>Creation Date: $((Get-date).ToUniversalTime()) UTC</ul> <ul>© 2020 DimCry's Garage</ul> </div> </body> </html> "@ } [int]$i = 1 [string]$TheBody = $HTMLBeginning ### For each scenario, convert the data to HTML foreach ($Entry in $TheObjectToConvertToHTML) { [string]$Emoji = $null if ($Entry.SectionTitleColor -eq "Green") { $Emoji = "happy" } elseif ($Entry.SectionTitleColor -eq "Red") { $Emoji = "disappointed" } else { $Emoji = "neutral" } $TheBody = $TheBody + " `<section class=`"accordion`"`> `<input type=`"checkbox`" name=`"collapse`" id=`"handle$i`" `> `<h2 class=`"handle`"`> `<label for=`"handle$i`" `> `<h2 class=`"ms-font-su ms-fontColor-themePrimary`" style=`"display: inline-block; color: $($Entry.SectionTitleColor); font-size: 20px; font-weight: 650;`"`>`<i class=`"ms-icon ms-icon--emoji$Emoji`"`>`</i`> $($Entry.SectionTitle)`</h2`> `</label`> `</h2`> `<div class=`"content`"`> `<h3`>`<i class=`"ms-icon ms-icon--description`"`>`<`/i`>$($Entry.Description)`</h3`> " if ($Entry.DataType -eq "String") { $TheValue = " `<p style=`"font-family: FabricMDL2Icons; font-weight: 800; margin-left: 10px;`"`>$($Entry.EffectiveData)`<`/p>" } else { $TheProperties = ($($Entry.EffectiveData)| Get-Member -MemberType NoteProperty).Name $TheValue = $($Entry.EffectiveData) | ConvertTo-Html -As $($Entry.TableType) -Property $TheProperties -Fragment if ($Entry.TableType -eq "List") { [int]$z = 0 foreach ($NewEntryFound in $TheValue) { if ($NewEntryFound -like "*<table>*") { $TheValue.Item($z) = $NewEntryFound.Replace("<table>", "<table style=`"text-align: left;`">") } elseif ($NewEntryFound -like "*<tr><td>*") { $TheValue.Item($z) = $NewEntryFound.Replace("<tr><td>", "<tr><th>") $TheValue.Item($z) = (($TheValue.Item($z) -split "<td")[0] -replace "`/td>", "`/th>") + ($TheValue.Item($z).Substring((($TheValue.Item($z) -split "<td")[0].Length),($TheValue.Item($z).Length-($TheValue.Item($z) -split "<td")[0].Length))) } $z++ } } } ### Adding sections in the body of the HTML report $TheBody = $TheBody + $TheValue $TheBody = $TheBody + " `<`/div`> `<`/section`> " $i++ } $TheBody = $TheBody + $HTMLEnd $TheBody | Out-File $FilePath -Force } <# .SYNOPSIS "Prepare-ObjectForHTMLReport" function is used to prepare the objects to be converted to HTML file .DESCRIPTION "Prepare-ObjectForHTMLReport" function is used to prepare the objects to be converted to HTML file .EXAMPLE [PSCustomObject]$TheCommand = Prepare-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor $SectionTitleColor -Description $Description -DataType "String" -EffectiveDataString $TheString Description ----------- This example is preparing an object that has a string as DataType, to be listed into the HTML report .EXAMPLE [PSCustomObject]$TheCommand = Prepare-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor $SectionTitleColor -Description $Description -DataType "TableStructure" -EffectiveDataTableStructure $TheTable -TableType "List" Description ----------- This example is preparing an object that has a TableStructure as DataType, to be listed as a List into the HTML report .EXAMPLE [PSCustomObject]$TheCommand = Prepare-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor $SectionTitleColor -Description $Description -DataType "TableStructure" -EffectiveDataTableStructure $TheTable -TableType "Table" Description ----------- This example is preparing an object that has a TableStructure as DataType, to be listed as a Table into the HTML report .NOTES This function can be used to correctly prepare any PowerShell content to be exported to an HTML report #> function Prepare-ObjectForHTMLReport { param ( [Parameter(ParameterSetName = "String", Mandatory=$false)] [Parameter(ParameterSetName = "TableStructure", Mandatory=$false)] [string]$SectionTitle, [Parameter(ParameterSetName = "String", Mandatory=$false)] [Parameter(ParameterSetName = "TableStructure", Mandatory=$false)] [ValidateSet("Black", "Green", "Red")] [ConsoleColor]$SectionTitleColor, [Parameter(ParameterSetName = "String", Mandatory=$false)] [Parameter(ParameterSetName = "TableStructure", Mandatory=$false)] [string]$Description, [Parameter(ParameterSetName = "String", Mandatory=$false)] [Parameter(ParameterSetName = "TableStructure", Mandatory=$false)] [ValidateSet("TableStructure", "String")] [string]$DataType, [Parameter(ParameterSetName = "String", Mandatory=$false)] [string]$EffectiveDataString, [Parameter(ParameterSetName = "TableStructure", Mandatory=$false)] [PSCustomObject]$EffectiveDataTableStructure, [Parameter(ParameterSetName = "TableStructure", Mandatory=$false)] [ValidateSet("List", "Table")] [string]$TableType ) ###Create the object, with all needed Properties, that will be used to convert into an HTML report $TheObject = New-Object PSObject $TheObject | Add-Member -NotePropertyName SectionTitle -NotePropertyValue $SectionTitle $TheObject | Add-Member -NotePropertyName SectionTitleColor -NotePropertyValue $SectionTitleColor $TheObject | Add-Member -NotePropertyName Description -NotePropertyValue $Description $TheObject | Add-Member -NotePropertyName DataType -NotePropertyValue $DataType if ($DataType -eq "TableStructure") { $TheObject | Add-Member -NotePropertyName EffectiveData -NotePropertyValue $EffectiveDataTableStructure $TheObject | Add-Member -NotePropertyName TableType -NotePropertyValue $TableType } else { $TheObject | Add-Member -NotePropertyName EffectiveData -NotePropertyValue $EffectiveDataString } ### Return the created object return $TheObject } function Test-ExportReportToHTMLUsingDummyData { [System.Collections.ArrayList]$TheObjectToConvertToHTML = @() ### "String1" section [string]$SectionTitle = "This is the title of the `"String1`" section" [ConsoleColor]$SectionTitleColor = "Green" [string]$Description = "This is the description of the `"String1`" section" [string]$TheString = "This is the content of the `"String1`" section" [PSCustomObject]$TheCommand = Prepare-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor $SectionTitleColor -Description $Description -DataType "String" -EffectiveDataString $TheString $null = $TheObjectToConvertToHTML.Add($TheCommand) ### "List" section [string]$SectionTitle = "This is the title of the `"List`" section" [ConsoleColor]$SectionTitleColor = "Black" [string]$Description = "This is the description of the `"List`" section" [System.Collections.ArrayList]$TheTable = @() $AList = New-Object PSObject $AList | Add-Member -NotePropertyName FirstRow -NotePropertyValue "A value of the first row" $AList | Add-Member -NotePropertyName SecondRow -NotePropertyValue "A value of the second row" $AList | Add-Member -NotePropertyName ThirdRow -NotePropertyValue "A value of the third row" $AList | Add-Member -NotePropertyName FourthRow -NotePropertyValue "A value of the fourth row" $AList | Add-Member -NotePropertyName FifthRow -NotePropertyValue "A value of the fifth row" $null = $TheTable.Add($AList) [PSCustomObject]$TheCommand = Prepare-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor $SectionTitleColor -Description $Description -DataType "TableStructure" -EffectiveDataTableStructure $TheTable -TableType "List" $null = $TheObjectToConvertToHTML.Add($TheCommand) ### "Table" section [string]$SectionTitle = "This is the title of the `"Table`" section" [ConsoleColor]$SectionTitleColor = "Red" [string]$Description = "This is the description of the `"Table`" section" [System.Collections.ArrayList]$TheTable = @() $ATable = New-Object PSObject $ATable | Add-Member -NotePropertyName FirstRow -NotePropertyValue "A value of the first column" $ATable | Add-Member -NotePropertyName SecondRow -NotePropertyValue "A value of the second column" $ATable | Add-Member -NotePropertyName ThirdRow -NotePropertyValue "A value of the third column" $ATable | Add-Member -NotePropertyName FourthRow -NotePropertyValue "A value of the fourth column" $ATable | Add-Member -NotePropertyName FifthRow -NotePropertyValue "A value of the fifth column" $null = $TheTable.Add($ATable) $ATable = New-Object PSObject $ATable | Add-Member -NotePropertyName FirstRow -NotePropertyValue "Another value of the first column" $ATable | Add-Member -NotePropertyName SecondRow -NotePropertyValue "Another value of the second column" $ATable | Add-Member -NotePropertyName ThirdRow -NotePropertyValue "Another value of the third column" $ATable | Add-Member -NotePropertyName FourthRow -NotePropertyValue "Another value of the fourth column" $ATable | Add-Member -NotePropertyName FifthRow -NotePropertyValue "Another value of the fifth column" $null = $TheTable.Add($ATable) [PSCustomObject]$TheCommand = Prepare-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor $SectionTitleColor -Description $Description -DataType "TableStructure" -EffectiveDataTableStructure $TheTable -TableType "Table" $null = $TheObjectToConvertToHTML.Add($TheCommand) ### "String2" section [string]$SectionTitle = "This is the title of the `"String2`" section" [ConsoleColor]$SectionTitleColor = "Black" [string]$Description = "This is the description of the `"String2`" section" [string]$TheString = "This is the content of the `"String2`" section" [PSCustomObject]$TheCommand = Prepare-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor $SectionTitleColor -Description $Description -DataType "String" -EffectiveDataString $TheString $null = $TheObjectToConvertToHTML.Add($TheCommand) # Export the content to an HTML report ### Create the folder, if doesn't exist $null = New-Item -ItemType Directory "$Env:Temp\DimCryGarage" -Force ### Manually set a name of the file $FilePath = "$Env:Temp\DimCryGarage\HTMLReport.HTML" $PageTitle = "This is the title of the page" $ReportTitle = "This is the title of the report" Export-ReportToHTML -FilePath $FilePath -PageTitle $PageTitle -ReportTitle $ReportTitle -TheObjectToConvertToHTML $TheObjectToConvertToHTML Write-Host "The HTML report is located on:" -ForegroundColor White Write-Host "`tLong path: " -ForegroundColor White -NoNewline Write-Host "$Env:Temp\DimCryGarage\HTMLReport.HTML" -ForegroundColor Cyan Write-Host "`tShort path: " -ForegroundColor White -NoNewline Write-Host "%temp%\DimCryGarage\HTMLReport.HTML" -ForegroundColor Cyan } function Write-Log { param ( [ValidateSet("INFO","SUCCESS","WARNING","ERROR")] [string]$Type, [PSCustomObject]$Description, [ConsoleColor]$ForegroundColor, [switch]$Interactive = $true, [switch]$LinkedToNextEntry, [switch]$SameLineLikePreviousEntry, [string]$KeyEntry = $null ) if (!$ForegroundColor) { switch ($Type) { "Success" {$ForegroundColor = "Green"} "Warning" {$ForegroundColor = "Yellow"} "Error" {$ForegroundColor = "Red"} Default { if (@($Global:LogObject).Count -gt 0) { $ForegroundColor = $($Global:LogObject[0].ForegroundColor) } else { $ForegroundColor = "White" } } } } if ($Interactive) { [bool]$Interactive = $true } else { [bool]$Interactive = $false } $TheObject = New-Object PSObject if ($Type) { [string]$Date = $((Get-Date).ToUniversalTime().ToString("dd.MM.yyyy HH:mm:ss.fff")) + " UTC" $TheObject | Add-Member -MemberType NoteProperty -Name Date -Value $Date $TheObject | Add-Member -MemberType NoteProperty -Name Type -Value $Type } else { $TheObject | Add-Member -MemberType NoteProperty -Name Date -Value "" $TheObject | Add-Member -MemberType NoteProperty -Name Type -Value "" } $TheObject | Add-Member -MemberType NoteProperty -Name Description -Value $Description $TheObject | Add-Member -MemberType NoteProperty -Name ForegroundColor -Value $ForegroundColor $TheObject | Add-Member -MemberType NoteProperty -Name SameLineLikePreviousEntry -Value $SameLineLikePreviousEntry $TheObject | Add-Member -MemberType NoteProperty -Name KeyEntry -Value $KeyEntry $TheObject | Add-Member -MemberType NoteProperty -Name LinkedToNextEntry -Value $LinkedToNextEntry $TheObject | Add-Member -MemberType NoteProperty -Name Interactive -Value $Interactive if (!(Test-Path $Global:HTMLLogPath)) { Create-HTMLLogFile } if ($TheObject.Date) { $Global:HTMLLogEntry.Date = $TheObject.Date } if ($TheObject.Type) { $Global:HTMLLogEntry.Type = $TheObject.Type } if (!$LinkedToNextEntry) { [string]$WriteHostTypeString = $null $null = $Global:LogObject.Add($TheObject) if (@($($TheObject.Description)).Count -gt 1) { if (@($($TheObject.Description) | Get-Member -MemberType NoteProperty).Count -gt 1) { [System.Collections.ArrayList]$TheProperties = @() $ListOfMembers = ($($TheObject.Description)| Get-Member -MemberType NoteProperty).Name $null = $TheProperties.Add($($TheObject.KeyEntry)) foreach ($MemberEntry in $ListOfMembers) { if ($MemberEntry -ne $($TheObject.KeyEntry)) { $null = $TheProperties.Add($MemberEntry) } } [string]$EntryToUse = $($TheObject.Description) | ConvertTo-Html -As Table -Property $TheProperties -Fragment $Global:HTMLLogEntry.Description = $Global:HTMLLogEntry.Description + $EntryToUse } else { [int]$i = 1 foreach ($DescriptionEntry in $($TheObject.Description)) { if ($i -le $(@($TheObject.Description).Count - 1)) { $Global:HTMLLogEntry.Description = $Global:HTMLLogEntry.Description + $DescriptionEntry + "<br>" } else { $Global:HTMLLogEntry.Description = $Global:HTMLLogEntry.Description + $DescriptionEntry } $i++ } } } else { if ($Global:HTMLLogEntry.Description) { if ($SameLineLikePreviousEntry) { if ($Global:HTMLLogEntry.Description.EndsWith("<br>")) { $Global:HTMLLogEntry.Description = $($Global:HTMLLogEntry.Description).Substring(0,$($Global:HTMLLogEntry.Description).Length-4) + $($TheObject.Description) + "<br>" } else { $Global:HTMLLogEntry.Description = $Global:HTMLLogEntry.Description + $($TheObject.Description) + "<br>" } } else { $Global:HTMLLogEntry.Description = $Global:HTMLLogEntry.Description + $($TheObject.Description) + "<br>" } } else { $Global:HTMLLogEntry.Description = $($TheObject.Description) } } [int]$i = 1 foreach ($ObjectEntry in $Global:LogObject) { if ($i -eq 1) { ### For HTML ### For CSV and Write-Host Write-EntryOnScreenOrLOGFileSameOrNextLine -ObjectEntry $ObjectEntry -IsFirstEntry $true } else { ### For HTML ### For CSV and Write-Host Write-EntryOnScreenOrLOGFileSameOrNextLine -ObjectEntry $ObjectEntry -IsFirstEntry $false } $i++ } Add-EntryInHTMLLogFile -theLogToAddInHTML $Global:HTMLLogEntry -description $($Global:HTMLLogEntry.Description) $Global:LogObject.Clear() $Global:HTMLLogEntry.Date = "" $Global:HTMLLogEntry.Type = "" $Global:HTMLLogEntry.Description = "" } else { $null = $Global:LogObject.Add($TheObject) if (@($($TheObject.Description) | Get-Member -MemberType NoteProperty).Count -gt 1) { [System.Collections.ArrayList]$TheProperties = @() $ListOfMembers = ($($TheObject.Description)| Get-Member -MemberType NoteProperty).Name $null = $TheProperties.Add($($TheObject.KeyEntry)) foreach ($MemberEntry in $ListOfMembers) { if ($MemberEntry -ne $($TheObject.KeyEntry)) { $null = $TheProperties.Add($MemberEntry) } } [string]$EntryToUse = $($TheObject.Description) | ConvertTo-Html -As Table -Property $TheProperties -Fragment } else { [string]$EntryToUse = $($TheObject.Description) } if (@($($TheObject.Description)).Count -gt 1) { $Global:HTMLLogEntry.Description = $Global:HTMLLogEntry.Description + $EntryToUse } else { if ($SameLineLikePreviousEntry) { if ($Global:HTMLLogEntry.Description.EndsWith("<br>")) { $Global:HTMLLogEntry.Description = $($Global:HTMLLogEntry.Description).Substring(0,$($Global:HTMLLogEntry.Description).Length-4) + $($TheObject.Description) + "<br>" } else { $Global:HTMLLogEntry.Description = $Global:HTMLLogEntry.Description + $($TheObject.Description) + "<br>" } } else { $Global:HTMLLogEntry.Description = $Global:HTMLLogEntry.Description + $($TheObject.Description) + "<br>" } } } } function Write-EntryOnScreenOrLOGFileSameOrNextLine { param ( [bool]$IsFirstEntry, $ObjectEntry ) [string]$WriteHostDescriptionString = " " * 40 if ($ObjectEntry.Type) { if ($($ObjectEntry.Type) -eq "INFO") { $WriteHostTypeString = " " * 3 } elseif ($($ObjectEntry.Type) -eq "ERROR") { $WriteHostTypeString = " " * 2 } } if ($($ObjectEntry.SameLineLikePreviousEntry)) { $SameLineLikePreviousEntry = $true } else { $SameLineLikePreviousEntry = $false } if ($($ObjectEntry.LinkedToNextEntry)) { $LinkedToNextEntry = $true } else { $LinkedToNextEntry = $false } [int]$i = 1 foreach ($DescriptionEntry in $($ObjectEntry.Description)) { if (@($DescriptionEntry | Get-Member -MemberType NoteProperty).Count -gt 1) { [System.Collections.ArrayList]$DescriptionEntryMembers = Create-DescriptionTableMembers -ListOfMembers (($DescriptionEntry | Get-Member -MemberType NoteProperty).Name) -KeyEntry $($ObjectEntry.KeyEntry) [string]$WriteHostMemberString = Create-DescriptionTableEntries -DescriptionEntryMembers $DescriptionEntryMembers -ObjectEntryDescription $($ObjectEntry.Description) -DescriptionEntry $DescriptionEntry [string]$EntryToUse = $WriteHostMemberString } else { [string]$EntryToUse = $DescriptionEntry } if (($i -eq 1) -and ($IsFirstEntry)) { if ($ObjectEntry.Interactive) { Write-Host $("`n" + "-" * $($ObjectEntry.Date).Length + " " + "-" * $($ObjectEntry.Type + $WriteHostTypeString).Length + " " + "-" * $($EntryToUse).Length) -ForegroundColor $($ObjectEntry.ForegroundColor) -NoNewline Write-Host "`n$($ObjectEntry.Date) $($ObjectEntry.Type)$WriteHostTypeString $EntryToUse" -ForegroundColor $($ObjectEntry.ForegroundColor) -NoNewline } if (!(Test-Path $Global:LogPath)) { Add-Content -LiteralPath $Global:LogPath -Value $("Date " + " " + "Type " + " " + "Description") -Force } if ($LinkedToNextEntry) { $Global:LogEntry = $("-" * $($ObjectEntry.Date).Length + " " + "-" * $($ObjectEntry.Type + $WriteHostTypeString).Length + " " + "-" * $($EntryToUse).Length) $Global:LogEntry = $Global:LogEntry + "`n$($ObjectEntry.Date) $($ObjectEntry.Type)$WriteHostTypeString $EntryToUse" } else { Add-Content -LiteralPath $Global:LogPath -Value $("-" * $($ObjectEntry.Date).Length + " " + "-" * $($ObjectEntry.Type + $WriteHostTypeString).Length + " " + "-" * $($EntryToUse).Length) -Force Add-Content -LiteralPath $Global:LogPath -Value "$($ObjectEntry.Date) $($ObjectEntry.Type)$WriteHostTypeString $EntryToUse" -Force } } else { if ($SameLineLikePreviousEntry) { if ($ObjectEntry.Interactive) { Write-Host "$EntryToUse" -ForegroundColor $($ObjectEntry.ForegroundColor) -NoNewline } if ($LinkedToNextEntry) { $Global:LogEntry = $Global:LogEntry + $EntryToUse } else { if ($i -le $(@($TheObject.Description).Count - 1)) { $Global:LogEntry = $Global:LogEntry + $EntryToUse } else { Add-Content -LiteralPath $Global:LogPath -Value "$Global:LogEntry$EntryToUse" -Force [string]$Global:LogEntry = $null } } } else { if ($ObjectEntry.Interactive) { Write-Host "`n$WriteHostDescriptionString$EntryToUse" -ForegroundColor $($ObjectEntry.ForegroundColor) -NoNewline } if ($LinkedToNextEntry) { if ($Global:LogEntry) { $Global:LogEntry = $Global:LogEntry + "`n" + $WriteHostDescriptionString + $EntryToUse } else { $Global:LogEntry = $WriteHostDescriptionString + $EntryToUse } } else { if ($i -le $(@($TheObject.Description).Count - 1)) { if ($Global:LogEntry) { $Global:LogEntry = $Global:LogEntry + "`n" + $WriteHostDescriptionString + $EntryToUse } else { $Global:LogEntry = $WriteHostDescriptionString + $EntryToUse } } else { if ($Global:LogEntry) { Add-Content -LiteralPath $Global:LogPath -Value $Global:LogEntry -Force [string]$Global:LogEntry = $null } Add-Content -LiteralPath $Global:LogPath -Value "$WriteHostDescriptionString$EntryToUse" -Force } } } } $i++ } } function Create-DescriptionTableMembers { param ( $ListOfMembers, $KeyEntry ) [System.Collections.ArrayList]$DescriptionEntryMembers = @() $null = $DescriptionEntryMembers.Add($KeyEntry) foreach ($MemberEntry in $ListOfMembers) { if ($MemberEntry -ne $KeyEntry) { $null = $DescriptionEntryMembers.Add($MemberEntry) } } return $DescriptionEntryMembers } function Create-DescriptionTableEntries { param ( [System.Collections.ArrayList]$DescriptionEntryMembers, $ObjectEntryDescription, $DescriptionEntry ) [int]$i = 1 [string]$WriteHostMemberString = "" foreach ($Member in $DescriptionEntryMembers) { $MaximumLengthOfMember = ($ObjectEntryDescription.$Member | sort {$_.ToString().Length} -Descending | select -First 1).ToString().Length $WriteHostMemberStringToAdd = " " * $($MaximumLengthOfMember - $DescriptionEntry.$Member.ToString().Length) if ($i -eq 1) { $WriteHostMemberString = "| " + $DescriptionEntry.$Member + $WriteHostMemberStringToAdd } elseif ($i -eq @($DescriptionEntry | Get-Member -MemberType NoteProperty).Count) { $WriteHostMemberString = $WriteHostMemberString + " | " + $DescriptionEntry.$Member + $WriteHostMemberStringToAdd + " |" } else { $WriteHostMemberString = $WriteHostMemberString + " | " + $DescriptionEntry.$Member + $WriteHostMemberStringToAdd } $i++ } return $WriteHostMemberString } function Create-HTMLLogFile { param ( [string]$lineToAdd ) $HTMLBeginning = @" <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="description" content="DimCry's Garage"> <meta name="keywords" content="PowerShell, HTML, Report, DimCry, Garage"> <meta name="author" content="Cristian Dimofte"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Filtrable / Searchable log file</title> <link rel="titlebar icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD0AAABOCAYAAACT1B6GAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGeSURBVHhe7duxSsNQFMbxvoCT7+Ab+Aw+hg/g6uDk4Kq4ODm4OwiC4uKkkwgigkipiBYVsWrVKmY95sBHPCml5EoOSXq/4Q8hvS3nBx1u0rSVJInEFtGxRPTeZV9aS+2JSk3WqBFN9IQUjJ5a7sjaUU92LvqNSGfVma0hGD290pHTu8/cG+qczqozWwPRiGii04huQEQjolEwevPkRWZWb7Lmtx/kbfCTva7Hes6u8UpnsbO5oXXXY9fMbXXl1aD1WM/ZNV7pLHY2ohHRKBh9cPUuC7uPWevHPfn4/kPrsZ6za7zSWexsbug6RzQiGhFNdBrRDYhoVAq6qguO2Y1bOb8f5GYZzg1d1Ta0yLeOaEQ0CkZXdcGxuP8k189fuVmGc0PXOaIR0YhootOIbkBEo1LQXpuTs+74i4kiuaG9tqGjhguN6DGfS3QRtNdNhMN2/teK/+SGrnNEI6IR0USnEd2AiEaloKN8/KKq+96j0lnsbEQjolEwOsrHJOsc0YhoRDTRaUQ3IKJRMDrKP5hOQkQjoqNExxLRsRQhOpFfossxSEw+JV4AAAAASUVORK5CYII=" /> <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/css/fabric.min.css" /> <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/css/fabric.components.min.css" /> <script src="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/js/fabric.min.js"></script> <style type="text/css"> .input { width: 15px; height: 24px; font-size: 18px; } #myInput { font-size: 16px; box-sizing: border-box; font-family: FabricMDL2Icons; font-size: 16px; border: none; outline: 1px solid #ddd; padding-left: 5px; padding-bottom: 5px; } #myInput:focus {outline: 3px solid #ddd;} .tooltip { position: relative; display: inline-block; } .tooltip .tooltiptext { visibility: hidden; width: 120px; background-color: #fff; color: #0078d7; text-align: center; border-radius: 6px; padding: 5px 0; position: absolute; z-index: 1; bottom: 125%; left: 50%; margin-left: -60px; opacity: 0; transition: opacity 0.5s; } .tooltip .tooltiptext::after { content: ""; position: absolute; top: 100%; left: 75%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: #555 transparent transparent transparent; } .tooltip:hover .tooltiptext { visibility: visible; opacity: 10; } :root { font-size: calc(16px + (24 - 16)*(100vw - 320px)/(1920 - 320)); } input { line-height: 1.5em; color: #171717; } .dropButtonType { border: none; cursor: pointer; border-style: none; float: right; } .dropButtonType:hover, .dropButtonType:focus { border: none; border-style: none; } .dropdown-content { display: none; position: absolute; background-color: #f6f6f6; overflow: auto; border-style: none; z-index: 1; resize: both; min-height: 110px; min-width: 130px; margin-top: 10px; } .dropdown-content a { color: black; padding: 12px 16px; text-decoration: none; display: block; border-style: none; } .show { display: block; border-style: none; } html { box-sizing: border-box; font-family: FabricMDL2Icons; } *, *:before, *:after { box-sizing: inherit; } .ms-font-su { font-family:FabricMDL2Icons; -webkit-font-smoothing:antialiased; font-weight:100 } .ms-fontColor-themePrimary,.ms-fontColor-themePrimary--hover:hover{ color:#0078d7 } @font-face{ font-family:FabricMDL2Icons; src:url(https://spoprod-a.akamaihd.net/files/fabric/assets/icons/fabricmdl2icons.woff) format('woff'),url(https://spoprod-a.akamaihd.net/files/fabric/assets/icons/fabricmdl2icons.ttf) format('truetype'); font-weight:400; font-style:normal } body { padding: 10px; font-family: FabricMDL2Icons; background: #f6f6f6; overflow: auto; } a { color: #06c; } h5 { display: block; padding: 0; margin: 5px 0px 0px 0px; font-size: 42px; font-weight: 100; font-family: FabricMDL2Icons; } p { margin: 0 0 1em; padding: 10px; font-family: FabricMDL2Icons; } .ms-icon--filtersolid:before { font-family: FabricMDL2Icons; content: "\F412"; color: #0078d7; margin-right: 0px; font-style: normal; font-size: 12px; float: right; } .ms-icon--sort:before { font-family: FabricMDL2Icons; content: "\E8CB"; color: #0078d7; margin-right: 5px; font-style: normal; font-size: 12px; float: right; } .label { width: 100%; height: 80px; background-color: #f6f6f6; color: #0078d7; font-size: 46px; display: inline-block; box-sizing: border-box; } .logtypeentryerror { color: Red; font-style: normal; } .logtypeentrywarning { color: #ffba00; font-style: normal; } .logtypeentrysuccess { color: Green; font-style: normal; } .logtypeentryinfo { color: Black; font-style: normal; } table { font-size: 14px; font-weight: 800; border: 1px solid #fff; border-collapse: collapse; font-family: FabricMDL2Icons; text-align: left; white-space: normal; } td { padding: 4px; margin: 0px; border: 1px solid #fff; border-collapse: collapse; vertical-align: top; } th.description { border: 1px solid #fff; border-collapse: collapse; vertical-align: middle; text-align: center; } td.description { border: 1px solid #fff; border-collapse: collapse; vertical-align: middle; } th { color: #0078d7; font-family: FabricMDL2Icons; text-transform: uppercase; padding: 10px 5px; border: 1px solid #fff; border-collapse: collapse; } tbody tr:nth-child(odd), tbody.description tr:nth-child(even) { background: #e6f3ff; } tbody.description tr:nth-child(odd), tbody tr:nth-child(even) { background: #fff; } @media (max-device-width:480px) and (orientation:landscape) { .dropdown-content { margin-top: 30px; } } @media screen and (max-width:639px){ h5 { margin: 5px 0px 0px 0px; font-size: 8vw; font-weight: 100; font-family: FabricMDL2Icons; } .dropdown-content { margin-top: 20px; } } </style> </head> <body class="ms-Fabric" dir="ltr"> <header> <div class="label"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD0AAABOCAYAAACT1B6GAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGeSURBVHhe7duxSsNQFMbxvoCT7+Ab+Aw+hg/g6uDk4Kq4ODm4OwiC4uKkkwgigkipiBYVsWrVKmY95sBHPCml5EoOSXq/4Q8hvS3nBx1u0rSVJInEFtGxRPTeZV9aS+2JSk3WqBFN9IQUjJ5a7sjaUU92LvqNSGfVma0hGD290pHTu8/cG+qczqozWwPRiGii04huQEQjolEwevPkRWZWb7Lmtx/kbfCTva7Hes6u8UpnsbO5oXXXY9fMbXXl1aD1WM/ZNV7pLHY2ohHRKBh9cPUuC7uPWevHPfn4/kPrsZ6za7zSWexsbug6RzQiGhFNdBrRDYhoVAq6qguO2Y1bOb8f5GYZzg1d1Ta0yLeOaEQ0CkZXdcGxuP8k189fuVmGc0PXOaIR0YhootOIbkBEo1LQXpuTs+74i4kiuaG9tqGjhguN6DGfS3QRtNdNhMN2/teK/+SGrnNEI6IR0USnEd2AiEaloKN8/KKq+96j0lnsbEQjolEwOsrHJOsc0YhoRDTRaUQ3IKJRMDrKP5hOQkQjoqNExxLRsRQhOpFfossxSEw+JV4AAAAASUVORK5CYII=" alt="DimCry's Garage" width="auto" height="90%" style="float: left; margin-right: 15px"> <div style="width: 100%; height: 100%; "> <h5 class="ms-font-su ms-fontColor-themePrimary" style="font-weight: 350; "> Filtrable / Searchable log file </h5> </div> </div> </header> <div style="margin-top: 10px;"> <form > <select name="searchIn" id="searchIn" onchange="selectFromWhereToSearch(value)"> <option value="allEntries">Search through all entries</option> <option value="descriptionEntries">Search through description entries</option> </select> <input type="text" id="myInput" onkeyup="searchFunction(window.theValue)" placeholder="Type here to search..." name="search" title="Type anything to search..." autocomplete="off" style="margin-top: 10px;"> </form> </div> <div style="margin: 10px 0px 0px 0px; display: block;"> <table id="myTable"> <tr class="header"> <th> Date <i onclick="sortTable(0)" style="font-style: normal; cursor: pointer;"> <i class="ms-icon ms-icon--sort"></i> </i> </th> <th class="tooltip"> Type <i class="tooltiptext">Sort or filter</i> <i onclick="showDropDownFilter('myTypeDropdown')" class="dropButtonType ms-icon ms-icon--filtersolid" ></i> <div id="myTypeDropdown" class="dropdown-content" > <form style="float:left; font-size: 15px;"> <input type="checkbox" id="showall" onclick="window.visibleEntries = filterTypeColumn('showall')" checked="checked" value="showall"> <label for="showall">Show all...</label><br /> <input type="checkbox" id="info" onclick="window.visibleEntries = filterTypeColumn('info')" checked="checked" value="info"> <label for="info">INFO</label><br> <input type="checkbox" id="success" onclick="window.visibleEntries = filterTypeColumn('success')" checked="checked" value="success"> <label for="success">SUCCESS</label><br /> <input type="checkbox" id="warning" onclick="window.visibleEntries = filterTypeColumn('warning')" checked="checked" value="warning"> <label for="warning">WARNING</label><br /> <input type="checkbox" id="error" onclick="window.visibleEntries = filterTypeColumn('error')" checked="checked" value="error"> <label for="error">ERROR</label><br /> </form> </div> <i onclick="sortTable(1)" style="font-style: normal; cursor: pointer;"> <i class="ms-icon ms-icon--sort"></i> </i> </th> <th>Description</th> </tr> "@ $HTMLEnd = @" </table></div> <div class="ms-font-su ms-fontColor-themePrimary" style="font-size: 15px; text-align: left; margin-left: 0px;"> <p style="margin:0px;line-height:0.5;"></p> <p style="margin:0px;line-height:0.5;">Creation Date: $((Get-date).ToUniversalTime()) UTC</p> <p style="margin:0px;line-height:0.5;">© 2020 <a href="https://github.com/dimcry/DimCry-Garage" target="_blank" title="https://github.com/dimcry/DimCry-Garage">DimCry's Garage</a></p> </div> <script> var theValue = "allEntries"; var theTypeFilter = ['info', 'success', 'warning', 'error']; var searchValue = ""; var visibleEntries = []; var hiddenEntries = []; myTable = document.getElementById("myTable"); trsFromMyTable = myTable.getElementsByClassName("filtrableTR"); for (var a = 0; a < trsFromMyTable.length; a++) { if (trsFromMyTable[a].style.display === "") { visibleEntries.push(trsFromMyTable[a]); } } function selectFromWhereToSearch(value) { window.theValue = value; } function filterTypeColumn(n) { var filter, theTable, tr, i, j, txtValue; var theVisibleEntries = []; theTable = document.getElementById("myTable"); tr = theTable.getElementsByClassName("filtrableTR"); if (document.getElementById(String(n)).checked == true) { if (n.toLowerCase() == "showall") { theCheckBox("info", true); theCheckBox("success", true); theCheckBox("warning", true); theCheckBox("error", true); theTypeFilter = ['info', 'success', 'warning', 'error']; } else { if (n.toLowerCase() == "info") { theTypeFilter.push('info'); } if (n.toLowerCase() == "success") { theTypeFilter.push('success'); } if (n.toLowerCase() == "warning") { theTypeFilter.push('warning'); } if (n.toLowerCase() == "error") { theTypeFilter.push('error'); } if (theTypeFilter.includes('info') && theTypeFilter.includes('success') && theTypeFilter.includes('warning') && theTypeFilter.includes('error')) { theCheckBox("showall", true); } } } else { if (n.toLowerCase() == "showall") { theCheckBox("info", false); theCheckBox("success", false); theCheckBox("warning", false); theCheckBox("error", false); theTypeFilter = []; } else { theCheckBox("showall", false); if (n.toLowerCase() == "info") { theTypeFilter.splice(theTypeFilter.indexOf('info'), 1); } if (n.toLowerCase() == "success") { theTypeFilter.splice(theTypeFilter.indexOf('success'), 1); } if (n.toLowerCase() == "warning") { theTypeFilter.splice(theTypeFilter.indexOf('warning'), 1); } if (n.toLowerCase() == "error") { theTypeFilter.splice(theTypeFilter.indexOf('error'), 1); } } } for (i = 0; i < tr.length; i++) { td = tr[i].getElementsByTagName("td")[1]; if (td) { txtValue = td.textContent || td.innerText; if (theTypeFilter.length > 0) { if (theTypeFilter.includes(txtValue.toLowerCase())) { tr[i].style.display = ""; theVisibleEntries.push(tr[i]); } else { tr[i].style.display = "none"; } } else { tr[i].style.display = "none"; } } } searchFunction(window.searchValue); return theVisibleEntries; } function theCheckBox(elementID, boolValue) { let inputs = document.getElementById(elementID); inputs.checked = boolValue; } function triggerAlert(n) { alert(n); } /* When the user clicks on the filter button, toggle between hiding and showing the dropdown content */ function showDropDownFilter(filter) { document.getElementById(filter).classList.toggle("show"); } function sortTable(n) { var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; table = document.getElementById("myTable"); switching = true; //Set the sorting direction to ascending: dir = "asc"; /*Make a loop that will continue until no switching has been done:*/ while (switching) { //start by saying: no switching is done: switching = false; rows = table.rows; /*Loop through all table rows (except the first, which contains table headers):*/ for (i = 1; i < (rows.length - 1); i++) { //start by saying there should be no switching: shouldSwitch = false; /*Get the two elements you want to compare, one from current row and one from the next:*/ x = rows[i].getElementsByTagName("TD")[n]; y = rows[i + 1].getElementsByTagName("TD")[n]; /*check if the two rows should switch place, based on the direction, asc or desc:*/ if (dir == "asc") { if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) { //if so, mark as a switch and break the loop: shouldSwitch= true; break; } } else if (dir == "desc") { if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) { //if so, mark as a switch and break the loop: shouldSwitch = true; break; } } } if (shouldSwitch) { /*If a switch has been marked, make the switch and mark that a switch has been done:*/ rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); switching = true; //Each time a switch is done, increase this count by 1: switchcount ++; } else { /*If no switching has been done AND the direction is "asc", set the direction to "desc" and run the while loop again.*/ if (switchcount == 0 && dir == "asc") { dir = "desc"; switching = true; } } } } window.addEventListener("click", function(event) { if (!event.target.matches('.dropButtonDate')) { if (!event.target.matches('.dropButtonType')) { var dropdowns = document.getElementsByClassName("dropdown-content"); } else { var dropdowns = document.getElementById("myDateDropdown"); } } else if (!event.target.matches('.dropButtonType')) { if (!event.target.matches('.dropButtonDate')) { var dropdowns = document.getElementsByClassName("dropdown-content"); } else { var dropdowns = document.getElementById("myTypeDropdown"); } } if (dropdowns) { for (let i = 0; i < dropdowns.length; i++) { var openDropdown = dropdowns[i]; if (openDropdown.classList.contains('show')) { openDropdown.classList.remove('show'); } } } }) function searchFunction(value) { var input, filter, theTable, tr, td, i, j; input = document.getElementById("myInput"); window.searchValue = value; filter = input.value.toUpperCase(); theTable = document.getElementById("myTable"); tr = window.visibleEntries; if (theTypeFilter.length > 0) { if (value == "allEntries") { for (i = 0; i < tr.length; i++) { var tds = tr[i].getElementsByTagName("td"); txtValue = tds[1].textContent || tds[1].innerText; var flag = false; if (theTypeFilter.includes(txtValue.toLowerCase())) { for (j = 0; j < tds.length; j++){ var td = tds[j]; if (td.innerHTML.toUpperCase().indexOf(filter) > -1) { flag = true; } } } if (flag){ tr[i].style.display = ""; } else { tr[i].style.display = "none"; } } } else if (value == "descriptionEntries") { for (i = 0; i < tr.length; i++) { var tds = tr[i].getElementsByTagName("td"); txtValue = tds[1].textContent || tds[1].innerText; var flag = false; if (theTypeFilter.includes(txtValue.toLowerCase())) { var td = tds[2]; if (td.innerHTML.toUpperCase().indexOf(filter) > -1) { tr[i].style.display = ""; } else { tr[i].style.display = "none"; } } } } } else { for (i = 0; i < tr.length; i++) { tr[i].style.display = "none"; } } } </script> </body> </html> "@ [string]$TheBody = $HTMLBeginning $TheBody = $TheBody + $lineToAdd $TheBody = $TheBody + $HTMLEnd $TheBody | Out-File $Global:HTMLLogPath -Force } function Add-EntryInHTMLLogFile { param ( $theLogToAddInHTML, $description ) [string]$theLineToAdd = " `<tr class=`"filtrableTR`"`> `<td class=`"filtrableTD`"`>$($theLogToAddInHTML.Date)`<`/td`> `<td class=`"filtrableTD`"`>`<i class=`"logtypeentry$($theLogToAddInHTML.Type.ToLower())`"`>$($theLogToAddInHTML.Type)`<`/i`>`<`/td`> `<td class=`"filtrableTD`"`>$description`<`/td`> `<`/tr`> `<`/table`>`<`/div`> " $theHTMLFile = Get-Content $Global:HTMLLogPath -Force $newHTMLFile = $theHTMLFile.Replace("</table></div>",$theLineToAdd) $newHTMLFile | Out-File $Global:HTMLLogPath -Force } function Test-WriteLogWithDummyData { ### Testing single entry with a description that contains an table with one column [System.Collections.ArrayList]$MultipleDescriptionEntries = @() $null = $MultipleDescriptionEntries.Add("First entry") $null = $MultipleDescriptionEntries.Add("Second entry") $null = $MultipleDescriptionEntries.Add("Third entry") $null = $MultipleDescriptionEntries.Add("Fourth entry") Write-Log -Type ERROR -Description $MultipleDescriptionEntries ### Testing multiple entries, that contains string or table with one column Write-Log -Type WARNING -Description "Testing Multiple entries:" -LinkedToNextEntry Write-Log -Description $MultipleDescriptionEntries -ForegroundColor White ### Testing multiple entries, that contains string or table with multiple columns - first entry is string Write-Log -Type WARNING -Description "The list of the first 5 services:" -LinkedToNextEntry Write-Log -Description (Get-Service | select -First 5 Name, Status) -LinkedToNextEntry -KeyEntry Name Write-Log -Description "Dummy text to check if it will be listed as expected" -ForegroundColor Cyan ### Testing single entries, that contains a table with multiple columns Write-Log -Type INFO -Description (Get-PSDrive | select -First 3 Name, @{n="Provider"; e={$_.Provider.ToString()}}, Root) -KeyEntry Name ### Testing multiple entries, that contains string or table with multiple columns - first entry is table Write-Log -Type WARNING -Description (Get-Service | select -First 5 Name, Status) -LinkedToNextEntry -KeyEntry Name Write-Log -Description "Dummy text to check if it will be listed as expected" -ForegroundColor White ### Testing multiple entries, that contains string or table with multiple columns, and ensure the first column in listed table is the selected one (KeyEntry) - first entry is string Write-Log -Type ERROR -Description "The list of the first 5 processes:" -LinkedToNextEntry Write-Log -Description (Get-Process | select -First 5 ProcessName, Id, Handles, SI) -KeyEntry ProcessName ### Testing single entries with a description that contains string Write-Log -Type INFO -Description "An INFO text" Write-Log -Type WARNING -Description "An WARNING text" Write-Log -Type SUCCESS -Description "An SUCCESS text" ### Testing single entries with a description that contains string - NonInteractive, means will not be listed on screen Write-Log -Type INFO -Description "An INFO text, NonInteractive" -Interactive:$false Write-Log -Type WARNING -Description "An WARNING text, NonInteractive" -Interactive:$false Write-Log -Type SUCCESS -Description "An SUCCESS text, NonInteractive" -Interactive:$false ### Testing multiple string entries, that need to list test on the same line, or next line, with different colors Write-Log -Type INFO -Description "Details for " -LinkedToNextEntry Write-Log -Description "DimCry" -ForegroundColor Cyan -SameLineLikePreviousEntry -LinkedToNextEntry Write-Log -Description " user:" -SameLineLikePreviousEntry -LinkedToNextEntry Write-Log -Description "Alias: " -LinkedToNextEntry Write-Log -Description "DimCry" -ForegroundColor Cyan -SameLineLikePreviousEntry ### Testing single entries with a description that contains string Write-Log -Type WARNING -Description "An WARNING text" ### Testing multiple entries, that contains multiple tables with one or multiple columns Write-Log -Type ERROR -Description (Get-Process | select -First 5 ProcessName, Id, Handles, SI) -KeyEntry ProcessName -LinkedToNextEntry Write-Log -Description $MultipleDescriptionEntries -ForegroundColor Cyan } #endregion "Functions" |