Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using VBScript to refresh group policy, restart, and log in.

288 views
Skip to first unread message

Centrist

unread,
Jun 14, 2007, 11:14:29 PM6/14/07
to
I am writing a script that needs to apply the domain's group policy,
restart, and automatically log the administrator back in without
needing any user interaction. The problem is that I cannot get rid of
the legal message. This is the popup that appears after you press CTL-
ALT-DEL on a Win2k or WinXP machine which has a message set in the
group policy. In my case, the message is set in a domain GPO.

My first solution was to delete the legalnoticetext and
legalnoticecaption registry values in HKLM. This is a very common
example on the internet. However, (like many of these examples) this
doesn't work because the group policy will just be applied again when
the computer is restarting.

My second solution was to make use of the NoMachinePolicy DWORD value
located in:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions
\{827D319E-6EAC-11D2-A4EA-00C04F79F83A}

When NoMachinePolicy is set to 1, it prevents the security policy from
being applied. I had the script set the value to 1 just before
rebooting, and then change the value back after logging in. This
solution also has problems, and I can't use it. In Windows XP, it
appears to reverse the changes made by the gpupdate /force command. I
am executing gpupdate /force, setting the auto logon registry entries,
setting NoMachinePolicy to 1, clearing the legal message text and
caption, and then restarting. But here's the problem: when the group
policy is applied, the administrator account is renamed to something
else. However, after I restart the account's name goes back to
administrator. My auto login fails because I have the wrong account
name for DefaultUserName. And I have verified that after the gpupdate
command is run, the account name does change just before the gpupdate
finishes. I have no idea why this is happening.

The second reason I don't like using this is because I cannot leave
NoMachinePolicy set to 1 the whole time the script is working. The
script installs several packages after restarting which need to be
able to apply group policy. And if I do not have it set the whole
time, the computer will not be able to automatically boot up and login
if one of the package installations forces a restart.


So I'm looking for a working solution that will let me bypass the
legal message for an automated logon. This is the only problem
stopping me from being able to use this script, and I would really
appreciate some help here.

Centrist

unread,
Jun 20, 2007, 12:03:45 AM6/20/07
to
Anyone?


The right way to do automated restarts can't be such a mystery.

Centrist

unread,
Jul 8, 2007, 6:40:07 PM7/8/07
to
I've found a way to make this work, and I'll explain it here for the
benefit of others (something which people here may not understand).

When the legalnoticetext and legalnoticecaption registry values have
been removed, the logon message does not appear after pressing CTL-ALT-
DEL at the login prompt. To prevent the group policy refreshes from
adding these keys back after you've deleted them, you can change the
ACL for the system key which contains these values to deny the Set
Value permission to the System account.

Unfortunately, this is very hard to do with vbscript - if not
completely impossible. So I've written a C++ program that will change
the ACL when run, and it will also remove the changes when run with a -
u argument. The source code is included at the end of this post, and
compiles fine with Dev-C++.

For my purposes, I need to write my own program rather than use
something already available (though I doubt there is anything already
out there). A benefit of using a single-purpose program is that you
can get a very small compiled executable. With Dev-C++, I got a size
of 10KB by removing the output code - which is small enough for me to
include the executable in my script.

I make no guarantees as to the safety of running this program. I
posted it on a programming board, but no one thought it was worthy of
comment.

For the time being, you can get the well-formatted version here:
http://docs.google.com/View?docid=ddmjgfnj_4d7rnzz

Here's the source:

#include <cstdlib>
#include <iostream>
#include <windows.h>
#include <aclapi.h>

using namespace std;

void Output(char errorMessage[100]);
int ChangeSysKeyPermissions(BOOL denySystem, HKEY &SysKey);
int DeleteLegalNoticeValues(HKEY &SysKey);

const DWORD REGERROR_NOTFOUND = 2;
const LPCTSTR SysKeyPath = "software\\microsoft\\windows\
\currentversion\\policies\\system";

int main(int argc, char *argv[])
{
HKEY SysKey;

// CHECK ARGS TO DETERMINE ACTION TO TAKE.
BOOL denySystem = true;
if(argc > 1 && strcmp(argv[1], "-u") == 0) denySystem = false;
//if(denySystem) Output("Ready to start."); else Output("Ready to
start. (undoing)");

// OPEN THE SYSTEM KEY.
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, SysKeyPath, 0, KEY_ALL_ACCESS,
&SysKey) != ERROR_SUCCESS)
{ Output("Could not open the system key."); return EXIT_FAILURE; }

if(denySystem)
{ // DELETE THE LEGAL NOTICE STRING VALUES.
if(DeleteLegalNoticeValues(SysKey) != 0) { Output("Could not open
the system key."); return EXIT_FAILURE; }
}

// MODIFY THE ACL TO DENY OR ALLOW SYSTEM THE SETVALUE RIGHT.
if(ChangeSysKeyPermissions(denySystem, SysKey) != 0)
{ Output("Failed to change the ACL."); return EXIT_FAILURE; }

// CLOSE THE SYSTEM KEY.
if(RegCloseKey(SysKey) != ERROR_SUCCESS) { Output("Could not close
the system key."); return EXIT_FAILURE; }

Output("All Done.");
return EXIT_SUCCESS;
}

void Output(char errorMessage[100])
{
cout << errorMessage << " " << GetLastError() << endl;
system("PAUSE");
}

int DeleteLegalNoticeValues(HKEY &SysKey)
{
// Delete the legal notice text and caption.
DWORD retval;
retval = RegDeleteValue(SysKey, "legalnoticecaption");
if(retval != ERROR_SUCCESS && retval != REGERROR_NOTFOUND)
{ Output("Could not delete caption."); return -1; }
retval = RegDeleteValue(SysKey, "legalnoticetext");
if(retval != ERROR_SUCCESS && retval != REGERROR_NOTFOUND)
{ Output("Could not delete text."); return -1; }
return 0;
}

int ChangeSysKeyPermissions(BOOL denySystem, HKEY &SysKey)
{
int result = -1;

// Get the security descriptor and DACL.
PACL OrigDacl = NULL;
PACL NewDacl = NULL;
PSECURITY_DESCRIPTOR SecDesc = NULL;
if(GetSecurityInfo(SysKey, SE_REGISTRY_KEY,
DACL_SECURITY_INFORMATION, NULL, NULL, &OrigDacl, NULL, &SecDesc) !=
ERROR_SUCCESS)
{ Output("Could not get security info."); goto cleanup; }

if(denySystem)
{
// Create an EXPLICIT_ACCESS structure for our ACE.
EXPLICIT_ACCESS Ace;
char AccountName[] = "System";
ZeroMemory(&Ace, sizeof(EXPLICIT_ACCESS));
Ace.grfAccessPermissions = KEY_SET_VALUE;
Ace.grfAccessMode = DENY_ACCESS;
Ace.grfInheritance = NO_INHERITANCE;
Ace.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
Ace.Trustee.ptstrName = AccountName;

// Create a new ACL and add our ACE to it.
if(SetEntriesInAcl(1, &Ace, OrigDacl, &NewDacl) != ERROR_SUCCESS)
{ Output("Could not add new ACE and Orig DACL."); goto cleanup; }
}
else
{
// Get the ACL's information.
ACL_SIZE_INFORMATION AclInfo;
if(!GetAclInformation(OrigDacl, &AclInfo,
sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
{ Output("Could not get the ACL information."); goto cleanup; }

// Make sure there are ACEs in our result.
if(AclInfo.AceCount < 1) { Output("Did not see any ACEs for the
system key."); goto cleanup; }

// Find and delete ACEs which deny access.
PVOID tempAce;
int AceTotal = AclInfo.AceCount;
for(int i = 0; i < AceTotal; i++)
{
// Get the ACE.
if(!GetAce(OrigDacl, i, &tempAce)) { Output("Could not get an ACE
from the Orig ACL."); goto cleanup; }

// Check to see if this ACE denies access.
if(((PACE_HEADER)tempAce)->AceType = ACCESS_DENIED_ACE_TYPE)
{
// Remove this ACE from the ACL.
if(DeleteAce(OrigDacl, i)) { AceTotal--; }
else { Output("Could not delete an ACE from the ACL."); goto
cleanup; }
}
}

// Set NewDacl to OrigDacl
NewDacl = OrigDacl;
}

// Change the key's ACL.
if(SetSecurityInfo(SysKey, SE_REGISTRY_KEY,
DACL_SECURITY_INFORMATION, NULL, NULL, NewDacl, NULL) !=
ERROR_SUCCESS)
{ Output("Could not change the key's ACL."); goto cleanup; }

result = 0; // If we got this far, it must be working!

cleanup: // These variables must have been defined before the first
goto cleanup.
if(SecDesc != NULL) LocalFree((HLOCAL)SecDesc);
if(NewDacl != NULL) LocalFree((HLOCAL)NewDacl);

return result;
}

Shenan Stanley

unread,
Jul 8, 2007, 6:50:41 PM7/8/07
to
Centrist wrote:
> I've found a way to make this work, and I'll explain it here for the
> benefit of others (something which people here may not understand).

While the first part is appreciated, the last part is just being an @$$.
Correct?

--
Shenan Stanley
MS-MVP
--
How To Ask Questions The Smart Way
http://www.catb.org/~esr/faqs/smart-questions.html


Centrist

unread,
Jul 8, 2007, 7:30:54 PM7/8/07
to
Yes, having come to the conclusion that posting here was a waste of
time, I am somewhat pissed off that no one could be bothered to reply.
I used to be a moderator for a scripting forum, and I spent a lot of
time answering peoples' questions and correcting code. I even answered
the stupid questions that I could have dismissed with an RTFM.

Now, having been in your situation, I naturally followed every point
your link makes about asking questions. And given that this question
comes up frequently, I would expect some of the regulars here to be
able to offer some advice - even if all you had to say was that you
doubted it was possible. But instead I get no replies at all. Why
would you expect any other kind of response from me?

Shenan Stanley

unread,
Jul 8, 2007, 8:31:32 PM7/8/07
to
Centrist wrote:
> I've found a way to make this work, and I'll explain it here for
> the benefit of others (something which people here may not
> understand).

Shenan Stanley wrote:
> While the first part is appreciated, the last part is just being an
> @$$. Correct?

I wouldn't - I don't expect anything from *you* in particular, I do not know
you.
It's not my standards you have to live by, it's your own.

http://groups.google.com/group/microsoft.public.scripting.vbscript/browse_thread/thread/d66936c4d07b00e4/759ecc0da9fca823?lnk=st&q=&rnum=5#759ecc0da9fca823

I see you got a response in another group...
http://groups.google.com/group/microsoft.public.windowsxp.general/browse_thread/thread/23fe3afc81e72c29/bec422ca7f85e32e?lnk=st&q=&rnum=1#bec422ca7f85e32e

Although not much actual help. Sometimes - the volunteers just do not
answer.
They are, after all, volunteers. You get what you pay for.

0 new messages