I want to uninstall a program using WMI, but I get this error : "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))". Installing it worked without any problems, using the same ConnectionOptions.
Is there any possibility that the Administrator user has rigths to install software, but not to uninstall? If so, how can I edit them?
Main()
{
ConnectionOptions oConn = new ConnectionOptions();
oConn.Impersonation = ImpersonationLevel.Impersonate;
oConn.EnablePrivileges = true;
oConn.Username = "Administrator";
oConn.Password = "password";
System.Management.ManagementScope oMs =
new System.Management.ManagementScope("\\\\192.168.14.128\\root\\cimv2", oConn);
Uninstall(oMs, "\\\\192.168.14.128\\root\\cimv2:Win32_Product.IdentifyingNumber= \"{926C96FB-9D0A-4504-8000-C6D3A4A3118E}\",Name=\"Java DB 10.4.2.1\",Version=\"10.4.2.1\"");
}
static void Uninstall(ManagementScope oMs, string path)
{
if (!oMs.IsConnected) oMs.Connect();
ManagementObject product = new ManagementObject(path);
if ((product != null) && (product.Path.ClassName ==
"Win32_Product"))
{
object result = product.InvokeMethod("Uninstall", null); //here is where I get the error
Console.WriteLine("The Uninstall method result is {0}",
result.ToString());
}
}
Thank You!
Are you doing this on an XP machine? I just Google-d your error number and got a couple links to this: http://www.0x80070005.net/. There's a lot of information about the problem, and here's a copy and paste:
The error 0x80070005 often occurs when
a scheduled task in Task Scheduler in
Windows becomes corrupt, you need to
install a security update which will
receive an error message. The error
message usually shows “Access denied”.
Here it needs a vulnerability task
scheduler which will allow code
execution. These are security updates
which were issued in the earlier
bulletin. This needs a Microsoft
knowledge base. So it is clear that
this error is about the security issue
and it finds error in the access.
Also, we're using WiX for our installer solution. Not sure if it' something you can use, but I figured I would just throw it out there.
Related
I have a C# program which checks if a specific directory exists.
It is simply doing:
Directory.Exists(path).
I tried other ways as well. Using DirectoryInfo and using AlphaFS
On my local machine, the path exists. When I run the same program on a server with the same credentials it doesn't exist.
I wonder if it is a group policy issue. But I am able to go up one level and see it.
\server\volume\share\sub directory - Doesn't exist remotely but on my desktop it does
\server\volume\share - Does exist both on my desktop and remote server
Update
I forgot to mention, that since I had access to my desktop, I got the ACL information.
None of the groups were able to translate.
I really just want to get this application to behave the same way is on the server and find out why it is behaving differently.
Update 2
These are physical servers.
My desktop is Liquid VDI
Below is the code:
var path = txtPath.Text;
using (var user = new Impersonation(fuserdomain, fc_user, fc_pass))
{
var alphaExists = Alphaleonis.Win32.Filesystem.Directory.Exists(path);
var alphaDIExists = new Alphaleonis.Win32.Filesystem.DirectoryInfo(path).Exists;
var SystemExists = System.IO.Directory.Exists(path);
var SystemDIExists = new System.IO.DirectoryInfo(path).Exists;
var AlphaHasFiles = false;
var AlphaDIHasFiles = false;
var SystemHasFiles = false;
var SystemDIHasFiles = false;
try
{
Directory.GetFiles(path);
AlphaHasFiles = true;
}
catch { }
try
{
new DirectoryInfo(path).GetFiles();
AlphaDIHasFiles = true;
}
catch { }
try
{
System.IO.Directory.GetFiles(path);
SystemHasFiles = true;
}
catch { }
try
{
new System.IO.DirectoryInfo(path).GetFiles();
SystemDIHasFiles = true;
}
catch { }
MessageBox.Show(string.Format("alphaExists: {0}\nalphaDIExists: {1}\nSystemExists: {2}\nSystemDIExists: {3}\nAlphaGetFiles: {4}\nAlphaDIGetFiles: {5}\nSystemGetFiles: {6}\nSystemDIGetFiles: {7}\n", alphaExists, alphaDIExists, SystemExists, SystemDIExists, AlphaHasFiles, AlphaDIHasFiles, SystemHasFiles, SystemDIHasFiles));
}
Update 3
Although I have workaround this issue; I am still not sure why I would have a difference between my desktop and server. Is there any tool that can help me see where the issue may be?
I've seen the same thing with File.Exists. I never found an answer and finally threw in the towel, I simply try to use it and catch the exception.
Robust code has to catch it anyway, all the test does is avoid trying if the file or directory is not there. (And the PITA that Visual Studio no longer as any way to ignore an exception on a certain line. No problem runtime, annoying in development.)
This is a complete shot in the dark, since we don't have any specific details to go on. e.g. Is the server you're talking about physically yours, or is it a cloud-based server service?
I'd guess that your machine is an older operating system than the server, and the folder that you're trying to access is one of those special folders that has become more locked down with more recent operating systems (particularly on server operating systems) like the "Program Files" folder. So even though the folder exists on both, the method works on your machine but not on the server, due to permissions.
Hope this helps.
As far as I can tell, the Impersonation class in your code is not part of the dot net framework. Googling finds a couple of implementations. Where does it come from and How confident are you that it actually works in your scenario?
For example, if you remove the Impersonation code, and actually run it as that user, does that make it work?
One other clarification... When you say
\server\volume\share
Do you mean this is a network location (e.g. a UNC location), so is the same network path you are trying to access from both machines? If so, this would open up new possibilities for problems like firewalls, etc... Is that location on either of the two machines that we know about from the question, or a different location?
I have a SSIS package with a script task, I get the following error when i try to run it in my local system. It works fine for my collegues as well as in production. However, I am not able to run it locally, to test. I keep a debug point in the main method, but it is never reached, I get the error before it goes to main method.
I am using VS 2010, .Net framework 4.5.
The script task does compile. I get the following messages SSIS package "..\Test.dtsx" starting. Error: 0x1 at Test: Exception has been thrown by the target of an invocation. Task failed: Test SSIS package "..\Test.dtsx" finished: Success. The program '[2552] DtsDebugHost.exe: DTS' has exited with code 0 (0x0).
The following is the code:
public void Main()
{
try
{
LogMessages("Update Bug package execution started at :: " + DateTime.Now.ToLongTimeString());
LogMessages("Loading package configuration values to local variables.");
strDBConn = Dts.Variables["User::DBConnection"] != null ? Dts.Variables["User::DBConnection"].Value.ToString() : string.Empty;
strTPCUrl = Dts.Variables["User::TPCUrl"] != null ? Dts.Variables["User::TPCUrl"].Value.ToString() : string.Empty;
TfsTeamProjectCollection objTPC = new TfsTeamProjectCollection(new Uri(strTPCUrl));
WorkItemStore objWIS = new WorkItemStore(objTPC);
WorkItemCollection objWIC = objWIS.Query("SELECT...");
foreach (WorkItem wi in objWIC)
{
}
}
catch(Exception ex)
{
}
When I commented the code from TfsTeamProjectCollection objTPC = new TfsTeamProjectCollection(new Uri(strTPCUrl)); The script executes successfully. However, if i keep TfsTeamProjectCollection objTPC = new TfsTeamProjectCollection(new Uri(strTPCUrl)); and comment the rest, i get the exception.
I do have access to the URL.
I am using Microsoft.TeamFoundation.Client.dll and Microsoft.TeamFoundation.WorkItemTracking.Client.dll, in my script task. However the dll version in the package is 10.0, and the version of the dll in my GAC is 12.0. Would that cause a problem?
I had the same Problem (i.e. the same error code Error: 0x1 ...).
The issue was with some of the libraries referenced from a missing folder.
Removing the references and adding them back from the correct path fixed the issue.
The Microsoft Reference (https://msdn.microsoft.com/en-us/library/ms345164.aspx) related to the Error code is very generic and doesn't help you much.
However, reading other articles it is quite likely it indicates an unknown failure reason to run the Script Task.
Hexadecimal code: 0x1
Decimal Code: 1
Symbolic Name: DTS_MSG_CATEGORY_SERVICE_CONTROL
Description: Incorrect function.
I got this error message when I referred to a passed ssis variable in Dts.Variables["User::xxxx].Value(); where xxxx did not exist and was not passed from the calling program. It was a simple Console.Writeline referring to a passed variable that didn't exist.
I fixed this error by changing the TargetServerVersion of the SSIS Project.
Integration Services Project Property Pages
This is just a different situation and not intended to be the end all be all solution for everyone.
When I was installing my DLLs into the GAC I forgot to run my script as Administrator and the script ran silently without error as though it was working.
I felt really dumb when I realized that's what I did wrong. Hopefully this can help prevent other people from wasting time on something so silly.
For reference this is what I use for installing my DLLs into the GAC and I modified it to tell me when I am not running it as Administrator now:
#https://superuser.com/questions/749243/detect-if-powershell-is-running-as-administrator
$isAdmin = ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent() `
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if($isAdmin -eq $false)
{
Write-Host "You have to run this script as Administrator or it just won't work!" -ForegroundColor Red
return;
}
$strDllPath = "C:\PathToYourDllsHere\"
#Note that you should be running PowerShell as an Administrator
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
$publish = New-Object System.EnterpriseServices.Internal.Publish
$arr = #(
"YourDLL01.dll",
"YourDLL02.dll",
"YourDLL03.dll"
)
get-date
foreach($d in $arr)
{
$p = ($strDllPath + $d);
$p
$publish.GacInstall($p);
}
#If installing into the GAC on a server hosting web applications in IIS, you need to restart IIS for the applications to pick up the change.
#Uncomment the next line if necessary...
#iisreset
Credit for how to determine if your PowerShell script is running in Admin mode or not:
https://superuser.com/questions/749243/detect-if-powershell-is-running-as-administrator
In my case it was missing DLLs or not having the correct version installed on the server.
Locally all tests were fine but on the server the error message Runtime error Exception has been thrown by the target of an invocation kept popping up.
No exception handler would be able to catch that error - the code in the script task would not even be executed, as soon as a DLL would be needed, that is not in the assembly cache on the server (it could happen on a local machine as well, with the same error).
The difficulty here is finding out what is missing and then either update the references to the correct version or install the missing DLL in the assembly cache with gacutil. The way I approached the debugging was to remove parts of the code in the script task until that error wouldn't appear, then analyze the missing part for references.
After not having any luck with the other answers here, I finally found that in my package, the problem was that I had created a new variable but not carried its name across into my new copy of the C# script. The variables were the ones to be used as connection string expressions. So it was ultimately a matter of changing:
Dts.Variables["Exists"].Value = File.Exists(Dts.Variables["OldSSISPackageVariableName"].Value.ToString());
to:
Dts.Variables["Exists"].Value = File.Exists(Dts.Variables["NewSSISPackageVariableName"].Value.ToString());
Once I kept them in sync, it worked fine.
Its fixed, when added reference to dll version 12.0.0 and changed Target Framework to .Net Framework 4.5
My problem was that I, in the script task, tried to fetch data like this:
public void Main()
{
using (var connection = Dts.Connections["localhost.Test"].AcquireConnection(Dts.Transaction) as SqlConnection)
{
connection.Open();
var command = new SqlCommand("select * from Table;", connection);
var reader = command.ExecuteReader();
while (reader.Read())
{
MessageBox.Show($"{reader[0]} {reader[1]} {reader[2]}");
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
However, my connection is of the type OLE DB, and therefore I needed to connect to it like this instead:
public void Main()
{
var connectionString = Dts.Connections["localhost.Test"].ConnectionString;
using (var connection = new OleDbConnection(connectionString))
{
connection.Open();
var command = new OleDbCommand("select * Table;", connection);
var reader = command.ExecuteReader();
while (reader.Read())
{
MessageBox.Show($"{reader[0]} {reader[1]} {reader[2]}");
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
Notice that I'm using OleDbConnection here.
For me what fixed the issue was updating the string parameter I passed to the script. it was missing "" at the end of the path (i.e. "e:\arcive" - needed to add "" at the end)
Recently two users in our system started getting this error when trying to add them to a role.
System.Runtime.InteropServices.COMException: Cannot create a file when that file already exists. (Exception from HRESULT: 0x800700B7)
What is interesting is that the same error occurs regardless of the configuration, running locally we use an XML store and in the test environment it uses SQL Server.
Here is code where is blows up - AddMemberName() - as you can see this is pretty straightforward stuff and it's worked well for a while, it's just these two users all of the sudden
public void AddUserToRole(string roleName, string userName, bool upn)
{
string uName = userName;
if (upn)
uName = getAltUserNames(userName).First();
AzAuthorizationStore store = new AzAuthorizationStoreClass();
store.Initialize(2, _provider.StoreLocation, null);
IAzApplication app = store.OpenApplication(_provider.ApplicationName, null);
IAzRole role = app.OpenRole(roleName, null);
role.AddMemberName(uName, null);
role.Submit(0, null);
Marshal.FinalReleaseComObject(role);
}
I tried googling various different terms but can't find much of anything regarding this. I did read this post but it doesn't seem to be the issue.
Thanks
Check you Active Directory usernames and the underlying OU name especially. Check for duplicates and mismatches.
I had an issue once where a user got married and her name changed.
I am currently developing an application in C# (.NET 4.0) that should have as a part of its functionality the ability to determine the percentage of fragmentation on a particular volume. All the other features have been tested and are working fine but I’ve hit a snag trying to access this data. I would ideally prefer to use WMI as this matches the format I’m using for the other features but at this point I’m willing to use anything that can be efficiently integrated into the application, even if I have to use RegEx to filter the data. I am currently doing the development on a Windows 7 Professional (x64) machine. I have tested the following Powershell snippet using Administrator rights and it works flawlessly.
$drive = Get-WmiObject -Class Win32_Volume -Namespace root\CIMV2 -ComputerName . | Where-Object { $_.DriveLetter -eq 'D:' }
$drive.DefragAnalysis().DefragAnalysis
This is the method I’m using in C# to accomplish the same thing, but the InvokeMethod keeps returning 11 (0xB).
public static Fragmentation GetVolumeFragmentationAnalysis(string drive)
{
//Fragmenation object initialization removed for simplicity
try
{
ConnectionOptions mgmtConnOptions = new ConnectionOptions { EnablePrivileges = true };
ManagementScope scope = new ManagementScope(new ManagementPath(string.Format(#"\\{0}\root\CIMV2", Environment.MachineName)), mgmtConnOptions);
ObjectQuery query = new ObjectQuery(string.Format(#"SELECT * FROM Win32_Volume WHERE Name = '{0}\\'", drive));
scope.Connect();
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
object[] outputArgs = new object[2];
foreach (ManagementObject moVolume in searcher.Get())
{
// Execution stops at this line as the result is always 11
UInt32 result = (UInt32)moVolume.InvokeMethod("DefragAnalysis", outputArgs);
if (result == 0)
{
Console.WriteLine("Defrag Needed: = {0}\n", outputArgs[0]);
ManagementBaseObject mboDefragAnalysis = outputArgs[1] as ManagementBaseObject;
if (null != mboDefragAnalysis)
{
Console.WriteLine(mboDefragAnalysis["TotalPercentFragmentation"].ToString());
}
}
else
{
Console.WriteLine("Return Code: = {0}", result);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Could not acquire fragmentation data.\n" + ex);
}
return result;
}
I have even added the following line to the app.manifest but still nothing.
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Could somebody please tell me what I’m overlooking? Failure is not an option for me on this, so if it cannot be done using C# I don’t mind creating a DLL in another language (even if I have to learn it), that will give me the results I need. Ideally the application should be able work on any OS from XP upwards and must be totally transparent to the user.
These are the resources I have already used. I wanted to add the jeffrey_wall blog on msdn as well but as a new user I can only add 2 hyperlinks at a time. Thanks again.
http://www.codeproject.com/Messages/2901324/Re-the-result-of-DefragAnalysis-method-in-csharp.aspx
http://social.technet.microsoft.com/Forums/vi-VN/winserverfiles/thread/9d56bfad-dcf5-4258-90cf-4ba9247200da
Try building your application targeting 'Any CPU' - on the Build tab of the project properties. I suspect you're using a target of x86. I get the same error code on my Win7 x64 machine if I do that.
In fact, running your PowerShell snippet in the x86 version of PowerShell gives an empty set of results, too.
You get the same error if you run either piece of code without full Administrator privileges, as you've found, so also ensure your app.manifest is correct. A UAC prompt is a handy hint that it's taking effect!
No idea why this WMI query doesn't like running under WoW64, I'm afraid, but hopefully this will give you a head-start.
You could simply call the PowerShell command you mentioned in your post, since you said the PowerShell code works. From C# you would want to follow this workflow:
Instantiate a PowerShell RunSpace
Open the RunSpace
Add a script to the Commands property
Invoke the command list
Here is an example of how to achieve this, and process the resulting object output.
http://www.codeproject.com/Articles/18229/How-to-run-PowerShell-scripts-from-C
For Windows XP and Windows Vista, you would have to ensure that PowerShell was installed on each of the systems you want to run your program on. Not a bad prerequisite to have, but something to keep in mind as a dependency.
Hope this helps.
The 32-bit WMI provider for Win32_Volume doesn't seem to be able to start the defragsvc for whatever reason. You can force the 64-bit WMI provider even in a 32-bit client running under WOW64 by changing your code to add an additional WMI connection option:
ConnectionOptions mgmtConnOptions = new ConnectionOptions {
EnablePrivileges = true,
Context = new ManagementNamedValueCollection() {
{ "__ProviderArchitecture", 64 }
}
};
I have a windows service which runs under system account and executes some programs from time to time (yeah,yeah, I know that's a bad practice, but that's not my decision). I need to set the "interact with desktop" check, to see the gui of that executed programs, after the service is installed. I've tried several ways, putting the code below in AfterInstall or OnCommited event handlers of my service installer:
ConnectionOptions coOptions = new ConnectionOptions();
coOptions.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope mgmtScope = new System.Management.ManagementScope(#"root\CIMV2", coOptions);
mgmtScope.Connect();
ManagementObject wmiService = new ManagementObject("Win32_Service.Name='" + ServiceMonitorInstaller.ServiceName + "'");
ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
InParam["DesktopInteract"] = true;
ManagementBaseObject OutParam = wmiService.InvokeMethod("Change", InParam, null);
or
RegistryKey ckey = Registry.LocalMachine.OpenSubKey(
#"SYSTEM\CurrentControlSet\Services\WindowsService1", true);
if(ckey != null)
{
if(ckey.GetValue("Type") != null)
{
ckey.SetValue("Type", ((int)ckey.GetValue("Type") | 256));
}
}
both of these methods "work". They set the check, but after I start the service it launches the exe - and gui isn't shown! So, if I stop the service, recheck and start it again - bingo! everything starts and is shown. The second way to achieve the result is to reboot - after it the gui is also shown.
So the question is: Is there a correct way to set "interact with desktop" check, so it'll start working without rechecks and reboots?
OS: Windows XP (haven't tried Vista and 7 yet...)
private static void SetInterActWithDeskTop()
{
var service = new System.Management.ManagementObject(
String.Format("WIN32_Service.Name='{0}'", "YourServiceName"));
try
{
var paramList = new object[11];
paramList[5] = true;
service.InvokeMethod("Change", paramList);
}
finally
{
service.Dispose();
}
}
And finally after searching the internet for a week - I've found a great working solution:
http://asprosys.blogspot.com/2009/03/allow-service-to-interact-with-desktop.html
Find the desktop to launch into. This
may seem facetious but it isn't as
simple as it seems. With Terminal
Services and Fast User Switching there
can be multiple interactive users
logged on to the computer at the same
time. If you want the user that is
currently sitting at the physical
console then you're in luck, the
Terminal Services API call
WTSGetActiveConsoleSessionId will get
you the session ID you need. If your
needs are more complex (i.e. you need
to interact with a specific user on a
TS server or you need the name of the
window station in a non-interactive
session) you'll need to enumerate the
Terminal Server sessions with
WTSEnumerateSessions and check the
session for the information you need
with WTSGetSessionInformation.
Now you know what session you need to
interact with and you have its ID.
This is the key to the whole process,
using WTSQueryUserToken and the
session ID you can now retrieve the
token of the user logged on to the
target session. This completely
mitigates the security problem of the
'interact with the desktop' setting,
the launched process will not be
running with the LOCAL SYSTEM
credentials but with the same
credentials as the user that is
already logged on to that session! No
privilege elevation.
Using CreateProcessAsUser and the
token we have retrieved we can launch
the process in the normal way and it
will run in the target session with
the target user's credentials. There
are a couple of caveats, both
lpCurrentDirectory and lpEnvironment
must point to valid values - the
normal default resolution methods for
these parameters don't work for
cross-session launching. You can use
CreateEnvironmentBlock to create a
default environment block for the
target user.
There is source code of the working project attached.
Same as Heisa but with WMI. (code is Powershell, but can be easily ported to C#)
if ($svc = gwmi win32_service|?{$_.name -eq $svcname})
{
try {
$null = $svc.change($svc.displayname,$svc.pathname,16,1,`
"Manual",$false,$svc.startname,$null,$null,$null,$null)
write-host "Change made"
catch { throw "Error: $_" }
} else
{ throw "Service $svcname not installed" }
See MSDN: Service Change() method for param description.