I am trying to create a batch file that will create a file that will send an email through powershell. It does many things, but email is just a snippet of it. Here is what I have so far:
REM Creates batch file with contents of the powershell script
echo "I need to add the below powershell script" > email.bat
echo "into email.bat with all the quotes included">> email.bat
echo "like what I'm doing now with appending text">> email.bat
REM powershell script to send email.
$smtp = new-object Net.Mail.SmtpClient("smtp.gmail.com")
if( $Env:SmtpUseCredentials -eq "true" ) {
$credentials = new-object Net.NetworkCredential("username","password")
$smtp.Credentials = $credentials
}
$objMailMessage = New-Object System.Net.Mail.MailMessage
$objMailMessage.From = "myemail#gmail.com"
$objMailMessage.To.Add("whereImsendingto#gmail.com")
$objMailMessage.Subject = "Logs for today"
$objMailMessage.Body = "(the logs)"
$smtp.send($objMailMessage)
In batch, I have the way to append text to another file down if what I'm adding does not have quotes, but I need to add text that includes quotes to the file.
Why don't you simply echo whithout quotes and escape possible chars <>|& with a caret ^ and double percent signs?
In a (code block) you've to also escape closing parentheses ^)
#Echo off
( Echo:$smtp = new-object Net.Mail.SmtpClient("smtp.gmail.com"^)
Echo:
Echo:if( $Env:SmtpUseCredentials -eq "true" ^) {
Echo: $credentials = new-object Net.NetworkCredential("username","password"^)
Echo: $smtp.Credentials = $credentials
Echo:}
Echo:$objMailMessage = New-Object System.Net.Mail.MailMessage
Echo:$objMailMessage.From = "myemail#gmail.com"
Echo:$objMailMessage.To.Add("whereImsendingto#gmail.com"^)
Echo:$objMailMessage.Subject = "Logs for today"
Echo:$objMailMessage.Body = "(the logs^)"
Echo:
Echo:$smtp.send($objMailMessage^)
) > "SomeFile.ps1"
Related
I used to use a tiny utility called ScriptMan, it would sit in the system tray, and with two clicks it would copy the contents of my selected RTF to the clipboard. I haven't found an equivalent that works on Windows 10 and doesn't monitor the clipboard constantly, so I've tried to write my own in PowerShell. It's worked - almost...
After spending a bit of (way too much of!!) my afternoon/evening on StackOverflow and several other places, I've come up with the following script:
function RTF_to_Clipboard {
$ScriptName = $this.Tag
Write-Host "ScriptName = $ScriptName"
$LabelOutput.Text = "Button $ScriptName clicked"
$ScriptFilePath = "$ScriptsFolder$ScriptName"
Write-Host "$ScriptFilePath = $ScriptFilePath"
#https://stackoverflow.com/questions/65543792/how-to-write-contents-of-an-rtf-file-to- windows-clipboard-with-one-liner
Add-Type -AssemblyName System.Windows.Forms
$rtf = Get-Content -Path $ScriptFilePath
$IsRTF = ($rtf | Select-String '\{\\rtf1' -Quiet)
Write-Host "File $ScriptFilePath" (&{If($IsRTF) {"is"} Else {"IS NOT"}}) "an RTF file."
#[Windows.Forms.Clipboard]::SetText($rtf, [System.Windows.Forms.TextDataFormat]::Rtf)
#[Windows.Forms.Clipboard]::SetDataObject($rtf, $true)
[Windows.Forms.Clipboard]::SetText($rtf, [System.Windows.Forms.TextDataFormat]::Text)
Write-Host $rtf
}
This function is launched by a GUI:
# https://theitbros.com/powershell-gui-for-scripts/
$ScriptsFolder = 'C:\Users\me\OneDrive\Documents\IT\scripts\'
$Scripts = #(
'script 1 - multiline text.rtf',
'script 2 - single line text.rtf',
'script 3 - multiline RTF.rtf'
)
Add-Type -assembly System.Windows.Forms
#Now create the screen form (window) to contain elements:
$main_form = New-Object System.Windows.Forms.Form
#Set the title and size of the window:
$main_form.Text ='Copy Scripts to Clipboard'
$main_form.Width = 600
$main_form.Height = 400
#If the elements on the form are out of window bounds, use the AutoSize property to make the form automatically stretch.
$main_form.AutoSize = $true
#Create button and label for each item in the $Scripts array
$loopcount = 0
foreach($Command in $Scripts)
#for ($loopcount=0; $loopcount -lt $Scripts.count; $loopcount++)
{
$YPos = 25 * $loopcount + 5
$loopcount++
# $Command = $Scripts[$loopcount]
#Now put the button on the form:
Echo "Create button $loopcount for function $Command"
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(0,$YPos)
$Button.Size = New-Object System.Drawing.Size(60,23)
$Button.Text = "Load"
$Button.Tag = $Command
$Button.Add_Click({
$LabelOutput.Text = "$Command clicked"
Write-Host "$Command clicked"
RTF_to_Clipboard
# RTF_to_Clipboard -ScriptName $Command
})
$main_form.Controls.Add($Button)
#Create a label element on the form:
$Label = New-Object System.Windows.Forms.Label
$Label.Text = $Command
$Label.Location = New-Object System.Drawing.Point(70,$YPos)
$Label.AutoSize = $true
$main_form.Controls.Add($Label)
}
$LabelOutput = New-Object System.Windows.Forms.Label
$LabelOutput.Text = "No command selected yet"
$LabelOutput.Location = New-Object System.Drawing.Point(0,150)
$LabelOutput.AutoSize = $true
$main_form.Controls.Add($LabelOutput)
#Now you can display the form on the screen.
$main_form.ShowDialog()
The form buttons appear to be working, but not copying the text/RTF to the clipboard.
As you can guess from the script names, I have 3 test scripts:
Multi-line plain text
Single-line plain text
Rich Text Format
You can see also from the # remming lines out that I've tried a few methods that others have said they used:
[Windows.Forms.Clipboard]::SetText($rtf, [System.Windows.Forms.TextDataFormat]::Rtf)
This method pastes the plain text into MS word, but doesn't paste anything into NotePad++ or PuTTY (where I need them. The RTF is correct in MS Word (tables preserved), but throws a bunch of errors about "This is not a valid style name."
[Windows.Forms.Clipboard]::SetDataObject($rtf, $true)
The second method copies the single-line text to the clipboard no worries, and it pastes OK in NotePad++, PuTTY and MS Word. The multi-line text and RTF buttons appear to put nothing on the clipboard.
[Windows.Forms.Clipboard]::SetText($rtf, [System.Windows.Forms.TextDataFormat]::Text)
With the last method, the single-line scripts work fine, but the multi-line script all ends up on one line. RTF files get their raw data converted to text - i.e.: a tonne of RTF formating code displayed as plain text; again, all on one line:
{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch31506\stshfhich31506\stshfbi31506\deflang2057\deflangfe2057\themelang2057\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi
\froman\fcharset0\fprq2{*\panose 02020603050405020304}Times New
Roman;}{\f0\fbidi \froman\fcharset0\fprq2{*\panose
02020603050405020304}Times New Roman;} {\f37\fbidi
\fswiss\fcharset0\fprq2{*\panose
020f0502020204030204}Calibri;}{\f38\fbidi
\fswiss\fcharset0\fprq2{*\panose
00000000000000000000}Tahoma;}{\flomajor\f31500\fbidi
\froman\fcharset0\fprq2{*\panose 02020603050405020304}Times New
Roman;} etc., etc., etc., etc., etc., etc., etc., etc., etc.....
When there is nothing pasting from the clipboard, the PowerShell console is still showing the text value of the files when I call Write-Host $rtf, so I know that $rtf = Get-Content -Path $ScriptFilePath worked each time.
Has anyone got any pointers as to how to get the multi-line text copied correctly to the clipboard at least?
I should mention that some of my multi-line scripts (the files that I'm trying to copy to the clipboard) are bash scripts, not sure if their content is breaking the PowerShell clipboard, e.g.:
alias pingAll="while true; do datenow=$(date -D "hh:mm:ss"|cut
-c12-19);echo -ne $datenow; echo -ne " -> VPN: "; if ping -q -c 1 -w 5 $VPN_Server_IP>/dev/null; then echo -ne "Up "; else echo -ne " Down"; fi; echo -ne " -> Server A: "; if ping -q -c 1 -w 5
$ServerA_IP>/dev/null; then echo -ne "Up "; else echo -ne "
Down"; fi; echo -ne " -> Server B: "; if ping -q -c 1 -w 5
$ServerB_IP>/dev/null ; then echo -ne "Up "; else echo -ne "
Down"; fi; echo ; sleep 5; done"
Version = ";grep "<version" /etc/stationInfo.xml |cut -f2 -d">"|cut
-f1 -d"<"; echo -ne "Firmware Revision = ";grep "<revision" /etc/stationInfo.xml |cut -f2 -d">"|cut -f1 -d"<"; echo -ne "Firmware
Grade = ";grep "<grade" /etc/stationInfo.xml |cut -f2 -d">"|cut -f1
-d"<"; echo -ne "Firmware Date = ";grep "<date" /etc/stationInfo.xml |cut -f2 -d">"|cut -f1 -d"<"'alias fwver='echo -ne "Firmware
I also tried Set-Clipboard -Path "c:\temp\script.rtf", but it pastes nothing into NotePad++, and pastes the text or RTF into MS word as an embedded object that needs to be opened to edit, not as inline text.
Any clues how to get this working?
Thanks for your help!
Cheers.
Here's the solution that I'm running now, works just as I want it (would be nice to hide the PowerShell output window, but not a problem).
I've removed the array of script paths, and have my script scan the script folder and grab every *.txt and *.rtf in the script folder instead. To add a new script, you just need to copy it to the script folder, no changes to this script required.
As I had too many scripts to fit on one screen, I now start a new column of buttons when half of them are displayed.
If a script contains "#", its label is set to red font, to make my email addresses stand out so I can grab them quickly. (Yes, I use this for even short things I need to type regularly. :) )
# Scott Critchley
# 16/02/2022
# With help from https://stackoverflow.com/questions/71149309/powershell-copy-rtf-to-cliboard-multiple-line-text-not-working?noredirect=1#comment125769903_71149309
# and https://stackoverflow.com/questions/65543792/how-to-write-contents-of-an-rtf-file-to-windows-clipboard-with-one-liner
# Detect if we're running in the ISE or not, so can exit the shell when done, but not when in ISE
# https://www.sapien.com/forums/viewtopic.php?t=14149#:~:text=Another%20way%20to%20determine%20what,'Windows%20PowerShell%20ISE%20Host'.
[bool]$ISE = 0
switch ($Host.Name){
ConsoleHost { }
PrimalScriptHostImplementation { }
'Windows PowerShell ISE Host' {
Write-Host 'Running in Windows PowerShell ISE Host'
$ISE = 1
}
}
#https://community.spiceworks.com/topic/1710213-hide-a-powershell-console-window-when-running-a-script?page=1#entry-5990631
$Script:showWindowAsync = Add-Type -MemberDefinition #"
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
"# -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru
Function Show-Powershell()
{
$null = $showWindowAsync::ShowWindowAsync((Get-Process -Id $pid).MainWindowHandle, 10)
}
Function Hide-Powershell()
{
$null = $showWindowAsync::ShowWindowAsync((Get-Process -Id $pid).MainWindowHandle, 2)
}
function RTF_to_Clipboard {
# param (
# [string]$ScriptName
# )
$ScriptName = $this.Tag
Write-Host "ScriptName = $ScriptName"
$LabelOutput.Text = "Button: $ScriptName clicked"
$ScriptFilePath = "$ScriptsFolder$ScriptName"
Write-Host "ScriptFilePath = $ScriptFilePath"
#https://stackoverflow.com/questions/65543792/how-to-write-contents-of-an-rtf-file-to-windows-clipboard-with-one-liner
Add-Type -AssemblyName System.Windows.Forms
$rtf = Get-Content -Path $ScriptFilePath -Raw
$IsRTF = ($rtf | Select-String '\{\\rtf1' -Quiet)
Write-Host "File $ScriptFilePath" (&{If($IsRTF) {"is"} Else {"IS NOT"}}) "an RTF file."
if ( $IsRTF )
{
[Windows.Forms.Clipboard]::SetText($rtf, [System.Windows.Forms.TextDataFormat]::Rtf)
}
else
{
[Windows.Forms.Clipboard]::SetDataObject($rtf, $true)
}
}
# https://theitbros.com/powershell-gui-for-scripts/
$ScriptsFolder = 'C:\Users\me\OneDrive\Documents\IT\scripts\'
Add-Type -assembly System.Windows.Forms
#Now create the screen form (window) to contain elements:
$main_form = New-Object System.Windows.Forms.Form
#Set the title and size of the window:
$main_form.Text ='Copy Scripts to Clipboard'
$main_form.Width = 60
$main_form.Height = 40
#If the elements on the form are out of window bounds, use the AutoSize property to make the form automatically stretch.
$main_form.AutoSize = $true
#Create button and label for each item in the $Scripts array
$loopcount = 0
$XPos = 0
$YPosCount = 0
# All files in folder from #https://www.winhelponline.com/blog/how-to-change-shortcut-lnk-targets-in-bulk-using-script/
# As implemented in Update Shortcuts.ps1
$ScriptCount = (gci $ScriptsFolder\* -Include *.txt, *.rtf |Measure-Object ).Count
Write-Host "Total Script Count = $ScriptCount"
gci $ScriptsFolder\* -File -Include *.txt, *.rtf | foreach {
$Command = $_.Name
$YPos = 25 * $YPosCount + 5
$YPosCount++
$loopcount++
if ($loopcount -eq ([math]::floor($ScriptCount/2))){
Write-Host "XPos = $XPos"
$XPos = 370
$YPosCount = 0
$YPosMax = $YPos
}
#Now put the button on the form:
Echo "Create button $loopcount for function $Command at $XPos,$YPos"
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size($XPos,$YPos)
$Button.Size = New-Object System.Drawing.Size(60,23)
$Button.Text = "Load"
$Button.Tag = $Command
$Button.Add_Click({
$LabelOutput.Text = "$Command clicked"
Write-Host "$Command clicked"
RTF_to_Clipboard
})
$main_form.Controls.Add($Button)
#Create a label element on the form:
$Label = New-Object System.Windows.Forms.Label
$Label.Text = $Command.Substring(0,$Command.Length - 4)
$LabelXPos = $XPos + 70
$Label.Location = New-Object System.Drawing.Point($LabelXPos,$YPos)
$Label.AutoSize = $true
if ($Command -like '*#*') {
$Label.ForeColor = 'Red'
$Label.BorderStyle = 'Fixed3D'
}
$main_form.Controls.Add($Label)
}
$YPos = $YPosMax + 5
$LabelOutput = New-Object System.Windows.Forms.Label
$LabelOutput.Text = "No command selected yet"
$LabelOutput.Location = New-Object System.Drawing.Point(0,$YPos)
$LabelOutput.AutoSize = $true
$main_form.Controls.Add($LabelOutput)
if($ISE)
{
Show-Powershell
}
else
{
Hide-Powershell
}
#Now you can display the form on the screen.
$main_form.ShowDialog()
if(-Not $ISE)
{[Environment]::Exit(1)}
I am trying to create a PowerShell script that will send an email if a service goes into a stopped state. I would like to be able to read the email configuration from another file.
Email configuration file:
.\emailconfig.conf
$emailSmtpServer = "smtp.company.com"
$emailSmtpServerPort = "587"
$emailSmtpUser = "usera"
$emailSmtpPass = "passwordb"
$emailFrom = "userA#company.com"
$emailTo = "userB#company.com"
$emailcc= "userC#company.com"
And this is what I have so far in the PowerShell script:
.\emailservicecheck.ps1
$A = Get-Service "Service B"
if ($A.Status -eq "Stopped") {
Get-Content emailconfig.conf | Out-String
$emailMessage = New-Object System.Net.Mail.MailMessage($emailFrom, $emailTo)
$emailMessage.Cc.Add($emailcc)
$emailMessage.Subject = "subject"
#$emailMessage.IsBodyHtml = $true # true or false depends
$emailMessage.Body = Get-Service "Service B" | Out-String
$SMTPClient = New-Object System.Net.Mail.SmtpClient($emailSmtpServer, $emailSmtpServerPort)
$SMTPClient.EnableSsl = $False
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($emailSmtpUser, $emailSmtpPass);
$SMTPClient.Send($emailMessage)
}
The script works if I enter the text from the email config file into the script but I cannot seem to be able to read in the data from the file on the fly and get the script to work. It errors out and says that my variables are empty.
What you are searching for, (I think) are .psd1 files. I personally prefer them (along with JSON) over the other configuration formats. The link I'm referring to also describes other well-known formats and how to use them in PowerShell.
In short, module manifests work as follows:
configuration.psd1
#{
SmtpServer = "";
MailFrom = "";
Auth = #{
User = "";
Pass = "";
};
}
Script.ps1
$mailConfig = Import-LocalizedData -BaseDirectory C:\ -FileName configuration.psd1
$emailMessage = New-Object System.Net.Mail.MailMessage( $$mailConfig.mailFrom , $mailConfig.mailTo )
As Mark already pointed out, Get-Content emailconfig.conf | Out-String will just output the content of the file, it won't define the variables in your code. For that you'd need to dot-source the file, which requires a file with the extension ".ps1".
If you want to stick with a simple config file format I'd recommend changing the file to something like this:
emailSmtpServer = smtp.company.com
emailSmtpServerPort = 587
emailSmtpUser = usera
emailSmtpPass = passwordb
emailFrom = userA#company.com
emailTo = userB#company.com
emailcc = userC#company.com
And importing it into a hashtable via ConvertFrom-StringData:
$cfg = Get-Content emailconfig.conf | Out-String | ConvertFrom-StringData
The data in the hashtable can be accessed via dot-notation ($cfg.emailFrom) as well as via the index operator ($cfg['emailFrom']), so your code would have to look somewhat like this:
$msg = New-Object Net.Mail.MailMessage($cfg.emailFrom, $cfg.emailTo)
$msg.Cc.Add($cfg.emailcc)
$msg.Subject = 'subject'
$msg.Body = Get-Service 'Service B' | Out-String
$smtp = New-Object Net.Mail.SmtpClient($cfg.emailSmtpServer, $cfg.emailSmtpServerPort)
$smtp.EnableSsl = $false
$smtp.Credentials = New-Object Net.NetworkCredential($cfg.emailSmtpUser, $cfg.emailSmtpPass)
$smtp.Send($msg)
It looks like what you're trying to do is include some script from another file. This can be done by dot sourcing, however the file needs to be saved as a .ps1 file, you can't use .conf.
You'd do it as follows (in place of your existing Get-Content) line:
. .\emailconfig.ps1
Assuming the file is kept in the current working directory of the script.
Your script wasn't working because
get-content emailconfig.conf | Out-String
Was returning the contents of that file to the output pipeline, rather than including it in the script and executing it.
I'm not sure i understood correctly what you want.
If you want to use variables from external file, you need to dot source your external script, for example, create a file named variables.ps1 and put in the same folder
In the beginning of the main script use
. .\variables.ps1
If you are after expanding variables that are in external file to ues as an email template please do as following:
$HTMLBody = get-content "yourfilepath" | Foreach-Object {$ExecutionContext.InvokeCommand.ExpandString($_)}
This will expand all variables and put it in the $HTMLBody variable
Then use:
$emailMessage.Body = (ConvertTo-Html -body $HTMLBody)
there!!
Here is my goal, I'm trying accomplish with Powershell script.
I have administrative user that need to be able extract csv file from password protected zip file and send this csv file by email.
Given directory has many zip files named by username (e.g. dana.zip) and protected with the same password (123456). The administrative user (who know the password for zip files) needs to run powershell script which asking for input desired user name and then do it's staff - extract file to the same directory and send it by email.
So far I find and adopt for above needs following powershell scripts.
Unzip Password protected file:
$7ZipPath = '"C:\Program Files\7-Zip\7z.exe"'
$User = Read-Host -Prompt 'Please Input Desired User Name'
write-host ""
write-host " --------------------------------------------------------------------------------- " -foregroundcolor DarkCyan
write-host ""
write-host " Desired file will be extracted to W:\ADMINISTRATION folder " -foregroundcolor Cyan
write-host ""
write-host " --------------------------------------------------------------------------------- " -foregroundcolor DarkCyan
write-host ""
$zipFile = '"W:\ADMINISTRATION\$User.zip"'
$zipFilePassword = "123456"
$command = "& $7ZipPath e -oW:\ADMINISTRATION -y -tzip -p$zipFilePassword $zipFile"
iex $command
This script doing it's job, but I'm trying to avoid usage of password as plain text in the script. Since this script will be run under same administrative user account I've tried to use encrypted password file in the script.
First, I've run following command to create encrypted password file:
"123456" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "W:\Admin\ZipPassword.txt"
Afterwards I've adopt my script to use encrypted password file:
$7ZipPath = '"C:\Program Files\7-Zip\7z.exe"'
$User = Read-Host -Prompt 'Please Input Desired User Name'
write-host ""
write-host " --------------------------------------------------------------------------------- " -foregroundcolor DarkCyan
write-host ""
write-host " Desired file will be extracted to W:\\ADMINISTRATION folder " -foregroundcolor Cyan
write-host ""
write-host " --------------------------------------------------------------------------------- " -foregroundcolor DarkCyan
write-host ""
$zipFile = '"W:\ADMINISTRATION\$User.zip"'
$cred = Get-Content "W:\Admin\ZipPassword.txt" | ConvertTo-SecureString
$zipFilePassword = new-object -typename System.Management.Automation.PSCredential -argumentlist ($cred)
$command = "& $7ZipPath e -oW:\ADMINISTRATION -y -tzip -p$zipFilePassword $zipFile"
iex $command
When running this script I'm getting following error:
If it possible to make this script use encrypted password file it will me very beneficial...
The second script - sending extracted file by email.
First, I've created encrypted password file (in this script it 's working perfectly):
"myPassword" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "W:\Admin\EmailPassword.txt"
And here is the script itself:
$User = "me.me#gmail.com"
$File = "W:\Admin\EmailPassword.txt"
$cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $File | ConvertTo-SecureString)
$EmailTo = "me.me#gmail.com"
$EmailFrom = "me.me#gmail.com"
$Subject = "Some text here"
$Body = "Some text here"
$SMTPServer = "smtp.gmail.com"
$filenameAndPath = "W:\ADMINISTRATION\dana.csv"
$SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$EmailTo,$Subject,$Body)
$Attachment = New-Object System.Net.Mail.Attachment($filenameAndPath)
$SMTPMessage.Attachments.Add($attachment)
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($cred.UserName, $cred.Password);
$SMTPClient.Send($SMTPMessage)
write-host "Mail Sent Successfully !!" -foregroundcolor Green
This script working as expected... The only problem is that administrative user need edit it each time and put proper filename (dana.csv, david.csc... etc). Of course I can use user input method in this script as well, but I want to combine both scripts into the single one... So far I tried this one:
$7ZipPath = '"C:\Program Files\7-Zip\7z.exe"'
$User = Read-Host -Prompt 'Please Input Desired User Name'
write-host ""
write-host " --------------------------------------------------------------------------------- " -foregroundcolor DarkCyan
write-host ""
write-host " Desired file will be extracted to W:\\ADMINISTRATION folder " -foregroundcolor Cyan
write-host ""
write-host " --------------------------------------------------------------------------------- " -foregroundcolor DarkCyan
write-host ""
$zipFile = '"W:\ADMINISTRATION\$User.zip"'
$zipFilePassword = "123456"
$command = "& $7ZipPath e -oW:\ADMINISTRATION -y -tzip -p$zipFilePassword $zipFile"
iex $command
$User = "me.me#gmail.com"
$File = "W:\Admin\EmailPassword.txt"
$cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $File | ConvertTo-SecureString)
$EmailTo = "me.me#gmail.com"
$EmailFrom = "me.me#gmail.com"
$Subject = "Some text here"
$Body = "Some text here"
$SMTPServer = "smtp.gmail.com"
$filenameAndPath = "W:\ADMINISTRATION\$User.csv"
$SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$EmailTo,$Subject,$Body)
$Attachment = New-Object System.Net.Mail.Attachment($filenameAndPath)
$SMTPMessage.Attachments.Add($attachment)
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($cred.UserName, $cred.Password);
$SMTPClient.Send($SMTPMessage)
write-host "Mail Sent Successfully !!" -foregroundcolor Green
But it's failed to attach file to email. I think I have problem here (wrong syntax):
$filenameAndPath = "W:\ADMINISTRATION\$User.csv"
So, if someone can help me to fix following issues, it will be much appreciated:
In the first portion of script, use encrypted password file instead of plain text
In the second portion, adopt user input from the first part of the script ($User) to be used as file name (for instance, if user input was "dana" , $User.csv will be equal to dana.csv)
Remove *.csv file after mail was sent.
Thank you in advance,
Igor.
I've fixed all the issues after "googling" them, So I can share my experience...
In the first portion of script, use encrypted password file instead of plain text
Like TheIncorrigible1 mentioned in his answer on my question:
You cannot completely avoid having a reversible password in your
script while using an external command like 7z unless it also supports
encrypted passwords being passed to it. SecurePassword is a
Windows-specific construct.
It looks like 7zip not supporting Windows-specific encrypted password, so I need convert it back to plain text before using it.
I've found how to do it in those sites:
https://blogs.msdn.microsoft.com/timid/2009/09/10/powershell-one-liner-decrypt-securestring/#comment-6495
and
http://www.travisgan.com/2015/06/powershell-password-encryption.html
So this peace of code helped me out fixing encrypted password issue:
$Password = Get-Content 'W:\Administration\EncryptedPasswords\ZipPassword.txt'| ConvertTo-SecureString
$Marshal = [System.Runtime.InteropServices.Marshal]
$Bstr = $Marshal::SecureStringToBSTR($Password)
$ZipPassword = $Marshal::PtrToStringAuto($Bstr)
$Marshal::ZeroFreeBSTR($Bstr)
In the second portion, adopt user input from the first part of the script ($User) to be used as file name (for instance, if user input
was "dana" , $User.csv will be equal to dana.csv)
This was my mistake,- I've used the same variable $User in the first and second portions of script, so $User variable from second portion of script override existing one... Therefore file wasn't attached to email. After changing variable in the first portion of script, issue goes away:
$Username = Read-Host -Prompt 'Please Input Desired User Name'....
$zipFile = "W:\ADMINISTRATION\$UserName.zip"...
$filenameAndPath = "W:\ADMINISTRATION\$UserName.csv"
Remove *.csv file after mail was sent.
I've accomplished this goal using separate PowerShell script:
Get-ChildItem W:\Administration\*.csv | Where { ! $_.PSIsContainer } | remove-item
write-host " ---------------------------------------------- " -foregroundcolor DarkCyan
write-host ""
write-host " All Operations Completed Successfully !!" -foregroundcolor Green
write-host ""
write-host " ---------------------------------------------- " -foregroundcolor DarkCyan
[VOID] [reflection.assembly]::loadwithpartialname("System.Windows.Forms ");[reflection.assembly]::loadwithpartialname ("System.Drawing")
$notify = new-object system.windows.forms.notifyicon
$notify.icon = [System.Drawing.SystemIcons]::Information
$notify.visible = $true
$notify.showballoontip(10,"Operation Complete","All updates have been installed.",[system.windows.forms.tooltipicon]::None)
Is it possible to run this powershell script to display a popup balloon notification from a batch file with parameters to change the title and message?
This works:
#echo off
setlocal EnableDelayedExpansion
PowerShell.exe ^
[VOID] [reflection.assembly]::loadwithpartialname(\"System.Windows.Forms\"); ^
[reflection.assembly]::loadwithpartialname(\"System.Drawing\"); ^
$notify = new-object system.windows.forms.notifyicon; ^
$notify.icon = [System.Drawing.SystemIcons]::Information; ^
$notify.visible = $true; ^
$notify.showballoontip(10,\"Operation Complete\",\"All updates have been installed.\",[system.windows.forms.tooltipicon]::None)
In order to change any parameter just use the usual %replacement% value in the PS lines. Remember that these lines will be evaluated as a long Batch line, and then executed as a PowerShell command. For the same reason, all quotes must be preceded by back-slash.
You could do
#ECHO OFF
PowerShell.exe
[VOID] [reflection.assembly]::loadwithpartialname("System.Windows.Forms ");[reflection.assembly]::loadwithpartialname ("System.Drawing")
$notify = new-object system.windows.forms.notifyicon
$notify.icon = [System.Drawing.SystemIcons]::Information
$notify.visible = $true
$notify.showballoontip(10,"Operation Complete","All updates have been installed.",[system.windows.forms.tooltipicon]::None)
Look at http://www.howtogeek.com/204088/how-to-use-a-batch-file-to-make-powershell-scripts-easier-to-run/
I know how to use cat file
cat file.txt
but I have variable
[string]$body = "Body message here"
I need help changing it to get the text content from file.txt
I tried, but it didn't work.
[string]$body = $cat file.txt
Here is full script, I am trying to change param section.
param
(
[string]$email = $(read-host "Enter a recipient email"),
[string]$subject = $(read-host "Enter the subject header"),
[string]$body = $(read-host "Enter the email text (optional)")
)
to
param
(
[string]$email = "my#email.com",
[string]$subject = "server",
[string]$body = gc C:\Users\myuser\Documents\somefolder\GnuWin32\bin\status.txt
)
# ==========================================================================
# Functions
# ==========================================================================
function Send-Email
(
[string]$recipientEmail = $(Throw "At least one recipient email is required!"),
[string]$subject = $(Throw "An email subject header is required!"),
[string]$body
)
{
$outlook = New-Object -comObject Outlook.Application
$mail = $outlook.CreateItem(0)
$mail.Recipients.Add($recipientEmail)
$mail.Subject = $subject
$mail.Body = $body
# For HTML encoded emails
# $mail.HTMLBody = "<HTML><HEAD>Text<B>BOLD</B> <span style='color:#E36C0A'>Color Text</span></HEAD></HTML>"
# To send an attachment
# $mail.Attachments.Add("C:\Temp\Test.txt")
$mail.Send()
Write-Host "Email sent!"
}
Write-Host "Starting Send-MailViaOutlook Script."
# Send email using Outlook
Send-Email -recipientEmail $email -subject $subject -body $body
Write-Host "Closing Send-MailViaOutlook Script."
Change:
[string]$body = ( gc C:\Users\myuser\Documents\somefolder\GnuWin32\bin\status.txt )
note the brackets.
Try the following
[string]$body = gc file.txt
The command gc is an alias for Get-Content which will get the content of the specified item and return it as a string
EDIT
As C.B. pointed out, in your example you are trying to use $cat instead of cat. $cat attempts to refer to a variable which isn't defined but cat is another alias for Get-Content
EDIT2
It looks like you are trying to initialize a param. If so you need to do the following
[string]$body = $(gc "C:\Users\myuser\Documents\somefolder\GnuWin32\bin\status.txt")