Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I have written an app that we want to distribute to a large number of customers to be used as the shell program when they log onto their server with a particular admin account.

I have figured out how to change the starting program by going to Administrative Tools->Computer Management->System Tools->Local Users and Groups->Users, selecting the properties for the user, going to the Environment tab, and changing the program file name under "Starting program" to my new app.

But is there a way I could do this with some code that could be sent out and run on all these servers?

share|improve this question
    
Are these servers under Active Directory? –  Mark Henderson Mar 19 '12 at 21:30
    
About half of them are set up that way. –  Joe M Mar 19 '12 at 21:35
1  
Does it really have to support Windows 2000 as well? I'm fairly sure that that sort of scripting in 2000 was nigh on impossible for local users... –  Mark Henderson Mar 19 '12 at 21:41
    
Haha, yes, it does. I am maintaining an ancient code base on these servers as well. –  Joe M Mar 19 '12 at 21:56
1  
I'm so sorry for you... Supporting Windows 2000... –  Mark Henderson Mar 19 '12 at 22:02

2 Answers 2

up vote 3 down vote accepted

If these servers are in an Active Directory, and you're only concerned about remote logins (not console logins) you can do this via Group Policy, under:

User Configuration\Policies\Administrative Templates\Windows Components\Remote Desktop Services\Remote Desktop Session Host\Remote Session Environment

enter image description here

Set that up as you please, then apply that group policy against your conditions (OU and Server, Group and Server, etc)


To do this via vbscript:

Set objUser = GetObject("WinNT://localhost/Administrator, user")
objUser.TerminalServicesInitialProgram = "TestProg"
objUser.TerminalServicesWorkDirectory = "C:\"
objUser.SetInfo

(where Administrator, user is where you define your user/group settings). I don't know how well that works on Windows 2000 though. I suspect it won't.

share|improve this answer
    
Most of the logins will be local. –  Joe M Mar 19 '12 at 21:38
1  
@JoeMajsterski - see my update –  Mark Henderson Mar 19 '12 at 21:49
    
Thanks for that. I'll play around with it and see what happens. –  Joe M Mar 19 '12 at 21:56
    
Well, this isn't working on my 2000 test server, but it worked perfectly on my 2003 server with this for the first line: Set objUser = GetObject("WinNT://localhost/sysadmin") I'm still looking into options for the 2000 server. It gave me error 80070035: The network path was not found. –  Joe M Mar 19 '12 at 22:41
    
You might be out of luck for Windows 2000 I'm afraid. It was 12 years ago... –  Mark Henderson Mar 19 '12 at 23:26

I finally found a way to do this in Windows 2000. It was a multi-step process. First, I wrote this script to run at logon:

Set WshNetwork = WScript.CreateObject("WScript.Network")
If WshNetwork.UserName = "sysadmin" Then
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    strLockFile = "C:\logonlock.txt"
    If objFSO.FileExists(strLockFile) Then
        If Now - objFSO.GetFile(strLockFile).DateLastModified < 0.0001 Then 'New file, means was double start, don't run
            objFSO.DeleteFile(strLockFile)
            objFSO.CreateTextFile(strLockFile)
            Set objFSO = Nothing
            WScript.Quit
        End If
    End If
    'File either doesn't exist, or is old, DO run
    If objFSO.FileExists(strLockFile) Then
        objFSO.DeleteFile(strLockFile)
    End If
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
    errResult = objWMIService.Create("C:\loginshell.exe", "C:\", null, intPosID)    
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colProcesses = objWMIService.ExecNotificationQuery ("Select * From __InstanceDeletionEvent " & "Within 1 Where TargetInstance ISA 'Win32_Process'")
    Do Until False = True
        Set objProcess = colProcesses.NextEvent
        If objProcess.TargetInstance.ProcessID = intPosID Then
            objFSO.CreateTextFile(strLockFile)
            Set WshShell = WScript.CreateObject("WScript.Shell")
            WshShell.Run "%COMSPEC% /c ""C:\Program Files\Resource Kit\logoff.exe"" /n /f", 0, False
            Exit Do
        End If
    Loop
Else
    Set WshNetwork = Nothing
End If

Windows 2000 doesn't come with a logoff executable, but there is a Resource Kit download for 2000 that includes it, and it appears that all our 2000 servers have it. I had to include this logonlock file code because there is an issue with the group policy, where it enacts a loopback action, causing the script to run twice. It is possible to turn that off, but because we're not 100% if any of the servers may need it, we left it on and just came up with a workaround.

Next, I needed to write a script to add this to the local group policy logon scripts. A few snippets of code for this:

Set oShell = CreateObject("Wscript.Shell") 
strScriptFile = oShell.ExpandEnvironmentStrings("%SYSTEMROOT%") & "\system32\GroupPolicy\User\Scripts\scripts.ini"

That scripts.ini file is where the vbs file is added in order to be called at logon. It will look something like this:

[Logon]
0CmdLine=C:\MyScript.vbs
0Parameters=

I had to write code to add my script to that file. I'll leave the details as an exercise for the reader. :)

Finally, I had to modify the file I found thus:

strGptFile = oShell.ExpandEnvironmentStrings("%SYSTEMROOT%") & "\system32\GroupPolicy\gpt.ini"

gpt.ini has a few lines that must be modified to make the logon script listed above actually run. Here's what it looks like initially:

[General]
gPCFunctionalityVersion=0
gPCMachineExtensionNames=
Version=0
gPCUserExtensionNames= 

The version numbers could be nonzero, and there could already be IDs on the names lines. The last two lines are the ones I had to modify for my logon script. First, the version value has to be incremented by 65536 whenever the gpt.ini file is updated. Second, you must add the following two IDs to the gPCUserExtensionNames= line:

{42B5FAAE-6536-11D2-AE5A-0000F87571E3} {40B66650-4972-11D1-A7CA-0000F87571E3}

It will end up looking something like this:

gPCFunctionalityVersion=0
gPCMachineExtensionNames=
Version=65536
gPCUserExtensionNames=[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}]

Don't forget to include the square brackets, and the Version value has to be incremented every time. Something else I discovered much later on was that sometimes the last line is not in the file at all, and must be added from scratch.

So, it took a ton of playing around, but I was able to programmatically install a logon script. I hope someone else can benefit from this monstrosity someday.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.