How do I programmatically change the label of a mapped drive? - c#

I'm writing a piece of software which maps a network drive using the WNetAddConnection2 API. Just in case it's relevant, this is a WebDAV drive, rather than a normal SMB share.
The drive takes on a default name which I'd like to change.
Some answers on the net recommend using System.IO.DriveType, e.g:
DriveInfo[] allDrives = DriveInfo.GetDrives();
foreach (var drive in allDrives)
{
if (drive.DriveType == DriveType.Network && drive.Name.StartsWith("Z:"))
{
drive.VolumeLabel = "DriveInfo";
}
}
This unequivically does not work on network drives, and this backed up by MSDN, where it's stated that an UnauthorizedAccessException Exception will be thrown.
Secondly, I attempted to use the shell method:
Shell32.Shell shell = new Shell32.Shell();
((Shell32.Folder2) shell.NameSpace("Z:")).Self.Name = "Shell";
The code executes with no errors, but the drive is not renamed. And this is where it gets weird, I found the registry path where these things get written:
HKEY_CURRENT_USER\ Software\ Microsoft\ Windows\ CurrentVersion\ Explorer\ MountPoints2
The code above creates a key which looks correct, and adds a _LabelFromReg REG_SZ with "Shell" as the value. However, this is NOT reflected in Explorer or anywhere else.
I then manually renamed the mapped the drive, by right clicking and selecting "Rename".
Doing so creates a new, slightly different key within MountPoints2 which works perfectly.
So, the shell code above isn't quite resolving the path correctly - is there something else I can try? The above leads me to believe Windows must use a different API call internally to rename the drive?
Update 1
This is definitely related to these being WebDAV drives. There must be some under-the-hood processing going on.
My software maps https://myurl.com#ssl/stuff/destination/docs. That exact path can be seen with the Net Use command. It's this path that the shell code above adds to the registry and attempts to name.
However, hovering over the drive in Windows Explorer gives me https://myurl.com#ssl/anotherfolder/stuff/destination and it's this path which renaming manually within Explorer adds to the registry.
All I've managed to figure out so far is how to return the second path from a WMI (Win32_LogicalDisk -> ProviderName) call, but I really want to avoid the manual registry entry approach.

You could use PowerShell in your C# code, the https://msdn.microsoft.com/en-us/library/system.management.automation.powershell(v=vs.85).aspx
Change DriveLetter E to Q with PowerShell
$drive = Get-WmiObject -Class win32_volume -Filter "DriveLetter = 'e:'"
Set-WmiInstance -input $drive -Arguments #{DriveLetter="Q:"; Label="Label"}

I know the question is old already but I had exactly the same issue with the renaming of a webdav drive letters and found a solution.
The problem occurs, if you ever connected your webDav drive with the address like:
https://www.myurl.com:5006/myFolder
Using this url-scheme will result in an registry entry in:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2
A "DavWWWRoot" will automatically inserted into your given address:
##myurl.com#SSL#5006#DavWWWRoot#myFolder
Also if you remove this drive, the RegistryEntry persists and will prevent you from renaming the drive via script also if you already made it to mount a drive with a registry-entry without the "DavWWWRoot" string in it. (using different url-scheme)
When you try to automatically rename the drives label with the method showed by Dan, the new name will be placed unter a new RegistryEntry with a different path (without the "DavWWWRoot") and the new name will not be used.
The solution is:
Unmount your webDav-drives you want to rename.
Delete the RegistryEntries with the DAVWWWRoot in it for all your drives you want to rename from `HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2´
Mount your webDav-drives with a slightly adapted url-scheme. For our example use a url-scheme like this one:
\\www.myurl.com#SSL#5006\myFolder
Check if a registry-entry was added without "DAVWWWRoot" in it. Should be:
##myurl.com#SSL#5006#myFolder
Now you can go and rename your drive-label with the method of Dan:
Shell32.Shell shell = new Shell32.Shell();
((Shell32.Folder2) shell.NameSpace("Z:")).Self.Name = "Shell";

Here is my solution (i dont use C#), when i connect a server : net use z: http://example.com:8000 /user:user password then windows show "DAVWWWRoot" in the explorer.
I add this in the registry to rename :
REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\##example.com#8000#DavWWWRoot" /v "_LabelFromReg" /t REG_SZ /d "Weytop Drive" /f
Explore the registry to see where you need to set this _LabelFromReg key.

Related

Directory.exists returns false for mapped drive in c# coding

I am using Directory.Exists() in my windows service (that is programmed in C#, 3.5 framework)to check to see whether a particular directory exists in the drive. When I run in local machine it works fine, meaning I am able to access the directory.
But when I deploy the windows service on a Virtual Machine, and start the service, it is not able to find the directory even though the directory exists. The directory is mapped on as
Q: drive, Q:\\temp\\local\\ folder
But the windows services always returns false for the Directory.Exists().
However when I give C:\ drive in place of Q:\ it works, but does not work for a mapped drive. I have tried with the UNC path, and I have made sure the mapped drive have the administrative rights and infact the read, write and execute permission. But it still returns false.
Can anyone please tell me why? And how to resolve?
Make sure the drive is mapped under the same user as the Service is running. If you map the drive as user A, it is not automatically mapped for anyone else too.
Mapped drives are only restored during interactive login which services generally do not perform:
Map a network drive to be used by a service
Short version: You can't do it, use the full UNC path instead.
This is most probably a problem with privileges. Your Windows service is probably running under an account which doesn´t have enough privileges to access the network path.
This is a possible duplicate: Accessing mapped folder from a Windows Service written in C#
Another possible solution is to use impersonation, check it out:
http://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.90).aspx
UPDATE
Came to think of it;
Try changing the identity of the application pool to a user with the same rights as your user.
As #Sriram pointed out the Directory.Exists() method will fail if any error occurs. What sort of exception do you get if you try to access the path?
Eg (for both mapped and UNC in case there is something going on there):
DirectoryInfo diMapped = new DirectoryInfo(#"Q:\temp\local\folder");
DirectoryInfo diUNC = new DirectoryInfo(#"\\servername\fnsw\tmp\126");
Note: Assuming that the white space before 'folder' in your path is a typo?
Steps to troubleshoot
Try accessing the network path manually in "Run" [WindowKey + R]
Try to access your map drive i.e.: M:\
Make sure you are the account owner of the mapping (mapping should be done under your account)
Go to Property and see if "Run As Administrator" is unchecked.
Remove mapping and re-add the mapping.
Make sure available offline (or sync offline) is turned off and folder is available from another computer.
Hope this helps!

C# - Access to mounted networkdrive

I have some networkshares mounted to my PC. I can see them in the Windows Explorer, with drive letters etc. If I try to read or write with c#, I always get a DirectoryNotFoundException.
The method to check if the directory exists
Directory.Exists(#"N:\test")
returns false (N:\ is the mounted share). If I open the path in the Explorer, the path exists.
Can you imagine, what the problem could be?
Thank you!
I just tested to see if this works when I run the application as administrator and it failed. So the reason is most probably because the user under which you execute the code doesn't have access to the path.
As you confirmed that you were indeed running the application with elevated privileges, you should follow the indications that are also suggested in this answer :https://stackoverflow.com/a/11268410/674700:
(...) open an administrative command prompt - where you have an
elevated token all the time - and create a matching drive mapping from
there (net use h: \server\share1). Since the standard user and the
elevated administrator have a common understanding of what "H:" drive
means, everything runs okay.
Well, I just try to assume why you can get this exception, here it is;
First of all, Directory.Exists() method works fine for network mounted drives. There could be a few more reason that why you get DirectoryNotFoundException in your work.
From MSDN;
The Exists method returns false if any error occurs while trying to
determine if the specified file exists. This can occur in situations
that raise exceptions such as passing a file name with invalid
characters or too many characters, a failing or missing disk, or if
the caller does not have permission to read the file.
I believe you have one of this but since we can't acces your computer, we can't know the real reason :)

Register ocx files remotely

I have some VB6 .ocx files that I would like to register. These .ocx files would be on a remote machine.
What is the best way to register these .ocx files programatically?
string arg_fileinfo = "/s" + " " + "\"" + "\\<remotemachine>\\<directory>\\<ocx>" + "\"";
Process reg = new Process();
//This file registers .dll files as command components in the registry.
reg.StartInfo.FileName = "regsvr32.exe";
reg.StartInfo.Arguments = arg_fileinfo;
reg.StartInfo.UseShellExecute = false;
reg.StartInfo.CreateNoWindow = true;
reg.StartInfo.RedirectStandardOutput = true;
reg.Start();
reg.WaitForExit();
reg.Close();
I'm not getting any errors but it isn't registering the .ocx either. Any ideas?
If you want to register a remote file for use on a local machine, there is nothing special required for registering a file on a UNC path, but you do need to make sure that the UNC path or mapped drive is still available to all users, especially the user that is running regsvr32. Presumably, this will be the local admin which (by default on Windows Vista+) will require elevation which can disconnect network connections.
Also note that your example is missing the extra \ from the beginning of the UNC path. Your code will result in arg_fileinfo containing /s "\<remotemachine>\<directory>\<ocx>".
You can add the extra \, or use the # decorator which makes it a lot clearer when entering Windows paths:
string arg_fileinfo = "/s \"" + #"\\<remotemachine>\<directory>\<ocx>" + "\"";
Or just use it for the entire string and the alternative quote escaping method:
string arg_fileinfo = #"/s ""\\<remotemachine>\<directory>\<ocx>""";
Take this as a warning you're free to ignore (because I know you will anyway):
Doing this isn't a good practice. Just to begin with "run from network" PE files (EXE, DLL, OCX) need to be specially linked for it or you risk high network activity and crashes due to intermittent network interruptions. And registering anything not on the boot drive or at least a local hard drive isn't sensible anyway. Doing any of this ranks high on the "poor practices" list even though it might seem to work most of the time.
Why not just do normal deployment following accepted practices?
My guess would be that you are doing a lot of Mort development, throwing together version after version of some program hoping one of them will eventually "stick." So you want to dump some or all of it onto a network share, thinking "Installation? Installation? We don't need no steenking installation. I can just plop new files out there and have everything magically work with no effort."
I'll assume you don't have the luxury of a managed network you can use to push out updates via Group Policy, and that you aren't creating the necessary MSI installer packages handling the Product and Upgrade Codes in them.
One alternative would be to use reg-free COM, which will solve a lot of small issues for you.
Now, you could do this and still ignore the hazards of PE files run from a network share, or you could bypass that using a small launcher program. That launcher could check a network share for a new version, and if found copy the newer files to the local PC before starting the actual application and terminating. This is basically an auto-updated XCopy Deployment technique.
You can get as fancy as need be. For example if your application accepts command line parameters it might do the new version check itself and if found then start the small updater (passing it the command line parameters), then terminate. The updater app could restart and pass those parameters to the new version.
But yes, life as Mort (or even an official on-the-payroll developer) can be a pain. It can be extremely difficult to get the attention of your friendly neighborhood box jockeys to do things properly even if you are working in a managed corporate LAN environment. That goes double if your application isn't part of some highly engineered sanctioned Major Project.
I had to do this several years ago. As best I can remember, UNC names wouldn't work, a mapped drive letter was required. Whether it was strictly a regsvr32 issue, or was caused by something else (e.g. Windows 95) is lost in the fog of time.
If you want to register the file for use on the remote machine, you you need to run the code on that remote machine.
You can either do this by physically sitting in front of the computer, using remote control software, or a remote admin tool like psexec.exe.

Application says network drive doesn't exist, but found using OpenFileDialog

I have made a little app that's running on a Win7-PC. All it does, is to check the content of a network drive at 1:00 O'clock in the morning (and compare it to a folder on its local hard drive), and if there´s differences, copy the differences to this folder.
The problem is, sometimes it can not find the network drive.
When the app starts up, the network drive is found using a button on the app which starts OpenFileDialog, and the resulting drive letter is put into a textbox beside the button. From that point it should just run by itself. The PC is never turned off.
When it says the network drive can not be found, I can manually press the button on the very same app, select the drive in the OpenFileDialog (the drive letter never changes), and the app will run flawless in a couple of days. Then the problem occurs again.
The question is: Why can the network drive be accessed through the OpenFileDialog on my app, but my app can not?
My app start the copy-process using this function (called with "Y:\") to determine whether the drive is present or not:
public bool fn_drive_exists(string par_string)
{
DirectoryInfo di_dir = new DirectoryInfo(par_string);
if (di_dir.Exists)
{
return true;
}
return false;
}
...and sometimes it returns a False, until I "wake it up" using the OpenFileDialog.
What does OpenFileDialog do, that my app do not?
According to this SO post, the problem should be gone if you use UNC path instead of mapped network drive.
If your destination has a static ip address, I suggest you use that ip address instead of domain name for network drive
This SO post describes a similar scenario to what you've described.
One of the links posted as a response to that question led me to this MSDN article which provides a variety of reasons as to why one might encounter errors when trying to access shared network drives by using a mapped drive letter.
Microsoft's suggestion (see below) is to simply use a UNC path.
A service (or any process running in a different security context) that must access a remote resource should use the Universal Naming Convention (UNC) name to access the resource.
To answer your actual question more specifically, with regards to why it suddenly can't access the network share, I would venture a guess to say that the network share is being disconnected by Windows due to an idle timeout, as discussed in KB297684. Any attempt to access the disconnected drive will be met with a small wait as the connection to the network share is re-established, which could presumably be what is causing your issue.
To test this theory, try writing some data to a file on the network drive at a relatively short interval (every 10 minutes, perhaps?) to try and convince Windows that the drive is still active.
You can also try to use:
System.IO.Directory.Exists(par_string);
instead of writing Your own method for the same thing. I would expect a framework method to be able to "wake" the network drive.
Note: Method also works for UNC paths (something like \\<server name or IP address>\<shared folder>)
Like Harvey says, use the UNC path to access the folder, for instance \\server\sharedfolder. In place of \\server use the name of the server. Your computer has a name and so does the server. You can also use the IP address if you know it. You replace \sharedfolder with the path to the files. Some examples:
\\AppsServer\c$\Program Files(x86)
\\FileServer1\d$\Users\John\My Documents
The c$ represents that the C drive is the shared folder. If the entire drive is not shared, you will need to share the specific folder. You can do that by logging onto the server, right clicking the folder, and selecting Properties. Then you go to the Sharing tab and check the Share this folder checkbox. If your shared folder is called MyShare, then your UNC path to access the folder will be
\\server\MyShare

Network Drive Not Available On Startup

I have a C# application which loads at startup, and logs data to a network drive, which is mounted as X:
When the machine first boots, the application throws an error that X:\ is not available. If I restart the app, same error.
However, if I open Windows Explorer and double click to browse the drive, I can then run the application and it will connect to X: just fine.
Do network drives not automatically initialise on startup, despite being mapped? Is there a way to set them to initialise automatically?
Ive had the exact same issue. I don't know if there are better methods out there, but I added this to my code before accessing the mapped drive.
Process mapDrive = new Process();
mapDrive.StartInfo.FileName = "net.exe";
mapDrive.StartInfo.Arguments = #"use c: \\server\share";
mapDrive.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
mapDrive.Start();
That way whether the drive is available at start up or not it will always be available.
See How Can I Access a Mapped Network Drive here on SO for a list of things to check. My guess is either the drive does not exist for your user, or there is a permissions issue accessing it. Another item to check is the order in which you call Impersonate, assuming that you are doing so, that is.
According to Cannot Access Files On Mapped Drive From Windows Service you should not do this at all. See the Microsoft link(s) provided in the accepted answer.

Categories

Resources