Problems changing encoding [duplicate] - powershell

This question already has answers here:
Word Document.SaveAs ignores encoding, when calling through OLE, from Ruby or VBS
(3 answers)
Closed 5 years ago.
I'm working on a PowerShell script to convert a docx to HTML, and also to change the encoding of the HTML, because by default it saves it as windows-1252.
I need this because later on I send this HTML saved as the body for an email also send by PowerShell. As I am Spanish I need accents and tildes to show up (those are appearing as ? right now).
I tried the SaveAs method with all the parameters, but I couldn't get it to work.
This is my script:
$MSWord = New-Object -ComObject Word.Application
$MSWord.Documents.Open(“C:\Users\USER\Videos\CAMBIO_TURNO.docx”)
$MSWord.Visible = $false
# Save HTML
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], “wdFormatHTML”);
$path = “C:\Users\USER\Videos\CAMBIO_TURNO.html”
$MSWord.ActiveDocument.SaveAs([ref]$path, [ref]$saveFormat)
# Close File
$MSWord.ActiveDocument.Close()
$MSWord.Quit()
Then, to send it to me, I use this other code on PowerShell:
$OutputEncoding = [System.Text.Encoding]::UTF8
$body = [IO.File]::ReadAllText(“C:\Users\USER\Videos\CAMBIO_TURNO.html”)
Send-MailMessage -To “EMAIL#EMAIL” -From “EMAIL#EMAIL” -Subject “CAMBIO” -Body $body -Encoding $OutputEncoding -BodyAsHtml -Attachments “C:\Users\USER\Videos\CAMBIO_TURNO.xlsx” -Dno onSuccess, onFailure -SmtpServer smtp.gmail.com -Credential EMAIL#EMAIL
SECOND UPDATE
(Although I went to the page that is marked as duplicate: Word Document.SaveAs ignores encoding, when calling through OLE, from Ruby or VBS it didn't solve my problem. that word configuration doesn't work)
Here is what I tried after saving my document with the web options as utf-8:
#DEFINE outputencoding FOR THE CONSOLE - IT SEEMS THAT IT DOESN'T WORK. I typed ñ and ó and they appear as ?? becasue it doesn't convert the hexadecimal values to the right charset
$OutputEncoding= New-Object -typename System.Text.ASCIIEncoding
# Open word to add input into the signature file
$MSWord = New-Object -ComObject word.application
$MSWord.Documents.Open('C:\Users\USER\Videos\CAMBIO_TURNO.docx')
# Save HTML
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], 'wdFormatFilteredHTML');
$path = 'C:\Users\USER\Videos\CAMBIO_TURNO.html'
$default = [Type]::Missing
$MSWord.ActiveDocument.SaveAs2([ref]$path, [ref]$saveFormat, [ref]$default, [ref]$default, [ref]$default, [ref]$default, [ref]$default, [ref]$default, [ref]$default, [ref]$default, [ref]$default, [ref]28591)
# Close File
$MSWord.ActiveDocument.Close()
$MSWord.Quit()
$HTMLw = Get-Content -Path 'C:\Users\USER\Videos\CAMBIO_TURNO.html' -Encoding ASCII -Force
$HTMLw -replace 'charset=windows-1252','charset=ISO-8859-1' | Set-Content -Path 'C:\Users\USER\Videos\CAMBIO_TURNO.html' -Encoding ASCII -Force

For one thing you should avoid typographic quotes (“). Always use straight quotes in code (").
With that said, the problem you're facing is most likely that passing a string with the name of a symbolic constant doesn't work. Either use the numeric value of the constant or define a constant yourself:
New-Variable -Name wdFormatHTML -Value 8 -Option Constant
$MSWord.ActiveDocument.SaveAs($path, $wdFormatHTML)
Alternatively you should be able to resolve the constants via the Interop API, but I don't have an Office installation at hand right now, so I can't test.
You also didn't specify the desired encoding of the output file when saving.
New-Variable -Name wdFormatHTML -Value 8 -Option Constant
$default = [Type]::Missing
$MSWord.ActiveDocument.SaveAs($path, $wdFormatHTML, $default, $default, $default, $default, $default, $default, $default, $default, $default, 65001)

Related

Hebrew send to google spreadsheet from PowerShell Hebrew correctly

Please help.
In console look hebrew correct but in spreadsheet is not correctenter image description here
$import = New-Object System.Collections.ArrayList($null)
$import.Add( #("route_id"))
$import.Add( #( 'אבא אבן 1 הרצליה' )) | Out-NULL
try {
$Response = Set-GSheetData -accessToken $accessToken -rangeA1 "A1:X$($import.Count)" -sheetName "23-07-21" -spreadSheetID $SpreadsheetID -values $import -Verbose
$Response | ConvertTo-Json
} catch {
$err = $_.Exception
$err | Select-Object -Property *
"Response: "
$err.Response
}
Hebrew might not be supported in Sheets, you would need to install a font. You can try with this one
https://fonts.google.com/noto/specimen/Noto+Sans+Hebrew?query=hebrew
Update
After testing using the Rest API, it works, so the issue might be related on how the PowerShell process hebrew characters.
I've found some information on how to process hebrew characters in the Windows Powershell
[Console]::OutputEncoding = [Text.Encoding]::GetEncoding(1255)
Make sure the console is outputting the right characters and the POST a request to Google Sheets
It's bug in the psmodule. Author must specify encoding UTF8.
https://github.com/umn-microsoft-automation/UMN-Google/pull/50

convert msg to html without using outlook in powershell

I want to convert msg files (in the local folder) to html in powershell. I have done this by using outlook but the problem is this script will work on server so I cant use outlook.
So far, I have searched these questions:
Save Email as MSG file without using Outlook (COM object, etc.) or 3rd party software
convert msg to html in background using vbscript
Read Outlook .msg File
I couldnt find many approaches with Powershell. However, with the help of the questions above I downloaded Redemption and used it like this:
$routlook = New-Object -COM Redemption.RDOSession
$routlook.Logon()
$msg = $routlook.GetMessageFromMsgFile("C:\temp\test.msg",$TRUE)
$path = "C:\temp\test.html"
$msg.HTMLBody | Set-Content $path
But $msg.HTMLBody just returns an empty html in the below and $msg.Body returns nothing:
<HTML>
<HEAD><META http-equiv=Content-Type content="text/html; charset=UTF-8">
</HEAD>
<BODY>
<!-- Converted from text/plain format -->
</BODY></HTML>
Probably I am using Redemption in a wrong way and dont know how to fix it. Or is there any other 3rd party solution that can be used in servers rather than using outlook?
Thanks for any help
The second parameter when you call GetMessageFromMsgFile is true, which means you are creating a brand new file. Pass false instead.
Also note that GetMessageFromMsgFile does not require an active session, so there is no need to call RDOSession.Logon. And there won't be a profile if you are running under a service user anyway.
To create an HTML file, you don't need to read the RDOMail.HTMLBody property. You can call RDOMail.SaveAs(..., olHTML).
You need to remove the $TRUE parameter:
$routlook = New-Object -COM Redemption.RDOSession
$routlook.Logon()
$msg = $routlook.GetMessageFromMsgFile("C:\temp\test.msg")
$path = "C:\temp\test.html"
$msg.HTMLBody | Set-Content $path
And you can open your msg file and after that, save as html
To make it clear, it worked fine with both answers and my complete code for either ways:
$routlook = New-Object -COM Redemption.RDOSession
$location = "C:\temp\Redemption\"
$msg = $routlook.GetMessageFromMsgFile("C:\temp\test.msg",$FALSE)
$name = "test.html"
$path = $location + $name
$msg.SaveAs($path,5)
Or
$routlook = New-Object -COM Redemption.RDOSession
$location = "C:\temp\Redemption\"
$msg = $routlook.GetMessageFromMsgFile("C:\temp\test.msg")
$name = $_.Name + ".html"
$path = $location + $name
$msg.HTMLBody | Set-Content $path

unable to set up send-email function as desired

I'm attempting to create a Send-Email function in a script which can change the email address each time the script is used. However, I'm currently suck being forced to use a static email:
function Send-Email (
$recipientEmail = "EMAIL",
$subject = "Ticket" + $type,
$body
) {
$outlook = New-Object -ComObject Outlook.Application
$mail = $outlook.CreateItem(0)
$mail.Recipients.Add("EMAIL")
$mail.Subject = ("Ticket - " + $type)
$mail.Body = $body # For HTML encoded emails
$mail.Send()
Write-Host "Email sent!"
}
I'd like to set it up so that I can define $recipientEmail and then later use this input with $mail.Recipients.Add("EMAIL") - I've beend doing $mail.Recipients.Add("$receipientemail") and the like without any luck and wondering if I'm approaching this completely wrong?
I'd like it to be set up in a way that it could use
[void] $listBox.Items.Add("Email1")
[void] $listBox.Items.Add("Email2")
[void] $listBox.Items.Add("Email3")
And accept that as the email to send to instead of only working with one email.
This whole thing rang a bell with me, and I went "code dumpster diving". I wrote this same function (more or less) a year ago. I'm not using $mail.recipients.add(); I'm using $Mail.To = $RecipientEmail; if I want multiple recipients, I simply -join ";" them and assign to $mail.To. The members $mail.CC and $mail.BCC work the same way:
Function Send-Email {
<#
.Synopsis
Sends Email using Microsoft Outlook
.DESCRIPTION
This cmdlet sends Email using the Outlook component of a locally-installed
Microsoft Office. It is not expected to work with the "Click-to-run" versions.
This version requires that Outlook be running before using the cmdlet.
.PARAMETER To
Must be a quoted string or string array, may not be omitted.
Specifies the address to send the message to. If an array, it will
be converted to a semicolon-delimited string. May contain contact
groups.
.PARAMETER Subject
Must be a quoted string, may not be omitted.
Specifies the subject of the message to be sent.
.PARAMETER Body
Must be a string or a string array, may not be omitted.
Contains the text of the message to be sent. If supplied as a string in double
quotes, any PowerShell variables will be expanded unless the leading $ is
escaped. If supplied in a script via a variable containing a here-doc, will
reproduce the here-doc. If supplied as an array, either by variable or by the
Get-Content cmdlet, the array elements will be joined with `r`n as "separators".
A body supplied via Get-Content will not have expanded variables; arrays created
in scripts using double quotes or via here-docs willl have expanded variables.
.PARAMETER CC
Must be a quoted string or string array, may be omitted.
Specifies an address to send a copy of the message to. If an array, it will be
converted to a semicolon-delimited string. All recipients can see that a copy
of the message was sent to the addresses here.
.PARAMETER BCC
Must be a quoted string or string array, may be omitted.
Specifies an address to send a copy of the message to. If an array, it will be
converted to a semicolon-delimited string. The recipients named here are not
displayed as a recipient of the message, even though they do receive the message.
.PARAMETER Attachments
Must be a quoted string or string array, may be omitted.
Specifies one or more files to be included with the message as attachments.
.INPUTS
This version of the cmdlet does not accept input from the pipeline
.OUTPUTS
No output to the pipeline is generated. The cmdlet does return an error code.
.EXAMPLE
Send-Email -To "boss#example.com" -Subject "Personnel Issue - John M. Ployee" -Body "I need a raise."
Sends an email with the indicated subject and body to the stated address.
.EXAMPLE
$messagebody = #"
Roses are red
Violets are blue
I need a raise
And so do you
"#
$others = "boss-of-boss#example.com","hr#example.com"
Send-Email -To "boss#example.com" -Subject "Personnel Issue - John M. Ployee" -cc $others -Body $messagebody
Sends an email with the indicated subject to the stated address. The body
will be composed of the lines in the variable $messagebody as shown; the
line breaks are preserved. A copy of the message is sent to the two addresses
listed in $others.
.EXAMPLE
Send-Email -To "boss#example.com" -Subject "Personnel Issue - John M. Ployee" -Body (Get-Content -Path "C:\Request-for-raise.txt")
Sends an email with the indicated subject and body to the stated address.
The body is drawn from the indicated file, and line breaks are preserved.
.EXAMPLE
Send-Email -To "boss#example.com" -Subject "Personnel Issue - John M. Ployee" -Body "Please see attached for rationale for raise" -Attachments (Get-Content -Path "C:\Request-for-raise.txt")
Sends an email with the indicated subject and body to the stated address.
The indicated file is included as an attachment.
.NOTES
Planned Future Enhancements:
1. Allow the cmdlet to accept input (message body text) from the pipe.
2. Allow the cmdlet to accept the body from a file (parameter -BodyFromFile)
3. Allow the cmdlet to start up Outlook if it is not already running.
This includes shutting it down afterward.
4. Allow the body to be formatted as HTML or RTF, and properly handle this.
Initially, switches (e.g., -BodyAsHTML or -BodyAsRTF); better would be to
use file name (e.g., -BodyFromFile "C:\Test.html" would still set the message
format to HTML even in the absence of -BodyAsHTML); best would be to inspect
content of file.
Based on a script from http://www.computerperformance.co.uk/powershell/powershell_function_send_email.htm
#>
[cmdletbinding()]
Param (
[Parameter(Mandatory=$True)]
[String[]]$To,
[String[]]$CC,
[String[]]$BCC,
[Parameter(Mandatory=$True)]
[String]$Subject,
[Parameter(Mandatory=$True)]
[String[]]$Body,
[String[]]$Attachments
)
Begin {
# Future Enhancement: Start Outlook if it's not already running
} # End of initialization
Process {
# Create an instance Microsoft Outlook
$Outlook = New-Object -ComObject Outlook.Application
# Create a new mail message
$Mail = $Outlook.CreateItem(0)
# Set up the email
$Mail.To = $To -join ";"
if ($CC -ne $null) {
$Mail.CC = $CC -join ";"
}
if ($bcc -ne $null) {
$Mail.BCC = $BCC -join ";"
}
$Mail.Subject = "$Subject"
$Mail.Body = $Body -join "`r`n"
if ($attachments -ne $null) {
foreach ($Attachment in $Attachments) {
$silencer = $Mail.Attachments.Add($Attachment)
}
}
# I need to investigate scripting Outlook more.
# The next three comments may be all that's needed
# to handle HTML and/or attachments.
# $Mail.HTMLBody = "When is swimming?"
# $File = "D:\CP\timetable.pdf"
# $Mail.Attachments.Add($File)
# Place message in outbox.
$Mail.Send()
} # End of Process section
End {
# Clean up after ourselves. This prevents Outlook from reporting
# an error on exit.
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook)
$Outlook = $null
# If Outlook settings are to Send/Receive only on command rather
# than as-needed, force the send at this time.
# NOTE TO SELF: CHECK THIS!
# $Outlook.GetNameSpace("MAPI").SendAndReceive(1)
# If we launched Outlook at the beginning, close it here.
# $Outlook.Quit()
} # End of End section!
} # End of function
<#
Note 2: Look in Outlook's outbox for a newly-created message.
Note 3: If you really want to send the email then append this command:
$Outlook.GetNameSpace("MAPI").SendAndReceive(1)
#>

Outputting a file with an Azure Function

I'm trying to experiment with Azure Functions. Basically my use case is calling the function with a GUID as GET Parameter, having the function download the WIX toolkit DLL and an MSI file, updating a parameter in the MSI file, and the returning that file to the caller of the function (as download prompt for example).
I'm mostly there, just need some help getting the download prompt/send to happen, my code so far:
$urlWix = "http://domain/wix.dll"
$outputWix = "$Env:TEMP\wix.dll"
Invoke-WebRequest -Uri $urlWix -OutFile $outputWix
try{Add-Type -Path $outputWix}catch{$Null}
$urlMSI = "http://domain/file.msi"
$outputFile = "$Env:TEMP\file.msi"
Invoke-WebRequest -Uri $urlMSI -OutFile $outputFile
$oDatabase = New-Object Microsoft.Deployment.WindowsInstaller.Database($outputFile,[Microsoft.Deployment.WindowsInstaller.DatabaseOpenMode]::Direct);
$sSQLQuery = "SELECT * FROM Property WHERE Property= 'MYPROPERTY'"
[Microsoft.Deployment.WindowsInstaller.View]$oView = $oDatabase.OpenView($sSQLQuery)
$oView.Execute()
$oRecord = $oView.Fetch()
$oRecord.SetString("Value","MyCustomValue")
$oView.Modify([Microsoft.Deployment.WindowsInstaller.ViewModifyMode]::Update,$oRecord)
$oView.Close();
$oDatabase.Dispose();
$file = get-item $outputFile
write-output $file
Unfortunately due to content type issues this is not possible in powershell. You can do this via a C#, F#, or Node (isRaw) function. The problem is that you need to specify headers via the JSON response format, which would convert any non-text data into a base64 string.
If you want to sent a text file via powershell it is possible:
$response = ConvertTo-JSON #{
Body="your file data";
Headers=#{
# unfortunately it seems functions does not support 'filename=...'
'Content-Disposition'='attachment';
# you would use application/octet-stream, but because it's converted to JSON you lose binary content
'Content-Type'='text/plain';
};
}
Out-File -Encoding Ascii -FilePath $res -inputObject $response

Encoding not working when email send by Powershell

Im sending a testemail via powershell like
$messageParameters = #{
Subject = "Email Tool"
Body = Get-Content "C:\body.txt" | out-string
From = "Info <info#xy.de>"
To = "Me <me#xy.de>"
SmtpServer = "mail.xy.de"
Encoding = New-Object System.Text.UTF8Encoding
}
send-mailmessage #messageParameters -BodyAsHtml
everything is working find except the encoding.
if i don't use encoding some characters are send as ??
and if i use it, what i actually want to do, than i get this Ä Ö Ü
but it should be ä ö ü and not this above.
If i don't send the mail as HTML it works.
How can i send the mail with the right encoding AND as html ?
I believe the problem is that your text-file is getting jumbled when you are reading it into a variable as non-utf8.
I would try getting the text file as UTF-8 and keeping the Encoding line.
Body = Get-Content "C:\body.txt" -Encoding UTF8 | Out-String
EDIT: Added Out-String per Dwza.