Send email with PowerShell - c#

I have a function that is able to send email by sending it through PowerShell.
Using the System.Management.Automation reference I am able to use the PowerShell class that allows me to add PowerShell script that will send the email.
If I were to type it directly into the PowerShell window it would look like this:
$password = ConvertTo-SecureString 'PASSWORD' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('sender#email.com', $password)
Send-MailMessage -From 'sender#email.com' -To 'receiver#email.com' -Subject 'Heres the Email Subject' -Body 'This is what I want to say' -SmtpServer 'smtp.office365.com' -Port '587' -UseSsl -Credential $Cred –DeliveryNotificationOption OnSuccess
It is able to send an email but I how would I check if an email wasn't sent?
The function is below.
private void SendEmail()
{
string from = "sender#email.com";
string to = "receiver#email.com";
string subject = "Heres the Email Subject";
string body = "This is what I want to say";
string server = "smtp.office365.com";
string port = "587";
//Password goes here
string password = "PASSWORD";
string pw = "ConvertTo-SecureString '" + password + "' -AsPlainText -Force";
string cred = "New-Object System.Management.Automation.PSCredential('" + from + "', $password)";
string send = "Send-MailMessage -From '" + from + "' -To '" + to + "' -Subject '" + subject + "' -Body '" + body + "' -SmtpServer '" + server + "' -Port '" + port + "' -UseSsl -Credential $Cred -DeliveryNotificationOption OnSuccess";
string psScript = "$password = " + pw + System.Environment.NewLine +
"$Cred = " + cred + System.Environment.NewLine +
send;
using (PowerShell ps = PowerShell.Create())
{
ps.AddScript(psScript);
// invoke execution on the pipeline (collecting output)
Collection<PSObject> PSOutput = ps.Invoke();
// loop through each output object item
foreach (PSObject outputItem in PSOutput)
{
// if null object was dumped to the pipeline during the script then a null
// object may be present here. check for null to prevent potential NRE.
if (outputItem != null)
{
//TODO: do something with the output item
Console.WriteLine(outputItem.BaseObject.GetType().FullName);
Console.WriteLine(outputItem.BaseObject.ToString() + "\n");
}
}
}
}

I found a way to check for errors using ps.HadErrors
using (PowerShell ps = PowerShell.Create())
{
//Add the powershell script to the pipeline
ps.AddScript(psScript);
// invoke execution on the pipeline (collecting output)
Collection<PSObject> PSOutput = ps.Invoke();
//check for any errors
if (ps.HadErrors)
{
foreach (var errorRecord in ps.Streams.Error)
{
Console.WriteLine(errorRecord);
}
}
}

Related

Run Powershell Graph script from Asp.Net

I have the following script to schedule an event on an O365 calendar.
The goal is to run this script from an Asp.net C# page.
If I run it in WindowPowershell ISE, it works perfectly.
The problem is when I run it from the page.
It returns me the following error: "The term 'Connect-MgGraph' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again."
C# CODE
public static string SetEvent(string Subject, string Date, string StartHour, string EndHour, string Location, string[] Attendees, string Body)
{
string result = "";
try
{
//Subject
string strSubject = Subject;
//Param StartDateHour && EndDateHour
DateTime datDate = Convert.ToDateTime(Date);
string strStartDateHour = datDate.Year.ToString() + "-" + datDate.Month.ToString() + "-" + datDate.Day.ToString() + "T" + StartHour;
string strEndDateHour = datDate.Year.ToString() + "-" + datDate.Month.ToString() + "-" + datDate.Day.ToString() + "T" + EndHour;
// Location
string strLocation = Location;
// Attendees
string strAttendees = "#(";
foreach (string item in Attendees)
{
strAttendees += "#{EmailAddress = #{" +
"Address = ' + item.ToString() + ' " +
"} " +
"Type = 'Required'" +
"}";
}
strAttendees += ")";
// Body
string strBody = Body;
//Secrets!
string strAppID = HIDDEN;
string strTenantID = HIDDEN;
string strClientSecret = HIDDEN;
// create Powershell runspace
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runspace);
string scriptfile = HttpContext.Current.Server.MapPath(#"~/PowerShell/scripts/Calendar/SetEvent.ps1");
// create a pipeline and feed it the script text
Pipeline pipeline = runspace.CreatePipeline();
Command myCommand = new Command(scriptfile);
CommandParameter SubjectParam = new CommandParameter("subject", strSubject);
myCommand.Parameters.Add(SubjectParam);
CommandParameter StartDateHourParam = new CommandParameter("startdatehour", strStartDateHour);
myCommand.Parameters.Add(StartDateHourParam);
CommandParameter EndDateHourParam = new CommandParameter("enddatehour", strEndDateHour);
myCommand.Parameters.Add(EndDateHourParam);
CommandParameter LocationParam = new CommandParameter("location", strLocation);
myCommand.Parameters.Add(LocationParam);
CommandParameter AttendeesParam = new CommandParameter("attendees", strAttendees);
myCommand.Parameters.Add(AttendeesParam);
CommandParameter BodyParam = new CommandParameter("body", strBody);
myCommand.Parameters.Add(BodyParam);
CommandParameter AppIDParam = new CommandParameter("appid", strAppID);
myCommand.Parameters.Add(AppIDParam);
CommandParameter TenantIDParam = new CommandParameter("tenantid", strTenantID);
myCommand.Parameters.Add(TenantIDParam);
CommandParameter ClientSecretParam = new CommandParameter("clientsecret", strClientSecret);
myCommand.Parameters.Add(ClientSecretParam);
pipeline.Commands.Add(myCommand);
pipeline.Invoke();
runspace.Close();
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
POWERSHELL CODE
[string]$subject,
[string]$startdatehour,
[string]$enddatehour,
[string]$location,
[string]$attendees,
[string]$appid,
[string]$tenantid,
[string]$clientsecret
)
Import-Module MSAL.PS
Import-Module Microsoft.Graph.Calendar
#Generate Access Token to use in the connection string to MSGraph
$AppId = $appid
$TenantId = $tenantid
$ClientSecret = $clientsecret
$MsalToken = Get-MsalToken -TenantId $TenantId -ClientId $AppId -ClientSecret ($ClientSecret | ConvertTo-SecureString -AsPlainText -Force)
#Connect to Graph using access token
Connect-MgGraph -AccessToken $MsalToken.AccessToken -Scopes "User.Read.All","Calendars.ReadWrite"
$params = #{
Subject = $subject
Start = #{
DateTime = $startdatehour
TimeZone = "GMT Standard Time"
}
End = #{
DateTime = $enddatehora
TimeZone = "GMT Standard Time"
}
Location = #{
DisplayName = $location
LocationType = "Default"
}
IsOnlineMeeting = $true
OnlineMeetingProvider = "teamsForBusiness"
Attendees = $attendees
}
# Create event
New-MgUserEvent -UserId "a#a.net" -BodyParameter $params´´´

System.Automation.Runspaces Error in .NET Core project

I've tried to run the a piece of code in a Console Application - C# (.NET Framework 4.5 project) and it works. But when I tried to migrate it to ASP.NET Core 2.0, the code would return an error(as shown below).
using System.Management.Automation.Runspaces;
public void Powershell()
{
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript("Import-Module AzureAD -Force;");
pipeline.Commands.AddScript("$password = ConvertTo-SecureString " + "\"Accenture01\"" + " -AsPlainText -Force");
pipeline.Commands.AddScript("$Cred = New-Object System.Management.Automation.PSCredential (" + "\"TestID01#eso.dev.accenture.com\"" + ", $password)");
pipeline.Commands.AddScript("Connect-AzureAD -Credential $Cred");
pipeline.Commands.AddScript("Get-AzureADApplication -Filter " + "\"DisplayName eq " + "\'TestApp\'" + "\"");
var result = pipeline.Invoke();
}
The error is
"'System.PlatformNotSupportedException: 'ReflectionOnly loading is
not supported on this platform.'"
Any ideas on this?
Use Powershell.Create() instead of Pipeline, Invoke the Import-Module before you continue, use Add-Command instead of AddScript
Try this: (after opening the runspace, e.g runspace.Open();)
using (var powershell = PowerShell.Create())
{
powershell.Runspace = runspace;
powershell.Commands.AddCommand("Import-Module").AddArgument("AzureAD");
powershell.Invoke();
powershell.Commands.Clear();
powershell.AddScript("$password = ConvertTo-SecureString " + "\"Accenture01\"" + " -AsPlainText -Force");
powershell.AddScript("$Cred = New-Object System.Management.Automation.PSCredential (" + "\"TestID01#eso.dev.accenture.com\"" + ", $password)");
powershell.AddScript("Connect-AzureAD -Credential $Cred");
powershell.AddScript("Get-AzureADApplication -Filter " + "\"DisplayName eq " + "\'TestApp\'" + "\"");
powershell.Invoke();
var results = powershell.Invoke();
}

Using PowerShell in c#

So basically im running a script to receive the IP adress of computer, date and time an account is locked out at work and to do this im making a small gui so all the network technicians can use it, my code Currently goes
private void btnSearch_Click(object sender, EventArgs e)
{
var username = textBox1.Text;
using (var powerShellInstance = PowerShell.Create())
{
try
{
powerShellInstance.AddScript(
"Get-WinEvent -ComputerName COMPUTERNAMEHERE -FilterHashtable #{logname=LOGNAMEHERE;id=IDHERE;data=" +
username + "} |" +
"Select-Object -Property timecreated, " +
"#{label='computername';expression={$_.properties[6].value.Split(':')[3]}} " +
"Get-WinEvent -ComputerName COMPUTERNAMEHERE -FilterHashtable #{logname=LOGNAMEHERE;id=IDHERE;data=" +
username + "} | " +
"Select-Object -Property timecreated, " +
"#{label='computername';expression={$_.properties[6].value.Split(':')[3]}} " +
"Get-WinEvent -ComputerName COMPUTERNAMEHERE -FilterHashtable #{logname=LOGNAMEHERE;id=IDHERE;data=" +
username + "} | " +
"Select-Object -Property timecreated, " +
"#{label='computername';expression={$_.properties[6].value.Split(':')[3]}} ");
// invoke execution on the pipeline (collecting output)
Collection<PSObject> PSOutput = powerShellInstance.Invoke();
// loop through each output object item
foreach (PSObject outputItem in PSOutput)
{
// if null object was dumped to the pipeline during the script then a null
// object may be present here. check for null to prevent potential NRE.
if (outputItem != null)
{
listView1.Items.Add(OUTPUTHERE);
}
}
}
catch
{
listView1.Items.Add("Failed");
}
}
but it currently crashes on the part of code where i invoke it, I've never worked on power shell before so any help would be appreciated and im really sorry if this is a stupid question xD

How to keep a process alive after remote PowerShell script completion?

I'm trying to start Zookeeper and Solr remotely via PowerShell scriptblock.
Then I see that the process is created in the remote machine (by checking the port 2181 of Zookeeper). And on the script completion it is being terminated.
How do I keep this alive even after the completion?
This code below stops the remote process on script completion. The script.ps1 does a lot of things that includes starting Zookeeper and Solr asJob.
int iRemotePort = 5985;
string strShellURI = #"http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
string strAppName = #"/wsman";
WSManConnectionInfo ci = new WSManConnectionInfo(
false,
machineName,
iRemotePort,
strAppName,
strShellURI,
new PSCredential(userName, secure));
Runspace runspace = RunspaceFactory.CreateRunspace(ci);
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{
session.Log(#"c:\temp\script.ps1 -serverID " + counter + " -copySolrConfig $" + status + " -currentHost \"" + machineName + "\" -IP_PORT_List \"" + String.Join(", ", machineWithPort) + "\"");
ps.Runspace = runspace;
ps.AddScript(#"c:\temp\script.ps1 -serverID " + counter + " -copySolrConfig $" + status + " -currentHost \"" + machineName + "\" -IP_PORT_List \"" + String.Join(", ", machineWithPort) + "\"");
var results = ps.Invoke();
foreach (var result in results)
{
session.Log(result.ToString());
}
}
runspace.Close();
So after a long try I came to a conclusion, Using power-shell script alive is not a appropriate way to keep zookeeper and solr running effectively. So moved it as a windows service and installed it on the remote machine via WiX.

Remove file present on Linux server

Trying to run sudo command with user who has all the priviledges, but something is wrong in my code .
I am trying to remove a file present on the remote server via C# code. It says : The name 'pass' does not exist in the current context.:
My Code :
SshExec sshExec = new SshExec("sj1slm612", "karansha");
sshExec.Password = "pass";
sshExec.Connect();
//Removing config files from sj1slm612 server
string remove_config_file_express = "echo " + "'" + pass + "'" + "| sudo -S -u wtsnqa rm " + "/apps/instances/express_13000/configuration/standalone-full.xml";
string output_express = sshExec.RunCommand(remove_config_file_express);
Console.WriteLine("All config files removed");
Console.ReadLine();
the compiler is indeed correct. you reference a variable called pass which you probably meant to be the string "pass"
string remove_config_file_express = "echo " + "'" + pass + "'" + "| sudo -S -u wtsnqa rm " + "/apps/instances/express_13000/configuration/standalone-full.xml";
Use tamir Library next code.
public static bool BorrarArchivo(string rutaRemota)
{
try
{
SshExec comando = new SshExec(Servidor, Usuario);
comando.Password = Password;
comando.Connect();
string paso = comando.RunCommand("rm " + rutaRemota);
comando.Close();
return true;
}
catch (Exception ex)
{
mErrorSFTP = ex.Message;
return false;
}
}

Categories