I'm basically trying to create a console application which executes a given script on a remote machines within a given IP range and stores the results.
This is my code so far but something is going wrong when I try to create a runspace with the WSManConnectionInfo object as arg.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Security;
namespace GetSysInfo
{
class Program
{
private static string outPath;
static void Main(string[] args)
{
//get script path
Console.WriteLine("Enter full path to script.");
string path = Convert.ToString(Console.ReadLine());
//get IP range
Console.WriteLine("Input start IPv4.");
IPAddress sIP = IPAddress.Parse(Console.ReadLine().ToString());
Console.WriteLine("Input end IPv4.");
IPAddress eIP = IPAddress.Parse(Console.ReadLine().ToString());
//get list of IPs in range
RangeFinder rf = new RangeFinder();
List<string> IPrange = rf.GetIPRangeList(sIP, eIP);
//run script
foreach (var IP in IPrange)
{
try
{
RunScriptRemote(LoadScript(path), IP);
}
catch (Exception e)
{
Console.WriteLine("An error occured" + Environment.NewLine + e.Message);
}
}
}
//script executer
private static void RunScriptRemote(string script, string address)
{
Console.WriteLine("Enter username.");
String username = Console.ReadLine();
Console.WriteLine("Enter password.");
ConsoleKeyInfo key;
SecureString pass = new SecureString();
do
{
key = Console.ReadKey(true);
if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter)
{
pass.AppendChar(key.KeyChar);
Console.Write("*");
}
else
{
if (key.Key == ConsoleKey.Backspace && pass.Length > 0)
{
pass.RemoveAt(pass.Length);
Console.Write("\b \b");
}
else if (key.Key == ConsoleKey.Enter && pass.Length > 0)
{
Console.Write(Environment.NewLine);
pass.MakeReadOnly();
}
}
}
while (key.Key != ConsoleKey.Enter);
PSCredential credential = new PSCredential(username, pass);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("http://" + address + ":5985/wsman"), "http://schemas.microsoft.com/powershell/Microsoft.PowerShell", credential);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Negotiate;
connectionInfo.EnableNetworkAccess = true;
Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);//point of crash
runspace.Open();
//set path to save results
Console.WriteLine("Enter full path to save results. Must be a directory.\nThis can be a local path or a network path.");
Console.WriteLine("In case of a network path the results will be merged automatically");
outPath = Convert.ToString(Console.ReadLine());
runspace.SessionStateProxy.SetVariable("filepath", outPath);
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = runspace;
ps.AddScript(script);
ps.Invoke();
}
//Pipeline pipeline = runspace.CreatePipeline();
//pipeline.Commands.AddScript(script);
//pipeline.Invoke();
runspace.Close();
}
//script loader
private static string LoadScript(string filename)
{
try
{
using (StreamReader sr = new StreamReader(filename))
{
StringBuilder fileContents = new StringBuilder();
string curLine;
while ((curLine = sr.ReadLine()) != null)
{
fileContents.Append(curLine + Environment.NewLine);
}
return fileContents.ToString();
}
}
catch (Exception e)
{
return e.Message;
}
}
}
public class RangeFinder
{
public IEnumerable<string> GetIPRange(IPAddress startIP,
IPAddress endIP)
{
uint sIP = ipToUint(startIP.GetAddressBytes());
uint eIP = ipToUint(endIP.GetAddressBytes());
while (sIP <= eIP)
{
yield return new IPAddress(reverseBytesArray(sIP)).ToString();
sIP++;
}
}
public List<string> GetIPRangeList(IPAddress startIP,
IPAddress endIP)
{
uint sIP = ipToUint(startIP.GetAddressBytes());
uint eIP = ipToUint(endIP.GetAddressBytes());
List<string> IPlist = new List<string>();
while (sIP <= eIP)
{
IPlist.Add(new IPAddress(reverseBytesArray(sIP)).ToString());
sIP++;
}
return IPlist;
}
//reverse byte order in array
protected uint reverseBytesArray(uint ip)
{
byte[] bytes = BitConverter.GetBytes(ip);
bytes = bytes.Reverse().ToArray();
return (uint)BitConverter.ToInt32(bytes, 0);
}
//Convert bytes array to 32 bit long value
protected uint ipToUint(byte[] ipBytes)
{
ByteConverter bConvert = new ByteConverter();
uint ipUint = 0;
int shift = 24;
foreach (byte b in ipBytes)
{
if (ipUint == 0)
{
ipUint = (uint)bConvert.ConvertTo(b, typeof(uint)) << shift;
shift -= 8;
continue;
}
if (shift >= 8)
ipUint += (uint)bConvert.ConvertTo(b, typeof(uint)) << shift;
else
ipUint += (uint)bConvert.ConvertTo(b, typeof(uint));
shift -= 8;
}
return ipUint;
}
}
}
I get the following error when trying to run: Common Language Runtime detected an invalid program.
I tried creating a new solution as Google suggested but it's obviously going wrong when creating the runspace.
I'm out of idea's and sources for help, so I'm reaching out to the Stackoverflow community.
Thanks in advance,
X3ntr
EDIT:
I tried cleaning my solution, manually deleting any pbd's, changed the target CPU, turned off code optimalization, allowed unsafe code, rebuilding, creating a new solution,... as suggested in this post.
I followed the advice from this answer: I added a reference to C:\windows\assembly\GAC_MSIL\System.Management.Automation and then ran this command in an elevated powershell: Copy ([PSObject].Assembly.Location) C:\
Related
I'm able to get a simple c# function to work, but when I introduce something more complicated such as what's below, I'm getting syntax errors and there isn't a lot of examples on how to do this.
I've made updates to the code based on advice received here, but this code still does not function properly
cls
$dagDistribution = $null;
$distribution =
#'
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Security.Principal;
namespace MultiThreading
{
public class dagDistribution
{
public List<string> get(string dag)
{
DateTime start = DateTime.Now;
var response = new ConcurrentBag<Collection<PSObject>>();
var exceptions = new ConcurrentQueue<Exception>();
string dagName = "hqdag1";
string[] serversUnsorted = getDagMembers(dagName);
var servers = from s in serversUnsorted orderby s select s;
try
{
Parallel.ForEach(servers, server =>
{
response.Add(runPowerShellScript(server));
});
}
catch (AggregateException ae)
{
foreach (var aex in ae.InnerExceptions)
{
exceptions.Enqueue(aex);
}
}
List<string> returnValues = new List<string>();
foreach (var item in response)
{
string returnValue = parseServerResults(item);
returnValues.Add(returnValue);
}
returnValues.Sort();
return returnValues;
}
private Collection<PSObject> runPowerShellScript(object server)
{
Collection<PSObject> psobjs = new Collection<PSObject>();
string result = "";
string serverName = server.ToString();
WSManConnectionInfo wmc = new WSManConnectionInfo(new Uri("http://xxx/powershell"));
wmc.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
wmc.ShellUri = "http://schemas.microsoft.com/powershell/Microsoft.Exchange";
using (Runspace runspace = RunspaceFactory.CreateRunspace(wmc))
{
PowerShell powershell = PowerShell.Create();
if (runspace.RunspaceStateInfo.State == RunspaceState.Opened)
{
// do nothing
}
else
{
runspace.Open();
powershell.Runspace = runspace;
}
try
{
PSCommand command = new PSCommand();
command.AddScript("get-mailboxdatabase -Server " + server + " -Status");
powershell.Commands = command;
psobjs = powershell.Invoke();
if (powershell.HadErrors == true)
{
result = "Failed - " + powershell.Streams.Error[0].ToString();
result = result.Replace("\"", "*");
}
}
catch (Exception ex)
{
string fail = ex.Message;
}
}
object serverNameO = server;
PSObject serverNameObj = new PSObject(serverNameO);
psobjs.Insert(0, serverNameObj);
return psobjs;
}
private string[] getDagMembers(string dagName)
{
Collection<PSObject> psobjs = new Collection<PSObject>();
string result = "";
string[] servers = null;
WSManConnectionInfo wmc = new WSManConnectionInfo(new Uri("http://xxx/powershell"));
wmc.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
wmc.ShellUri = "http://schemas.microsoft.com/powershell/Microsoft.Exchange";
using (Runspace runspace = RunspaceFactory.CreateRunspace(wmc))
{
PowerShell powershell = PowerShell.Create();
if (runspace.RunspaceStateInfo.State == RunspaceState.Opened)
{
// do nothing
}
else
{
runspace.Open();
powershell.Runspace = runspace;
}
try
{
PSCommand command = new PSCommand();
command.AddScript("Get-DatabaseAvailabilityGroup -Identity " + dagName);
powershell.Commands = command;
psobjs = powershell.Invoke();
if (powershell.HadErrors == true)
{
result = "Failed - " + powershell.Streams.Error[0].ToString();
result = result.Replace("\"", "*");
}
PSPropertyInfo serversTemp = null;
foreach (PSObject psobj in psobjs)
{
serversTemp = psobj.Properties["servers"];
}
string s_servers = serversTemp.Value.ToString();
servers = s_servers.Split(' ');
}
catch (Exception ex)
{
string fail = ex.Message;
}
}
return servers;
}
private string parseServerResults(Collection<PSObject> serverObjs) // needs servername, totaldbs, activedbs, passivedbs, preferencecount (11,11,11,11), mounteddbs, dismounteddbs, dagname
{
// called independently with each server, first object is always the server name
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int index = 0;
string returnValue = "";
string serverName = "";
int totalDbs = 0;
int activeDbs = 0; // whichever has activation preference 1
int passiveDbs = 0; // whichever has activation preference 2, 3 or 4
string activeCopyServerName = "";
int activationPreferenceOne = 0;
int activationPreferenceTwo = 0;
int activationPreferenceThree = 0;
int activationPreferenceFour = 0;
int mountedCount = 0;
int dismountedCount = 0;
string dagName = "";
string dagServerAndDatabaseName = "";
foreach (PSObject obj in serverObjs)
{
if (index == 0)
{
serverName = obj.ToString();
}
totalDbs = (serverObjs.Count - 1);
PSMemberInfoCollection<PSPropertyInfo> props = obj.Properties;
string currentPrimaryActivationServer = "";
foreach (PSPropertyInfo prop in props)
{
if (prop.Name == "MountedOnServer")
{
currentPrimaryActivationServer = prop.Value.ToString();
break;
}
}
List<string> propertyNames = new List<string>();
foreach (PSPropertyInfo prop in props)
{
string result = prop.Name + " | " + prop.Value;
if (prop.Name == "Mounted")
{
if (prop.Value.ToString() == "True")
{
if (currentPrimaryActivationServer.ToLower().StartsWith(serverName.ToLower()))
{
mountedCount++;
}
}
else
{
dismountedCount++;
}
}
else if (prop.Name == "MountedOnServer")
{
activeCopyServerName = prop.Value.ToString();
}
else if (prop.Name == "ActivationPreference")
{
string arr = prop.Value.ToString();
string[] vals = arr.Split(']');
foreach (string val in vals)
{
if (val != "")
{
string valTemp = val;
if (val.Contains("["))
{
valTemp = val.Replace("[", "");
}
string[] preference = valTemp.Split(',');
string preferenceZero = preference[0].ToString().Trim();
string preferenceOne = preference[1].ToString().Trim();
if (preferenceZero.ToLower() == serverName.ToLower())
{
if (preferenceOne == "1")
{
if (currentPrimaryActivationServer.ToLower().StartsWith(serverName.ToLower()))
{
activeDbs++;
}
else
{
passiveDbs++;
}
}
else
{
if (!(currentPrimaryActivationServer.ToLower().StartsWith(serverName.ToLower())))
{
passiveDbs++;
}
else
{
activeDbs++;
}
}
switch (preferenceOne)
{
case "1":
activationPreferenceOne++;
break;
case "2":
activationPreferenceTwo++;
break;
case "3":
activationPreferenceThree++;
break;
case "4":
activationPreferenceFour++;
break;
default:
break;
}
}
}
}
}
else if (prop.Name == "Server")
{
string activeCopyServerName2 = prop.Value.ToString();
}
else if (prop.Name == "MasterServerOrAvailabilityGroup")
{
dagName = prop.Value.ToString();
}
else if (prop.Name == "MailboxProvisioningAttributes")
{
dagServerAndDatabaseName = prop.Value.ToString();
}
propertyNames.Add(prop.Name.ToString()); // cumulative count of the property names
}
index++;
}
stopwatch.Stop();
Console.WriteLine(serverName + " - " + stopwatch.Elapsed.ToString());
return returnValue = serverName + "|" + totalDbs + "|" + activeDbs + "|" + passiveDbs + "|" + activationPreferenceOne + "," + activationPreferenceTwo + "," +
activationPreferenceThree + "," + activationPreferenceFour + "|" + mountedCount + "|" + dismountedCount + "|" + dagName;
}
}
}
'#
write-host "after here-string";
Add-Type -TypeDefinition $distribution -ReferencedAssemblies System.Collections, System.ComponentModel, System.Data, System.Drawing, System.Linq, System.Management.Automation, System.Security, System.Threading.Tasks, System.Windows.Forms, System.Threading, System.Collections.Concurrent, System.Security.Principal
$dagDistribution = New-Object MultiThreading.dagDistribution;
$val = $dagDistribution.get("dag2");
You have two problems. Probably really just one. By default Add-Type uses the C# version 5 compiler, which is the latest one to be included in Windows. The string interpolation with $ is a newer feature. See this answer Powershell Add-Type C# 6.0.
Second, you have powershell escape characters in your C# code that shouldn't be there. Instead use a literal here-string to include arbitrary C# source. EG:
$distribution = #'
namespace MultiThreading
{
....
}
'#
C# has no "special" way to reference .NET Framework types, so you have to provide the compiler with a list of assemblies your code depends on.
Add-Type will use will use the current .NET Framework assemblies if you specify the "short name" of the assembly in the -ReferencedAssemblies argument. So:
Add-Type -TypeDefinition $distribution -ReferencedAssemblies System.Data, System.Xml
If you need an assembly that can't be resolved this way, you have to list the Assembly FullName, and Add-Type will try to load it.
You definitely want to avoid putting a full AssemblyName for a .NET Framework assembly in your powershell code, as that might cause your script to break when running on a machine with a different .NET Framework version, or with .NET Core.
I have a RFID devices connected to my laptop through Port COM1(Confirmed correct whereby i had using device manager). However, when i run these code in C# language. It give me an exception Access to the port "COM1" is denied. Anyone can help me to solve this problem? Below is my code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO.Ports;
using System.Threading;
namespace Testing1
{
public class Testing1
{
public static SerialPort iSerialPort = new SerialPort();
static int Main()
{
string strException = string.Empty;
string strComPort = "COM1";
int nBaudrate=Convert.ToInt32(9600);
int nRet = OpenCom(strComPort, nBaudrate, out strException);
if (nRet != 0)
{
string strLog = "Connect reader failed, due to: " + strException;
Console.WriteLine(strLog);
//return;
}
else
{
string strLog = "Reader connected " + strComPort + "#" + nBaudrate.ToString();
Console.WriteLine(strLog);
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
iSerialPort.Close();
return 0;
}
public static int OpenCom(string strPort, int nBaudrate, out string strException)
{
strException = string.Empty;
if (iSerialPort.IsOpen)
{
iSerialPort.Close();
}
try
{
iSerialPort.PortName = strPort;
iSerialPort.BaudRate = nBaudrate;
iSerialPort.ReadTimeout = 200;
iSerialPort.DataBits = 8;
iSerialPort.Parity = Parity.None;
iSerialPort.StopBits = StopBits.One;
iSerialPort.Open();
}
catch (System.Exception ex)
{
strException = ex.Message;
return -1;
}
return 0;
}
}
}
This exception can occur when some other program is accessing the COM1 port. Do you have any other program open that uses the RFID device?
You can check what programs use what ports using Portmon.
I have created a web service that should allow to pass commands to the Exchange Server Powershell. When I test it by running it on the machine with VS (localhost) everything works. However, when I try to use this service from a other machine. I get Access Denied Error.
This is the service:
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Remoting;
using System.Management.Automation.Runspaces;
using System.Configuration;
using Microsoft.Exchange.WebServices.Data;
namespace pshell
{
[WebService(Namespace = "http://some1.domain.int/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class PowerShellService : System.Web.Services.WebService
{
private bool Authenticate(string u, string p)
{
if ((u == "xxxxxx") && (p == "xxxxxxx"))
return true;
else
return false;
}
private int SecurityLevel(string u)
{
if (u == "xxxxx")
return 100;
else
return 0;
}
[WebMethod]
public string PSCmd(string authuser, string authpass, string cmd, string pars)
{
if (!Authenticate(authuser, authpass))
return "<collection><RESULT status=\"ERROR\" message=\"Authentication failed!\" /></collection>";
String Password = System.Configuration.ConfigurationManager.AppSettings["UUPASS"];
System.Security.SecureString secureString = new System.Security.SecureString();
foreach (char c in Password)
secureString.AppendChar(c);
PSCredential ExchangeCredential = new PSCredential(System.Configuration.ConfigurationManager.AppSettings["UUNAME"], secureString);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri(System.Configuration.ConfigurationManager.AppSettings["UURI"]), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", ExchangeCredential);
Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
if (cmd.Trim() != "")
{
//here we check for security level
if (SecurityLevel(authuser) >= 100)
{
//admin fully allowed
command.AddCommand(cmd);
}
else
{
//test for allowed commands
if ((SecurityLevel(authuser) < 100) &&
(SecurityLevel(authuser) >= 90))
{
if (cmd.ToLower() == "get-mailbox")
{
command.AddCommand(cmd);
}
}
}
}
else
return "<collection><RESULT status=\"ERROR\" message=\"Missing command!\" /></collection>";
if (pars.Trim() != "")
{
string[] parameters = pars.Split('|');
foreach (string item in parameters)
{
String p = item.Substring(0, item.IndexOf("="));
String v = item.Substring(item.IndexOf("=") + 1);
if (p.Trim().ToLower() == "password")
{
System.Security.SecureString passString = new System.Security.SecureString();
foreach (char c in v)
passString.AppendChar(c);
command.AddParameter(p, passString);
}
else if ((v.Trim().ToLower() == "false") ||
(v.Trim().ToLower() == "true"))
{
if (v.Trim().ToLower() == "false")
command.AddParameter(p, false);
else
command.AddParameter(p, true);
}
else
{
command.AddParameter(p, v);
}
}
}
powershell.Commands = command;
runspace.Open();
Pipeline pl = runspace.CreatePipeline();
powershell.Runspace = runspace;
Collection<PSObject> results = null;
string xml = "<collection>";
try
{
results = powershell.Invoke();
var error = pl.Error.Read() as Collection<ErrorRecord>;
if (error != null)
{
foreach (ErrorRecord er in error)
{
xml += "<RESULT status=\"ERROR\" type=\"pipe\" message=\"" + er.ErrorDetails.Message + "\" />";
}
pl.Stop();
}
xml += "<RESULT status=\"OK\" />";
}
catch(Exception err)
{
xml += "<RESULT status=\"ERROR\" type=\"exception\" codelevel=\"1\" message=\"" + err.Message + "\" />";
}
try
{
foreach (PSObject item in results)
{
for (int i = 0; i < item.Properties.Count(); i++)
{
if (item.Properties.ElementAt(i).MemberType == PSMemberTypes.Property)
{
xml += "<" + item.Properties.ElementAt(i).Name + ">" +
item.Properties.ElementAt(i).Value +
"</" + item.Properties.ElementAt(i).Name + ">";
}
}
}
}
catch(Exception err)
{
xml += "<RESULT status=\"ERROR\" type=\"exception\" codelevel=\"2\" message=\"" + err.Message + "\" />";
}
xml += "</collection>";
return xml;
}
}
}
and this is the PHP code that I want to use to send a command:
$ini = ini_set("soap.wsdl_cache_enabled","0");
$params = array('authuser' => 'xxxx',
'authpass' => 'xxxx',
'cmd' => 'get-mailbox',
'pars' => '');
$client = new SoapClient("http://web.domain.com/pshell/callpshell.asmx?WSDL", array('soap_version' => SOAP_1_2));
$response = $client->PSCmd($params)->PSCmdResult;
print $response;
and this is the error message I receive:
Connecting to remote server some1.domain.int failed with the following error message : Access is denied. For more information, see the about_Remote_Troubleshooting Help topic.
I have enabled Remote Access on the Exchange Server, and I did everything Remote Troubleshooting suggested.
Any suggestions?
The Access Denied Error occurs because the web service is launched as IIS_USER which has insufficient rights to call remote powershell.
OK after long poking around, I resolved the issue like this:
Create a new Applciation Pool
Set the Identity of the application pool to the user that has the rights to access Powershell remotely
Bind the WebService to the Application pool
and it works :)
I have a program that converts .ppt or pptx files to png's using C# and the Microsoft.Office.Interop stuff.
It works most of the time, but under certain circumstances, it seems to fail on specific filenames for some nondescript reason.
HRESULT E_FAIL at ... Presentations.Open
It'll fail on CT_Stress_Test - Copy (16).pptx and CT_Stress_Test - Copy (11).pptx It works for (2) thru (19), but fails on only these two. My question is why?
If I were to make copies of these copies, or rename them to something else, it'll convert just fine, so I think it might have something to do with the filename.
I have the same conversion program running on my server and my local machine. My local machine (Win 7) converts the problem files just file. It's only on the server (Win 2008) that I have problems with these two filenames.
EDIT: I've found another number that doesn't work: (38)
EDIT: I formatted the strings with Path functions, and that didn't help.
EDIT: I was able to fix it by trimming all the spaces from the file names. I still want to know why this happens, though.
Here's the program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.Diagnostics;
using System.Timers;
using System.Security.Permissions;
using System.Collections.Concurrent;
namespace converter
{
class Program
{
public static int threadLimit=0;
public static string inDir;
public static string outDir;
public static string procDir;
public static Thread[] converterThreads;
public static BlockingCollection<string> todo;
static void Main(string[] args)
{
todo = new BlockingCollection<string>();
inDir = args[0];
outDir = args[1]+"\\";
procDir = args[2]+"\\";
Int32.TryParse(args[3],out threadLimit);
converterThreads = new Thread[threadLimit];
FileSystemWatcher watcher = new FileSystemWatcher(inDir); //Watcher "thread"
watcher.Filter = "*.ppt*";
watcher.NotifyFilter = watcher.NotifyFilter | NotifyFilters.CreationTime;
watcher.IncludeSubdirectories = false;
watcher.Created += new FileSystemEventHandler(fileChanged);
watcher.EnableRaisingEvents = true;
//Create consumer threads
for(var i=0;i<threadLimit;i++)
{
Conversion con = new Conversion();
converterThreads[i] = new Thread(new ThreadStart(con.watchCollection));
converterThreads[i].Start();
}
//stay open
Console.ReadLine();
}
//Producer
private static void fileChanged(object sender, FileSystemEventArgs e)
{
if(!(e.FullPath.Contains("~$"))){ //Ignore temp files
Console.WriteLine("found =" + e.FullPath);
todo.Add(e.FullPath);
}
}
}
class Logger{
static void toLog(String msg)
{
//TODO: log file
}
}
//Consumer
class Conversion
{
String input;
String output;
String outDir;
String process;
String nameWith;
String nameWithout;
string dir;
static List<CorruptFile> cFiles = new List<CorruptFile>();
int retryLimit = 20;
public Conversion()
{
this.outDir = Program.outDir;
this.process = Program.procDir;
}
//Continually watches collection for files to take.
public void watchCollection()
{
while (true)
{
System.Threading.Thread.Sleep(1000);
try
{
dir = Program.todo.Take();
if (dir != null)
{
this.nameWithout = Path.GetFileNameWithoutExtension(dir);
this.nameWith = Path.GetFileName(dir);
this.output = Path.GetDirectoryName(dir) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(dir);
Console.WriteLine("output = " + this.output);
this.input = Path.GetFullPath(dir);
Console.WriteLine("thread took " + this.nameWith);
convertPpt();
}
}
catch (InvalidOperationException) { }
}
}
public void convertPpt()
{
try
{
var app = new PowerPoint.Application();
var pres = app.Presentations;
var file = pres.Open(input, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
file.SaveAs(output, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPNG, MsoTriState.msoTrue);
file.Close();
app.Quit();
Console.WriteLine("file converted " + input);
moveFile();
}
catch (Exception e)
{
Console.WriteLine("convertPpt failed " + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
Console.WriteLine("process killed");
}
}
catch (Exception e3)
{
}
try
{
if (!(cFiles.Any(x => x.fileName == dir)))
{
cFiles.Add(new CorruptFile(dir));
Console.WriteLine("file added to watch list");
Program.todo.Add(dir);
}
else
{
var found = cFiles.Find(x => x.fileName == dir);
Console.WriteLine("in watch list = " + found.fileName);
if (found.numRetry >= retryLimit)
{
Console.WriteLine(nameWith+ " to be ignored");
try
{
cFiles.Remove(found);
Console.WriteLine("File ignored");
System.Threading.Thread.Sleep(300);
Console.WriteLine("Moving: " + input);
if (File.Exists("C:\\corrupt\\" + nameWith))
{
File.Replace(input, "C:\\corrupt\\" + nameWith, null);
Console.WriteLine("file moved to C:\\corrupt\\");
}
else
{
File.Move(input, "C:\\corrupt\\" + nameWith);
Console.WriteLine("file moved to C:\\corrupt\\");
}
}
catch(Exception e5)
{
Console.WriteLine("could not move file " + e5);
}
}
else
{
Console.WriteLine("retrying file on watch list");
found.numRetry++;
Program.todo.Add(dir);
}
}
}
catch { }
}
moveDir();
}
public void moveFile()
{
Console.WriteLine("moving" + input);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving {0} to {1}", input, process + nameWith));
if (File.Exists(process + nameWith))
{
File.Replace(input, process + nameWith, null);
}
else
{
File.Move(input, process + nameWith);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the file {0} ", input) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
public void moveDir()
{
if(!Directory.Exists(output)){
return;
}
Console.WriteLine("moving dir " + output);
try
{
Console.WriteLine(string.Format("moving dir {0} to {1} ", output, outDir + nameWithout));
if (Directory.Exists(outDir + nameWithout))
{
Directory.Delete(outDir + nameWithout, true);
}
if (Directory.Exists(output))
{
Directory.Move(output, outDir + nameWithout);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the directory {0} ", output) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
}
class CorruptFile{
public string fileName;
public int numRetry;
public CorruptFile(string fn){
fileName = fn;
}
}
}
First up is a warning from Microsoft in this KB article here. Money quote is:
Microsoft does not currently recommend, and does not support,
Automation of Microsoft Office applications from any unattended,
non-interactive client application or component (including ASP,
ASP.NET, DCOM, and NT Services), because Office may exhibit unstable
behaviour and/or deadlock when Office is run in this environment.
Next question is why not use OpenXML for this? Here's a simple sample to get you started which counts the number of slides in a deck.
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace OpenXmlDemo
{
class PptOpenXmlDemo
{
public int PptGetSlideCount(string fileName)
{
// Return the number of slides in a PowerPoint document.
const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
const string presentationmlNamespace = "http://schemas.openxmlformats.org/presentationml/2006/main";
int returnValue = 0;
using (Package pptPackage = Package.Open(fileName, FileMode.Open, FileAccess.Read))
{
// Get the main document part (presentation.xml).
foreach (System.IO.Packaging.PackageRelationship relationship in pptPackage.GetRelationshipsByType(documentRelationshipType))
{
// There should be only a single relationship that refers to the document.
Uri documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), relationship.TargetUri);
PackagePart documentPart = pptPackage.GetPart(documentUri);
// Get the slide part from the package.
if (documentPart != null)
{
XmlDocument doc = new XmlDocument();
doc.Load(documentPart.GetStream());
// Manage namespaces to perform XPath queries.
XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("p", presentationmlNamespace);
// Retrieve the list of slide references from the document.
XmlNodeList nodes = doc.SelectNodes("//p:sldId", nsManager);
if (nodes != null)
{
returnValue = nodes.Count;
}
}
// There is only one officeDocument part. Get out of the loop now.
break;
}
}
return returnValue;
}
}
}
The code below performs a WMI query to enumerate the working devices on my computer (the OS is windows 7). It retrieves one USB serial port when I have several devices connected to USB plugs. Therefore I have three questions on the topic:
1) Does all USB plugs have a separate com port or is there one com port for all the USB?
2) If I send an array of string to the USB serial port, how will it reach the specific device?
3) Can I extract the USB port from this query to keep it as a string?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Windows.Forms;
namespace MyNamespace
{
class Program
{
static void Main(string[] args)
{
MyClass x = new MyClass();
var com = x.GetCOMs();
foreach (string port in com)
{
Console.WriteLine(port);
}
Console.ReadLine();
}
}
class MyClass
{
public List<string> GetCOMs()
{
List<string> coms = new List<string>();
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");
foreach (ManagementObject obj in searcher.Get())
{
object captionObj = obj["Caption"];
if (captionObj != null)
{
string caption = captionObj.ToString();
if (caption.Contains("(COM"))
{
coms.Add(caption);
}
}
}
m_ParseCOMs(ref coms);
}
catch (ManagementException ex)
{
MessageBox.Show("An error occurred while querying for WMI data: " + ex.Message);
return coms;
}
return coms;
}
private void m_ParseCOMs(ref List<string> comPorts)
{
string[] temp;
List<string> temp2 = new List<string>();
int index = 0;
foreach (string s in comPorts)
{
string temp3 = "";
temp = s.Split(' ');
temp3 += temp[temp.Length - 1] + " - ";
for (int i = 0; i < temp.Length - 1; i++)
{
temp3 += temp[i] + " ";
}
temp2.Insert(index, temp3);
index++;
}
comPorts = temp2;
}
}
}
Many thanks in advance!