I've got PowerShell script that acts like expected if I run it from PowerShell ISE.
$ol = #()
$ProcessActive = Get-Process outlook -ErrorAction SilentlyContinue
if($ProcessActive -eq $null)
{
$ol = New-Object -comObject Outlook.Application
}
else
{
$ol = [Runtime.InteropServices.Marshal]::GetActiveObject("Outlook.Application")
}
$file = "c:\testfile.pdf"
$mail = $ol.CreateItem(0)
$Mail.Recipients.Add("test#test.nl")
$mail.Subject = "This is a subject"
$mail.HTMLBody = "<html><body><h3>Hello world</h3></body></html>"
$mail.Attachments.Add($file)
$inspector = $mail.GetInspector
$inspector.Display()
However ... if I start a process in C# to execute the script it will only work if the Outlook process is not running.
var filename = "script.ps1";
var fullname = path + filename;
if (System.IO.File.Exists(fullname))
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"powershell.exe";
startInfo.Arguments = string.Format(#"& '{0}'", fullname);
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
System.IO.File.Delete(fullname);
}
The process eventually ends execution and the file is deleted in both cases (outlook running or not).
What do I need to change in order to let the script execute properly when started from a C# process (even if Outlook is running)?
Thanks in advance.
In order to answer what the difference was between script and process I've created a log of the process that was running the script. To create the log i've used
System.IO.File.WriteAllText(#"c:\log.txt",process.StandardError.ReadToEnd())
First the exception was: missing references. After fixing the missing reference by adding at the top of the powershell script :
Add-Type -Path 'Dir\To\Dll'
After that I received another error:
Exception calling "GetActiveObject" with "1" argument(s): "Operation unavailabl
e (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))"
I've read some articles and this has to do with that Outlook does not allow different users 'using' the running instance (current user vs admin-like current user running script). I'm now using the Microsoft.Office.Interop.Outlook dll to open a new email window and the console application that executes it can run as current user without the need of admin rights. This solved my problem: i'm now able to open a new email window even if outlook is already running.
Related
Hello everyone and thank you for the help
I made a word Addin while clicking some of the buttons like upload file or login,c# calling exe to run
But for some reason, the exe does not work each time I try, only half of the time, and if I succeed, when I am trying to call the exe again for a different purpose, I failed (nothing happend)
one more thing, I need to get the output of the exe file.
the exe in the debug folder
the code below:
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.WorkingDirectory = Path.GetDirectoryName("Api_Layer.exe");
processInfo.FileName = "Api_Layer.exe";
processInfo.ErrorDialog = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;
Process proc = Process.Start(processInfo);
List<string> output = new List<string>();
while (!proc.HasExited)
{
output.Add(proc.StandardOutput.ReadToEnd());
}
I have a powershell script which spits out file information for a given file. The script is executed in a process from a windows service like so:
Process p = new Process();
ProcessStartInfo s = new ProcessStartInfo();
s.FileName = "powershell.exe";
s.Arguments = "./script.ps1";
s.RedirectStandardOutput = true;
s.RedirectStandardError = true;
s.UseShellExecute = false;
s.CreateNoWindow = true;
p.StartInfo = s;
p.EnableRaisingEvents = true;
/* ... defined output handlers ... */
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
The powershell script is as follows:
function ChangeDir($dir)
{
try
{
echo ("Attempting to change directory: {0}" -f ($dir))
Set-Location -Path $dir -ErrorAction Stop
}
catch
{
echo $error[0].Exception
}
}
function OutputFileInfo($filePath)
{
try
{
echo ("Attempting to read file: {0}" -f ($filePath))
$file = #(Get-ChildItem $filePath -ErrorAction Stop)
for ($i = 0; $i -lt $file.Count; $i++)
{
echo ("{0},{1}" -f ($file[$i].Name, $file[$i].Length))
}
}
catch
{
echo $error[0].Exception
}
}
ChangeDir "/Windows/System32/drivers"
OutputFileInfo "tcpip.sys"
The output when running the powershell script from the command line is as I expect it to be:
Attempting to change directory: /Windows/System32/drivers
Attempting to read file: tcpip.sys
tcpip.sys,2773400
When the script executes via the windows service the output is this:
Attempting to change directory: /Windows/System32/drivers
Attempting to read file: tcpip.sys
Cannot find path 'C:\Windows\System32\drivers\tcpip.sys' because it does not exist.
For other files it works perfectly fine from the command line and the service. Could it have something to do with the service running the powershell script as SYSTEM which somehow doesn't have access to that file? Although if that were the case I would expect a permissions error instead of a file not found error.
Ok.... this was because system32/drivers is not accessible for 32bit applications that run on 64bit machines and I didn't realize I had my application set to the default in visual studio which I guess is 32bit. I changed it to 64bit and it works from the service now.
I am currently trying to "convert" a bash script I wrote to C#.
This script starts a program in a shell and then executes a few commands in this shell and looks similar to this:
cd /$MYPATH
./executible -s << EOF
start_source_probe -hardware_name "USB" -device_name "#1: EP3C(10|5)"
write_source_data -instance_index 0 -value "11111"
write_source_data -instance_index 0 -value "10111"
write_source_data -instance_index 0 -value "00111"
exit
EOF
Now I would like to do the same using Visual Studio C#.
At the moment my attempt looks like this:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = "pathToExe\\";
startInfo.FileName= "executible.exe";
startInfo.Arguments= "-s";
//startInfo.UseShellExecute = false;
//startInfo.RedirectStandardInput = true;
Process proc = new Process();
proc.StartInfo = startInfo;
proc.Start();
//StreamWriter myStreamWriter = proc.StandardInput;
//Console.WriteLine("start_source_probe - hardware_name \"USB\" -device_name \"#1: EP3C(10|5)\"");
//Console.WriteLine("write_source_data -instance_index 0 -value \"11111\"");
proc.WaitForExit();
With the comments activated (so with the "//" in code) I manage to open the shell (-s stands for shell) but I wonder how I am able to execute commands in this shell additionally.
I managed to execute multiple commands with something like this (as long as I am not starting the shell because destination output differs I guess)
const string strCmdText = "/C command1&command2";
Process.Start("CMD.exe", strCmdText);
I would appreciate it if someone could tell me how to add the argument "-s" and execute commands in the started process.
I am not sure if i did understood your question, but you can create a batch file outside your c# code and call It from your c# code like the following :
System.Diagnostics.ProcessStartInfo ProcStartInfo = new System.Diagnostics.ProcessStartInfo("cmd");
ProcStartInfo.RedirectStandardOutput = true;
ProcStartInfo.UseShellExecute = false;
ProcStartInfo.CreateNoWindow = false;
ProcStartInfo.RedirectStandardError = true;
System.Diagnostics.Process MyProcess = new System.Diagnostics.Process();
ProcStartInfo.Arguments = "/c start /wait batch.bat ";
MyProcess.StartInfo = ProcStartInfo;
MyProcess.Start();
MyProcess.WaitForExit();
I added the /wait so your c# code is going to wait for your batch to finish, to pursuit the c# code execution
I'm setting local auditing policies from a C# .NET program that reads settings from a file then uses Process.Start() with 'cmd' to execute the commands. This way has worked in the past for everything that I've needed it to do (including this exact situation), but recently it's just started to mysteriously fail to set the policies.
Here's the code: (command is of the form "auditpol /set /subcategory:"blah" /success:enable")
ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
proc.WaitForExit();
string result = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
In debug in VS2013 it's applying the policies just fine and even on the same computer in the full on .exe it's applying just fine, but when it gets transferred to another computer it will not set the policies from the auditpol command. Anyone have any ideas what could be happening?
I try to start ilasm from C# using class ProcessInfo
string arguments = string.Format("\"{0}\" /exe /output:\"{1}\" /debug=IMPL", ilFullFileName, exeFileFullName);
ProcessStartInfo processStartInfo = new ProcessStartInfo(CILCompiler, arguments);
processStartInfo.UseShellExecute = false;
processStartInfo.CreateNoWindow = false;
processStartInfo.WorkingDirectory = #"c:\Windows\Microsoft.NET\Framework\v4.0.30319\";
using (Process process = Process.Start(processStartInfo))
{
process.WaitForExit();
}
the arguments are:
"path_to_il.il" /exe /output:"path_to_exe.exe" /debug=IMPL
and then it gives me the error:
The application was unable to start correctly (0xc0000007b). Click Ok to close the application.
The odd part of that is, when I do exactly the same actions manually using bat file
"c:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" "path_to_il.il" /exe /output:"path_to_exe.exe" /debug=IMPL
pause
it does work.
What did I miss?
I think you need to set the file name as well:
processStartInfo.FileName = "ilasm.exe";