Sunday, August 31, 2008

Win32Exception error code 267 "The directory name is invalid"

I'm currently working on an "Automated Run As" tool. Its goal is helping admins which, like me, have to give users a means to execute one or two programs as Administrator and would like to do so without having to surrender an admin's password.

So, I'm developing on Vista and I just whipped up a small proof of concept prototype, that'd run calc.exe as a different user, using ProcessStartInfo and Process. This worked fine when I executed it as myself (a rather pointless exercise, I must admit), but when I created a new user and tried to run it as him, I stumbled upon a Win32Exception complaining that the directory name is invalid, native error code 267. I was instsantly baffled, as I knew of no supplied directory name that could be invalid. I then tested the code on an XP machine and it worked!

I started googling on it to no avail, many reports of that error but no conclusive solution, or on different contexts. Finally, after a while it dawned on me, I wasn't specifying the WorkingDirectory property of the ProcessStartInfo class, as soon as I added the lines

FileInfo fileInfo = new FileInfo(path);
startInfo.WorkingDirectory = fileInfo.DirectoryName;

to my code, it was allowed to run code as different than logged in user.

As to why, I haven't looked deep enough yet, I think that it may have something to do with default values of the property or with default behavior when it is not specified, plus default permissions (which were tightened on Vista, if I'm not mistaken).

Do *you*, my non existent reader, know why?

Friday, August 22, 2008

Moving from a Workgroup based network to an Active Directory one

Back from vacation! I spent this week (yes, you read that correctly) migrating our 10 machine workgroup based network to an Active Directory setup. Despite the long time taken I must confess it was not too painful, as most of that time was spent first designing the user/group/permission setup I wanted to enforce in our network (previously everyone was an admin and we had a mess on the network) then reconfiguring the damn application we have to run on all the machines and waiting for data to move, machines to reboot and so on. I learned more about Windows this week than in my previous 15 years working with computers (mainly on Linux :-)), I honestly didn't want to know that much.

First the good news, I used a Windows Server 2003 (x64) as a server and all our machines are XP Pro so there was much pain avoided. I've read that in an heterogeneous or bigger setup lots of issues arise.

So, the steps I followed and stones I had to kick were, roughly:

1) Configure Windows Server 2003 DNS, making it serve a fake domain just for AD, thus avoiding to configure zone transfers between our ISP's DNS and this server. Also I make this DNS to cache our ISP's one for the clients to be able to navigate normally.

2) Configure Active Directory, define shares and some other stuff, the wizard is fine for that. Afterwards define the groups and users you'll use.

3) Configure each machine network connection to use the Windows Server's DNS.

4) Go on each machine to System, Computer Name, Change, pick Domain and put the name of the domain. It'll ask you the password of a Domain Admin so the machine can be added. Reboot and the machine's now a member of the domain!

5) I wanted for each user to be able to log on on any machine and carry his profile with him, so I learned about and configured Roaming Profiles. This is done by first defining a share that'll store profiles and having write permissions for the users' group, let's say \\server\profiles. Then you must log on to the machine as an administrator (and also a DIFFERENT account than the one you want to copy) to copy the profile of the user of the machine by going to System, Advanced, User Profiles and click the button and then "Copy To" for the profile you're interested in. On the popup we select the share we created plus the username, for instance, \\server\profiles\jdoe and in the lower part of the popup we can tell which domain user can use this profile, in this case jdoe@domain.local. Then wait for the data to move to the share. Afterwards configure the account on the domain controller to use the profile located on \\server\profiles\jdoe (This is under the Profile tab, if I remember correctly)

Caveat: When the Copy To button is grayed out it means that the account the profile belongs to is either logged on or a process is running with that account's credentials (this last one took me a while to figure out).

6) Now we can test the profile works by logging out of the admin account and logging in as the domain user in the machine.

Okay, so, what's next? We have all the machines in the domain and the roaming profiles set up. Why have them in the domain if we won't use it, no? So

7) Define and configure the Global Policy. This is too huge to get into details but basically you can configure here everything from registry access to installed software to firewall setup to password policies for all the machines in the domain AND for individual users (which would override the machine's one if they are both set up for the same parameters). To do this it is recommended to download the Global Policy Management Console (GPMC) which can be downloaded here, and a relatively good reference is here.

Caveats: It needs .NET Framework 1.1 and it only works on 32 bit machines. Good news is it can be used from any machine in the domain logged in as administrator. Also you must remember to activate the policy with the command gpupdate /force on each machine you want the policy to get activated right now as opposed to when it reboots or somebody logs off and on

8) Test your applications, see if you need extra rules on the firewall or permissions on the folders, etc.

Pending issues:
a) Remote software installation (ie, not needing the msi supported by the Global Policy) or else how to convert any app to a GPO usable msi.

b) Write a tool to run programs as different accounts without sharing the administrator password.

c) Find out about controlling a user's session without having him log off from the machine, all I've managed so far is to use remote desktop to log off the user, which is not nice, sometimes I'd like to enter her own session.

Phew, that was quite a bit of information :-)

Hope this helps somebody.