Line break removed in output in PowerShell - powershell

I'm using the following script to get a list of all the services that are automatic but not running on a set of servers.
Code:
$Me = 'me#domain.com'
function Get-AutoServiceStatus
{
$Servers = 'SRV1', 'SRV2', 'SVR3', 'SVR4'
foreach ($Server in $Servers)
{
Write-Output "`nThe automatic services that aren't running on $Server are:"
Get-WmiObject win32_service -Filter "StartMode = 'auto' AND state != 'Running'" -ComputerName $Server | select -ExpandProperty DisplayName | Format-List
}
}
$Output = Get-AutoServiceStatus | Out-String
$Body = "Hi team,`n`nHere are the services that are set to start automatically on each of the listed servers, but aren't running.`n" + $Output + "Please take the necessary actions.`n`nRegards,`nBig Guy"
Send-MailMessage -From 'BigGuy#domain.com' -To $Me -SmtpServer 'smtpserver.domain.com' -Body $Body -Subject 'Post-reboot service check on Servers'
Console output:
The automatic services that aren't running on MySrv are:
Microsoft .NET Framework NGEN v4.0.30319_X86
Microsoft .NET Framework NGEN v4.0.30319_X64
Software Protection
Windows Image Acquisition (WIA)
Received email:
The automatic services that aren't running on SRV1 are:
Microsoft .NET Framework NGEN v4.0.30319_X86Microsoft .NET Framework NGEN v4.0.30319_X64Software ProtectionWindows Image Acquisition (WIA)
Desired email:
Some friendly text here
The automatic services that aren't running on MySrv are:
Microsoft .NET Framework NGEN v4.0.30319_X86
Microsoft .NET Framework NGEN v4.0.30319_X64
Software Protection
Windows Image Acquisition (WIA)
Bye
As in, I need each service name appear on a separate line. However, all the names of the services appear on the same line.
PS version: 3.0
Please help me with this. Thanks in advance!
Regards,
Ram

Have you tried formatting the email to HTML?
Function Send-Email {
$From = "email1#domain.com"
$To = "bigguy#domain.com"
$Body = "<strong>Date:</strong>"+(Get-Date)+"<br>"+"<strong>Hostname:</strong>$hostname<br>"+"`<strong>The automatic services that aren't running on MySrv are:</strong>.<br>$Output<br><br><br><br><br><br><br><h3 style=""color:red;"">*** This is an automatically generated email, please do not reply ***</h3>"
Send-MailMessage -From $From -to $To -Subject $Subject `
-Body $Body -SmtpServer $SMTPServer -BodyAsHtml
}
Email:
Hostname: SERV1
Date:04/25/2016 11:55 AM
The automatic services that aren't running on MySrv are:
upnbphost
WinMgmt
*** This is an automatically generated email, please do not reply ***

Related

Issue in Executing a batch script during -XX:OnOutOfMemoryError event

I have written a power shell script in my Win 2008 server, to execute the below mentioned 4 steps whenever an OutOfMemoryError occurs in the system.
Email users that the applications is going to be restarted.
stop the app service
clear cache and tmp files
start the service
email users that the service is started
The Script is given below and it is working like a gem when executed manually. I have added the below .ps1 script in a .bat file and updated the registry entry as
-server -Xms1024m -Xmx1536m -XX:MaxPermSize=256m -XX:+UseParallelOldGC -XX:OnOutOfMemoryError="D:\Support\UWD_OOM_restart.bat"
Issue: Whenever an OOM error occurs, the batch script invokes the power shell script, but only the first 3 steps are getting executed automatically. The last 2 steps( starting the service and emailing end users are not getting executed automatically). Need some assistance in this case
Power shell script:
$hostname = 'XXXXXX'
$smtpServer = 'xxxxxxxx'
$from = "xxxxxxxx#xxxxxxxx.com"
$recipients = 'xxxxxxxx#xxxxxxxx.com'
$Subject = "Restarting Apps - UWD Service on $hostname due to Java OUT OF MEMORY ERROR"
$body = "This is an automated message to confirm that the UWD service on xxxxxxxx server is about to be restarted, as the application has encountered Java out of memory error and went to unresponsive state. Kindly ignore any alerts for the next 10 minutes from this service."
Send-MailMessage -To $recipients -Subject $Subject -Body $body -From $from -SmtpServer $smtpServer
# Stop service
$service = 'xxxxxxxx"
Stop-Service -name $service -Verbose
do {
Start-sleep -s 5
}
until ((get-service $service).Status -eq 'Stopped')
# Folder delete
rm -r -fo 'D:\xxxxxxx\cache'
rm -r -fo 'D:\xxxxxxx\tmp'
# Start service
start-Service -name $service -Verbose
do {
Start-sleep -s 5
}
until ((get-service $service).Status -eq 'Running')
# Send confirmation that service has restarted successfully
$Subject = "UWD Service Restarted Successfully on $hostname"
$body = "This mail confirms that the UWD application service on $hostname is now running.
Application Team, Kindly smoke test your application and inform xxxxxx for any issues."
Start-Sleep -s 5
Send-MailMessage -To $recipients -Subject $Subject -Body $body -From $from -SmtpServer $smtpServer

Windows Service Recovery, Unable to execute PS-script

OS: Win 2012 R2
Hi,
I tried setting up certain services so that when they fail the second time a powershell script is triggered which emails certain people. This is done through services > (specific service) > properties > recovery.
Tried nearly every conceivable combination of Program:
Powershell.exe, C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe, same as the last but with capital "P".
Commandline parameters: -NoProfile -Executionpolicy bypass C:\users\username\appdata\local\myscript.ps1, the parameters after the path to the script.
The script is not signed.
Now my script uses the Send-MailMessage and the password is saved using ConvertFrom-SecureString and I was thinking that the service/user which actually runs the script maybe couldn't decrypt the password since it was created with my admin account.
I tried logging in as the same service account that is running the processes I want to monitor and create the encrypted password file from their user and saving it in a path that don't require that user to be admin (i.e. %localappdata%) but the script still fails to trigger when I use pskill on the PID.
When executing the command manually in PS everything works and I am not prompted for anything. It does exactly what it should do.
Now I am quite new to the Windows admin scene so which user or service actually triggers the PowerShell script? Is it the same identity that is running the service, i.e. the specific service account I specified? Or is it something else?
I'll happily post the code here but it is on my other computer and I will update this later with it. Googled for hours and tried almost everything, it might be something basic I am missing however.
Thank you very much for your help - TheSwede86
Edit: Here is the code and I also tried Ronald Rink 'd-fens'suggestion and it logs the user when I manually execute the script (showing an event with my username) but not when I try to simulate service failure.
$PSEmailServer = "<address to smtp-server>"
$SMTPPort = <port>
$SMTPUsername = "<email-address to send from>"
$EncryptedPasswordFile = "<path and filename to pwd-file, currently on C:\>.securestring"
$SecureStringPassword = Get-Content -Path $EncryptedPasswordFile | ConvertTo-SecureString
$EmailCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $SMTPUsername,$SecureStringPassword
$MailTo = "<email-address to mail to>"
$MailFrom = $SMTPUsername
$hostname = Hostname
$service = Get-Service -Name "<Servicename*>" | Where-Object {$_.Status -eq "Stopped"}
$MailSubject = "ALERT: Service on $hostname has stopped and failed to restart after one attempt"
$MailBody = "$service"
$OtherEmail = "<Other email-address to send to>"
$whoami = whoami
Send-MailMessage -From $MailFrom -To $MailTo -Bcc $OtherEmail -Subject $MailSubject -Body $MailBody -Port $SMTPPort -Credential $EmailCredential -UseSsl -Priority High
Write-EventLog –LogName Application –Source “PowerShell Script Debug” –EntryType Information –EventID 1 -Message $whoami
Redacted email-addresses, SMTP-server etc.
Edit 1: Added trying to log which user who executes the script.
Edit 2: #Ronald Rink 'd-fens'
I tried the following:
$PlainPassword = "<passwordForEmailToSendFrom>"
$SecurePassword = $PlainPassword | ConvertTo-SecureString -AsPlainText -Force | Out-File -FilePath C:\temp\<filename>.securestring
I let the service fail once with above so it will convert the plaintext password to a securestring-file which I then call upon in my script; this does not work.
If I try your suggestion:
1)
$password = "<passwordForEmailToSendFrom>" | ConvertTo-SecureString -asPlainText -Force
$username = "<domain\serviceAccountWhichRunsTheService>"
$credential = New-Object System.Management.Automation.PSCredential($username,$password)
$credential | Export-CliXml C:\temp\credential.xml
It successfully creates "credential.xml" in my chosen path
2)
$credential = Import-CliXml C:\temp\credential.xml
$decryptedCredential = "{0} - {1}" -f $credential.UserName, $credential.GetNetworkCredential().Password
$decryptedCredential | Out-File C:\temp\ServiceRecovery.txt -Append -Force
I get the password unencrypted in "ServiceRecovery.txt" and the but not SYSTEM.
I added "SYSTEM" to the local "Administrators"-group and tried again;
it just adds another line to "ServiceRecovery.txt" with the username I specified in "1" and the unencrypted password.
I was however successful when I tried your script about which user who actually runs the script and that was indeed "SYSTEM".
Sorry for my bad explanation, have sat for hours trying to get this final bit sorted but unable to do so.
Edit 3:
Thanks to #Ronald Rink 'd-fens' I solved it this way:
New-Object System.Management.Automation.PSCredential("<EmailAddressToSendFrom>", (ConvertTo-SecureString -AsPlainText -Force "<PasswordForAboveEmailAccount>")) | Export-CliXml C:\temp\MyCredential.xml
Above converts unencrypted password to encrypted using API (DPAPI) only usable for the account/machine that it is created on!
Let the service fail once with above script to generate the file with the SERVICE account
$PSEmailServer = "<smtp-address>"
$SMTPPort = <port>
$SMTPUsername = "<EmailAddressToSendFrom>"
$credpath = Import-Clixml -Path C:\temp\MyCredential.xml
$MailTo = "<EmailAddressToSendTo>"
$MailFrom = $SMTPUsername
$hostname = Hostname
$service = Get-Service -Name "<Servicename(s)>" | Where-Object {$_.Status -eq "Stopped"} | Select-Object -Property DisplayName | Out-String
$MailSubject = "ALERT: Service on $hostname has stopped and failed to restart after one attempt"
$MailBody = $service
$OtherEmail = "<AnotherEmailAddressToSendTo>"
Send-MailMessage -From $MailFrom -To $MailTo -Bcc $OtherEmail -Subject $MailSubject -Body $MailBody -Port $SMTPPort -Credential $credpath -UseSsl -Priority High
Above is the actual script that will run when the service fails
Arguments in Services > Recovery is:
Program: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Command line parameters:
-File C:\temp\myscriptname.ps1
Enable actions for stops with errors
First failure: Restart the Service
Second failure: Run a Program
It seems very much that the script you entered to be run in case of a failure is not running under the service account (nor under your admin account) but under an account of the operating system. You can verify this by logging the username from within the script when executed after your service failed (use Write-EventLog or save it from to a text file).
Here is an example of how you can verify that your script runs under the local system:
# C:\src\TEMP\ServiceRecovery.ps1
cd C:\src\TEMP\
$ENV:USERNAME | Out-File C:\src\TEMP\ServiceRecovery.txt -Append -Force
You can configure your service as shown in the following screenshots:
The service account was created like this:
PS > net user ServiceAccount P#ssw0rdP#ssw0rd /ADD
PS > net localgroup Administrators ServiceAccount /ADD
If I then stop the process by invoking Stop-Process -Name teamviewer_service -Force I can see the following name in the generated text file:
SYSTEM
This means you would have to encrypt the secure string via the SYSTEM account and not via your personal user or service user account or you have to resort to some other means on how to read your encrypted password.
Encrypting your password via the service account can be achieved by creating a script to create a password and store it in encrypted form. Put this script into your service recovery settings and make this service fail once. Then remove the script and insert your original script which will then be able to import the encrypted password.
Here you find the scripts with which I tested it:
(1) Script to encrypt credentials
# Creating a PS Credential from a Clear Text Password in Powershell
# https://blogs.technet.microsoft.com/gary/2009/07/23/creating-a-ps-credential-from-a-clear-text-password-in-powershell/
$password = "P#ssw0rdP#ssw0rd" | ConvertTo-SecureString -asPlainText -Force
$username = ".\ServiceAccount"
$credential = New-Object System.Management.Automation.PSCredential($username,$password)
$credential | Export-CliXml C:\src\TEMP\credential.xml
(2) Script to decrypt credentials
$credential = Import-CliXml C:\src\TEMP\credential.xml
$decryptedCredential = "{0} - {1}" -f $credential.UserName, $credential.GetNetworkCredential().Password
$decryptedCredential | Out-File C:\src\TEMP\ServiceRecovery.txt -Append -Force
Now the generated text file contains
.\ServiceAccount - P#ssw0rdP#ssw0rd
Note: the first "encrypt" script contains a plain text password which is only used once for encryption. We have to go this way, in order to run under the SYSTEM account. An alternative to this might be using RunAs from SysInternals.

Send-MailMessage : The SMTP server requires a secure connection or the client was not authenticated. The

First time poster - I've been googling this all week! I'm fairly new to Powershell and I'm trying to utilise Send-MailMessage. The objective is to set a Powershell script on a scheduled task to send out an automated email. I know setting a Powershell script as a scheduled task has it's own nuances which I have researched and I think I know what to do next in regards to that but before I even get to that point I keep running across the following error when I call the script:
Send-MailMessage : The SMTP server requires a secure connection or the client was not authenticated. The server
response was: 5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL FROM
$secpasswd = ConvertTo-SecureString “PASSWORD” -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential "user#domain.com", $secpasswd
Send-MailMessage -To "user#domain.com" -Subject "Subject" -SmtpServer "smtp.office365.com" -Credential $mycreds -UseSsl -Port "587" -From "user#domain.com"
I'm trying to send the message using Office 365 (as you can see from the SMTP server). This works fine when I copy and paste it directly into the console but when I try to call the script using the following command it shows the above error.
Powershell.exe -File C:\my_path\Script.ps1
Is there something that I'm missing? Possibly a better way of calling the script which authenticates it?
Any help would be greatly appreciated, I've been staring at various forum posts for days now! :)
Please take a look at my Github Gist for this Click Here or see example below.
I had the same issue and is seems that this is a generic error message, most of the time i get this message when i entered a wrong password, but i believe not having SendAs rights gave the same error, the Port , SMTPServer and UseSSL Parameters in the example are configured for Office365 which i just tested and it works.
Also note that i provided an example for Secure Strings, you should use this if you want to store passwords securely in your script files.
### Script Global Settings
#Declare SMTP Connection Settings
$SMTPConnection = #{
#Use Office365, Gmail, Other or OnPremise SMTP Relay FQDN
SmtpServer = 'outlook.office365.com'
#OnPrem SMTP Relay usually uses port 25 without SSL
#Other Public SMTP Relays usually use SSL with a specific port such as 587 or 443
Port = 587
UseSsl = $true
#Option A: Query for Credential at run time.
Credential = Get-Credential -Message 'Enter SMTP Login' -UserName "emailaddress#domain.tld"
<#
#Option B: Hardcoded Credential based on a SecureString
Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList #(
#The SMTP User Emailaddress
"emailaddress#domain.tld"
#The Password as SecureString encoded by the user that wil run this script!
#To create a SecureString Use the folowing Command: Read-Host "Enter Password" -AsSecureString | ConvertFrom-SecureString
"Enter the SecureString here as a single line" | ConvertTo-SecureString
)
#>
}
### Script Variables
#Declare Mailmessages.
$MailMessageA = #{
From = "emailaddress#domain.tld"
To = #(
"emailaddress#domain.tld"
)
#Cc = #(
# "emailaddress#domain.tld"
#)
#Bcc = #(
# "emailaddress#domain.tld"
#)
Subject = 'Mailmessage from script'
#Priority = 'Normal' #Normal by default, options: High, Low, Normal
#Attachments = #(
#'FilePath'
#)
#InlineAttachments = #{
#'CIDA'='FilePath'
#} #For more information about inline attachments in mailmessages see: https://gallery.technet.microsoft.com/scriptcenter/Send-MailMessage-3a920a6d
BodyAsHtml = $true
Body = "Something Unexpected Occured as no Content has been Provided for this Mail Message!" #Default Message
}
### Script Start
#Retrieve Powershell Version Information and store it as HTML with Special CSS Class
$PSVersionTable_HTLM = ($PSVersionTable.Values | ConvertTo-Html -Fragment) -replace '<table>', '<table class="table">'
#Retrieve CSS Stylesheet
$CSS = Invoke-WebRequest "https://raw.githubusercontent.com/advancedrei/BootstrapForEmail/master/Stylesheet/bootstrap-email.min.css" | Select-Object -ExpandProperty Content
#Build HTML Mail Message and Apply it to the MailMessage HashTable
$MailMessageA.Body = ConvertTo-Html -Title $MailMessageA.Subject -Head "<style>$($CSS)</style>" -Body "
<p>
Hello World,
</p>
<p>
If your recieved this message then this script works.</br>
</br>
<div class='alert alert-info' role='alert'>
Powershell version
</div>
$($PSVersionTable_HTLM)
</P>
" | Out-String
#Send MailMessage
#This example uses the HashTable's with a technique called Splatting to match/bind the Key's in the HashTable with the Parameters of the command.
#Use the # Symbol instead of $ to invoke Splatting, Splatting improves readability and allows for better management and reuse of variables
Send-MailMessage #SMTPConnection #MailMessageA

Send-MailMessage : The SMTP server requires a secure connection... The server response was: 5.5.1 Authentication Required.

Alright so as the title says, I get this error when trying to send email via PowerShell:
Send-MailMessage : The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required.
I have looked at numerous questions related to the same issue. But I can't seem to make my script work:
#Email alerts when a user gets locked out
##############################################################################
$pass = Get-Content .\securepass.txt | ConvertTo-SecureString -AsPlainText -Force
$name = "sender#gmail.com"
$cred = New-Object System.Management.Automation.PSCredential($name,$pass)
##############################################################################
$From = "sender#gmail.com"
$To = "recipient#domain.org"
$Subject = "User Locked Out"
$Body = "A user has been locked out of his/her account."
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
Send-MailMessage -From $From -to $To -Subject $Subject `
-Body $Body -SmtpServer $SMTPServer -port $SMTPPort `
-Credential $cred -UseSsl
##############################################################################
I have logged into the Gmail account from the machine that will be running the script. I have also enabled Access for less secure apps from the Google account manager. I do get this to work just fine if I prompt for the credentials using the -Credential (Get-Credential) instead of calling for the $cred variable.
Is there something I am missing?
Thanks,
Dan
If the file contains the encrypted password it's better to read it like this (without the parameters -AsPlainText and -Force):
$pass = Get-Content .\securepass.txt | ConvertTo-SecureString
Demonstration:
PS C:\> $sec = 'foobar' | ConvertTo-SecureString -AsPlainText -Force
PS C:\> $sec
System.Security.SecureString
PS C:\> $txt = $sec | ConvertFrom-SecureString
PS C:\> $txt
01000000d08c9ddf0115d1118c7a00c04fc297eb01000000615ce070639b9647a5e05d42b41d373
0000000000200000000001066000000010000200000001614c19281e7c0b076cceb38e284b0f18b
c0d813ea40ed055dde96fd9ccb6977000000000e8000000002000020000000a10c7019eb224c3c6
387ba03bcd94993a50e0c468248284bbce4d235b11f1b94100000002421a5d7102de13c46ccc1db
c4921287400000000412332ecb500828f4403f3e225089c629369744bad62609b528ed0a7318abf
512c9b6a8884c43b3adc8a13d5d21a9ed27e56702bcc7db094da9d9d4c02dfa74
PS C:\> $sec2 = $txt | ConvertTo-SecureString
PS C:\> $sec2
System.Security.SecureString
PS C:\> $cred = New-Object Management.Automation.PSCredential 'foo', $sec2
PS C:\> $cred.GetNetworkCredential().Password
foobar
Beware though that encryption of secure strings is tied to the user and host encrypting them, meaning you can't decrypt a secure string on another host or as another user.
I found my answer after looking at my passwords file content, thanks to Angsgar. The securepass.txt had the encrypted contents inside, not plaintext. What I did was replace it with the actual password that will then be encrypted when setting my $pass variable. All is good now!
Ansgar's answer is a good generic answer, but for Google, they have multiple SMTP servers that you can use. smtp.google.com requires authentication, but not all of them do.
From Google's doc, if your site is a G Suite site and you will always be sending from a specific IP address, you can specify the address in G Suite configuration and then use the G Suite SMTP relay at smtp-relay.gmail.com. This is only available to G Suite users, and requires either authentication or a static IP. At our site, we have an internal SMTP server that we use for these sorts of emails which relays to Google's G Suite SMTP relay server.
If you are sending email only to Google or G Suite addresses, you can specify aspmx.l.google.com as your SMTP address. This is known as the restricted Gmail SMTP server.

Email credentials when using send-mailmessage command

I have searched through many many forums and they do explain how to do this but the technical language is just too difficult to understand as I'm very new to powershell. I would like this explained to me step by step (baby steps). I would like to run this powershell command in a batch file (.bat). I have a batch file that does robocopy backups weekly and I want the batch file to send me a email when the backup is complete. The only issue I have is the credentials, I get a pop-up box asking for the user name and password. When I eneter this information the email will send successfully. Here is what I have;
Using: powershell V2.0 Windows 7 Ultimate
Powershell -command send-mailmessage -to emailadress#provider.com -from emailaddress#provider.com -smtp smtp.broadband.provider.com -usessl -subject 'backup complete'
$from = "example#mail.com"
$to = "example#mail.com"
$smtp = "smtpAddress.com"
$sub = "hi"
$body = "test mail"
$secpasswd = ConvertTo-SecureString "yourpassword" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential($from, $secpasswd)
Send-MailMessage -To $to -From $from -Subject $sub -Body $body -Credential $mycreds -SmtpServer $smtp -DeliveryNotificationOption Never -BodyAsHtml
You could pass the credential object in your same command - which would avoid the popup:
Powershell -Command 'Send-MailMessage -to "emailadress#provider.com" -from "emailaddress#provider.com" -smtp "smtp.broadband.provider.com" -usessl -subject "backup complete" -credential (new-object System.Net.NetworkCredential("user","pass","domain"))'
I'd recommend storing the username/password in a somewhat more safer format, but this should do your trick.
I'm not sure you can do SMTP authentication using the send-mailmessage command. But, you can send a message through an SMTP server that requires authentication using the Net.Mail.SmtpClient object and the System.Net.Mail.MailMessage object. See How to pass credentials to the Send-MailMessage command for sending emails for a good example.
look at the last exemple of send-mailmessage helppage
you will see you can pass credential whith the parameter -credential domain01\admin01
look here Using PowerShell credentials without being prompted for a password if you dont want any prompt (save your cred in a text file)