How can various classes use only one instance of a logfile class - c#

I'm working on C# script ConsoleApp with a few dll type projects added.
Overview of the script is this- The script will basically connect to an external ActiveDirectory and do a search on a given OU. Get a list of all users from that OU and then connect via Microsoft Graph API and do 1) Invite the user for B2B and 2) Update some attributes on these invited users in AzureAD.
My solution has a few projects.
ConsoleApp - (this is start of the program)
LogicLayer - DLL. This is where the main logic resides. Such as which users are new in AD, which ones to remove from Azure etc.
DALActiveDirectory - DLL. This is where script will connect to AD and return data back to LogicLayer.
DALGraphAPI - DLL. This is where the script will connect to GraphAPI. Contains functions to get all users, get user by Id, update user attributes etc. Mainly methods here are called from LogicLayer.
PasswordCrypto - Dll. contains function to retrieve encrypted text from a file and decrypt it to get the passwords. Both DALGraphAPI and DALActiveDirectory use respective passwords.
LogFile - dll This is where I have defined a class to create a logfile with its name formatted with timestamp. eg "Log-yyyy_MM_dd_HH_mm_ss_ffff.txt".
Now I want to use LogFile instance to log certain things (such as errors, some debug messages) as control passes from ConsoleApp to LogicLayer to DALActiveDirectory to PasswordCrypto ...and so on. However, I only want one instance of this LogFile class. And no matter where the control is, the app should use that one instance to log to that one log file. If I do this in every class:
LogFile logFile = new LogFile();
then, it creates a new log file (with new name because of the timestamp). I want only one logfile created per full run of the console app. How can I achieve this? One way is to create one instance in ConsoleApp (which is the startup project) and then pass it other classes. I think it will work but is not very elegant solution. I've read something called Singleton pattern on internet but not sure if it applies to this.
Any suggestions?

Here is an example of a singleton pattern.
Private Shared objLoggerTool As LoggerTool
Public Shared Function GetLoggerToolInstance(ByVal strLogPath As String, ByVal iLogLevel As Integer) As LoggerTool
If (objLoggerTool Is Nothing) Then
objLoggerTool = New LoggerTool(strLogPath, iLogLevel)
End If
Return objLoggerTool
End Function
you instantiate the logger as
'instantiate the logger
_loggerTool = LoggerTool.GetLoggerToolInstance(config.LogFilePath, config.LogLevel)
This is a vb.net example from an app I did but it should help you understand how to create the logger and use it.

Related

How Can I Expose or Limit Commands via Group Membership (e.g.: RBAC)?

I have PowerShell commands that I've written and rather than reinventing the wheel, I want to consume RBAC as a viable means to expose the commands to users when they load the assemblies in PowerShell (via Import-Module).
In conducting my search in (insert your favourite search engine here), I've come across things that are far-out in left field, like ACEs/ACLs. The closest that I found was JEA but this looks to be specific for remoting; which defeats the purpose, since the module would be loaded locally.
I saw there was a way to do group membership verification by a SQL table but that would require standing-up the server/database/table and defeats the purpose of wanting to consume resources that already exist.
I've checked out PSPrinicpal.IsInRole(), WindowsPrincipal.IsInRole(), and GenericPrincipal.IsInRole() but these require access/use inside of a namespace/class and, thus, aren't sufficient for what I'm trying to do; which is to prevent [a] specific command[s] from being available on "Import-Module", if the user doesn't belong to 'x' group; which I believe would need to be done on decoration of the class, itself?
namespace ExamplePowerShell
{
using System;
using System.Management.Automation;
using System.ServiceModel;
/// <summary>
/// Initializes a new instance of the <see cref="RestartRemoteServer"/> class.
/// </summary>
[SOMETHING SHOULD GO HERE?]
[Cmdlet(VerbsLifecycle.Restart, "RemoteServer")]
public class RestartRemoteServer : Cmdlet
{
....
}
}
Ask: Is there a way to consume RBAC, without having to reinvent the entire premise from scratch?
Currently, all commands are available to anyone who loads the module and, rather than creating a separate module (which isn't any form of security if a user can find the other module), I want to ensure that no one else can run the commands in question without the appropriate group memberships.
Goal: To limit commandlet availability by group membership (or lack thereof), when the assembly is imported into the local PowerShell session.
(Concept) Example: A commandlet, "Restart-RemoteServer", should only be available to be run by individuals in the "DevOps" group and not be available to anyone with RDP permission to the machine, as anyone can import the module into PowerShell (or it could be loaded by default via PowerShell profiles).
Edit: Found an example that uses OData but I would prefer to depend on AD.
Limit the permissions of your users. They should not be able to do the actions themselves. This should be primary since generally nothing stops users write their own scripts/modules to do what yours do.
In your example, users with the incorrect permissions should not have shutdown or restart permissions on the remote servers, much less access to your module. Your module should just be doing error catching on the permissions side.
Split the commands into different module files. Then set read permissions on the module files using your AD groups
Query AD within your cmdlet. For example in powershell:
((Get-ADPrincipalGroupMembership $env:username | where {$_.name -like "Domain Users"}) -like (get-adgroup "Domain Users"))
JEA. Like you've already mentioned, you can limit access by only allowing your users to be active within locked-down sessions (these sessions can be local).

Rest API restore last connection

I am working on a Rest API. So far I build a Webview where the user can make inputs and send them to the server. When the server receives the information it will start a program and do some calculations. The problem here is that opening the program needs a lot of time. So the user has to wait for +20 seconds.
The point is that the user will change data of the same object and send them back to the server. When the server gets these data again it has to open the program again so that the user has to wait for another 20 seconds.
The program is referenced as a library. I create an instance of it within the controller class. So each time the server gets a new request it will open an instance, pass the data to the program and return the result to the client.
My question here is: Is there a way to avoid opening an instance for each request and instead open an instance temporarily for each user?
Edit:
The program is written in VBA. It is a configurator which calculates whether an option works out or not. I will access it by creating an instance of it:
Configurator conf = new Configurator
After that you can either create a new position or recall an old one by passing an ID like this:
conf.ID = id;
This process needs a lot of time because the program is collecting a lot of data from a database.
So this is the process I want to skip and instead use the object I created before.
After that you can pass other data to the program/object like height etc.
You can use dependency injection engines like Autofac. Register your program instance onApplicationStart as a singleton instance. Then whenever you want an instance of the program.dll, autofac will give you the same instance according to your defined registration config which is singleton.

Way to copy parts of windowsEventLog to a defined location? (sec,app, sys)

I need to create three seperate evtx files containing all events from the last X days found in each eventLog (security, application, system) and save those files in a defined location.
I am using c# to implement the functionality. It is also possible to execute a powershell script / bat file. If administration rights are a problem is it possible to do this for application and system only?
From my understanding:
It is not possible to create eventLogs in custom locations without changing the registry.
It is not possible to create eventLogs in the default location without Administration Rights since for creating a new eventlog file it needs to make sure that the eventlog is not already existing and it is not possible to access the security eventLog to check.
Exception message:
"The source was not found, but some or all event logs could not be searched. To create the source, you need permission to read all event logs to make sure that the new source name is unique. Inaccessible logs: Security."
Creating a evtx file with File.Create Method (String) and writing to it with File.WriteAllText Method (String, String) is also not possible
I also tried doing all of this with a powershell script but I pretty much ran into the same problems. $foo = Get-EventLog System -after (Get-Date).addays(-3) -asbaseobject
Check out this VERY useful cmdlet--which I think should have natively shipped with Windows-- Export-EventLog by Jeffrey Patton on TechNet.
It gives you a new function you can run called Export-EventLog, which even allows you to specify a custom location! It even runs on remote computers!
Export-EventLogs -ComputerName $computerName -Credential (Get-Credential) -LogName Application -Destination 'C:\LogFiles1\Application.evtx'

DLL doesn't store string C#

I have an application that can be launched from the explorer context menu for a Windows drive. When you click the menu item the drive letter is passed to the new instance. I want to make sure that any old instance is closed.
I also want to make sure that the last drive that was selected is persisted, so that when I start the application again from the start-menu, it will remember the drive I originally selected.
It would be best if the already running application would receive an event so that it can update without having to kill and restart.
I tried the following, but that doesn't seem to be working:
This is my Class library method(it is just a line that define a variable so just i have a DLL that there a variable in it and no more)
namespace Dispatch
{
public class cls_get_drive_letter
{
public static string drive_letter;
}
}
This is my loading form code: (Here i will fill the DLL's variable)
private void Frm_loading_Load(object sender, EventArgs e)
{
Dispatch.cls_get_drive_letter.drive_letter = "XXX";
Process currentProcess = Process.GetCurrentProcess();
if (Process.GetProcessesByName(currentProcess.ProcessName, currentProcess.MachineName).Length >1)
{
currentProcess.Kill();
}
}
So when i run this for first time the "XXX" will be stored in DLL but when the current instance of application is running and i am going to run next instance of it the application will be closed because of this code:
Process currentProcess = Process.GetCurrentProcess();
if (Process.GetProcessesByName(currentProcess.ProcessName, currentProcess.MachineName).Length >1)
{
currentProcess.Kill();
}
So when closing code occurs with this code the new "XXX" will not stored in DLL and the last string will be in dll.
All variables, in this case a static field, will only remain the same for the running instance of your application.
When the application is started again the field is empty
A static variable is not stored 'inside a dll' but is stored inside the memory of the application that loads the dll. When a second instance of the application starts, it will have its own memory space and it will have its own version of the string variable. The variable is also not kept between instances, so as soon as you start a new instance it will have its own, empty string variable.
When the application is stopped, the memory for that instance is released and the variable is 'forgotten'.
If you want to share state between applications, there are all kinds of solutions, one could be the System.Configuration.Settings API, a file somewhere, a memory mapped file shared between multiple processes, a Named Pipe, a Kernel Semaphore. Options aplenty.
Until we understand exactly what it is you're trying to accomplish with this shared state, we can't provide you with a better alternative than the explanation that what you're doing right now, will not work do to the way static variables work.
Update based on new information:
You can store your currently selected drive in a Settings file for your project. You can add such file from the project properties in Visual Studio. There's a tab called settings. Create a new setting for "Selected Drive" and make it a User setting (that way you can update it without Admin rights).
To communicate a new drive letter to your already running application, you have a number of options.
For one, you could check whether your executable is already running (like you're doing now) and in that case update the settings file and exit the new instance. Your already running instance could periodically refresh the settings to pick up new values.
When your application starts, you can open a named pipe on your machine on which you listen for drive changes. When the 2nd instance starts, it can detect that the pipe is already there, write the new drive to the pipe and close. The already running application can pick up this message and change its configuration.
You can send a WindowMessage to the other application
You can host a simple WCF service to receive the notification
You can write the new drive letter to a file stored in a known location and have the other instance use a FileSystemWatcher to detect the changes to that file.
As I said the possibilities are endless.
If I were you I'd first make sure that the value is persisted between relaunches by implementing the Settings file in your application. Then investigate the options I described above, do some experimentation and then ask new questions when you cannot figure out how to make it work.

windows service: Read from different servers with different settings

Scenario:
Read files from different servers. Each server provide files with different format, extension and data.
The reading process is periodically different for each server (per minute, hour, weekly, monthly).
There should be config file (or whatever) to set the configuration related to "File format", "File extension", "Server credentials".
My Implementation:
I wrote an application to read these different files depending on configuration set as follow:
interface IServer
{
// Common implementation
}
[ServerPath("anyLocation")]
[FileDelimiter(",")]
[FileSearchPattern("*.txt")]
class Server2 : IServer
{
// Specific implementation
}
[ServerPath("anyLocation")]
[FileDelimiter("|")]
[FileSearchPattern("*.csv")]
class Server1 : IServer
{
// Specific implementation
}
Questions:
Should I use a windows service to run this app?
The settings I set as attributes should exists as settings accessible to the user, How to do?
Most importantly, I don't know if I should use a separate service for each server, taking into consideration that reading time may interfere (what happen in that case?). I still prefer to have a single service.
I wouldn't create a windows service for this kind of problem.
Create a simple console application that accepts a commend line parameter to specify the desired target (server) and read the according configuration from a simple App.config instead of hardcoding it into your app.
Run your console app useing Scheduled Tasks - this will give you fine grained scheduling control, built in monitoring and error tracking without any additional code.

Categories

Resources