Break lines in powershell array and then convert it to html? - powershell

I swear I've been searching a lot and still haven't found any solution to this thing.
What I do is basically converting arrays to HTML but I can't find any way to break the words of the array in new lines.
For example:
$Member.ExpireOn=((Invoke-SqliteQuery -SQLiteConnection $C -Query "SELECT expireon FROM exceptions_test WHERE (identity='$User')").ExpireOn -join "`r`n")
$Member.ExpireOn is basically this:
31/01/2019 00:00:00 31/03/2019 00:00:00 31/03/2019 00:00:00
so even if I join it with -join "rn" or with <br> I can't find any way to have a line for each element in the array.
I need to do it because after that I print the whole array in a HTML file and this is what I get:
instead of having a <br> between those words.
Hopefully somebody can help me :)

even if I join it with -join "`r`n"
Whitespace in HTML is insignificant, so you cannot force line breaks this way; they will show in the HTML markup (source code), but not when rendered.
or with <br>
The problem is that ConvertTo-Html - which I assume you're using - escapes any HTML markup in the input objects' property values (it assumes you want to use the values verbatim), so you cannot pass <br> through in order to make a single table cell use multiple line - you'll see literal <br> strings in the table, because ConvertTo-Html has escaped them as <br>.
A quick and dirty workaround would be to manually convert the escaped <br> elements back to their HTML form:
# Sample input objects
$o = [pscustomobject] #{
Foo = 'Cert A'
# Join the array elements with <br>
ExpireOn = (Get-Date), (Get-date).AddDays(1) -join '<br>'
}, [pscustomobject] #{
Foo = 'Cert B'
ExpireOn = (Get-Date).AddDays(2), (Get-date).AddDays(3) -join '<br>'
}
# Convert *escaped* <br> elements back to literal '<br>'
# NOTE: This will replace *all* instances of '<br>' in the
# document text, wherever it may occur.
($o | ConvertTo-Html) -replace '<br>', '<br>'
This yields the following, showing that the <br> was effectively passed through, which should make the input date values render on individual lines:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTML TABLE</title>
</head><body>
<table>
<colgroup><col/><col/></colgroup>
<tr><th>Foo</th><th>ExpireOn</th></tr>
<!-- Note the <br> elements -->
<tr><td>Cert A</td><td>2/5/2020 12:51:45 PM<br>2/6/2020 12:51:45 PM</td></tr>
<tr><td>Cert B</td><td>2/7/2020 12:51:45 PM<br>2/8/2020 12:51:45 PM</td></tr>
</table>
</body></html>
In Chrome on my Mac, this renders as follows:
If you need a more robust solution, you'll have to use an HTML parser - see this answer.

Related

Creating correct SHA256 hash in Powershell

Good evening everybody. I have a problem with sha256 Hash.
I have this example string from the amazon pages:
GET
/
Action=ListUsers&Version=2010-05-08
content-type:application/x-www-form-urlencoded; charset=utf-8
host:iam.amazonaws.com
x-amz-date:20150830T123600Z
content-type;host;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Amazon shows the hash result of this example string
as the following:
**f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59**
The description is: this one: The hashed canonical request must be represented as a string of lowercase hexadecimal characters. The following example shows the result of using SHA-256 to hash the example canonical request.
Example Hashed canonical request
No matter what i do, i receive this hash:
B51325A14138B31939381CB391819CE8A5F09DEEA778721C4360F0DAC1FAB79C
Here are 3 example codes:
function hash($request) {
$sha256 = new-object -TypeName System.Security.Cryptography.SHA256Managed
$utf8 = new-object -TypeName System.Text.UTF8Encoding
$hash = [System.BitConverter]::ToString($sha256.ComputeHash($utf8.GetBytes($request)))
return $hash.replace('-','').toLower()
}
function hash2($request){
$mystream = [IO.MemoryStream]::new([byte[]][char[]]$request)
$hash = Get-FileHash -InputStream $mystream -Algorithm SHA256
$hash = $hash.Hash
return $hash.toLower()
}
function hash3($request)
{
$hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
$hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($request))
$hashString = [System.BitConverter]::ToString($hash)
$hash = $hashString.Replace('-', '')
return $hash.toLower()
}
$string = "GET
/
Action=ListUsers&Version=2010-05-08
content-type:application/x-www-form-urlencoded; charset=utf-8
host:iam.amazonaws.com
x-amz-date:20150830T123600Z
content-type;host;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
hash $string
hash2 $string
hash3 $string
The only online calculator i found which calculates the same hash as amazon was this one: https://xorbin.com/tools/sha256-hash-calculator
Here is the original conent from amazon: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
Can anyone help, please?
Best regards
Patrick
At first I couldn't reproduce this behavior by copy-pasting your code. Then I pasted it into an editor configured to save all linebreaks as CRLF - at which point I also got B51325A14138B31939381CB391819CE8A5F09DEEA778721C4360F0DAC1FAB79C.
So the likely explanation is that you wrote your script in an editor that saves all files with Windows-style line breaks.
You can work around this by replacing all Windows style linebreaks in the resulting string value with a single newline character at runtime:
hash $string.Replace("`r`n", "`n")
To complement Mathias R. Jessen's helpful answer:
It is the newline format (Windows CRLF vs. Unix LF) of the enclosing script file (.ps1) that determines the newline format of multiline string literals contained in the script (including here-string literals).
An alternative to explicitly replacing the CRLF sequences with LFs, as shown in Mathias' answer, is to re-save your .ps1 file with LF newlines (PowerShell won't mind).
For better cross-platform compatibility, consider configuring your editor to create LF-format PowerShell scripts by default.

Get NodeSet Size in XML::XPath

I have a XML i want to get the size of node set in the XML.
XML
<a>
<b>
<c>data</c>
<c>data</c>
<c>data</c>
</b>
</a>
I want to get the count c in the b tag.
my $obj = XML::XPath->new(xml => $xml);
print size(($obj->find('/a/b'));
I am not able to get the count of c in this XML
size is a method, not a function. Also, your XPath expression matches the b node, not its children.
The following works:
my $cs = $obj->find('/a/b/c');
print $cs->size, "\n";
Or, shorter, without the intermediate variable:
print $obj->find('/a/b/c')->size, "\n";

How can I generate and send an email in HTML format using data from a text file?

I have a file that looks like this:
cat output_title.txt
C817491287 Cat: Nor Sus: something date: 02/26/14
C858151287 Cat: Nor Sus: really something date: 02/26/14
I would like to send an email in HTML format, using parameters from the file, e.g.
mine :firstparamter starting with C
sus: ?
date: ?
How can I do this?
EDIT: CODE
open (FILE, 'output_title.txt');
while (<FILE>) {
chomp;
($chg, $Cat, $category, $sta, $stus, $sus, $open, $open_date) = split(" ");
print "Chnge is:$chg\n";
}
After doncoyote comments :
use strict;
use warnings;
open (FILE, 'output_title.txt');
while (<FILE>) {
my ($Cnum,$Cat,$Sus,$Date) = m!(C\d{9})\s+Cat:\s+(\w+)\s+Sus:\s([\w\s]*?)date:\s+([\d/]+)$! ;
print "Cnum:$Cnum\t";
print "Caty:$Cat\t";
print "Stus:$Sus\t";
print "opendate:$Date\n";
}
close (FILE); exit;
You may find a regex pattern capture to define the required variables works better than split, when there are slight but quantifiable differences in the extraction text.
something like this should handle the cases provided. This could be improved but makes an ok starting point of the top of my head.
my ( $Cnum, $Cat, $Sus, $Date )
= m!(C\d{9})\s+Cat:\s+(\w+)\s+Sus:\s([\w\s]*?)date:\s+([\d/]+)$!
You should start to look into regexes in the perlretut documentation to understand what is going on. Basically the escaped letters w,d,s stand for word digit and non-printable character(spaces,tabs) respectively. The Parentheses capture the pattern and pass those as a list to the assignment variables. The square brackets define a multiple choice of characters.
Quantifiers: + is one or more, * is zero or more, and curly braces is the comma separated specified min/max. Each of the character they immediately follow. The question mark is a non-greedy * and the $ is the end of line anchor.
I'm pretty sure there are several methods to send html-mails from perl.
For example:
use MIME::Lite;
my $msg = MIME::Lite->new(
From => from_you#somedomain.com,
To => to_someone_else#someotherdomain.com,
Subject => "your mail subject",
Type => 'text/html',
Data => qq {
<body>
<table>
<tr> <td>$chg</td><td>$Cat</td>.....</tr>
</table>
</body>
},
);
$msg->send();

Parsing HTML with Mojolicious User Agent

I have html something like this
<h1>My heading</h1>
<p class="class1">
<strong>SOMETHING</strong> INTERESTING (maybe not).
</p>
<div class="mydiv">
<p class="class2">
interesting link </p>
<h2>Some other heading</h2>
The content between h1 and h2 varies - I know I can use css selectors in Mojo::Dom to, say, select the content of h1 or h2, or p tags - but how to select everything between h1 and h2? Or more generally, everything between any two given sets of tags?
It's pretty straightforward. You can just select all interesting elements in a Mojo::Collection object (this is what Mojo::DOM's children method does for example) and do some kind of a state-machine like match while iterating over that collection.
Probably the most magic way to do this
is to use Perl's range operator .. in scalar context:
In scalar context, ".." returns a boolean value. The operator is bistable, like a flip-flop, and emulates the line-range (comma) operator of sed, awk, and various editors. Each ".." operator maintains its own boolean state, even across calls to a subroutine that contains it. It is false as long as its left operand is false. Once the left operand is true, the range operator stays true until the right operand is true, AFTER which the range operator becomes false again. It doesn't become false till the next time the range operator is evaluated.
Here's a
simple example
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Mojo::DOM;
# slurp all DATA lines
my $dom = Mojo::DOM->new(do { local $/; <DATA> });
# select all children of <div id="yay"> into a Mojo::Collection
my $yay = $dom->at('#yay')->children;
# select interesting ('..' operator in scalar context: flip-flop)
my $interesting = $yay->grep(sub { my $e = shift;
$e->type eq 'h1' .. $e->type eq 'h2';
});
say $interesting->join("\n");
__DATA__
<div id="yay">
<span>This isn't interesting</span>
<h1>INTERESTING STARTS HERE</h1>
<strong>SOMETHING INTERESTING</strong>
<span>INTERESTING TOO</span>
<h2>END OF INTERESTING</h2>
<span>This isn't interesting</span>
</div>
Output
<h1>INTERESTING STARTS HERE</h1>
<strong>SOMETHING INTERESTING</strong>
<span>INTERESTING TOO</span>
<h2>END OF INTERESTING</h2>
Explanation
So I'm using Mojo::Collection's grep to filter the collection object $yay. Since it looks for truth it creates a scalar context for the given function's return value and so the .. operator acts like a flip-flop. It becomes true after it first saw a h1 element and becomes false after it first saw a h2 element, so you get all lines between that headlines including themselves.
Since I think you know some Perl and you can use arbitrary tests together with .. I hope this helps to solve your problem!

Perl get text between tags

I tried so many codes that I found on internet but none of them would work.
I have a HTML code something like this.
<div class="usernameHolder">Username: user123</div>
what I want is get the text user123 from this line of code, of course this code is with the rest of the HTML content (an HTML page) Can anyone point me to the right direction?
$text = #source=~ /Username:\s+(.*)\s+</;
print $text;
but it won't return anything.
If the HTML is in a string:
$source = '<div class="usernameHolder">Username: user123</div>';
# Allow optional whitespace before or after the username value.
$text = $source=~ /Username:\s*(.*?)\s*</;
print $1 . "\n"; # user123
If the HTML is in an array:
#source = (
'<p>Some text</p>',
'<div class="usernameHolder">Username: user123</div>',
'<p>More text</p>'
);
# Combine the matching array elements into a string.
$matching_lines = join "",grep(/Username:\s*(.*?)\s*</, #source);
# Extract the username value.
$text = $matching_lines =~ /Username:\s*(.*?)\s*</;
print $1 . "\n"; # user123
A more-compact version using an array:
#source = (
'<p>Some text</p>',
'<div class="usernameHolder">Username: user123</div>',
'<p>More text</p>'
);
# Combine the matching array elements in a string, and extract the username value.
$text = (join "",grep(/Username:\s*(.*?)\s*</, #source)) =~ /Username:\s*(.*?)\s*</;
print $1 . "\n"; # user123
Your second \s+ doesn't match anything, since there is no space between user123 and the following tag.
How about this?
/Username:\s*(.*?)\s*</
Here, \s* is discarding spaces if there are any, and .*? is there so that you don't grab most of the document in the process. (See greedy vs. non-greedy)