C# loop through app.config but only use keys like "service" - c#

I'm looping through a txt file currently to get server names and check a specific services status and start it if stopped. This works perfectly with my service names stored in my app.config.
What I want to do is also store my file path, file name, timeout, and any other keys I want to put in the app.config down the road.
My issue is when I loop through the app.config currently I only have service names which works perfectly. If I add the other keys that I want to add I obviously will get "Service Not Found".
How do I only pick keys that are "like" "service". I'm naming the keys "service1", 2, 3, etc.
foreach (string key in ConfigurationManager.AppSettings)
{
string value = ConfigurationManager.AppSettings[key];
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader(txtFilePath + txtFile))
{
String line;
// Read and display lines from the file until the end
// of the file is reached.
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
// Check for lines with semi-colon. If semi-colon at
// line start skip it
if (line.StartsWith(";"))
{
continue;
}
else
{
ServiceController sc = new ServiceController(value, line);
//Create new timeout module.
TimeSpan timeout = new TimeSpan();
//Write current service status to console.
Console.WriteLine(
"The " + value + " service status is currently set to {0}",
sc.Status.ToString()
);

You should move to a named configuration section with elements that you define VS using the AppSetting collection.
I'd follow the recommendations here on how to make a custom section in your config file, and then you're no longer finding items by key, but by section.

Related

Changing values of settings files runtime

I'm working on a windows based project , in this project we used multiple settings files in order to set text of controls for example buttons.settings, lables.settings and .....
now I need to change the content of these settings files with other values at run time, for this reason we created same settings files with same column "Name" but different values, now I really have problem with changing content of these settings files.
I tried to change content of my tow settings file by loading and saving them as xmlDocument, but unfortunately my app.config doesnt change by new values.
I also used ConfigurationManager.RefreshSection ...
plz help me
thnx in advance
I'll start from describing my setup, just to be sure that we are on the same page.
Thats my setting file - Settings1.settings, with just one setting Test, & the default value being DefaultValue
At this point, the default value is also copied to app.config.
Now, I have a template whose settings which shall come into effect at run time, Its in the form of user.config. And this is how it looks like -
here is the code from working experiment -
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(Settings1.Default.Test); // this shows "DefaultValue" in a message box
// Now change the user.config file with our template file -
//1. I get the location of user config
var fileForUser = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath;
//2. now I'll Place my template file, where user.config should be present
// create directory if it doesnt exist
if(Directory.Exists(Path.GetDirectoryName(fileForUser)) == false)
Directory.CreateDirectory(Path.GetDirectoryName(fileForUser)) ;
// I have kept my template at E:\template.config
File.Copy(#"E:\template.config", fileForUser, true);
MessageBox.Show(Settings1.Default.Test); // this still shows "DefaultValue" because the user.config is not reloaded
//3. Read the new setting
Settings1.Default.Reload();
MessageBox.Show(Settings1.Default.Test); // this shows "Default Value is changed to ABC" because the user.config is now reloaded
}
The App.config remains as it is & incase I delete the user.config or call Settings1.Default.Reset() then its the App.config which provides the application with default values
Hope it helps. Do let me know if it served yr purpose or not.
Update 1 Supporting the already tried approach by author of the question
Here is the working code to support yr approach, which will bring the settings file's setting in applicaion -
regret my typo - Lables2.settings, Lables.settings instead of Labels2.settings & Labels.settings
{
// 1. Open the settings xml file present in the same location
string settingName = "Lables2.SETTINGS"; // Setting file name
XmlDocument docSetting = new XmlDocument();
docSetting.Load(Application.StartupPath + Path.DirectorySeparatorChar + settingName);
XmlNodeList labelSettings = docSetting.GetElementsByTagName("Settings")[0].ChildNodes;
// 2. Open the config file
string configFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
XmlDocument appSettingDoc = new XmlDocument();
appSettingDoc.Load(configFile);
XmlNodeList appConfigLabelSettings = appSettingDoc.GetElementsByTagName("userSettings")[0].
SelectNodes("WindowsFormsApplication2.Lables")[0].ChildNodes;
//ProjectName.Setting file
//3. update the config file
for (int i = 0; i < appConfigLabelSettings.Count; i++)
{
var v = appConfigLabelSettings.Item(i).ChildNodes[0];
v.InnerText = labelSettings.Item(i).InnerText;
}
//4. save & load the settings
appSettingDoc.Save(configFile);
Lables.Default.Reload();
MessageBox.Show(Lables.Default.Code); // test pass... shows A2
}
My project settings -
Thats the executable folder, where
And this is how the labels2.settings look like
Update 2 Approach without xml document
All the setup is same & this is much cleaner. Please try -
{
// 1. Open the settings xml file present in the same location
string settingName = "Lables2.SETTINGS"; // Setting file name
XmlDocument docSetting = new XmlDocument();
docSetting.Load(Application.StartupPath + Path.DirectorySeparatorChar + settingName);
XmlNodeList labelSettings = docSetting.GetElementsByTagName("Settings")[0].ChildNodes;
Console.WriteLine("Code {0} Group{1} Name{2}", Lables.Default.Code, Lables.Default.Group, Lables.Default.Name); //prints Code A1 GroupB1 NameC1
//2. look for all Lables2 settings in Label settings & update
foreach (XmlNode item in labelSettings)
{
var nameItem = item.Attributes["Name"];
Lables.Default.PropertyValues[nameItem.Value].PropertyValue = item.InnerText;
}
Lables.Default.Save(); // save. this will save it to user.config not app.config but the setting will come in effect in application
Lables.Default.Reload();
Console.WriteLine("Code {0} Group{1} Name{2}", Lables.Default.Code, Lables.Default.Group, Lables.Default.Name); //prints Code A2 GroupB2 NameC2
}
Perhaps its the problem with xmlDocument as mentioned here Changing App.config at Runtime
Please keep the setup same as my last response of label.settings & label2.settings.
And try this implementation
{
// 1. Open the settings xml file present in the same location
string settingName = "Lables2.SETTINGS"; // Setting file name
XmlDocument docSetting = new XmlDocument();
docSetting.Load(Application.StartupPath + Path.DirectorySeparatorChar + settingName);
XmlNodeList labelSettings = docSetting.GetElementsByTagName("Settings")[0].ChildNodes;
Console.WriteLine("Code {0} Group{1} Name{2}", Lables.Default.Code, Lables.Default.Group, Lables.Default.Name); //prints Code A1 GroupB1 NameC1
//2. look for all Lables2 settings in Label settings & update
foreach (XmlNode item in labelSettings)
{
var nameItem = item.Attributes["Name"];
Lables.Default.PropertyValues[nameItem.Value].PropertyValue = item.InnerText;
}
Lables.Default.Save(); // save. this will save it to user.config not app.config but the setting will come in effect in application
Lables.Default.Reload();
Console.WriteLine("Code {0} Group{1} Name{2}", Lables.Default.Code, Lables.Default.Group, Lables.Default.Name); //prints Code A2 GroupB2 NameC2
}
It works for me, & because its without xmldocument, I'm hopeful it'll work at yr end too. Do let me know the result.
XmlDocument doc = new XmlDocument();
//doc.Load(#"C:\Users\***\Documents\Visual Studio 2008\Projects\ChangingLablesRuntime\ChangingLablesRuntime\_Labels2.settings");
//doc.Save(#"C:\Users\SHYAZDI.IDEALSYSTEM\Documents\Visual Studio 2008\Projects\ChangingLablesRuntime\ChangingLablesRuntime\_Labels.settings");
doc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
var root = doc.GetElementsByTagName("userSettings")[0];
doc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
var Config = System.Configuration.ConfigurationManager.OpenExeConfiguration(#"path of app.config");
var root = doc.GetElementsByTagName("userSettings")[0];
doc.GetElementsByTagName("userSettings")[0].SelectSingleNode("Zeus._Labels").InnerText = doc.GetElementsByTagName("userSettings")[0].SelectSingleNode("ChangingLablesRuntime._Labels2").InnerText;
//var newEml = root.SelectSingleNode("ChangingLablesRuntime._Labels2");
//var oldEml = root.SelectSingleNode("Zeus._Labels");
//oldEml.InnerText = newEml.InnerText;
//oldEml.ParentNode.ReplaceChild(newEml, oldEml);
doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
Config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("userSettings");
here is my code , lables2 is same as lables1 with different values, after running this code nothing happened.
this is piece of lables1.settings , that I want to replace with lables2.settings:
this is piece of lables2.settings :
and app.config related code :

Windows, C#: reading eventlog entries from active AND saved logs

I know that I can read the Security logs of a Windows PC using:
var securityLog = new EventLog("security");
foreach (EventLogEntry entry in securityLog.Entries) {
...
}
The entry item contains all the interesting log fields I expect to see like: InstanceId, Message and others. What I want to do now is read the same things from an event log that was saved to disk as an .evtx file.
I have seen suggestions for using
string xpathQuery = "*";
var eventsQuery = args.Length == 0
? new EventLogQuery("Security", PathType.LogName, xpathQuery)
: new EventLogQuery(args[0], PathType.FilePath, xpathQuery);
using (var eventLogReader = new EventLogReader(eventsQuery)) {
EventLogRecord entry;
while ((entry = (EventLogRecord) eventLogReader.ReadEvent()) != null) {
...
}
}
but the entry in the second version doesn't contain the same members/values as the first example. I totally dig that I am confused and am looking at the problem the wrong way.
How should one go about reading the actual per record content from either an active or saved system log?
Or, can I go from an EventLogRecord to an EventLogEntry? I have not seen that conversion method yet.

Code to reformat file

Need help formatting a seperated .txt file in C#. I have a text file that contains a directory listing and looks like as follows when I open up in notepad or ultra-edit. First column is date and time, next column is the size of file in bytes, third column is the username and fourth column is the name of the file. Each column is separated by one or more spaces, and the filename column at the end can contain spaces in the filename. They consist of more directories and the total amount of lines in the file is about 200,000.
Directory of V:\word
01/10/2013 12:30 PM 23,000 BUILTIN/ADMINISTRATOR FILE NAME.XLS
10/25/2013 10:39 AM 1,332,432 AMERICAS/DOEJ FILENAME2.CSV
11/31/2000 09:54 PM 21,999,999 AMERICAS/DOEF F_I_L_E_N_A_M_E_4.PDF
Directory of V:\word\administrators
01/10/2013 12:30 PM 23,000 BUILTIN/ADMINISTRATOR FILENAME.XLS
10/25/2013 10:39 AM 1,332,432 AMERICAS/DOEJ FILENAME2.CSV
11/31/2000 09:54 PM 21,999,999 AMERICAS/DOEF F_I_L_E_N_A_M_E_4.PDF
My goal is to try and add the path of the directory (ex. V:\Word or other directories) in a fixed format at the end of the filename. So Once you see the "Directory V:\word" then you know every line after and up until a new Directory, should show that path at the end of the filename. This would be considered the fifth column.
Here is some code, but I still need to help. I am able to get V:\word at the end of the file, but how do I read the new directory and append that to the end of the lines for all subsequent lines?
private void button1_Click(object sender, EventArgs e)
{
var sbText = new StringBuilder(10000);
string currLine = " Directory of V:\\word ";
try
{
using (StreamReader Reader = new StreamReader(#"C:\V.txt"))
{
while (!Reader.EndOfStream)
{
if (currLine != " Directory of V:\\word ")
{
MessageBox.Show("No Directory");
}
else
{
sbText.AppendLine(Reader.ReadLine() + "V:\\word");
}
}
// When all of the data has been loaded, write it to the text box in one fell swoop
richTextBox1.Text = sbText.ToString();
using (StreamWriter Writer = new StreamWriter(#"C:\NEWFILE.txt"))
{
Writer.WriteLine(sbText);
}
}
}
catch (Exception ex)
{
MessageBox.Show("An error has occured. " + ex.Message);
}
Here's a fairly straight-forward approach--which defines a simple class that represents your data, and parses each line into a class instance. It's efficient, and the results can easily be written to a new file, queried, or displayed:
void Main()
{
var lines = ReadFile();
lines.ToList().ForEach (Console.WriteLine);
}
IEnumerable<Line> ReadFile()
{
using (var reader = new StreamReader(File.OpenRead(#"file.txt")))
{
const string directoryPrefix = " Directory of ";
Regex splittingRegex = new Regex(#"\s+", RegexOptions.Compiled);
string directory = null;
string line;
while ((line = reader.ReadLine()) != null)
{
line = line.TrimEnd();
if (line.StartsWith(directoryPrefix))
{
directory = line.Substring(directoryPrefix.Length);
continue;
}
// The "6" parameter means the regex will split the string into 6 parts at most--leaving the last column (filename) unsplit
var lineParts = splittingRegex.Split(line, 6);
yield return new Line{ Date = lineParts[0], Time = lineParts[1], Period = lineParts[2], Bytes = lineParts[3], User = lineParts[4], Filename = Path.Combine(directory, lineParts[5]) };
}
}
}
// Define other methods and classes here
class Line
{
public string Date{get;set;}
public string Time {get;set;}
public string Period {get;set;}
public string Bytes {get;set;}
public string User {get;set;}
public string Filename {get;set;}
}
Note: This is derived from a couple helper methods for parsing simple text files. One of my earlier revisions include the helper methods, which might be of use to you (but aren't quite suited for this due to the need to remember the directory value).
You're incrementing wCurrLine but never resetting it. I think you want to reset it after each directory?
You're not incrementing totalLines, but then displaying it in label2. I think you should be incrementing it.
How do you check if the input line of text is a directory entry? If your text is consistent as presented, you could check the first letter of each row as it's read in and check if it is the letter 'D'.
You need to AppendLine not Append to put the carriage returns back in

How to convert .evtx eventlog to csv

My windows service needs to save the contents of one eventlog to a file. This is done by EventLogSession.ClearLog. However, i cannot force it to save the eventlog to CSV directly. The saved format is EVTX.
EventLogSession els = new EventLogSession();
//stel de filename samen door het appdata pad te combinen met een tempfile name
string tempData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "templog.csv");
// Clears all the events and archives them to the .evtx file
els.ClearLog(eventLogName, tempData); // Backup File Path
How can i force the EventlogSession class to save directly to CSV, or, if that is impossible. How do i convert an EVTX to CSV (using C# or VB.net)
Thanks!
This is pretty easy to do with the API provided by Log Parser.
Download & Install Log Parser 2.2
Add a reference to the COM library "MS Utility 1.0 Type Library - LogParser Interfaces collection". Searching for Log narrowed the list pretty dramatically.
Change the properties of the Reference so that the it does NOT embed Interop Types.
If you don't do this, you will get compile errors like this:
Interop type 'MSUtil.COMCSVOutputContextClassClass' cannot be embedded. Use the applicable interface instead.
The contents of the LogParser help file have a great reference for the API, but I've included the parts I used inline with the code.
using System;
using MSUtil;
namespace LogParserTest
{
using LogQuery = LogQueryClassClass;
using EventLogInput = COMEventLogInputContextClassClass;
using CSVOutput = COMCSVOutputContextClassClass;
using XMLOutput = COMXMLOutputContextClassClass;
class Program
{
static void Main(string[] args)
{
try
{
// Instantiate the LogQuery object
LogQuery oLogQuery = new LogQuery();
// Instantiate the Event Log Input Format object
EventLogInput eventInputFormat = new EventLogInput();
// When set to "FW", events are retrieved from the oldest to the
// newest. When set to "BW", events are retrieved from the newest
// to the oldest.
eventInputFormat.direction = "FW";
// Event text messages often span multiple lines. When this parameter
// is set to "ON", the EVT input format preserves readability of the
// messages by removing carriage-return, line-feed, and multiple space
// characters from the message text.
// When this parameter is set to "OFF", the EVT input format returns
// the original message text with no intervening post-processing.
eventInputFormat.formatMessage = true;
eventInputFormat.binaryFormat = "ASC";
eventInputFormat.stringsSep = ",";
CSVOutput csvOutputFormat = new CSVOutput();
// ON: always write the header;
// OFF: never write the header;
// AUTO: write the header only when not appending to an existing file.
csvOutputFormat.headers = "ON";
// Setting this parameter to "ON" causes the CSV output format to write
// a tab character after each comma field separator, in order to
// improve readability of the CSV output. Note that using tabs between
// field values might generate output that is not compatible with
// certain spreadsheet applications.
csvOutputFormat.tabs = false;
// ON: always enclose field values within double-quote characters;
// OFF: never enclose field values within double-quote characters;
// AUTO: enclose within double-quote characters only those field
// values that contain comma (,) characters.
csvOutputFormat.oDQuotes = "AUTO";
// This parameter specifies the date and/or time format to use when
// formatting values of the TIMESTAMP data type.
csvOutputFormat.oTsFormat = "yyyy-MM-dd";
// 0 is the system codepage, -1 is UNICODE.
csvOutputFormat.oCodepage = -1;
// 0: existing files are appended with the output;
// 1: existing files are overwritten with the output;
// 2: existing files are left intact, discarding the output.
csvOutputFormat.fileMode = 1;
/*
EventLog STRING Name of the Event Log or Event Log backup file
RecordNumber INTEGER Index of this event
TimeGenerated TIMESTAMP Event generated date/time (local time)
TimeWritten TIMESTAMP Event logged date/time (local time)
EventID INTEGER The ID of the event
EventType INTEGER The numeric type of the event
EventTypeName STRING The descriptive type of the event
EventCategory INTEGER The numeric category of the event
EventCategoryName STRING The descriptive category of the event
SourceName STRING The source that generated the event
Strings STRING The textual data
ComputerName STRING The name of the computer
SID STRING The Security Identifier associated with the event
Message STRING The full event message
Data STRING The binary data associated with the event
*/
string query = #"SELECT TOP 10 EventLog, RecordNumber, Message INTO "
// Enclose path in single ticks to handle spaces.
query += "'" + FullPathToCsv + "' FROM ";
// Name of application Log, System, Security, Application, CustomLogName
query += "System";
oLogQuery.ExecuteBatch(query, eventInputFormat, csvOutputFormat);
}
catch (System.Runtime.InteropServices.COMException ex)
{
Console.WriteLine("Unexpected error: " + ex.Message);
}
}
}
}
This Powershell function is the most efficient I could find. Not C# code, but I thought it might be useful. It takes a filename (evtx) or a variable array of file names in Powershell like this:
[array]$filelist =
"file1",
"file2",
"file3"
Function Convert-Logs3 {
[cmdletbinding()]
Param(
$filelist=$NULL
)
$filelist | foreach-object {
Get-WinEvent -Path "$PSItem"| Select RecordID,ID,TimeCreated, Message | export-csv - ``notypeinformation -path $(write "$PSItem.csv");
[System.gc]::collect();
}}
If you just want a tool that converts EVTX to CSV, you can use the LogParser tool directly:
C:\> logparser "SELECT TimeGenerated, SourceName, EventCategoryName, EventId, Message INTO C:\eventlog.csv FROM C:\eventlog.evtx" -i:EVT
I was able to use that to convert a 3 GB EVTX file to CSV in about 10 minutes.
It turned out that all existing solutions didn't meet my requirements.
I simply wanted a tool that takes an evtx as input and exportes a csv. Nothing more nothing less.
I built one myself and it workes fine. Its called EVTX2CSV
You can download it here: http://essaver.net/evtxecsv or directly via http://www.essaver.net/downloads/setupevtx2csv.exe

How can I read a value from an INI file in C#?

I have an INI file that I want to read the line DeviceName=PHJ01444-MC35 from group [DEVICE] and assign the value to a string.
[BEGIN-DO NOT CHANGE/MOVE THIS LINE]
[ExecList]
Exec4=PilotMobileBackup v1;Ver="1.0";NoUninst=1
Exec3=MC35 108 U 02;Ver="1.0.8";NoUninst=1
Exec2=FixMGa;Ver="1.0";Bck=1
Exec1=Clear Log MC35;Ver="1.0";Bck=1
[Kiosk]
Menu8=\Program Files\PilotMobile\Pilot Mobile Backup.exe
MenuCount=8
AdminPwd=D85F72A85AE65A71BF3178CC378B260E
MenuName8=Pilot Mobile Backup
Menu7=\Windows\SimManager.exe
MenuName7=Sim Manager
UserPwd=AF2163B24AF45971
PasswordPolicy=C34B3DE916AA052DCB2A63D7DCE83F17
DisableBeam=0
DisableBT=0
DisableSDCard=0
EnableAS=1
ActionCount=0
Url=file://\Application\MCPortal.htz
AutoLaunch=0
Menu6=\Windows\solitare.exe
MenuName6=Solitare
Menu5=\Windows\bubblebreaker.exe
MenuName5=Bubble Breaker
Menu4=\Windows\wrlsmgr.exe
MenuName4=Communications
Menu3=\Windows\Calendar.exe
MenuName3=Calendar
Menu2=\Windows\tmail.exe
MenuName2=Text Messaging
Menu1=\Program Files\PilotMobile\Pilot.Mobile.exe
MenuName1=Pilot Mobile
ShowStartMenu=1
CustomTaskBar=0
IdleTimeout=0
NoTaskbar=0
PPCKeys=1111111111111111
On=1
[Status]
MCLastConn=2006/10/01 00:50:56
[Connection]
DeploySvr1=********
[Locations]
Backup=Backup
Install=\Application
[Comm]
RetryDelay=60000
NoInBoundConnect=0
TLS=0
Broadcast=1
[Info]
LID=090128-117
PWDID=081212-10
TimeSyncID={249CEE72-5918-4D18-BEA8-11E8D8D972BF}
TimeSyncErrorInterval=5
TimeSyncInterval=120
AutoTimeSync=1
SecondarySNTPServer=ntp1.uk.uu.net
DefaultSNTPServer=ntp0.uk.uu.net
DepServerTimeSyncType=4
TimeSyncServerType=1
DFID=080717-8
Platform=PPC
Method=39
SiteName=*****
[Device]
SyncTimer=4
Ver=1
DeviceID={040171BD-3603-6106-A800-FFFFFFFFFFFF}
ShowTrayIcon=1
DeviceIDType=2
DeviceClass=AADE7ECE-DF8C-4AFC-89D2-DE7C73B579D0
DeviceName=PHJ01444-MC35
NameType=2
[END-DO NOT CHANGE/MOVE THIS LINE]
You could use Windows API for this. See http://jachman.wordpress.com/2006/09/11/how-to-access-ini-files-in-c-net/
Edit: As noted in the comments the page is no longer available on the original site, however it's still accessible on the Wayback Machine.
Additionally there is a more recent article on MSDN about accessing the required functions.
Because writing everything in one line makes me a better person than you:
string s = File.ReadAllText("inifile.ini").Split('\r', '\n').First(st => st.StartsWith("DeviceName"));
If you wanted the very simple but not very clean answer:
using System.IO;
StreamReader reader = new StreamReader(filename);
while(reader.ReadLine() != "[DEVICE]") { continue; }
const string DeviceNameString = "DeviceName=";
while(true) {
string line = reader.ReadLine();
if(line.Length < DeviceNameString.Length) { continue; }
else if(line.Substring(0, DeviceNameString.Length) != DeviceNameString) { continue; }
return line.Substring(DeviceNameString.Length);
}
If you're only intending to read one value from the file, it's a plausible option. I would probably combine the loops and add for some end of file checking though myself if you're serious about using this code.
string line;
string deviceName = string.Empty;
// Read the file and display it line by line.
using (System.IO.StreamReader file =
new System.IO.StreamReader("c:\\file.ini"))
{
while ((line = file.ReadLine()) != null)
{
if (line.ToLower().StartsWith("devicename"))
{
string[] fullName = line.Split('=');
deviceName = fullName[1];
break;
}
}
}
Console.WriteLine("Device Name =" + deviceName);
Console.ReadLine();
I am sure there are other ways.

Categories

Resources