Pass powershell variable to batch script - powershell

Here is powershell script
$a = get-date -format "MMM-d-yyyy"
Start-Process "D:\Script\send_report.bat"
send_report.bat uses blat to send email
D:
cd "D:\Program Files (x86)\blat321\full"
blat -s "Daily Report" -i "Our Team" -to member1#team.org,member2#team.org -body "Please see attached." -priority 1 -attach D:\Script\Daily_Report.xlsx
How do I insert $a into send_report.bat? I would like value of $a next to "Daily Report"

#echo off
cd /d "D:\Program Files (x86)\blat321\full"
set "the_date=%~1"
blat -s "Daily Report" -i "Our Team" -to member1#team.org,member2#team.org -body "Please see attached." -priority 1 -attach D:\Script\Daily_Report_%the_date%.xlsx
and call the bat like :
$a = get-date -format "MMM-d-yyyy"
Start-Process "D:\Script\send_report.bat" $a

In your PowerShell script, add $a as a parameter to the batch file:
Start-Process "D:\Script\send_report.bat" $a
In you batch file reference the parameter as %1.
blat -s "Daily Report %1" -i "Our Team" -to member1#team.org,member2#team.org -body "Please see attached." -priority 1 -attach D:\Script\Daily_Report.xlsx

Related

Catch error from Send-MailMessage cmdlet when called from batch file

I have a batch file that uses PowerShell's Send-MailMessage cmdlet to send emails out with status updates:
powershell -command " & {Send-MailMessage -SMTPServer smtp.somewhere.com -From 'Sender <sender#email.com>' -To 'Recipient <recipient#email.com>' -Subject 'Subject' -Body 'Body' -Attachments 'D:\Logs\Log.log';}"
if %ERRORLEVEL% neq 0 (
echo ERROR - Something went wrong sending the email
goto Error
)
If the Send-MailMessage command fails (e.g. if attachment file not found, or other error), the %ERRORLEVEL% is not raised above 0.
Other answers suggest adding explicit exit codes into a PowerShell script to return a code, but I can't find anything about how to capture an error if using a built in PS cmdlet like Send-MailMessage. Can it be done, or do I need to wrap Send-MailMessage in another PS script?
Wrap the whole command in a try catch block and throw an explicit error. This will return a non-zero exit code.
powershell -command "Try {Send-MailMessage ... -ErrorAction Stop;} Catch { Exit 1 }"
It's a little harder to read in a one line but:
powershell -command "Try {Send-MailMessage -SMTPServer smtp.somewhere.com -From 'Sender <sender#email.com>' -To 'Recipient <recipient#email.com>' -Subject 'Subject' -Body 'Body' -Attachments 'D:\Logs\Log.log' -ErrorAction Stop;} Catch { Exit 1 }"
if %ERRORLEVEL% neq 0 (
echo ERROR - Something went wrong sending the email
goto Error
)

Powershell plink telnet command output into var

I'm trying to write a script (based on some internet examples) for some telnet/ssh command execution, using powershell and plink. But the main feature, which I'd like to implement - is to catch this command's output into the variable or a text file. How can I intercept the output of the specific command?
For example: when I send "get-status" command, it returns "Status is 01 02 03". Can I assign this string to the var or text file? Maybe, only "01 02 03" without "Status" text?
$ps = New-Object -TypeName System.Diagnostics.Process
$ps.StartInfo.UseShellExecute = $false
$ps.StartInfo.RedirectStandardInput = $true
$ps.StartInfo.FileName = "plink"
$ps.StartInfo.Arguments = "-telnet XXX.XXX.XXX.XXX"
[void]$ps.Start()
$PlinkStreamWriter = $ps.StandardInput
Start-Sleep -m 500
$PlinkStreamWriter.Write("login`r")
Start-Sleep -m 500
$PlinkStreamWriter.Write("password`r")
Start-Sleep -m 500
$PlinkStreamWriter.Write("get-status")
Start-Sleep -m 500
Write-Host "Status string: " .....
$PlinkStreamWriter.Write("exit`r")
$PlinkStreamWriter.Close();
if (!$ps.HasExited) { $ps.Kill() }
If I understand you correctly, when you send
$PlinkStreamWriter.Write("get-status")
You receive
Status is 01 02 03
If this is consistent and you want to assign this value to a variable, just define the variable at the beginning of your command:
$result = $PlinkStreamWriter.Write("get-status")
Now if you want to remove "Status is" from the value stored in $result:
$result = $result -replace "Status is ",""
Now $result contains only "01 02 03"
You can now update your write-host command:
Write-Host "Status string: $result"
A simple redirect (>) is all that is needed. I verified this works for me in PowerShell v5.1.22000.282. Here is my approach for anyone who needs it.
$filepath = "$PSScriptRoot"
$PUTTY="$Env:ProgramFiles\PuTTY\plink.exe"
$commands = #"
y
vncserver -geometry 1920x1080
exit"#
#echoes yes onto putty prompt if it exists and spits output to out.txt
echo $commands | & $PUTTY -ssh $IP -l $USER -pw $PW > "$filepath/out.txt"
This may be of use, you can redirect the outputs from error messages and warning messages into standard out. Example:
Invoke-Expression "cmd /c 'C:\Program Files (x86)\PuTTY\plink.exe'$plinkcmd 4>&1 3>&1 2>&1"

Powershell Script To Reindex WSUS DB and email results

Hi I am trying to write a PowerShell script that reindexs the WSUS Database and I am stuck. So far I have a separate config file that holds the email details of the server, and I think I have got the WSUS reindex working. However I'm stuck getting the data from the sql query. I have used a TechNet article as a starting point.
The code I have so far is:
$configKey = #{}
Get-Content server.ini | ForEach-Object {
$keys = $_ -split "="
$configKey += #{$keys[0]=$keys[1]}
}
cd "c:\Program Files\Microsoft SQL Server\100\Tools\Binn\"
"Invoke-sqlcmd -I -i"c:\scripts\WSUSDBMaintenance.sql" -S "np:\\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query"
#file backup
$body += '<font size="5" face="Calibri"Windows Server Reindex Report:</font><br / ><font face="Calibri">'
$body += $Result + "<br>"
"
Invoke-Sqlcmd -Query "PRINT 'Number of indexes to rebuild: ' + cast(##ROWCOUNT as nvarchar(20)';" -Verbose
$body += "</div></font>"
$subject += $configKey.company
#Send Email
Send-MailMessage -From $configKey.from -To $configKey.to -Subject $subject -Body $Body -BodyAsHtml -Smtpserver $configKey.server
a few things jump out at me.
"Invoke-sqlcmd -I -i"c:\scripts\WSUSDBMaintenance.sql" -S "np:\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query"
should probably be
Invoke-sqlcmd -I -i "c:\scripts\WSUSDBMaintenance.sql" -S "np:\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query"
And you have an extraneous double quote here:
$body += $Result + "<br>"
"<<<<<<<<<<<<<<<<<<<<<<<<<
Also, are the tools really in a directory called Binn rather than Bin?

IF statement + send-mailmessage confused

Quick question;
I want to make a log of bad stuff happening to the servers, but that's not the question.
The log should be deleted upon send, and if there is no log at the time the script is being run it should send a different message, without an attachment.
Here's the script so far:
<#
Set-ExecutionPolicy unrestricted -Force
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
cinst BetterCredentials
#>
Import-Module BetterCredentials
$Mailcred = Get-Credential -user user#gmail.com -pass 12345password
Try{
$File = C:/path/errorfile.log
}
Catch [System.Management.Automation.PSArgumentException]
{
"invalid object"
}
Catch [system.exception]
{
"caught a system exception"
}
Finally
{
If ($File -eq ){
then (send-mailmessage -ErrorAction SilentlyContinue -from "Server <Server#company.com>" -to "IT Dept. <Itdept#company.com>" -subject "Log of the day." -body "Good Morning,
Fortuneatly, nothing bad to report today!" -priority High -dno onSuccess, onFailure -smtpServer smtp.company.com -credential ($Mailcred) -usessl)
else (send-mailmessage -ErrorAction SilentlyContinue -from "Servers <Server#company.com>" -to "IT Dept. <ITDept#company.com>" -subject "Log of the day." -body "Good Morning,
Here is your daily report." -Attachments $File -priority High -dno onSuccess, onFailure -smtpServer smtp.company.com -credential ($Mailcred) -usessl)
}
}
What AM I doing wrong here?
Some parts of your code do not make any sense. Let's review those.
$File = C:/path/errorfile.log
...
If ($File -eq ){
The first part is about assignment. In order to find out wether errorfile.log exists, use the Test-Path cmdlet like so,
$File = test-path 'C:/path/errorfile.log'
Always use quotes around file name. If you got spaces within path, unquoted path doesn't work.
The second part is the actual test.
If ($File){
... # file was on disk, send alert and delete it
} else {
... # no file found, send ok
}

Robocopy sending email, attachment, appending file name

I am using robocopy to backup one hard drive to another below is the code that I am using:
robocopy "\\server_location\XXXX" "\\local_location\xxxx" /copyall /TEE /S /r:1 /ndl /xc /xo /xn /log+:"C:\desktop\log.TXT"
START mailto:myemail.job.com?subject=Ovl%%2Reportˆ&body=Test,%%0D%%0A%%0D%%0AHere%%20is%%20is%%the%%20ovl%%20report.%%0D%%0A%%0D%%0ABye
I need to be able to do a couple of things:
email the text file (powershell?) automatically through outlook.
When comparing files if the time stamp is different, append the destination file name, and copy over the file from the source.
So here is a script I've used for a lot of my robocopy jobs. I'm not sure if it fits your "send email through outlook" as it's just doing an SMTP, it's not actually hooking in to Outlook to do it. The script is a Powershell 2.0 script, and remember only Server 2008R2 and Windows Vista+ have the /MT option, which is bad to use with the /TEE option. Script is at the bottom of the post.
For the second point you have, I think you might want two different scripts, one that specifically ignores timestamps, and then another that would include the timestamp difference files, which if ran directly after the first should be about right. This would be with the /XO switch which is "/XO : eXclude Older - if destination file exists and is the same date or newer than the source - don’t bother to overwrite it."
Other options that might help you in scripting that out are:
/XC | /XN : eXclude Changed | Newer files
/XL : eXclude "Lonely" files and dirs (present in source but not destination) This will prevent any new files being added to the destination.
/XX : eXclude "eXtra" files and dirs (present in destination but not source) This will prevent any deletions from the destination. (this is the default)
#*=============================================
#* Base variables
#*=============================================
$SourceFolder = "C:\SourceFolder"
$DestinationFolder = "C:\DestinationFolder"
$Logfile = "C:\Robocopy.log"
$Subject = "Robocopy Results: Copy Purpose - Location to Location"
$SMTPServer = "smtp.server.com"
$Sender = "Server <email#address.com>"
$Recipients = "User1 <email#address.com>"
$Admin = "Admin <email#address.com>"
$SendEmail = $True
$IncludeAdmin = $True
$AsAttachment = $False
#*=============================================
#* GMAIL variables
#*=============================================
#$SMTPServer = "smtp.gmail.com"
#$cred = New-Object System.Net.NetworkCredential("username", "password");
# Add "-UseSsl -Credential $cred" to the Send-MailMessage
#*=============================================
#* SCRIPT BODY
#*=============================================
# Change robocopy options as needed. ( http://ss64.com/nt/robocopy.html )
Robocopy $SourceFolder $DestinationFolder /MIR /R:2 /W:5 /LOG:$Logfile /NP /NDL
# The following attempts to get the error code for Robocopy
# and use this as extra infromation and email determination.
# NO OTHER CODE BETWEEN THE SWITCH AND THE ROBOCOPY COMMAND
Switch ($LASTEXITCODE)
{
16
{
$exit_code = "16"
$exit_reason = "***FATAL ERROR***"
#$IncludeAdmin = $False
#$SendEmail = $False
}
8
{
$exit_code = "8"
$exit_reason = "**FAILED COPIES**"
#$IncludeAdmin = $False
#$SendEmail = $False
}
4
{
$exit_code = "4"
$exit_reason = "*MISMATCHES*"
$IncludeAdmin = $False
#$SendEmail = $False
}
2
{
$exit_code = "2"
$exit_reason = "EXTRA FILES"
$IncludeAdmin = $False
#$SendEmail = $False
}
1
{
$exit_code = "1"
$exit_reason = "Copy Successful"
$IncludeAdmin = $False
#$SendEmail = $False
}
0
{
$exit_code = "0"
$exit_reason = "No Change"
$SendEmail = $False
$IncludeAdmin = $False
}
default
{
$exit_code = "Unknown ($LASTEXITCODE)"
$exit_reason = "Unknown Reason"
#$SendEmail = $False
$IncludeAdmin = $False
}
}
# Modify the subject with Exit Reason and Exit Code
$Subject += " : " + $exit_reason + " EC: " + $exit_code
# Test log file size to determine if it should be emailed
# or just a status email
If ((Get-ChildItem $Logfile).Length -lt 25mb)
{
If ($IncludeAdmin)
{
If ($AsAttachment)
{
Send-MailMessage -From $Sender -To $Recipients -Cc $Admin -Subject $Subject -Body "Robocopy results are attached." -Attachment $Logfile -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
} Else {
Send-MailMessage -From $Sender -To $Recipients -Cc $Admin -Subject $Subject -Body (Get-Content $LogFile | Out-String) -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
}
} Else {
If ($AsAttachment)
{
Send-MailMessage -From $Sender -To $Recipients -Subject $Subject -Body "Robocopy results are attached." -Attachment $Logfile -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
} Else {
Send-MailMessage -From $Sender -To $Recipients -Subject $Subject -Body (Get-Content $LogFile | Out-String) -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
}
}
} Else {
# Creat the email body from the beginning and end of the $Logfile
$Body = "Logfile was too large to send." + (Get-Content $LogFile -TotalCount 15 | Out-String) + (Get-Content $LogFile | Select-Object -Last 13 | Out-String)
# Include Admin if log file was too large to email
Send-MailMessage -From $Sender -To $Recipients -Cc $Admin -Subject $Subject -Body $Body -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
#Exclude Admin if log file was too large to email
#Send-MailMessage -From $Sender -To $Recipients -Subject $Subject -Body $Body -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
}
#*=============================================
#* END OF SCRIPT: Copy-RobocopyAndEmail.ps1
#*=============================================