How to read errors from Powershell pipeline in c#? - c#

I am using System.Management.Automation.Runspaces.Pipleline to create a powershell pipeline instance and execute my powershell scripts in c# console application, the problem is that if the script end up with an error, then i don't know how to print that error on the console screen.
This is my code,
System.Management.Automation.Runspaces.Runspace PowershellRunspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();
PowershellRunspace.Open();
System.Management.Automation.RunspacesPipeline PowershellPipeline = PowershellRunspace.CreatePipeline();
PowershellPipeline.Commands.AddScript(PowershellScript);
PowershellPipeline.Commands.AddScript("Out-String");
foreach (string IpAddress in ActiveSystemIPAddresses)
{
PowershellPipeline.Commands.AddScript("Stop-Computer -ComputerName \"" + IpAddress + "\" -Credential $Credentials");
}
try
{
Collection<PSObject> output = PowershellPipeline.Invoke();
if (PowershellPipeline.HadErrors)
{
Console.WriteLine("Cannot shutdown this server IP");
}
PowershellPipeline.Stop();
StringBuilder results = new StringBuilder();
foreach (PSObject obj in output)
{
results.AppendLine(obj.ToString());
}
Console.WriteLine(results);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
PowershellRunspace.Close();
I can see the property Pipeline.HadErrors but it only rake me to the loop if there are errors detected, its doing anyhting to get the error message. My problem is how to get the actual error on the console screen?

Something like this should get you the errors.
var rs = RunspaceFactory.CreateRunspace();
rs.Open();
var ps = rs.CreatePipeline();
ps.Commands.AddScript("Get-Member");
ps.Commands.AddScript("ps");
try
{
var result = ps.Invoke();
if (ps.HadErrors)
{
var errors = ps.Error.ReadToEnd();
foreach (var error in errors)
{
Console.WriteLine(error);
}
}
foreach (var r in result)
{
Console.WriteLine(r);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
ps.Stop();
}

With the recent changes, following works with Microsoft.powershell.5.referenceAssemblies in C#
var result = ps.Invoke();
if (ps.HadErrors)
{
foreach (ErrorRecord error in ps.Streams.Error.ReadAll())
{
Console.WriteLine(error.ToString());
// You can access error.FullyQualifiedErrorId or error.Exception if you needed to
// be specific in what you were looking for when it failed.
}
}

To see the errors you can look at the collection PowerShell.Streams.Error.
If you wanted to do this natively in a PowerShell script and return the error you could wrap it in a try/catch and return the $error variable.
$error is a PowerShell variable where all errors are automatically added in an array. The first item in the array is always the newest error.

Related

Foreach not completing iterations

C# Foreach not completing iterations: if I have 10 XML records it only creates about 6 XML files.
public void PRODUCT()
{
try
{
var toProdSignlCRMList = _db.kv_sp_Product().ToList();
if (toProdSignlCRMList.Count > 0)
{
foreach (kv_sp_Product_Result myProdSignalLoop in toProdSignlCRMList)
{
var erp_prod_signal = new erp_crm_class.PRODUCT
{
CODE = myProdSignalLoop.Code.ToString().Trim(),
SHORTDESC = myProdSignalLoop.Description_1.ToString().Trim(),
INTERNATIONAL = false,
};
XmlSerializer xsSubmit = new XmlSerializer(typeof(erp_crm_class.PRODUCT));
var ProdSignalxml = "";
using (var sww = new StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sww))
{
xsSubmit.Serialize(writer, erp_prod_signal);
ProdSignalxml = sww.ToString();
using (StreamWriter outputFile = new StreamWriter(Convert.ToString("C:\\Upload\\" + "PRODUCT" + DateTime.Now.ToString("yyyyMMddhhmmssfff") + ".xml")))
{
outputFile.Write(ProdSignalxml);
}
}
}
}
}
}
catch (Exception ex)
{
}
}
You are using a Try/Catch block.
A Try/Catch block exits the Try block any time the code fails, and immediately runs the Catch block.
Normally you'd have some sort of error-handling in the catch block but for debugging you could also add the following to help you find out what is going on:
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
If the actual message doesn't contain any useful information, another way to go about is stepping through each loop and see what part fails and why.
Third option and most likely the best one is to remove your Try/Catch block and make sure you are using a debugger that is configured to break at exceptions - this way you get the actual error in your debugger.

C# Interops error running MS ACCESS macros

I developed a command line app in C# that runs some macros in MS ACCESS but I am getting the following error in the production environment:
System.Runtime.InteropServices.COMException (0x800A09B6): You canĀ“t carry out this action at the present time.
at Microsoft.Office.Interop.Access.DoCmd.RunMacro(Object MacroName, Object RepeatCount, Object RepeatExpression)
When I run the application again it works fine.
This is the code:
public void RunMacros()
{
Application access = null;
_runningMacros = true;
CloseMessageBox("Microsoft Access"); // Thread to close MsgBoxes
try
{
access = new Application();
access.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityLow;
var databases = MdbSettings.Config.Databases;
for (var mdbIndex = 0; mdbIndex < databases.Count; mdbIndex++)
{
if (databases[mdbIndex].Type == ReportType)
{
var mdbFile = databases[mdbIndex].File;
if (mdbFile.StartsWith("OcnTs*", StringComparison.InvariantCultureIgnoreCase))
{
mdbFile = mdbFile.Replace("*", Settings.DateReplaceName);
}
var mdbFullPath = GetFileFullPath(mdbFile, MdbPath);
access.OpenCurrentDatabase(mdbFullPath, Settings.IsDbExclusive);
for (var macrosIndex = 0; macrosIndex < databases[mdbIndex].Macros.Count; macrosIndex++)
{
var macro = databases[mdbIndex].Macros[macrosIndex].Name;
var message = string.Format("{0}, macro: {1}", Path.GetFileName(mdbFullPath), macro);
Log.Write(message);
access.DoCmd.RunMacro(macro);
}
access.CloseCurrentDatabase();
}
}
_runningMacros = false;
access.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveNone);
Marshal.ReleaseComObject(access);
access = null;
}
catch (Exception ex)
{
Log.Write(ex.ToString());
try
{
Marshal.ReleaseComObject(access);
}
catch (Exception e)
{
Log.Write("Error realeasing Access application: " + e.ToString(), Log.Severity.Warning);
}
throw;
}
}
Can someone help me to fix the error?
EDITED:
- The error only occurs in production environment
- The production environment has installed MS Access 2010
- The development environment has installed MS Access 2016
- Every macro run between 6 and 20 queries
- The error does not always occur in the same macro

ClrMD could not attach to process on production server

I am trying to use ClrMD to dump the stacktrace of all threads running within a specific process. The code works fine in my devlopment enviornment but not on the production server.
The server is running: Windows Server 2012 R2 Standard
The error I recieve is:
Could not attach to process. Error 0.
This post asks how to attach ClrMD to another users process, which was what I was trying to do. I terminated the process (which is running as a windows service) and started it as the same user that I am trying to execute ClrMD with. I still get the error.
Tried giving the user debugging privlidges but that didnt help either.
I bet the problem has something to do with how to production server is configured. I have administrator rights.
Any suggestions on what to do next?
Code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Diagnostics.Runtime;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
int pid = 0;
var result = new Dictionary<int, string[]>();
var targetProcessName = "Dist.TingbogScraper.Business.TingbogScraperService.vshost";
// Change this to the process you are looking for
var outputPath = "C:\\temp\\ClrMDresult.txt";
var exceptionOutput = "C:\\temp\\ClrMDdump.txt";
var processes = Process.GetProcesses();
foreach (var process in processes)
{
if (process.ProcessName.Contains(targetProcessName))
{
pid = process.Id;
}
}
try
{
using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive))
{
ClrRuntime runtime = dataTarget.ClrVersions.First().CreateRuntime();
foreach (var t in runtime.Threads)
{
try
{
if (t.StackTrace != null)
{
result.Add(
t.ManagedThreadId,
t.StackTrace.Select(f =>
{
if (f.Method != null)
{
return f.Method.Type.Name + "." + f.Method.Name;
}
return null;
}).ToArray()
);
}
}
catch (Exception ex)
{
}
}
}
foreach (var kvp in result)
{
var value = kvp.Value;
foreach (var stacktrace in value)
{
System.IO.File.AppendAllText(outputPath,
string.Format("{0} {1} {2}", kvp.Key, stacktrace, Environment.NewLine));
}
}
}
catch (ClrDiagnosticsException ex)
{
System.IO.File.AppendAllText(outputPath,
string.Format("{0} {1} {2}", ex.Message, ex.StackTrace, ex.Source));
}
}
}
}
Found out that the name of the process was different on my development environment compared to production.
Correcting the name of the process fixed the error.

C# Swi-Prolog: how to consult external prolog file in C#?

So far I am able to communicate with prolog with sample code available at prolog website.
But when I am trying to extract result from my prolog file it does not get the file and ended without any error.
Well the sample code I tested is as below:
if (!PlEngine.IsInitialized)
{
String[] param = { "-q" }; // suppressing informational and banner messages
PlEngine.Initialize(param);
PlQuery.PlCall("assert(father(martin, inka))");
PlQuery.PlCall("assert(father(uwe, gloria))");
PlQuery.PlCall("assert(father(uwe, melanie))");
PlQuery.PlCall("assert(father(uwe, ayala))");
using (PlQuery q = new PlQuery("father(P, C), atomic_list_concat([P,' is_father_of ',C], L)"))
{
foreach (PlQueryVariables v in q.SolutionVariables)
Console.WriteLine(v["L"].ToString());
Console.WriteLine("all child's from uwe:");
q.Variables["P"].Unify("uwe");
foreach (PlQueryVariables v in q.SolutionVariables)
Console.WriteLine(v["C"].ToString());
}
PlEngine.PlCleanup();
Console.WriteLine("finshed!");
Console.ReadLine();
}
And the code I am trying to use is as, my prolog file "OT.pl" is placed in swi-prolog folder:
String[] param = { "-q", "-f", #"OT.pl" };
if (!PlEngine.IsInitialized)
{
try
{
PlEngine.Initialize(param);
PlQuery carrega = new PlQuery("carrega('OT.bd')");
carrega.NextSolution();
PlQuery listQuery= new PlQuery("list(X)");
foreach (PlQueryVariables v in listQuery.SolutionVariables)
listBox1.Items.Add(v["X"].ToString());
}
catch (System.Exception ex)
{
Console.WriteLine("Failure: " + ex.Message);
// return;
}
}
Console.WriteLine("Finished!");
Console.ReadLine();
Kindly ignore any indentation mistakes. Thank you in advance.

How to run powershell script using c# in SharePoint solution

i am getting below error while i am trying to run power-shell script in my SharePoint solution
The type initializer for
'System.Management.Automation.SessionStateScope' threw an exception.
just a reference
private void RunPowershellScript(string scriptFile, List<string> parameters)
{
PowerShell OPowerShell = null;
Runspace OSPRunSpace = null;
try
{
RunspaceConfiguration OSPRSConfiguration = RunspaceConfiguration.Create();
PSSnapInException OExSnapIn = null;
//Add a snap in for SharePoint. This will include all the power shell commands for SharePoint
PSSnapInInfo OSnapInInfo = OSPRSConfiguration.AddPSSnapIn("Microsoft.SharePoint.PowerShell", out OExSnapIn);
OSPRunSpace = RunspaceFactory.CreateRunspace(OSPRSConfiguration);
OPowerShell = PowerShell.Create();
OPowerShell.Runspace = OSPRunSpace;
Command Cmd1 = new Command("backup-spsite");
Cmd1.Parameters.Add("identity", "Your Site Coll URL");
Cmd1.Parameters.Add("path", "Back up file path");
OPowerShell.Commands.AddCommand(Cmd1 );
OSPRunSpace.Open();
OPowerShell.Invoke();
OSPRunSpace.Close();
}
catch (Exception Ex)
{
//Handle exception
}
finally
{
if (OSPRunSpace != null)
{
OSPRunSpace.Dispose();
OSPRunSpace = null;
}
if (OPowerShell != null)
{
OPowerShell.Dispose();
OPowerShell = null;
}
}

Categories

Resources