Access is denied.
private void MakeRule(string IP, int Protocole, NET_FW_RULE_DIRECTION_ ruleDirection, string ruleName)
{
Type tNetFwPolicy2 = Type.GetTypeFromProgID("HNetCfg.FwPolicy2");
INetFwPolicy2 fwPolicy2 = (INetFwPolicy2)Activator.CreateInstance(tNetFwPolicy2);
var currentProfiles = fwPolicy2.CurrentProfileTypes;
// Let's create a new rule
INetFwRule2 Rule = (INetFwRule2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FWRule"));
Rule.Enabled = true;
NET_FW_RULE_DIRECTION_ direction = ruleDirection;
Rule.Direction = direction; //Inbound
Rule.Action = NET_FW_ACTION_.NET_FW_ACTION_BLOCK;
Rule.Profiles = currentProfiles;
Rule.Protocol = protNumber; // ANY/TCP/UDP
try
{
Rule.RemoteAddresses = str;
}
catch (Exception)
{
MessageBox.Show("Can't add Rules. Maybe a Format failure?");
}
//Rule.LocalPorts = "81"; //Port 81
//Name of rule
Rule.Name = ruleName;
// ...//
//Rule.Profiles = (int)NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_TYPE_MAX;
// Now add the rule
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
try
{
firewallPolicy.Rules.Add(Rule);
}
catch (Exception ex)
{
throw ex;
}
}
If you want to make your app run as administrator, you can create a manifest file to make it work.
First, please right click your project and add a new item called Application Manifest File.
Second, please find requestedExecutionLevel tag and change into the following tag:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Third, you will get a UAC prompt when they start the program. Choose Restart under different credentials.
Finally, you can run the program with the amdin power.
Also, you can read the following link to use c# code to run the app as admin.
Run as administrator C#
Testabc user have the administrator right.
//Run EXTERNAL APP AS AN ADMIN
var pass = new SecureString();
pass.AppendChar('t');
pass.AppendChar('e');
pass.AppendChar('s');
pass.AppendChar('t');
var ps1File = #"C:\Users\testabc\Desktop\LT_Admin.ps1";
ProcessStartInfo processAdmin;
processAdmin = new ProcessStartInfo();
processAdmin.UseShellExecute = false;
processAdmin.CreateNoWindow = true;
processAdmin.WindowStyle=System.Diagnostics.ProcessWindowStyle.Hidden;
processAdmin.Password = pass;
processAdmin.UserName = "testabc";
processAdmin.Domain = "soft";
processAdmin.FileName = #"C:\windows\system32\windowspowershell\v1.0\powershell.exe";
processAdmin.Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{ps1File}\"";
processAdmin.RedirectStandardOutput = true;
Process.Start(processAdmin);
In ps1File I have this code
Start-Process -FilePath "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" -Verb RunAs
Working perfectly...
Related
When trying to retrieve the value of a registry key from a remote machine for a key that has spaces using WMI in C# (Reason for using WMI: Authentication and Impersonation needed), the GetStringValue returns null but when the key doesn't have spaces, it works perfectly. Using either the # notation or standard " notation for strings didn't help. I tried enclosing the key in double-quotes. Didn't help either.
Here's the code I have written:
public static string GetRemoteRegistryValue(string MachineName, string username, string password)
{
string regValue = string.Empty;
ConnectionOptions opt = new ConnectionOptions();
opt.Impersonation = ImpersonationLevel.Impersonate;
opt.EnablePrivileges = true;
opt.Username = username;
opt.Password = password;
opt.Impersonation = ImpersonationLevel.Impersonate;
opt.EnablePrivileges = true;
try
{
ManagementPath p = new ManagementPath("\\\\" + MachineName + "\\root\\cimv2");
ManagementScope msc = new ManagementScope(p, opt);
msc.Connect();
string softwareRegLoc = "\"SOFTWARE\\VMware, Inc.\\VMware Drivers\"";
//string softwareRegLoc = #"""SOFTWARE\SAP BusinessObjects\Suite XI 4.0\Config Manager""";
ManagementClass registry = new ManagementClass(msc, new ManagementPath("StdRegProv"), null);
ManagementBaseObject inParams = registry.GetMethodParameters("GetStringValue");
inParams["hDefKey"] = 0x80000002;//HKEY_LOCAL_MACHINE
inParams["sSubKeyName"] = softwareRegLoc;
inParams["sValueName"] = "VmciHostDevInst";
// Read Registry Key Names
ManagementBaseObject outParams = registry.InvokeMethod("GetStringValue", inParams, null);
if (outParams.Properties["sValue"].Value != null)
{
regValue = outParams.Properties["sValue"].Value.ToString();
}
}
catch (ManagementException Ex)
{
}
catch (System.UnauthorizedAccessException Ex)
{
}
catch (Exception Ex)
{
}
return regValue;
}
What is the solution for this issue?
Okay, two points here:
You shouldn't use quotation marks. So, replace "\"SOFTWARE\\VMware, Inc.\\VMware Drivers\"" with "SOFTWARE\\VMware, Inc.\\VMware Drivers".
The path that you're trying to access belongs to the 64-bit provider. In order to be able to access it (by default), your application needs to have its Platform Target set to x64. Otherwise, your application would be trying to access the HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\VMware, Inc.\VMware Drivers path, which probably doesn't exist.
Removing the quotation marks and targeting x64 worked just fine for me and I got the value of the exact path mentioned in the question.
If your Platform Target is set to x86 (or Any CPU with the Prefer 32-bit checkbox ticked) and you don't want to change it to x64, then you have to force WMI to access the 64-bit Registry Hive. Check the documentation for more info.
Here's a full example:
public static string GetRemoteRegistryValue(string MachineName, string username, string password)
{
string regValue = string.Empty;
ConnectionOptions opt = new ConnectionOptions();
opt.Impersonation = ImpersonationLevel.Impersonate;
opt.EnablePrivileges = true;
opt.Username = username;
opt.Password = password;
opt.Impersonation = ImpersonationLevel.Impersonate;
opt.EnablePrivileges = true;
try
{
ManagementPath p = new ManagementPath("\\\\" + MachineName + "\\root\\cimv2");
ManagementScope msc = new ManagementScope(p, opt);
msc.Connect();
string softwareRegLoc = "SOFTWARE\\VMware, Inc.\\VMware Drivers";
ManagementClass registry = new ManagementClass(msc, new ManagementPath("StdRegProv"), null);
ManagementBaseObject inParams = registry.GetMethodParameters("GetStringValue");
inParams["hDefKey"] = 0x80000002;//HKEY_LOCAL_MACHINE
inParams["sSubKeyName"] = softwareRegLoc;
inParams["sValueName"] = "VmciHostDevInst";
ManagementNamedValueCollection objCtx = new ManagementNamedValueCollection();
objCtx.Add("__ProviderArchitecture", 64);
objCtx.Add("__RequiredArchitecture", true);
InvokeMethodOptions options = new InvokeMethodOptions(objCtx, TimeSpan.MaxValue);
// Read Registry Key Names
ManagementBaseObject outParams = registry.InvokeMethod("GetStringValue", inParams, options);
if (outParams.Properties["sValue"].Value != null)
{
regValue = outParams.Properties["sValue"].Value.ToString();
}
}
catch (ManagementException Ex)
{
throw;
}
catch (System.UnauthorizedAccessException Ex)
{
throw;
}
catch (Exception Ex)
{
throw;
}
return regValue;
}
The code above returned the value of VmciHostDevInst while the app is targeting x86.
I am trying to run application remotely on WinXP. Here is the code.
void RemoteExecute(string userName,
string password,
string path,
object[] commandLine)
{
ConnectionOptions options = new ConnectionOptions();
options.Impersonation = ImpersonationLevel.Impersonate;
options.Authentication = AuthenticationLevel.Default;
options.Username = userName;
options.Password = password;
options.Authority = null;
options.EnablePrivileges = true;
ManagementScope scope = new ManagementScope(path, options);
scope.Connect();
using (ManagementClass process = new ManagementClass("Win32_Process"))
{
process.Scope = scope;
process.InvokeMethod("Create", commandLine);
}
}
...
object[] commandLine = { "cmd.exe", null, null, 0 };
RemoteExecute("acid",
"123",
#"\\192.168.142.128\Root\CIMV2",
commandLine);
Then I got exception on scope.Connect(): Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)). Googling about this lead me to tweak Security settings on target machine. Here is what I have done.
Disabled firewalls on both source and target boxes
DCOMCNFG => Component Services => My Computer => Properties => COM Security => Access Permissions/Lunch and Activation Permissions => Edit Limits/Edit Default => add account/put all possible allow checkmarks.
WMI Control => Properties => Security ROOT and CIMV2 => Security => Added new account/put checkmark on Allow everywhere.
Tried with account administrator. No empty passwords.
What else should I do to avoid exception?
Is it possible to access a network folder with Directory.GetFiles() that I would normally have to enter my credentials for when opening through explorer?
If the running user is the logon user (with profil loading) and have already access to the remote path (by entering credentials), your application, which may run with user's profile loaded, should access to the UNC path without any login.
Otherwise, you can use this piece of code to logon you can find in GitHub :
using (UNCAccessWithCredentials unc = new UNCAccessWithCredentials())
{
if (unc.NetUseWithCredentials("uncpath", user, domain, password))
{
// Directory.GetFiles() here
}
}
It is possible. I usually spawn a process to pass the credentials to the system. Please see the code posted below which does exactly this. Once the process has completed you will be able to use the network share.
public void MapPath() {
string strServer = “ServerName”;
string strShare = “ServerShare”;
string strUsername = “ServerUsername”;
string strPassword = “ServerPassword”;
Process pNetDelete = new Process();
pNetDelete.StartInfo.CreateNoWindow = true;
pNetDelete.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pNetDelete.StartInfo.UseShellExecute = false;
pNetDelete.StartInfo.FileName = “net”;
pNetDelete.StartInfo.Arguments = string.Format(“use /DELETE {0}\
{1} /Y”, strServer, strShare);
pNetDelete.Start();
pNetDelete.WaitForExit();
Process pNetShare = new Process();
pNetShare.StartInfo.CreateNoWindow = true;
pNetShare.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pNetShare.StartInfo.UseShellExecute = false;
pNetShare.StartInfo.RedirectStandardError = true;
pNetShare.StartInfo.RedirectStandardOutput = true;
pNetShare.StartInfo.FileName = “net”;
pNetShare.StartInfo.Arguments = string.Format(“use \\{0}\{1} /u:"{2}" "{3}"”,
strServer, strShare, strUsername, strPassword);
pNetShare.Start();
pNetShare.WaitForExit();
string strError = pNetShare.StandardError.ReadToEnd();
if (pNetShare.ExitCode != 0)
{
throw new Exception(strError);
}
}
I'm trying to change the permissions for a directory. To do this I am running an elevated process that actually performs the SetAccessControl.
static void Main(string[] args)
{
var options = new Options();
if (!CommandLine.Parser.Default.ParseArguments(args, options)) return;
var myDirectoryInfo = new DirectoryInfo(options.folder);
var myDirectorySecurity = myDirectoryInfo.GetAccessControl();
var usr = options.user;
myDirectorySecurity.AddAccessRule(new FileSystemAccessRule(usr, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, AccessControlType.Allow));
try
{
myDirectoryInfo.SetAccessControl(myDirectorySecurity);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
When I run this as administrator there are no errors, but the folder access permissions remain unchanged. Any ideas what is wrong?
The answer that worked for me was using ModifyAccessRule to first grant permissions to the directory. Then to add the inheritance rules.
Also I found that the windows explorer is not always showing the current permissions, not sure what causes it to refresh, but I noticed that at times the permissions were set properly, and my program could access the files in directory,even though explorer showed no permission.
private static bool SetAccess(string user, string folder)
{
const FileSystemRights Rights = FileSystemRights.FullControl;
// *** Add Access Rule to the actual directory itself
var AccessRule = new FileSystemAccessRule(user, Rights,
InheritanceFlags.None,
PropagationFlags.NoPropagateInherit,
AccessControlType.Allow);
var Info = new DirectoryInfo(folder);
var Security = Info.GetAccessControl(AccessControlSections.Access);
bool Result;
Security.ModifyAccessRule(AccessControlModification.Set, AccessRule, out Result);
if (!Result) return false;
// *** Always allow objects to inherit on a directory
const InheritanceFlags iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
// *** Add Access rule for the inheritance
AccessRule = new FileSystemAccessRule(user, Rights,
iFlags,
PropagationFlags.InheritOnly,
AccessControlType.Allow);
Security.ModifyAccessRule(AccessControlModification.Add, AccessRule, out Result);
if (!Result) return false;
Info.SetAccessControl(Security);
return true;
}
Use the following instead of myDirectoryInfo.SetAccessControl(myDirectorySecurity);
try
{
Directory.SetAccessControl(options.folder,myDirectorySecurity);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I have a program that installs a service, and I'd like to be able to give the user the option later on to change the startup type to "Automatic".
The OS is XP - if it makes any difference (Windows APIs?).
How can I do this in .NET? C# if possible! :)
I wrote a blog post on how to do this using P/Invoke. Using the ServiceHelper class from my post you can do the following to change the Start Mode.
var svc = new ServiceController("ServiceNameGoesHere");
ServiceHelper.ChangeStartMode(svc, ServiceStartMode.Automatic);
In the service installer you have to say
[RunInstaller(true)]
public class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
...
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
}
}
You could also ask the user during installation and then set this value. Or just set this property in the visual studio designer.
You can use the OpenService() and ChangeServiceConfig() native Win32 APIs for that purpose. I believe that there is some information on pinvoke.net and of course on MSDN. You might want to check out the P/Invoke Interopt Assistant.
You can use WMI to query all services and then match the service name to the inputted user value
Once the service has been found just change the StartMode Property
if(service.Properties["Name"].Value.ToString() == userInputValue)
{
service.Properties["StartMode"].Value = "Automatic";
//service.Properties["StartMode"].Value = "Manual";
}
//This will get all of the Services running on a Domain Computer and change the "Apple Mobile Device" Service to the StartMode of Automatic. These two functions should obviously be separated, but it is simple to change a service start mode after installation using WMI
private void getServicesForDomainComputer(string computerName)
{
ConnectionOptions co1 = new ConnectionOptions();
co1.Impersonation = ImpersonationLevel.Impersonate;
//this query could also be: ("select * from Win32_Service where name = '" + serviceName + "'");
ManagementScope scope = new ManagementScope(#"\\" + computerName + #"\root\cimv2");
scope.Options = co1;
SelectQuery query = new SelectQuery("select * from Win32_Service");
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
ManagementObjectCollection collection = searcher.Get();
foreach (ManagementObject service in collection)
{
//the following are all of the available properties
//boolean AcceptPause
//boolean AcceptStop
//string Caption
//uint32 CheckPoint
//string CreationClassName
//string Description
//boolean DesktopInteract
//string DisplayName
//string ErrorControl
//uint32 ExitCode;
//datetime InstallDate;
//string Name
//string PathName
//uint32 ProcessId
//uint32 ServiceSpecificExitCode
//string ServiceType
//boolean Started
//string StartMode
//string StartName
//string State
//string Status
//string SystemCreationClassName
//string SystemName;
//uint32 TagId;
//uint32 WaitHint;
if(service.Properties["Name"].Value.ToString() == "Apple Mobile Device")
{
service.Properties["StartMode"].Value = "Automatic";
}
}
}
}
I wanted to improve this response... One method to change startMode for Specified computer, service:
public void changeServiceStartMode(string hostname, string serviceName, string startMode)
{
try
{
ManagementObject classInstance =
new ManagementObject(#"\\" + hostname + #"\root\cimv2",
"Win32_Service.Name='" + serviceName + "'",
null);
// Obtain in-parameters for the method
ManagementBaseObject inParams = classInstance.GetMethodParameters("ChangeStartMode");
// Add the input parameters.
inParams["StartMode"] = startMode;
// Execute the method and obtain the return values.
ManagementBaseObject outParams = classInstance.InvokeMethod("ChangeStartMode", inParams, null);
// List outParams
//Console.WriteLine("Out parameters:");
//richTextBox1.AppendText(DateTime.Now.ToString() + ": ReturnValue: " + outParams["ReturnValue"]);
}
catch (ManagementException err)
{
//richTextBox1.AppendText(DateTime.Now.ToString() + ": An error occurred while trying to execute the WMI method: " + err.Message);
}
}
How about make use of c:\windows\system32\sc.exe to do that ?!
In VB.NET Codes, use System.Diagnostics.Process to call sc.exe to change the startup mode of a windows service. following is my sample code
Public Function SetStartModeToDisabled(ByVal ServiceName As String) As Boolean
Dim sbParameter As New StringBuilder
With sbParameter
.Append("config ")
.AppendFormat("""{0}"" ", ServiceName)
.Append("start=disabled")
End With
Dim processStartInfo As ProcessStartInfo = New ProcessStartInfo()
Dim scExeFilePath As String = String.Format("{0}\sc.exe", Environment.GetFolderPath(Environment.SpecialFolder.System))
processStartInfo.FileName = scExeFilePath
processStartInfo.Arguments = sbParameter.ToString
processStartInfo.UseShellExecute = True
Dim process As Process = process.Start(processStartInfo)
process.WaitForExit()
Return process.ExitCode = 0
End Function
In ProjectInstaller.cs, click/select the Service1 component on the design surface. In the properties windo there is a startType property for you to set this.
ServiceInstaller myInstaller = new System.ServiceProcess.ServiceInstaller();
myInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
You can do it in the Installer class for the service by setting ServiceInstaller.StartType property to whatever value you get (you'll probably have to do this in a custom action since you want the user to specify) or you can modify the Service's "Start" REG_DWORD entry, the value 2 is automatic and 3 is manual. Its in HKEY_LOCAL_MACHINE\SYSTEM\Services\YourServiceName
One way would be to uninstall previous service and install new one with updated parameters directly from your C# application.
You will need WindowsServiceInstaller in your app.
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
{
public WindowsServiceInstaller()
{
ServiceInstaller si = new ServiceInstaller();
si.StartType = ServiceStartMode.Automatic; // get this value from some global variable
si.ServiceName = #"YOUR APP";
si.DisplayName = #"YOUR APP";
this.Installers.Add(si);
ServiceProcessInstaller spi = new ServiceProcessInstaller();
spi.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
spi.Username = null;
spi.Password = null;
this.Installers.Add(spi);
}
}
and to reinstall service just use these two lines.
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });