How can i add new row to com HTML object powershell - html

I have a table where i'm trying to add more rows with powershell then export it as a new HTML file.
Here's the body of the HTML i'm trying to add rows to.
<BODY>
<TABLE style="WIDTH: 100%" cellPadding=5>
<TBODY>
<TR>
<TH>Bruger</TH>
<TH>Windows</TH>
<TH>Installations dato</TH>
<TH>Model</TH>
<TH>Sidst slukket</TH></TR>
<TR>
<TD>Users name</TD>
<TD>Windows 10 Pro</TD>
<TD>23-01-2020</TD>
<TD>ThinkPad</TD>
<TD>7 dage</TD></TR></TBODY></TABLE>
<TABLE>
<TBODY></TBODY></TABLE></BODY>
I figured i'd need to change the inner html of an object but it's just throwing an error.
Here's my code
$src = [IO.File]::ReadAllText($outPath)
$doc = New-Object -com "HTMLFILE"
$doc.IHTMLDocument2_write($src)
$elm = $doc.getElementsByTagName('tr')[0]
$elm.innerHTML = "<TR>New row!</TR>"
When I check the inner html variable I get the HTML output that I would expect, so it's grabbing the correct object, but I can't assign anything to it for whatever reason.
Here's the error
Exception from HRESULT: 0x800A0258
At line:1 char:1
+ $elm.innerHTML = "<TH>User</TH>"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException

Instead of modifying the innerHTML contents of an existing <tr> element, you'll want to:
Create a new <tr> element
Create any requisite <td> child element(s)
Append <td> element(s) to your new row
Append the new row to the existing <tbody>
Try something like this:
$html = #'
<BODY>
<TABLE style="WIDTH: 100%" cellPadding=5>
<TBODY>
<TR>
<TH>Bruger</TH>
<TH>Windows</TH>
<TH>Installations dato</TH>
<TH>Model</TH>
<TH>Sidst slukket</TH></TR>
<TR>
<TD>Users name</TD>
<TD>Windows 10 Pro</TD>
<TD>23-01-2020</TD>
<TD>ThinkPad</TD>
<TD>7 dage</TD></TR></TBODY></TABLE>
<TABLE>
<TBODY></TBODY></TABLE></BODY>
'#
# Create HTML document object
$doc = New-Object -ComObject HTMLFile
# Load existing HTML
$doc.IHTMLDocument2_write($html)
# Create new row element
$newRow = $doc.createElement('tr')
# Create new cell element
$newCell = $doc.createElement('td')
$newCell.innerHTML = "New row!"
$newCell.colSpan = 5
# Append cell to row
$newRow.appendChild($newCell)
# Append row to table body
$tbody = $doc.getElementsByTagName('tbody')[0]
$tbody.appendChild($newRow)
# Inspect resulting HTML
$tbody.outerHtml
You should expect to see the new row appended to the table body:
<TBODY><TR>
<TH>Bruger</TH>
<TH>Windows</TH>
<TH>Installations dato</TH>
<TH>Model</TH>
<TH>Sidst slukket</TH></TR>
<TR>
<TD>Users name</TD>
<TD>Windows 10 Pro</TD>
<TD>23-01-2020</TD>
<TD>ThinkPad</TD>
<TD>7 dage</TD></TR>
<TR>
<TD colSpan=5>New row!</TD></TR></TBODY>
You could create a nice little helper function for adding new rows:
function New-HTMLFileTableRow {
param(
[Parameter(Mandatory)]
[mshtml.HTMLDocumentClass]$Document,
[Parameter(Mandatory)]
[string[]]$Property,
[Parameter(Mandatory, ValueFromPipeline)]
$InputObject
)
process {
$newRow = $Document.createElement('tr')
foreach($propName in $Property){
$newCell = $Document.createElement('td')
$newCell.innerHtml = $InputObject.$propName
[void]$newRow.appendChild($newCell)
}
return $newRow
}
}
Then use like:
Import-Csv .\path\to\user-os-list.csv |New-HTMLFileTableRow -Property User,OSVersion,InstallDate,Model,LastActive -Document $doc |ForEach-Object {
[void]$tbody.appendChild($_)
}

Related

Insert Data from CSV to HTML table using powershell

I am new to powershell and I want to insert the data from csv to html table which is I create separately. This is my csv
Sitename EmailAddress
Test example#gmail.com
Asking for help of how should I insert this data to my html table and then if I add data in csv it also automatically added on HTML table.
test.ps1 script
$kfxteam = Get-Content ('.\template\teamnotif.html')
$notifteam = '' #result html
$teamlist = Import-Csv ".\list\teamlist.csv" | select 'SiteName','EmailAddress'
For($a=0; $a -lt $kfxteam.Length; $a++) {
# If the "<table class=content>" matches on what written on $kfxteam it will show the result`
if($kfxteam -match "<table class=content >"){
# should be replacing the data came from csv to html and also adding new row
write-host $teamlist[$a].SiteName
}
}
html format
<<table class=content >
<td class=c1 nowrap>
Remote Sitenames
</td>
<td class=c1 nowrap >
Users Email Address
</td>
</tr>
<tr>
<td class=c1 nowrap>
usitename
</td>
<td class=c1 nowrap>
[uemail]
</td>
</tr>
</table>
The output html table should be
Remote Sitenames Email Address
Test example#gmail.com
If I were you, I'd change the HTML template file regarding the table to become something like this:
<table class=content>
<tr>
<td class=c1 nowrap>Remote Sitenames</td>
<td class=c1 nowrap>Users Email Address</td>
</tr>
##TABLEROWSHERE##
</table>
Now, you have a placeholder which you can replace with the table rows you create using the CSV file like:
# create a template for each of the rows to insert
# with two placeholders to fill in using the -f Format operator
$row = #"
<tr>
<td class=c1 nowrap>{0}</td>
<td class=c1 nowrap>{1}</td>
</tr>
"#
# import the csv, loop over the records and use the $row template to create the table rows
$tableRows = Import-Csv -Path '.\list\teamlist.csv' | ForEach-Object {
$row -f $_.Sitename, $_.EmailAddress
}
# then combine it all in the html
$result = (Get-Content -Path '.\template\teamnotif.html' -Raw) -replace '##TABLEROWSHERE##', ($tableRows -join [Environment]::NewLine)
# save the completed HTML
$result | Set-Content -Path '.\list\teamlist.html'

Creating HTML Table in AngularJS

var str1 = "Sarah";
var str2 = "Tom";
var strTable = "<table style='width:100%'><tr><th>"+ str1 +"</th><th>"+ str2 +"</th> <th>Age</th> </tr> <tr> <td>Jill</td><td>Smith</td><td>50</td></tr></table>";
$scope.rTable= strTable;
I am trying to pass HTML code in $Scope.rTable but instead of rendering the table it shows the HTML code as it is in the output.
i.e.
<table style='width:100%'><tr><th>Sarah</th><th>Tom</th> <th>Age</th> </tr> <tr> <td>Jill</td><td>Smith</td><td>50</td></tr></table>
I want it like:
Its a improper way to code.
The code should be like
In Controller
$scope.str1 = "Sarah";
$scope.str2 = "Tom";
In HTML
Considering your controller name as DemoController
<body ng-controller="DemoController">
<table style='width:100%'>
<tr><th> {{str1}} </th>
<th> {{str2}} </th>
<th>Age</th>
</tr>
</table>
</body>
And if your data is huge its recommended to use an Array of Object with ng-repeat. you can read it here -> https://docs.angularjs.org/api/ng/directive/ngRepeat
Use ng-bind-html and $sce.
Controller
app.controller('MainCtrl', function($scope, $sce) {
var str1 = "Sarah";
var str2 = "Tom";
var strTable = "<table style='width:100%'><tr><th>" + str1 + "</th><th>" + str2 + "</th> <th>Age</th> </tr> <tr> <td>Jill</td><td>Smith</td><td>50</td></tr></table>";
$scope.rTable = $sce.trustAsHtml(strTable);
});
HTML
<body ng-controller="MainCtrl">
<div ng-bind-html="rTable"></div>
</body>

TreeBuilder Get embedded nodes

Basically, I need to get the names and emails from all of these people in the HTML code.
<thead>
<tr>
<th scope="col" class="rgHeader" style="text-align:center;">Name</th><th scope="col" class="rgHeader" style="text-align:center;">Email Address</th><th scope="col" class="rgHeader" style="text-align:center;">School Phone</th>
</tr>
</thead><tbody>
<tr class="rgRow" id="ctl00_ContentPlaceHolder1_rg_People_ctl00__0">
<td>
Michael Bowen
</td><td>mbowen#cpcisd.net</td><td>903-488-3671 ext3200</td>
</tr><tr class="rgAltRow" id="ctl00_ContentPlaceHolder1_rg_People_ctl00__1">
<td>
Christian Calixto
</td><td>calixtoc#cpcisd.net</td><td>903-488-3671 x 3430</td>
</tr><tr class="rgRow" id="ctl00_ContentPlaceHolder1_rg_People_ctl00__2">
<td>
Rachel Claxton
</td><td>claxtonr#cpcisd.net</td><td>903-488-3671 x 3450</td>
</tr>
</tbody>
</table><input id="ctl00_ContentPlaceHolder1_rg_People_ClientState" name="ctl00_ContentPlaceHolder1_rg_People_ClientState" type="hidden" autocomplete="off"> </div>
<br>
I know how to use treebuilder with the nodes and such, and I'm using this code in some of my script.
my ($file) = #_;
my $html = path($file)-> slurp;
my $tree = HTML::TreeBuilder->new_from_content($html);
my #nodes = $tree->look_down(_tag => 'input');
my $val;
foreach my $node (#nodes) {
$val = $node->look_down('name', qr/\$txt_Website/)->attr('value');
}
return $val;
I was going to use the same code for this function, but I realized that I don't have much to search for, since the <td> tag is in so many other places in the script. I'm sure there's a better way to approach this problem, but I can't seem to find it.
LINK TO HTML CODE: http://pastebin.com/qLwu80ZW
MY CODE: https://pastebin.com/wGb0eXmM
Note: I did look on google as much as possible, but I'm not quite sure what I should search for.
The table element that encloses the data you need has a unique class rgMasterTable so you can search for that in look_down
I've written this to demonstrate. It pulls the HTML directly from your pastebin
use strict;
use warnings 'all';
use LWP::Simple 'get';
use HTML::TreeBuilder;
use constant URL => 'http://pastebin.com/raw/qLwu80ZW';
my $tree = HTML::TreeBuilder->new_from_content(get URL);
my ($table) = $tree->look_down(_tag => 'table', class => 'rgMasterTable');
for my $tr ( $table->look_down(_tag => 'tr') ) {
next unless my #td = $tr->look_down(_tag => 'td');
my ($name, $email) = map { $_->as_trimmed_text } #td[0,1];
printf "%-17s %s\n", $name, $email;
}
output
Michael Bowen mbowen#cpcisd.net
Christian Calixto calixtoc#cpcisd.net
Rachel Claxton claxtonr#cpcisd.net

html wont render using ng-bind-html-unsafe

i was able to break string to chars array and surround each char in <span></span> but when im trying to pass this array to table the html wont render.
breaking the string:
//parse cron_format and edit each digit individually
$scope.parse = function (cron_format){
var parsed = cron_format.split('');
for(var i = 0; i < parsed.length; i++) {
parsed[i] = '<span>' + parsed[i] + '</span>';
}
return parsed;
}
when i try to create the table like this:
<table class="table table-bordered table-hover">
<thead>
<td>user name</td>
<td>script name</td>
<td>cron format</td>
</thead>
<tbody ng-repeat="(user_id,script_id) in data | filter: test">
<tr ng-repeat="(script_id, cron_format) in script_id">
<td>{{user(user_id)}}</td>
<td>{{script(script_id)}}</td>
<td ng-bind-html-unsafe="{{parse(cron_format)}}"></td>
</tr>
</tbody>
</table>
there are no values in cron_format:
without trying to render -> <td>{{parse(cron_format)}}</td>
the table looks like this:
what am i doing wrong?
UPDATE:
i changed function's two last rows :
$scope.parsed.htmlSafe = $sce.trustAsHtml(parsed.html);
return parsed;
and i get this error:
Can't interpolate: {{parse(cron_format)}}
TypeError: Cannot set property 'htmlSafe' of undefined
can someone explain whats the mistake im doing here?

Webscraping In powershell monitor page

I want to be able to monitor my printers status web page and have a script email me when the ink level falls below 25%. Im pretty sure this can be done in Powershell, but Im at a loss on how to do it.
This is the page HTML in question:
<h2>Supply Status</h2>
<table class="matrix">
<thead>
<tr>
<th>Supply Information</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Black Toner</td>
<td>End of life</td>
</tr>
<tr>
<td>Cyan Toner</td>
<td>Under 25%</td>
</tr>
<tr>
<td>Magenta Toner</td>
<td>Under 25%</td>
</tr>
<tr>
<td>Yellow Toner</td>
<td>Under 25%</td>
</tr>
</tbody>
</table>
<p>
Thanks.
Adam
Building on #Joey's answer, give this a whirl with the HTML Agility Pack.
$html = new-object HtmlAgilityPack.HtmlDocument
$result = $html.Load("http://full/path/to/file.htm")
$colors = $html.DocumentNode.SelectNodes("//table[#class='matrix']//tbody/tr")
$result = $colors | % {
$color = $_.SelectSingleNode("td[1]").InnerText
$level = $_.SelectSingleNode("td[2]").InnerText
new-object PsObject -Property #{ Color = $color; Level = $level; } |
Select Color,Level
}
$result | Sort Level | ft -a
This assumes you already have the HTML Agility Pack loaded into PowerShell. Mine is loaded in my profile as:
[System.Reflection.Assembly]::LoadFrom(
(join-path $profileDirectory HtmlAgilityPack)
+ "\HtmlAgilityPack.dll" ) | Out-Null
Using the example HTML provided, your output looks like:
At this point, you have the output and can email it out.
The easiest way would probably be the HTML Agility Pack which you can import in PowerShell. Lee Holmes has a short article demonstrating a simple example with it. Essentially you're using an XML-like API to access the HTML DOM.