UserPrincipal.FindByIdentity fails in C# under 64bit WinPE - c#

I am writing a 64-bit C# Windows forms application that will run under Windows PE 10 64-bit to pull the Display Name from Active Directory. I have to use 64-bit because the PCs I am running this on will only boot UEFI so I cannot boot into a 32-bit recovery environment. Every time my code reaches a certain spot, I receive the error message: Unknown Error [0x80005000]. If I compile this and run in 32-bit Windows PE 10, it runs fine, with no modification to the code other than compiling 32-bit.
I am using VS2019 and the code is using .NET v4.7.
Below is the code that I am using:
using (PrincipalContext ad = new PrincipalContext(ContextType.Domain,
"dotted.domain.com", "OU=Users,DC=dotted,DC=domain,dc=com",
ContextOptions.Negotiate, main.interactiveUser, main.interactivePwd))
{
try
{
//this is where it fails
using (UserPrincipal wantedUser = UserPrincipal.FindByIdentity(ad, combo1.Text))
{
if (wantedUser != null)
{
givenName = wantedUser.DisplayName;
}
else
{
MessageBox.Show("User name not found in AD. Please locate manually",
"Error finding name", MessageBoxButtons.OK, MessageBoxIcon.Error);
givenName = "DisplayNameNotFoundInAD";
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
break;
}
}
Here are the meanings of my variables:
dotted.domain.com = the name of my domain
main.interactiveUser = user name to log into the domain with from another form
main.interactivePwd = password for said user name
combo1.Text = text from combo box that has the user name I want to search for
wantedUser = user name of the person I want the display name for
givenName = display name for the user name I am searching for
I have tried it with and without the OU=Users with the same result. It also works fine if I am running in Windows normally. I found some other posts about possibly editing the registry with owner info, that made no difference.
Any ideas on why this is happening?

Had a similar issue accessing the registry in 64-bit WinPE in the past. From my understanding it is exactly what PrincipalContext does.
In my case, I had to uncheck
prefer 32-bit
on the build-tab in VS.
PS: Would have commented only, but currently I'm not on enough reputation

Related

Error while starting a WPF-Application on System-Startup

I have a WPF-Application that I would like to start automatically if I start my Computer.
I have a window where a user can configure some settings for the application, one of the possible configuration options is a checkbox, that allows the user to dis- or enable the application to automatically start on the System-Startup.
This is how I set or delete the value in the Registry, depending on the users choice in the Checkbox:
try
{
var currentAssembly = Assembly.GetExecutingAssembly();
var rkApp = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
if (settingsViewModel.AutostartEnabled)
{
rkApp.SetValue(currentAssembly.GetName().Name, currentAssembly.Location);
}
else
{
rkApp.DeleteValue(currentAssembly.GetName().Name, false);
}
}
catch (Exception exception)
{
}
My Problem is, that even though the Application gets registered and can also be seen in the Autostart-Section within the Task-Manager, that I get the following error every time I restart my computer to check if the Appliction is started:
"You are attempting to open a file of type Application extension (.dll)"
So what am I doing wrong? Is there any way to avoid this error or to fix it? I already tried adding an application manifest file to my project to always start my Application as an Administrator. But that didn't seem to work either.
I'd appreciate any help.
Try to use System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName instead of currentAssembly.Location.
This should give you the path of the running executable. Assembly.GetEntryAssembly does not.

xamarin device owner self upgrade only updates manifest, not executables

I have a strange problem. I have a kiosk application (running as device owner, set by dpm) that is attempting to perform a self upgrade from an apk file that has already been downloaded. The file is downloaded correctly and the upgrade appears to work correctly. The application quits, the system gives a notification that the application has been upgraded by the device owner before the application relaunches.
When the application has relaunched, the version number is reporting as the new version, but none of the modified functionality in the app is present. On the initial login form I added a label with the version number hardcoded into it to compare to the version pulled using Xamarin.Essentials.AppInfo.Version.ToString(). The hardcoded version does not update, but the software version shows correctly.
The device is a Samsung Galaxy Tab A.
I have added a toast on exception which is showing no error messages. I have tried changing the PackageInstallMode to InheritExisting, this didn't seem to make any difference.
The method used for the upgrade is here.
public void UpgradeFromLocalFile(string downloadedFile)
{
try
{
if (MainActivity.Instance.CheckSelfPermission(Manifest.Permission.WriteExternalStorage) == Permission.Denied)
{
MainActivity.Instance.RequestPermissions(new string[] { Manifest.Permission.WriteExternalStorage }, 0);
}
if (MainActivity.Instance.CheckSelfPermission(Manifest.Permission.ReadExternalStorage) == Permission.Denied)
{
MainActivity.Instance.RequestPermissions(new string[] { Manifest.Permission.ReadExternalStorage }, 0);
}
if (MainActivity.Instance.CheckSelfPermission(Manifest.Permission.InstallPackages) == Permission.Denied)
{
MainActivity.Instance.RequestPermissions(new string[] { Manifest.Permission.InstallPackages }, 0);
}
var installer = MainActivity.Instance.PackageManager.PackageInstaller;
var parameters = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);
parameters.SetAppPackageName("my.package.name");
var sessionid = installer.CreateSession(parameters);
var session = installer.OpenSession(sessionid);
var fis = File.OpenRead(downloadedFile);
using (var outputstream = session.OpenWrite("my.package.name", 0, -1))
{
fis.CopyTo(outputstream);
session.Fsync(outputstream);
outputstream.Close();
outputstream.Dispose();
fis.Close();
fis.Dispose();
GC.Collect();
}
var pendingIntent = PendingIntent.GetBroadcast(MainActivity.Instance, sessionid, new Intent(Intent.ActionInstallPackage), 0);
session.Commit(pendingIntent.IntentSender);
}
catch(Exception ex)
{
Toast.MakeText(MainActivity.Instance.ApplicationContext, string.Format("Update failed, you may not have full device admin privileges. Error - {0}", ex.ToString()), ToastLength.Long).Show();
}
}
I'd expect the software version to change as well as the actual executable version. Does anyone have any clues as to what I'm doing wrong.
Ok, after much stuffing around and inspecting install logs with logcat, it seems the apk I was generating by deploy is incomplete. I had to set up a keystore to sign my app and then create a complete archive.
Right click the android proj -> archive.. -> Distribute -> Ad Hoc
This allowed me to self update properly.
Phew. Was bashing my head against it for days. Hope this saves someone else some time.

Issue with Web Application and ISA Authentication

right now this code works by picking up the authenticated user (windows authentication). we are using active directory. however if you are off the network and try to log into this specific application you get redirected to our ISA 2006 server, which then passes login information into the application (in theory, lol)
when I access this app on my phone over 3g its pretty slow, but i dont get an error (the error just being a popup with an ok button, sometimes it says error, sometimes it doesnt). However when I use a faster better computer over the external it does give me this error. Unit testing by my colleagues revealed there to be some sort of recursive loop or some sort which was giving the error. any time you log into the web application while on the network, it picks up windows authentication with no problem and gives no error. I have spent 3 days trying to figure out my bug but cant find it, I hope another few set of eyes can help me track it down (I am using ASP.net 4.0 with C#)
public string IdentifyUser()
{
string retval = string.Empty;
try{
//System.Security.Principal.WindowsPrincipal p = System.Threading.Thread.CurrentPrincipal as System.Security.Principal.WindowsPrincipal;
//string UserIdentityName = p.Identity.Name;
string UserIdentityName = Request.ServerVariables["AUTH_USER"];
//string UserIdentityName = HttpContext.Current.User.Identity.Name.ToString();
string slash = #"\";
string Username = UserIdentityName.Substring(UserIdentityName.IndexOf(slash) + 1);
retval = Data_Access_Layers.SQL.GetUserID(Username);
}
catch (Exception ex)
{
throw ex;
}
return retval;
}
basically this fires off, pulls the username, it gets sent to "GetUserID" which looks up that username and sends back the user id attached to that person, which is then sent back out to the main page, and is stored in a javascript variable (to be used on other parts of the page)
Is the problem that AUTH_USER is empty?
What is the value of the AUTH_TYPE header when accessing the app from inside and outside the network?

How to obtain DefragAnalysis using C#

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 }
}
};

How to set "interact with desktop" in windows service installer

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.

Categories