Как создать электронное письмо с помощью Powershell, содержащее неизвестные размеры таблиц с цветовыми схемами для конкретного офиса? - PullRequest
1 голос
/ 10 марта 2019

Уважаемые коллеги-программисты,

Я изо всех сил старался найти решение этой проблемы, но в конце концов решил создать учетную запись stackoverflow и попросить о помощи.

Что яя пытаюсь сделать:
1. Получить входные данные из нескольких источников.
2. Поместите эти данные в таблицы и отформатируйте их как «Сетка Таблица 5 Dark Accent 5».
3. Выведите этитаблицы в электронном письме.

С какой проблемой я сталкиваюсь:
- Так как количество столбцов и строк меняется каждый раз, когда я хочу генерировать электронное письмо, кажется, что невозможно получить "Таблица таблицы 5Dark Accent 5 ", который будет применяться ко всем таблицам и при этом выводиться в виде электронного письма.

Что я сделал до сих пор:
1. Я пытался применить css в целомк таблицам, которые работали бы, если бы я знал все столбцы и строки заранее, чего, к сожалению, я не знаю.Я не смог реализовать html-теги TR, но только TH и TD.
2. Я также пытался применить css к каждому фрагменту html (= таблица), используя параметр -CSSUri, но это, по-видимому, недопустимо вкомбинация с параметром фрагмента.

CODE
Код, приведенный ниже, представляет собой пример результата, но вместо простого html css, примененного в начале, следует применять «Сетка Таблица 5 Dark Accent 5»во все таблицы.
Скопируйте и вставьте приведенные ниже фрагменты кода по порядку в IDE Powershell и запустите их целиком.Письмо придет.Вместо общего синего цвета «Таблица 5 Темный Акцент 5» следует применять ко всем таблицам.

Применение универсального стиля ко всем таблицам (вместо этого следует использовать «Сетка Таблица 5 Темный Акцент 5»).):

function table_style {

$style = "<head><style>BODY{font-size: 12pt;}";
$style += "TABLE{border: 3px solid black; border-collapse: collapse; overflow-x:auto;}";
$style += "TH{border: 2px solid black; background: #4472C4; padding: 4px; }";
$style += "TD{border: 2px solid black; padding: 7px; }";
$style += "</style></head>";
return $style;

}

Создание первой таблицы (будет извлекать данные из API):

function Table1_creation {
   $Table = New-Object System.Data.DataTable

   $col1 = New-Object system.Data.DataColumn Table1_Column1,([string]);
   $col2 = New-Object system.Data.DataColumn Table1_Column2,([string]);
   $col3 = New-Object system.Data.DataColumn Table1_Column3,([string]);
   $Table.columns.add($col1);
   $Table.columns.add($col2);
   $Table.columns.add($col3);

   $Tablerows = "Table1_Column1_Row2","Table1_Column1_Row3","Table1_Column1_Row4","Table1_Column1_Row5","Table1_Column1_Row6";

   foreach ($Row in $Tablerows) {
   $row = $Row;
   $Table.rows.add($row) | Out-Null;
   }


   return $Table | Select Table1_Column1, Table1_Column2, Table1_Column3 | ConvertTo-Html -Fragment ;
}

Создание второй таблицы (будетизвлечение данных из API):

function Table2_creation {
   $Table = New-Object System.Data.DataTable

   $col1 = New-Object system.Data.DataColumn Table2_Column1,([string]);
   $col2 = New-Object system.Data.DataColumn Tabl2_Column2,([string]);
   $Table.columns.add($col1);
   $Table.columns.add($col2);

   $Tablerows = "Table2_Column1_Row2","Table2_Column1_Row3","Table2_Column1_Row4";

   foreach ($Row in $Tablerows) {
   $row = $Row;
   $Table.rows.add($row) | Out-Null;
   }


   return $Table | Select Table2_Column1, Tabl2_Column2 | ConvertTo-Html -Fragment;
}

Создание третьей таблицы (получение данных из API):

function Table3_creation {
   $Table = New-Object System.Data.DataTable

   $col1 = New-Object system.Data.DataColumn Table3_Column1,([string]);
   $col2 = New-Object system.Data.DataColumn Table3_Column2,([string]);
   $col3 = New-Object system.Data.DataColumn Table3_Column3,([string]);
   $col4 = New-Object system.Data.DataColumn Table3_Column4,([string]);
   $col5 = New-Object system.Data.DataColumn Table3_Column5,([string]);
   $col6 = New-Object system.Data.DataColumn Table3_Column6,([string]);
   $Table.columns.add($col1);
   $Table.columns.add($col2);
   $Table.columns.add($col3);
   $Table.columns.add($col4);
   $Table.columns.add($col5);
   $Table.columns.add($col6);

   $Tablerows = "Table3_Column1_Row2","Table3_Column1_Row3";

   foreach ($Row in $Tablerows) {
   $row = $Row;
   $Table.rows.add($row) | Out-Null;
   }


   return $Table | Select Table3_Column1, Table3_Column2, Table3_Column3, Table3_Column4, Table3_Column5, Table3_Column6 | ConvertTo-Html -Fragment;
}

Создание xthтаблица с неизвестными столбцами и строками с данными из API:
#Create tables

Создание всех таблиц и добавление заголовков:

function generate_Table1 {
$html = insert_heading "THIS IS TABLE 1";
$html += Table1_creation;
return $html;
}

function generate_Table2 {
$html = insert_heading "THIS IS TABLE 2";
$html += Table2_creation;
return $html;
}

function generate_Table3 {
$html = insert_heading "THIS IS TABLE 3";
$html += Table3_creation;
return $html;
}

Генерация электронной почты:

function generate_Email { 
$mail = $Outlook.CreateItem(0);
$emailHTML = $(table_style);

$emailHTML += if (!$tables) {
    generate_Table1;
    generate_Table2;
    generate_Table3;
} else {
Write-Host -ForegroundColor Red "Error...";
}

Write-Host -ForegroundColor Green "Generating Email...";
$mail.HTMLBody = "$emailHTML";

$inspector = $mail.GetInspector;
$inspector.Display();
}

generate_Email;

Ответы [ 2 ]

1 голос
/ 11 марта 2019

Другой способ - преобразовать HTML в XmlDocument, а затем добавить атрибуты стиля.Используя XPath, вы можете эффективно придать ему стиль.

filter Add-InlineStyle {
    $doc = [xml]$_

    # body
    $doc.SelectNodes("//body").SetAttribute("style", "font-size: 12pt")
    # tables
    $doc.SelectNodes("//table").SetAttribute("style", "font-size: 11pt; border: 2px solid black; border-collapse: collapse; overflow-x: auto")
    # column headers
    $doc.SelectNodes("//th").SetAttribute("style", "border: 0.5px solid white; text-align: center; padding: 0px 5px; font-weight: bold; color: white; background: black")
    # row headers
    $doc.SelectNodes("//td[1]").SetAttribute("style", "border: 0.5px solid white; text-align: center; padding: 0px 5px; font-weight: bold; color: white; background: black")
    # even rows
    $doc.SelectNodes("//tr[position() mod 2 = 0]/td[position() != 1]").SetAttribute("style", "border: 0.5px solid white; text-align: right; padding: 0px 5px; background: #CCCCCC")
    # odd rows
    $doc.SelectNodes("//tr[position() mod 2 = 1]/td[position() != 1]").SetAttribute("style", "border: 0.5px solid white; text-align: right; padding: 0px 5px; background: #999999")

    $doc.OuterXml;
}

Использование ниже.

$data1 = @"
Table1,Column1,Column2
Row1,1,2
Row2,3,4
Row3,5,6
Row4,7,8
Row5,9,10
"@

$data2 = @"
Table2,Column1
Row1,1
Row2,2
Row3,3
"@

$data3 = @"
Table3,Column1,Column2,Column3,Column4,Column5
Row1,1,2,3,4,5
Row2,6,7,8,9,10
"@


$html = @(
    "<html><body>"
    "This is table1"
    $data1 | ConvertFrom-Csv | ConvertTo-Html -Fragment
    "This is table2"
    $data2 | ConvertFrom-Csv | ConvertTo-Html -Fragment
    "This is table3"
    $data3 | ConvertFrom-Csv | ConvertTo-Html -Fragment
    "</body></html>"
) | Out-String | Add-InlineStyle
0 голосов
/ 10 марта 2019

Как прокомментировано, вам нужно сделать гораздо больше стилей, чтобы имитировать стиль таблицы "Grid Table 5 Dark Accent 5" из Word. Поскольку Outlook не обрабатывает рендеринг HTML, как это делает современный браузер, для кода требуется целый ряд встроенных определений стилей.

Поскольку ConvertTo-Html -Fragment не может этого сделать, вам нужно вручную создавать таблицы HTML.

Код ниже делает это с помощью функции ConvertTo-HtmlTable. В качестве параметра он ожидает либо объект System.Data.DataTable, либо массив PSCustomObjects.

# needed for [System.Web.HttpUtility]::HtmlEncode()
Add-Type -AssemblyName System.Web

function ConvertTo-HtmlTable {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [object]$Table
    )
    if ($Table -is [System.Data.DataTable]) {
        # convert to array of PSCustomObjects
        $Table = $Table | Select-Object * -ExcludeProperty ItemArray, Table, RowError, RowState, HasErrors
    }

    # manually build the HTML table
    $tdFirst = '<td style="background: black; color: white; font-weight: bold;">'
    $tdOdd   = '<td style="background: #999999;">'
    $tdEven  = '<td style="background: #CCCCCC;">'

    # add the headers row
    $headers = @($Table[0].PSObject.Properties | Select -ExpandProperty Name)
    $tbl = New-Object -TypeName System.Text.StringBuilder
    [void]$tbl.Append('<table><thead><tr>')
    foreach ($col in $headers) {
        [void]$tbl.Append("<th>$col</th>")
    }
    [void]$tbl.Append('</tr></thead><tbody>')
    # next add the data rows
    $row = 0
    $Table | ForEach-Object {
        [void]$tbl.AppendLine('<tr>')
        for ($col = 0; $col -lt $headers.Count; $col++) {
            [string]$val =$_.$($headers[$col])
            $td = if ($col -eq 0) { $tdFirst } elseif ($row -band 1) { $tdOdd } else { $tdEven }
            [void]$tbl.Append($td)
            $data = if ([string]::IsNullOrWhiteSpace($val)) { '&nbsp;' } else { [System.Web.HttpUtility]::HtmlEncode($val) }
            [void]$tbl.AppendLine("$data</td>")
        }
        [void]$tbl.AppendLine('</tr>')
        $row++
    }
    [void]$tbl.Append('</tbody></table>')

    return $tbl.ToString()
}

Теперь, когда у нас есть эта функция, вы можете использовать ее в своих TableX_creation функциях, подобных этой:

function Table1_creation {
    $Table = New-Object System.Data.DataTable

    $col1 = New-Object system.Data.DataColumn Table1_Column1,([string])
    $col2 = New-Object system.Data.DataColumn Table1_Column2,([string])
    $col3 = New-Object system.Data.DataColumn Table1_Column3,([string])
    $Table.columns.add($col1)
    $Table.columns.add($col2)
    $Table.columns.add($col3)

    $Tablerows = "Table1_Column1_Row2","Table1_Column1_Row3","Table1_Column1_Row4","Table1_Column1_Row5","Table1_Column1_Row6"

    foreach ($row in $Tablerows) {
        $Table.Rows.Add($row) | Out-Null
    }

    $result = ConvertTo-HtmlTable $Table
    $Table.Dispose()

    return $result
}

function Table2_creation {
    $Table = New-Object System.Data.DataTable

    $col1 = New-Object system.Data.DataColumn Table2_Column1,([string])
    $col2 = New-Object system.Data.DataColumn Tabl2_Column2,([string])
    $Table.columns.add($col1)
    $Table.columns.add($col2)

    $Tablerows = "Table2_Column1_Row2","Table2_Column1_Row3","Table2_Column1_Row4"

    foreach ($Row in $Tablerows) {
        $Table.Rows.Add($row) | Out-Null
    }

    $result = ConvertTo-HtmlTable $Table
    $Table.Dispose()

    return $result
}

function Table3_creation {
    $Table = New-Object System.Data.DataTable

    $col1 = New-Object system.Data.DataColumn Table3_Column1,([string])
    $col2 = New-Object system.Data.DataColumn Table3_Column2,([string])
    $col3 = New-Object system.Data.DataColumn Table3_Column3,([string])
    $col4 = New-Object system.Data.DataColumn Table3_Column4,([string])
    $col5 = New-Object system.Data.DataColumn Table3_Column5,([string])
    $col6 = New-Object system.Data.DataColumn Table3_Column6,([string])
    $Table.columns.add($col1)
    $Table.columns.add($col2)
    $Table.columns.add($col3)
    $Table.columns.add($col4)
    $Table.columns.add($col5)
    $Table.columns.add($col6)

    $Tablerows = "Table3_Column1_Row2","Table3_Column1_Row3"
    foreach ($Row in $Tablerows) {
        $Table.Rows.Add($row) | Out-Null
    }

    $result = ConvertTo-HtmlTable $Table
    $Table.Dispose()

    return $result
}

Затем я сделал функцию, чтобы соединить все эти фрагменты HTML:

function Generate_Html { 
    Write-Host -ForegroundColor Green "Generating Email Body..."

    # main style settings mimicing "Grid Table 5 Dark Accent 5"
    $style = @'
<head>
    <style>
    BODY  { font-size: 12pt; font-family: calibri, Arial, Helvetica, sans-serif; }
    TABLE { font-size: 11pt; font-family: calibri, Arial, Helvetica, sans-serif; 
            border: 0.5px solid white; border-collapse: collapse; overflow-x:auto; color: white; width: auto; }
    TH    { border: none;background: black; padding: 0 8px 0 8px; font-weight: bold; text-align: left; }
    TD    { border: 0.5px solid white; padding: 0 8px 0 8px; color: black; text-align: left; }
    </style>
</head>
'@

    $sb = New-Object -TypeName System.Text.StringBuilder
    [void]$sb.AppendLine("<html>")
    [void]$sb.AppendLine($style)
    [void]$sb.AppendLine("<body>")
    if (!$tables) {
        [void]$sb.AppendLine('<h3>THIS IS TABLE 1</h3>')
        [void]$sb.AppendLine((Table1_creation))
        [void]$sb.AppendLine('<h3>THIS IS TABLE 2</h3>')
        [void]$sb.AppendLine((Table2_creation))
        [void]$sb.AppendLine('<h3>THIS IS TABLE 3</h3>')
        [void]$sb.AppendLine((Table3_creation))
    } 
    else {
        Write-Host -ForegroundColor Red "Error...";
    }
    [void]$sb.AppendLine("</body></html>")

    return $sb.ToString()
}

Итак, в конце вы делаете такие вещи в Outlook, как это:

# I'm guessing you create your `$Outlook` variable sort of like below
if(([System.Diagnostics.Process]::GetProcessesByName("OUTLOOK")).length -gt 0){
    $Outlook = [Runtime.InteropServices.Marshal]::GetActiveObject("Outlook.Application")
}
else {
    $Outlook = New-Object -comObject Outlook.Application
}

$mail = $Outlook.CreateItem(0)
$mail.HTMLBody = Generate_Html
$inspector = $mail.GetInspector
$inspector.Display()

Окончательный результат должен выглядеть следующим образом:

HTML tables

...