jdhitsolutions / PSScriptTools

:wrench: :hammer: A set of PowerShell functions you might use to enhance your own functions and scripts or to facilitate working in the console. Most should work in both Windows PowerShell and PowerShell 7, even cross-platform. Any operating system limitations should be handled on a per command basis. The Samples folder contains demonstration script files
MIT License
875 stars 110 forks source link

ConvertTo-Markdown -AsTable processing of some characters seems to prematurely end the table #97

Closed mdcaddic closed 3 years ago

mdcaddic commented 3 years ago

Describe the bug A clear and concise description of what the bug is.

To Reproduce Steps to reproduce the behavior:

  1. Connect to ExchangeOnline
  2. $rules = Get-TransportRule
  3. $rules | Select-Object Name, Priority, Description | ConvertTo-Markdown -AsTable | Out-File -Encoding utf8 rules.md
  4. View output in vscode

Expected behavior Complete table.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Additional context This is the output from the convertto-markdown

Name Priority Description
Block executable content 0 If the message:
includes an attachment with executable content
Take the following actions: reject the message and include the explanation 'The email contains an attachment that is not allowed' with the status code: '5.7.1' Block External Forwarding 1 If the message: Is sent to 'Outside the organization' and Is message type 'Auto-forward' and Is received from 'Inside the organization' Take the following actions: reject the message and include the explanation 'AutoForward to External Recipients is not allowed' with the status code: '5.7.1'
encrypt_external_emails 2 If the message:
Is sent to 'Outside the organization'

Take the following actions: rights protect message with RMS template: 'Encrypt' |

jdhitsolutions commented 3 years ago

Can you export a sample rule using Export-Clixml and copy and paste the XML here? I can then import that rule and test. But I'm guessing there is an issue with the apostrophes and/or colons.

jdhitsolutions commented 3 years ago

You might need to modify the Width. The default is 80. Try ConvertTo-Markdown with something like -width 150.

jdhitsolutions commented 3 years ago

I think you need to adjust the output of the command before you convert and/or extend the width. I think that's why you are seeing things cut off. I had to make a number of adjustments to get this to work:

get-netfirewallrule | select -first 10 -Property Name,description,enabled,group | Format-List -Group Name -property Description,Enabled,Group | ConvertTo-Markdown -Title "FireWall Rules" -PreContent "This is from the localhost" -width 100 | out-file c:\work\fw.md -Encoding utf8
jdhitsolutions commented 3 years ago

I was able to re-construct your problem. The issue is that the description has returns. And this is only an issue when creating a table I may have to see about changing

If the message:
    Is sent to 'Outside the organization'
    And Is message type 'Auto-forward'
    And Is received from 'Inside the organization'
    Take the following actions:
    reject the message and include the explanation 'AutoForward to External Recipients is not allowed' with the status code: '5.7.1'

to this


If the message:\n    Is sent to 'Outside the organization'\n    And Is message type 'Auto-forward'\n    And Is received from 'Inside the organization'\n    Take the following actions:\n    reject the message and include the explanation 'AutoForward to External Recipients is not allowed' with the status code: '5.7.1'
```. 
jdhitsolutions commented 3 years ago

I might be on to something. If I replace line returns with <br> this seems to work.


# My result

| Name | Priority | Description |
| ---- | -------- | ----------- |
| block executable content | 0 | If the message:includes an attachment with executable content Take the following actions:reject the message and include the explanation 'The email contains an attachment that is not allowed' with the status code: '5.7.1' |
| block external forwarding | 1 | If the message:<br>    Is sent to 'Outside the organization'<br>    And Is message type 'Auto-forward'<br>    And Is received from 'Inside the organization'<br>    Take the following actions:<br>    reject the message and include the explanation 'AutoForward to External Recipients is not allowed' with the status code: '5.7.1' |

My result

Name Priority Description
block executable content 0 If the message:includes an attachment with executable content Take the following actions:reject the message and include the explanation 'The email contains an attachment that is not allowed' with the status code: '5.7.1'
block external forwarding 1 If the message:
Is sent to 'Outside the organization'
And Is message type 'Auto-forward'
And Is received from 'Inside the organization'
Take the following actions:
reject the message and include the explanation 'AutoForward to External Recipients is not allowed' with the status code: '5.7.1'

The first row is my test with the line breaks removed.

jdhitsolutions commented 3 years ago

I think I have this working. Copy and save this version of the function. Then test it with your data and let me know. The function has a different name to avoid conflicts.

Function ConvertTo-MDTest {

[cmdletbinding()]
    [outputtype([string[]])]
    [alias('ctm')]

    Param(
        [Parameter(Position = 0, ValueFromPipeline)]
        [object]$Inputobject,
        [Parameter()]
        [string]$Title,
        [string[]]$PreContent,
        [string[]]$PostContent,
        [ValidateScript( {$_ -ge 10})]
        [int]$Width = 80,
        #display results as a markdown table
        [switch]$AsTable
    )

    Begin {
        Write-Verbose "[BEGIN  ] Starting $($myinvocation.MyCommand)"
        #initialize an array to hold incoming data
        $data = @()

        #initialize an empty here string for markdown text
        $Text = @"

"@
        If ($title) {
            Write-Verbose "[BEGIN  ] Adding Title: $Title"
            $Text += "# $Title`n`n"
        }
        If ($precontent) {
            Write-Verbose "[BEGIN  ] Adding Precontent"
            $Text += $precontent
            $text += "`n`n"
        }

    } #begin
    Process {
        #add incoming objects to data array
        Write-Verbose "[PROCESS] Adding processed object"
        $data += $Inputobject

    } #process
    End {
        #add the data to the text
        if ($data) {
            if ($AsTable) {
                Write-Verbose "[END    ] Formatting as a table"
                $names = $data[0].psobject.Properties.name
                $head = "| $($names -join " | ") |"
                $text += $head
                $text += "`n"

                $bars = "| $(($names -replace '.','-') -join " | ") |"

                $text += $bars
                $text += "`n"

                foreach ($item in $data) {
                    $line = "| "
                    $values = @()
                    for ($i = 0; $i -lt $names.count; $i++) {

                        #if an item value contains return and new line replace them with <br> Issue #97
                        if ($item.($names[$i]) -match "`n") {
                            Write-Verbose "[END    ] Replacing line returns for property $($names[$i])"
                            [string]$val = $($item.($names[$i])).replace("`r`n","<br>") -join ""
                            Write-Verbose $val
                        }
                        else {
                            [string]$val = $item.($names[$i])
                        }

                        $values += $val
                    }
                    $line += $values -join " | "
                    $line += " |"
                    $text += $line
                    $text += "`r"
                }
            }
            else {
                #convert data to strings and trim each line
                Write-Verbose "[END    ] Converting data to strings"
                [string]$trimmed = (($data | Out-String -Width $width).split("`n")).ForEach({ "$($_.trim())`n" })
                Write-Verbose "[END    ] Adding to markdown"
                $clean = $($trimmed.trimend())
                $text += @"
``````text
$clean

"@

        } #else as text
    } #if $data
    If ($postcontent) {
        Write-Verbose "[END    ] Adding postcontent"
        $text += "`n"
        $text += $postcontent
    }

    #write the markdown to the pipeline
    $text.TrimEnd()
    Write-Verbose "[END    ] Ending $($myinvocation.MyCommand)"
} #end

}

mdcaddic commented 3 years ago

Haven't forgotten. Seems to work to produce standard markdown but that doesn't convert neatly using pandoc. I'll keep working on it. Converting the new markdown using pandoc results in tables with a single row

jdhitsolutions commented 3 years ago

I got your issues mixed up. From all of my testing this works. Although, if you want to upload a clixml file as I suggested earlier I can test with that. LIke the caption issue, you may need to come up with your own version of this function too create Pandoc-compatible output.

jdhitsolutions commented 3 years ago

A new version of this command has been released in v2.33.0 of the module.