So I have a foreach loop that goes through a DataGridView. For each row in the grid it executes a pspasswrd.exe and changes the password of a local account. How can I pause the foreach loop until the process completes before moving onto the next computer in the list?
I am not sure, I tried WaitForExit but this is not reliable since it is synchronous so it cause my program to not respond if it takes a long time. I need to utilize Process.Exited but unsure how to do this correctly.
Here is my foreach loop. Which also checks if the password was changed successfully. And inputs data into another Datagridview if it was success.
foreach (DataGridViewRow row in dgvData.Rows)
{
if (!row.IsNewRow && row.Cells["cIPAddress"].Value.ToString().Contains("Invalid") == false)
{
if (pspasswrd(row.Cells["cIPAddress"].Value.ToString(), tbTargetUser.Text, NewPassword).Contains("Password successfully changed"))
{
dgvResults.Rows.Add(row.Cells["cIPAddress"].Value.ToString(), tbTargetUser.Text, NewPassword);
AppendNumber = AppendNumber + IncreaseNumber;
NewPassword = BasePassword + AppendNumber;
}
else
row.DefaultCellStyle.BackColor = Color.Red;
}
Thread.Sleep(1000);
}
But what I am unsure is that if I change my code below to use process.exited. How will it associate the password change to the computer it was successfully on. As it will be asynchronous.
public string pspasswrd(string ip, string user, string password)
{
String CD = #Directory.GetCurrentDirectory() + "\\pspasswrd.exe";
ProcessStartInfo p = new ProcessStartInfo();
string result = null;
p.FileName = CD;
p.Arguments = #"\\" + ip + " " + user + " " + password + " -accepteula";
p.CreateNoWindow = true;
p.RedirectStandardOutput = true;
p.RedirectStandardError = true;
p.UseShellExecute = false;
Process x = Process.Start(p);
StreamReader stream = x.StandardOutput;
result = stream.ReadToEnd();
x.WaitForExit(2000);
x.Close();
return result;
}
You should first collect all the needed information from DataGridView in a collection then run your code for executing pspasswrd.exe in a background thread looping on the collection instead of DataGridView and use WaitForExit, this will not block your UI thread.
EDIT
Here is the code with WaitForExit and a new thread. I believe that you will not gain much using the Exit event instead of WaitForExit other then much more complexity and deadlock scenarios:
private void OnSomeUIEvent()
{
//In UI thread
var ipRows = new Dictionary<string, DataGridViewRow>();
var targetUser = ""; //tbTargetUser.Text
var pwd = ""; //NewPassword
var basePassword = ""; //Some value
foreach (DataGridViewRow row in dgvData.Rows)
{
var ipAddress = row.Cells["cIPAddress"].Value.ToString();
if (!row.IsNewRow && ipAddress.Contains("Invalid") == false)
{
ipRows.Add(ipAddress, row);
}
}
Task.Factory.StartNew(() => {
ChangePassword(ipRows, targetUser, pwd, basePassword);
}).ContinueWith(t => {
//Do Something when task completed
});
}
private void ChangePassword(Dictionary<string, DataGridViewRow> ipRows, string targetUser, string newPwd, string basePwd)
{ //in background thread
foreach (var ipRow in ipRows)
{
var pwd = newPwd;
var basePassword = basePwd;
var appendNumber = 0;
var increaseNumber = 1; //some number
if (pspasswrd(ipRow.Key, targetUser, pwd).Contains("Password successfully changed"))
{
dgvResults.Invoke((MethodInvoker)(() =>
{
dgvResults.Rows.Add(ipRow.Key, targetUser, pwd);
}));
appendNumber = appendNumber + increaseNumber;
pwd = basePassword + increaseNumber;
}
else
{
dgvData.Invoke((MethodInvoker)(() =>
{
ipRow.Value.DefaultCellStyle.BackColor = Color.Red;
}));
}
}
}
Related
I would like to ask, How I can use the While statement for downloading URL?
Here's what I want to happen.
I want to check if the url from CheckBoxListItems is already exist from my ListView
There's a case that I'm adding another urls to my listbox and I don't want to download again.
if url is already exists in my listview it will skip and proceed to the next url(which is not yet downloaded).
Here's my current codes:
int count = 0;
int total = LB.CheckedItems.Count;
string counter = string.Empty;
using (cts = new CancellationTokenSource())
{
try
{
if (cts.IsCancellationRequested) { throw new TaskCanceledException(); }
txtOutput.Text = string.Empty;
Cursor = Cursors.WaitCursor;
Parsing = true;
Text = "Getting links information. Please wait...";
foreach (string url in LB.CheckedItems)
{
var info = await Task.Run(() => Parser.GetJsonData(url, cts.Token));
count++;
counter = "( " + count + " of " + total + " )";
lblTotalLinks.Text = counter;
Text = "Parsing in progress. Please wait... " + counter;
AddToListView(info); //ADD DOWNLOADED STRINGS TO LISTVIEW
}
Text = "Parsing done. " + counter;
}
catch (OperationCanceledException ex)
{ Text = ex.Message; }
catch (Exception ex)
{ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); }
}
Parsing = false;
Cursor = Cursors.Default;
cts = null;
//ADD TO LISTVIEW()
private void AddToListView(MediaInfo info)
{
int count = LV.Items.Count + 1;
var results = new List<ListViewItem> { new ListViewItem(new[]
{
count.ToString(),
info.Series,
"Episode " + info.Episode,
info.Title,
info.Runtime,
info.Resolution,
info.Category,
info.URL, //here's what I want to check if already exists
info.M3u8_url,
info.FileSize,
info.Fragments
})};
ListViewItem[] array = results.ToArray();
LV.BeginUpdate();
LV.ListViewItemSorter = null;
LV.Items.AddRange(array);
LV.Focus();
LV.EndUpdate();
Countlists();
LV.Items[LV.Items.Count - 1].EnsureVisible();
}
this is the example of what I want:
string urlExists = string.Empty;
foreach (ListViewItem item in LV.Items)
{
urlExists = item.SubItems[7].Text;
foreach (string url in LB.CheckedItems)
{
while (url != urlExists)
{
}
}
Have a utility I wrote that checks (among other things) the last time a set of servers was rebooted. This works great as long as the servers are all within my domain and the user launching the app have rights on the servers. Added a section where the user can specify alternative credentials, in our case specifically to deal with another domain. The credentials I am feeding into have domain admin rights on the destination domain, yet my code is getting an Access Denied (Unauthorized Access) error.
thanks!
private void btnLastReboot_Click(object sender, EventArgs e)
{
ConnectionOptions conOpts = new ConnectionOptions();
if (selectedList.Count > 0)
{
Cursor currentCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
stripProgress.Visible = true;
stripProgress.Minimum = 0;
stripProgress.Maximum = selectedList.Count();
stripProgress.Step = 1;
stripProgress.Value = 0;
rtfOut.SelectionTabs = new int[] { 100, 200 };
rtfOut.Text = "";
var sq = new SelectQuery("Win32_OperatingSystem");
if (prefs.useCurrentUser == true)
{
// Setting all fields to NULL causes current user info to be used
conOpts.Username = null;
conOpts.Password = null;
conOpts.Authority = null;
}
else
{
conOpts.Username = prefs.userName;
conOpts.Password = prefs.password.ToString();
conOpts.Authority = "ntlmdomain:" + prefs.domain;
}
foreach (ServerList anEntry in selectedList)
{
stripProgress.Value++;
try
{
var mgmtScope = new ManagementScope("\\\\" + anEntry.ServerName + "\\root\\cimv2", conOpts);
mgmtScope.Connect();
var mgmtSearcher = new ManagementObjectSearcher(mgmtScope, sq);
foreach (var item in mgmtSearcher.Get())
{
var lastBoot = item.GetPropertyValue("LastBootUpTime").ToString();
DateTime lboot = ManagementDateTimeConverter.ToDateTime(lastBoot);
rtfOut.Text += anEntry.ServerName + "\t";
if(anEntry.ServerName.Length <= 9)
{
rtfOut.Text += "\t";
}
rtfOut.Text += lboot.ToLongDateString() + " (" + lboot.ToLongTimeString() + ")\r\n";
}
}
catch (Exception ex)
{
if (ex is UnauthorizedAccessException)
{
rtfOut.Text += anEntry.ServerName + "\t <Access Denied>\r\n";
}
else
{
rtfOut.Text += anEntry.ServerName + "\t <not responding>\r\n";
}
}
}
stripProgress.Visible = false;
Cursor.Current = currentCursor;
}
}
Had to sleep on it, but the answer finally hit me in the shower...
I store the password the user provides in a SecureString variable, but the ConnectionOptions' password field expects the value as a clear string. I was able to test this by temporarily hard coding a password in, which then worked. The final solution was to convert the SecureString to a clear string and then assign it to the ConnectionOption.
If anyone is curious, I used this bit to convert the password back:
string password = new System.Net.NetworkCredential(string.Empty, securePassword).Password;
I have a small issue when trying to append text from a loop into a stringbuilder, after trying a few things out, i think i'm on the right track with this.
Code:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
// STRING VALUE IT SO WE CAN REUSE //
string action = e.Argument as string;
// CONNECTION //
if (action == "wraith_create_project")
{
// STRING BUILDER //
StringBuilder sb = new StringBuilder();
// VARS //
var articleSource = "";
// INVOKE - AVOID CROSS THREAD ERRORS //
Invoke(new MethodInvoker(() => { articleSource = comboBoxArticleSources.Text; }));
// TRY/CATCH //
try
{
// INVOKE - AVOID CROSS THREAD ERRORS //
Invoke(new MethodInvoker(() => { listBoxMain.Items.Add("[" + DateTime.Now + "] Creating project ... " + txtBoxProjectName.Text); }));
// ARTICLE SOURCE //
if (articleSource == "Internal Article Builder")
{
// VARS/CONSTANTS //
var separator = Environment.NewLine;
const string gsaSeparator = "\x01";
// WHICH SPINNER TO USE //
if (chkBoxInternalSpinner.Checked) {
// LOOP //
var title = "";
var body = "";
var hash = "";
//var gsaArticleInfo = "";
for (int x = 0; x <= 5; x++ ) {
// EVERY LOOP REQUESTS AN ARTICLE //
var requestArticles = Helpers.getArticleTitleAndBodyInternalSpinner("https://www.wraithseo.com/api.php?articleBuilder=1&q=" + txtBoxScrapeKeyword.Text.Replace(" ", "_"));
title = Helpers.internalSpinner(requestArticles.Item1); // SEND TO INTERNAL SPINNER FOR SPINNING ...
body = Helpers.internalSpinner(requestArticles.Item2); // SEND TO INTERNAL SPINNER FOR SPINNING ...
hash = To32BitFnv1aHash(body).ToString("X8");
Invoke(new MethodInvoker(() =>
{
listBoxMain.Items.Add("[" + DateTime.Now + "] Returned article ... " + requestArticles.Item1);
listBoxMain.Items.Add("[" + DateTime.Now + "] Spun the article ... " + title);
}));
// ENCODE WITH THE GSA SEPERATOR BETWEEN EACH FIELD //
var gsaArticleInfo = title + gsaSeparator + "%first_paragraph-article%" + gsaSeparator + body + gsaSeparator + hash;
// ADD TO THE RICHTEXTBOX ALL FIELDS FROM ABOVE //
var richTextBoxText = string.Join(separator, gsaArticleInfo);
// APPEND FIELDS TO THE STRINGBUILDER //
sb.Append(richTextBoxText);
}
// INVOKE - AVOID CROSS THREAD ERRORS //
Invoke(new MethodInvoker(() => { richTxtBoxArticle.Text = sb.ToString(); }));
}
} else if (articleSource == "") {
// RESERVED FOR ADDITIONAL SOURCES //
}
} catch (Exception ex) {
Helpers.returnMessage(ex.ToString());
}
}
}
What i'm doing here is sending a request to my server which is returning an article sized bunch of text, i'm then spinning that text and trying to display it in a richTextBox, i noticed that instead of adding each article to the richTextBox it was being overwritten by the same article, i thought by using the stringbuilder to append the article to it on each loop i could then display it outside the loop but it always seems to overwrite, instead of adding 5 articles (which is the max i have set for tetsing)
Any help would be appreciated.
Updated Code:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
string action = e.Argument as string;
if (action == "wraith_create_project")
{
StringBuilder sb = new StringBuilder();
var separator = Environment.NewLine;
const string gsaSeparator = "\x01";
var articleSource = "";
var title = "";
var body = "";
var hash = "";
var gsaArticleInfo = "";
var richTextBoxText = "";
// TEST //
List<string> gsaStuff = new List<string>();
// TEST //
Invoke(new MethodInvoker(() => { articleSource = comboBoxArticleSources.Text; }));
try
{
Invoke(new MethodInvoker(() => { listBoxMain.Items.Add("[" + DateTime.Now + "] Creating project ... " + txtBoxProjectName.Text); }));
if (articleSource == "Internal Article Builder")
{
if (chkBoxInternalSpinner.Checked) {
for (int x = 0; x <= 5; x++ ) {
// EVERY LOOP REQUESTS AN ARTICLE WHICH IS RETURNED AT RAND() //
var requestArticles = Helpers.getArticleTitleAndBodyInternalSpinner("https://www.wraithseo.com/api.php?articleBuilder=1&q=" + txtBoxScrapeKeyword.Text.Replace(" ", "_"));
title = Helpers.internalSpinner(requestArticles.Item1); // SEND TO INTERNAL SPINNER FOR SPINNING ...
body = Helpers.internalSpinner(requestArticles.Item2); // SEND TO INTERNAL SPINNER FOR SPINNING ...
hash = To32BitFnv1aHash(body).ToString("X8");
Invoke(new MethodInvoker(() =>
{
listBoxMain.Items.Add("[" + DateTime.Now + "] Returned article ... " + requestArticles.Item1);
listBoxMain.Items.Add("[" + DateTime.Now + "] Spun the article ... " + title);
}));
// ENCODE WITH THE GSA SEPERATOR BETWEEN EACH FIELD //
gsaArticleInfo = title + gsaSeparator + "%first_paragraph-article%" + gsaSeparator + body + gsaSeparator + hash;
// ADD TO THE RICHTEXTBOX ALL FIELDS FROM ABOVE //
richTextBoxText = string.Join(separator, gsaArticleInfo);
// APPEND FIELDS TO THE STRINGBUILDER //
sb.Append(string.Join(separator, gsaArticleInfo));
gsaStuff.Add(richTextBoxText);
// INVOKE - AVOID CROSS THREAD ERRORS //
Invoke(new MethodInvoker(() => { richTxtBoxArticle.AppendText(richTextBoxText); }));
Invoke(new MethodInvoker(() => { richTxtBoxArticle.Lines = gsaStuff.ToArray(); }));
} // End for loop.
Invoke(new MethodInvoker(() => { richTxtBoxArticle.Lines = gsaStuff.ToArray(); }));
//Helpers.returnMessage("SB Contents: > " + sb.ToString());
} // End checkbox.
} else if (articleSource == "") {
// RESERVED FOR ADDITIONAL SOURCES //
}
} catch (Exception ex) {
Helpers.returnMessage(ex.ToString());
}
}
}
This is happening because you're calling onto the UI thread from another thread REALLY QUICKLY. The textbox simply can't keep up.
The solution here is to use the BackgroundWorker.ReportProgress method, and pass the strings back out of your worker to your UI thread. You'd handle the ProgressChanged event of the worker from your Form, and update your controls within there instead.
Hope that helps you out.
I have attached my code below. I am trying to get the message box to go away after one pop up until another action within the application triggers it.
using (VIModel vi = new VIModel())
{
var VideoFiles = vi.VI_VIDEO_FILES.Where(a => a.SEGMENT_ID == segmentId);
foreach (var vf in VideoFiles)
{
string location = vf.URL;
location = location.Replace('/', '\\');
string[] smain = location.Split('\\');
string unamemain = smain.Last().ToString();
string fileToCopySource = Path.Combine(inputDirectory, location);
string fileToCopyDestination = Path.Combine(outputDirectory, unamemain);
foreach (char c in fileToCopySource)
{
if (fileToCopySource.Contains(c))
{
// notify user that the inputDirectory isn't valid
MessageBox.Show("FOO");
}
}
if (!File.Exists(fileToCopySource))
{
// notify user that file doesn't exist
MessageBox.Show("FOO");
}
//File.Copy(inputDirectory + location, outputDirectory + unamemain, true);
File.Copy(fileToCopySource, fileToCopyDestination, true);
lbConsole.Items.Add("Moved " + location + " from: " + inputDirectory + " to " + fileToCopyDestination);
}
}
Your code is alerting multiple times -- once for every "alertable" condition it finds, i.e. input directory not valid. What you need to do is record the fact that anything caused the condition that will need to be alerted, and then alert only once, outside of the loop:
bool needAlert = false;
foreach (char c in fileToCopySource)
{
if (fileToCopySource.Contains(c))
{
needAlert = true;
break; // no more looping needed.
}
}
if(needAlert) MessageBox.Show("FOO"); // notify user that the inputDirectory isn't valid
What I need to do is be able to cancel a task that is running async.
I have been searching and cannot seem to wrap my head around it. I just cant seem to discern how it would be implemented into my current setup.
Here is my code that fires my task off. Any help on where or how to implement a cancellation token would be greatly appreciated.
private async void startThread()
{
//do ui stuff before starting
ProgressLabel.Text = String.Format("0 / {0} Runs Completed", index.Count());
ProgressBar.Maximum = index.Count();
await ExecuteProcesses();
//sort list of output lines
outputList = outputList.OrderBy(o => o.RunNumber).ToList();
foreach (Output o in outputList)
{
string outStr = o.RunNumber + "," + o.Index;
foreach (double oV in o.Values)
{
outStr += String.Format(",{0}", oV);
}
outputStrings.Add(outStr);
}
string[] csvOut = outputStrings.ToArray();
File.WriteAllLines(settings.OutputFile, csvOut);
//do ui stuff after completing.
ProgressLabel.Text = index.Count() + " runs completed. Output written to file test.csv";
}
private async Task ExecuteProcesses()
{
await Task.Factory.StartNew(() =>
{
int myCount = 0;
int maxRuns = index.Count();
List<string> myStrings = index;
Parallel.ForEach(myStrings,
new ParallelOptions()
{
MaxDegreeOfParallelism = settings.ConcurrentRuns
}, (s) =>
{
//This line gives us our run count.
int myIndex = myStrings.IndexOf(s) + 1;
string newInputFile = Path.Combine(settings.ProjectPath + "files/", Path.GetFileNameWithoutExtension(settings.InputFile) + "." + s + ".inp");
string newRptFile = Path.Combine(settings.ProjectPath + "files/", Path.GetFileNameWithoutExtension(settings.InputFile) + "." + s + ".rpt");
try
{
//load in contents of input file
string[] allLines = File.ReadAllLines(Path.Combine(settings.ProjectPath, settings.InputFile));
string[] indexSplit = s.Split('.');
//change parameters here
int count = 0;
foreach (OptiFile oF in Files)
{
int i = Int32.Parse(indexSplit[count]);
foreach (OptiParam oP in oF.Parameters)
{
string line = allLines[oP.LineNum - 1];
if (oP.DecimalPts == 0)
{
string sExpression = oP.Value;
sExpression = sExpression.Replace("%i", i.ToString());
EqCompiler oCompiler = new EqCompiler(sExpression, true);
oCompiler.Compile();
int iValue = (int)oCompiler.Calculate();
allLines[oP.LineNum - 1] = line.Substring(0, oP.ColumnNum - 1) + iValue.ToString() + line.Substring(oP.ColumnNum + oP.Length);
}
else
{
string sExpression = oP.Value;
sExpression = sExpression.Replace("%i", i.ToString());
EqCompiler oCompiler = new EqCompiler(sExpression, true);
oCompiler.Compile();
double dValue = oCompiler.Calculate();
dValue = Math.Round(dValue, oP.DecimalPts);
allLines[oP.LineNum - 1] = line.Substring(0, oP.ColumnNum - 1) + dValue.ToString() + line.Substring(oP.ColumnNum + oP.Length);
}
}
count++;
}
//write new input file here
File.WriteAllLines(newInputFile, allLines);
}
catch (IOException ex)
{
MessageBox.Show(ex.ToString());
}
var process = new Process();
process.StartInfo = new ProcessStartInfo("swmm5.exe", newInputFile + " " + newRptFile);
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Start();
process.WaitForExit();
Output output = new Output();
output.RunNumber = myIndex;
output.Index = s;
output.Values = new List<double>();
foreach(OutputValue oV in OutputValues) {
output.Values.Add(oV.getValue(newRptFile));
}
outputList.Add(output);
//get rid of files after run
File.Delete(newInputFile);
File.Delete(newRptFile);
myCount++;
ProgressBar.BeginInvoke(
new Action(() =>
{
ProgressBar.Value = myCount;
}
));
ProgressLabel.BeginInvoke(
new Action(() =>
{
ProgressLabel.Text = String.Format("{0} / {1} Runs Completed", myCount, maxRuns);
}
));
});
});
}
The best way to support cancellation is to pass a CancellationToken to the async method. The button press can then be tied to cancelling the token
class TheClass
{
CancellationTokenSource m_source;
void StartThread() {
m_source = new CancellationTokenSource;
StartThread(m_source.Token);
}
private async void StartThread(CancellationToken token) {
...
}
private void OnCancelClicked(object sender, EventArgs e) {
m_source.Cancel();
}
}
This isn't quite enough though. Both the startThread and StartProcess methods will need to be updated to cooperatively cancel the task once the CancellationToken registers as cancelled