PHPMail output labels - phpmailer

When the site owner receives an email based on form input, I want there to be bold labels...
Like this...
Name: $name
Phone: $phone
Email Address: $email
etc, etc...
But they're not displaying correctly.
Here's the way I have the email set up...
$msg = "You have been contacted by $name with regards to $subject. Their message is as follows:";
$msg .= "" . PHP_EOL;//Line Break
$msg .= "Name:".$name . PHP_EOL . PHP_EOL;
$msg .= "Phone:".$phone . PHP_EOL . PHP_EOL;
$msg .= "Email Address:".$email . PHP_EOL . PHP_EOL;
$msg .= "Low Budget:".$budgetlow . PHP_EOL . PHP_EOL;
$msg .= "High Budget:".$budgethigh . PHP_EOL . PHP_EOL;
$msg .= "Venue Name:".$venuename . PHP_EOL . PHP_EOL;
$msg .= "Event Capacity:".$eventcapacity . PHP_EOL . PHP_EOL;
$msg .= "<strong>Event Description:</strong>".$eventdescription . PHP_EOL . PHP_EOL;
$msg .= "" . PHP_EOL . PHP_EOL; //Line Break
$msg .= "You can contact $name via email at $email or via phone at $phone." . PHP_EOL . PHP_EOL;
I want the labels to show up in bold. Above, I've added tags to Event Description to try and bold it, but it doesn't come out bold.
Here is how I have my headers set up...
$headers = "From: $email" . PHP_EOL;
$headers .= "Reply-To: $email" . PHP_EOL;
$headers .= "MIME-Version: 1.0" . PHP_EOL;
$headers .= "Content-Type: text/plain; charset=us-ascii" . PHP_EOL;
$headers .= "Content-Transfer-Encoding: quoted-printable" . PHP_EOL;

You're sending a plain text email, but you're trying to make parts of it bold by including <strong> tags.
This won't work. A plain text email will only ever be displayed as plain text. If you want to send it with HTML markup, you need to make the whole thing into an HTML document, and send it with the HTML content type.
I would also strongly recommend using a decent PHP mailer library such as phpMailer or Swiftmailer. This will make it a lot easier to send HTML formatted emails -- you'll be able to get rid of all the code you have to setup the headers entirely; the library will take care of all this sort of thing for you.
[EDIT]
Okay, just to prove how easy this is, how about I give you some code to demonstrate? Let's assume you use phpMailer. Your code would look like this:
//somewhere at the top of your program
require('/path/to/phpMailer.class.php');
//your existing $msg code, but with <br> tags instead of PHP_EOL
$msg = ....
//this bit replaces your header block...
$mail = new PHPMailer();
$mail->From = 'from#example.com';
$mail->AddReplyTo('info#example.com', 'Information');
$mail->AddAddress('recipient#example.net');
$mail->IsHTML(true);
$mail->Subject = 'Here is the subject';
$mail->Body = $msg;
//and send it (replaces the call to php's mail() function)
$mail->send();
It really is that easy. Seriously. Especially if you're a beginner, you are a lot more likely to get it right doing it this way than trying to hand-code your mail header. That's just crazy.
But more importantly, it adds a whole stack of other features.
Want to include attachements? Without the library, it would be a mountain of code. With phpMailer, it's a single extra line.
Security. phpMailer will validate the addresses and other fields, and prevent hackers from using your system to send spam (if you're writing your own headers, the odds are strong that you're vulnerable to attack).
Sending to multiple recipients? Just call AddAddress multiple times.

Related

powershell psobject showing as string instead of psobject, how to convert back to psobject

I have the following variable $Obj set to the following string value:
$Obj = '#{Version=1; Name=a;}'
How do I convert this value from a string into a custom psobject?
I would like to be able to call
$Obj.Version and get the value 1. Currently this call returns nothing.
Note: Due to how I am retrieving this variable, I can't initialize it without the single quotes.
Edit:
Here is the current code:
$Command = "script.ps1 -ExtraInfo $_"
Write-Host $Command
Invoke-Expression -Command $Command
where $_ is #{Version=1; Name=a;} (without the quote)
Originally this code was written as
. script.ps1 -ExtraInfo $_
and worked, but when I added unit tests I changed it to use Invoke-Expression so that it could be testable with Pester unit tests. Is there a better way?
Edit2:
Turns out this can be solved by putting a back tic ` before the expression and that solves the issue for me. Thank you everyone for your input.
$Command = "script.ps1 -ExtraInfo `$_"
Write-Host $Command
Invoke-Expression -Command $Command
The stringified version of a [pscustomobject] instance, which resembles a hashtable literal, is not suitable for programmatic processing, as the following example demonstrates:
# Stringify a [pscustomobject] instance.
PS> "$([pscsutomobject] #{ Version=1; Name='a value' })"
#{Version=1; Name=a value} # !! Quoting of the .Name value was lost
The problem gets worse for property values that are themselves complex objects.
Since you do appear to have access to the original [pscustomobject] instance, the solution is not to stringify.
For that, you simply need to avoid up-front string interpolation by using a verbatim (single-quoted) string literal ('...') and letting Invoke-Expression - which should generally be avoided - interpret the $_ variable as its original type:
# Use *single* quotes to prevent up-front expansion.
$Command = 'script.ps1 -ExtraInfo $_'
Write-Host $Command
Invoke-Expression -Command $Command
Note that the use of a verbatim (non-interpolating) string literal makes the use of Invoke-Expression safe here, though, as Santiago Squarzon points out, there may be a better alternatives in general, and particularly in the context of Pester.
A script-block-based solution ({ ... }) that receives the object as an argument:
$Command = { script.ps1 -ExtraInfo $args[0] }
Write-Host "Calling { $Command } with argument $_"
. $Command $_
This doesn't work with Name=a because a is not a known object (or at least not defined in my PS Session). But if this is a string, this can be done with the following script:
$Obj = '#{Version=1; Name="a";}'
$s= [System.Management.Automation.ScriptBlock]::Create("New-Object -TypeName PSObject -Property $Obj")
$o = Invoke-Command -ScriptBlock $s
$o.Version
As I stated in my comment, this is odd, and should be resolved earlier in the code base. However, if that is not possible, use Invoke-Expression
like so
$newObj = Invoke-Expression $Obj
Further reading on Invoke-Expression

How to make sure string is being given a proper format

I'm coding a progress bar for my script, and I've run into an issue where a string is being fed data in an incorrect format.
foreach ($User in $Users) {
#Set UserPrincipalName for current user
$upn = $User
#Display progress bar
$percentage = [math]::Round($loopcount / $maxcount *100)
$message = "Applying changes for $upn ($loopcount of $maxcount)" -f $percentage
Write-Progress -Activity $message -ErrorAction SilentlyContinue -PercentComplete ($percentage) -Status "Progress $percentage% :"
This is the main part of the code that makes up the progress bar (there's more, but that's irrelevant). It works great when it is being fed user identities (via $User) like "delat" and "damo", but when it gets to a user called "DiscoverySearch {D919BA05-46A6-415f-80AD-XXXXXXXXXXXXXXXX}" it understandably throws a "Error formatting a string" error.
How do I go about solving this issue?
Edit: Below is the source of $User, in case that's needed.
$MailboxRegionList = Get-Mailbox | Get-MailboxRegionalConfiguration
$Users += $MailboxRegionList | Select-Object -ExpandProperty Identity
This happens, as -f $percentage is not doing what you'd expect. It is not going to format the message as percentage a value.
$message = "Applying changes for $upn ($loopcount of $maxcount)" -f $percentage
The format operator, -f will fill in a value in string. The placeholder is to be marked with curly brackets {}, which your string doesn't usually have. When the $user is DiscoverySearch {D919BA05-46A6-415f-80AD-XXXXXXXXXXXXXXXX}, it contains curly brackets. Now, the curly brackets should follow .Net composite formatting syntax, and a GUID in account name does not do that.
As for a fix, try
$message = "Applying changes for $upn ($loopcount of $maxcount) $percentage"

How do I export a to an excel spreadsheet using powershell

I have this PowerShell script that strips html tags and just leaves the text and have it display the word count for that html file when the script is executed. My question is when I execute:
function Html-ToText {
param([System.String] $html)
# remove line breaks, replace with spaces
$html = $html -replace "(`r|`n|`t)", " "
# write-verbose "removed line breaks: `n`n$html`n"
# remove invisible content
#('head', 'style', 'script', 'object', 'embed', 'applet', 'noframes', 'noscript', 'noembed') | % {
$html = $html -replace "<$_[^>]*?>.*?</$_>", ""
}
# write-verbose "removed invisible blocks: `n`n$html`n"
# Condense extra whitespace
$html = $html -replace "( )+", " "
# write-verbose "condensed whitespace: `n`n$html`n"
# Add line breaks
#('div','p','blockquote','h[1-9]') | % { $html = $html -replace "</?$_[^>]*?>.*?</$_>", ("`n" + '$0' )}
# Add line breaks for self-closing tags
#('div','p','blockquote','h[1-9]','br') | % { $html = $html -replace "<$_[^>]*?/>", ('$0' + "`n")}
# write-verbose "added line breaks: `n`n$html`n"
#strip tags
$html = $html -replace "<[^>]*?>", ""
# write-verbose "removed tags: `n`n$html`n"
# replace common entities
#(
#("&bull;", " * "),
#("&lsaquo;", "<"),
#("&rsaquo;", ">"),
#("&(rsquo|lsquo);", "'"),
#("&(quot|ldquo|rdquo);", '"'),
#("&trade;", "(tm)"),
#("&frasl;", "/"),
#("&(quot|#34|#034|#x22);", '"'),
#('&(amp|#38|#038|#x26);', "&"),
#("&(lt|#60|#060|#x3c);", "<"),
#("&(gt|#62|#062|#x3e);", ">"),
#('&(copy|#169);', "(c)"),
#("&(reg|#174);", "(r)"),
#("&nbsp;", " "),
#("&(.{2,6});", "")
) | % { $html = $html -replace $_[0], $_[1] }
# write-verbose "replaced entities: `n`n$html`n"
return $html + $a | Measure-Object -word
}
And then run:
Html-ToText (new-object net.webclient).DownloadString("test.html")
it displays 4 words that are displayed in the output in PowerShell. How do I export that output from the PowerShell window into a an excel spreadsheet with the column words and the count 4?
The CSV you want just looks like this:
Words
4
it's easy enough to just write that to a text file, Excel will read it. But you're in luck, the output of Measure-Object is already an object with 'Words' as a property and '4' as a value, and you can feed that straight into Export-Csv. Use select-object to pick just the property you want:
$x = Html-ToText (new-object net.webclient).DownloadString("test.html")
# drop the Lines/Characters/etc fields, just export words
$x | select-Object Words | Export-Csv out.csv -NoTypeInformation
I'd be tempted to see if I could use
$x = Invoke-WebResponse http://www.google.com
$x.AllElements.InnerText
to get the words out of the HTML, before I tried stripping the content with replaces.
I figured it out. What I did was added
+ $a | Measure-Object -Word after the #html variable in the script and then ran:
Html-ToText (new-object net.webclient).DownloadString("test.html") + select-Object Words | Export-Csv out.csv -NoTypeInformation and it exported the word count – josh s 1 min ago

Comparing strings inside of foreach

I want to compare 2 strings in PowerShell. One is the actual date and the other will be read from a file that contains a lot of rows. The row always will contain the same structure, then we can extract a substring for compare the date.
The file will be a plain text. The types of a date and the substring are the same.
MyProblem:
If I execute this code the program doesn't write anything, the Write-Host is not executing, even if the strings are the same. Can someone help me?
$list = Import-Csv C:\file.txt
#actual date
$date = Get-date -Format d
$day = $fecha.Substring(0,2)
$month = $fecha.Substring(3,2)
$year = $fecha.Substring(6,4)
$date = "$year$month$day"
#I do this because if I use $list will return me an pscustomobject object
$file = Get-Content -Path C:\file.txt
#Use a ForEach loop to process all lines in the source file
foreach ($row in $file) {
$sub = $entrada.Substring(7,7)
if ($date-like $sub) {Write-Host "They are equals"}
if ($sub -Match $date) {Write-Host "They are equals"}
if ($date.Equals($sub)) {Write-Host "They are equals"}
if ($date-eq $sub) {Write-Host "They are equals"}
if ($sub -contains $date) {Write-Host "They are equals"}
}
Your reference date string is 8 characters long, but the string you extract from the lines has only 7 characters, so it's unlikely you'll ever get a match. Particularly since you carefully chose your comparisons to avoid even accidental matches. ;) Also, as #arco444 pointed out in the comments to your question, your loop variable $row is never used anywhere inside the loop.
I would suggest to simplify the code to something like this:
$date = Get-Date -f 'yyyyMMdd'
Get-Content -Path 'C:\file.txt' | Where-Object { $_.Substring(7,8) -eq $date }
That would list only those lines from the input file that contain a matching date.
Another option would be to use the Contains() method on each line:
Get-Content -Path 'C:\file.txt' | Where-Object { $_.Contains($date) }
but that would find a matching date anywhere in a line, not just at the given position.
I'd avoid using wildcard (-like) or regular expression (-match) checks, since you want to compare a fixed value, not a pattern. And you can't use the -contains operator, because that one is for checking if an array contains a particular element.
It looks like "entrada" and "row" were intended to refer to the same data item.
Try it like this:
$list = Import-Csv C:\file.txt
#actual date
$date = Get-date -Format d
$day = $fecha.Substring(0,2)
$month = $fecha.Substring(3,2)
$year = $fecha.Substring(6,4)
$date = "$year$month$day"
#I do this because if I use $list will return me an pscustomobject object
$file = Get-Content -Path C:\file.txt
#Use a ForEach loop to process all lines in the source file
foreach ($entrada in $file) {
$sub = $entrada.Substring(7,7)
if ($date-like $sub) {Write-Host "They are equals"}
if ($sub -Match $date) {Write-Host "They are equals"}
if ($date.Equals($sub)) {Write-Host "They are equals"}
if ($date-eq $sub) {Write-Host "They are equals"}
if ($sub -contains $date) {Write-Host "They are equals"}
}

Powershell - parsing a PDF file for a literal or image

Using Powershell & running PowerGUI. I have a PDF file that I need to search through in order to find if there was an attachment referenced within the content of a particular page. Either that, or I need to search for images, such as a Microsoft Word or Excel icon or a PDF icon within the document.
I am using the following code to read in the page:
Add-Type -Path "c:\itextsharp-all-5.4.5\itextsharp-dll-core\itextsharp.dll"
$reader = New-Object iTextSharp.text.pdf.pdfreader -ArgumentList "c:\files\searchfile.pdf"
for ($page = 1; $page -le 3; $page++) {
$lines = [char[]]$reader.GetPageContent($page) -join "" -split "`n"
foreach ($line in $lines) {
if ($line -match "^\[") {
$line = $line -replace "\\([\S])", $matches[1]
$line -replace "^\[\(|\)\]TJ$", "" -split "\)\-?\d+\.?\d*\(" -join ""
}
}
}
However, the above gives a few bits of text, but mostly unprintable characters.
How can you search a PDF file using Powershell searching for either a literal (like ".doc" or ".xlsx")? Can a PDF be searched for a graphic (like the Excel or Word icon)?
Without seeing the PDF raw content, it's not easy to give specific help, so if you can share a sample PDF or it's contents that would be helpful.
Once you know what to look for in the stream, you can search by reading in the file line by line and using the -match operator:
$file = [io.file]::ReadAllLines('C:\test​.pdf')
$title = ($file -match "<rdf:li")[0].Split(">")[1].Split("<")[0]
$description = ($file -match "<rdf:li")[2].Split(">")[1].Split("<")[0]
write-host ("Title: " + $title)
write-host ("Description: " + $description)
I doubt very much that the contents of the file will tell you much more than that an image exists at particular page coordinates (although I'm by no means a PDF expert) but it may also include the binary file stream, in which case you may be able to save that stream as a file (I haven't tried it as yet).

Resources