Concepts:
There is a policy running on the system. There may be one or more databases in .sdb files which are files representing a possible policy that could be run. These are stored in c:\windows\security\database\. One may “export” a policy out to a configuration .ini file (the docs for secedit say .inf, but it is clearly the venerable .ini format), which policy comes either from a database .sdb file, or from the current running system policy (if no policy is specified when running secedit.exe on the command line). One may edit this configuration .ini file (the docs ambiguously call it a “security template” as well, but the command line options all say “cfg”). You then create a new security database .sdb file with the “import” syntax. Contrary to a lot of stuff on the Web, you don’t need to put it into some particular magic database (but see below for path gotchas) like the original secedit.sdb; put it in a new one. Once you have a new, valid, legit database .sdb file, you only then use “configure” to apply the database file to the current system.
Lots of gotchas here.
Sometimes when secedit.exe fails, it is silent, like a good UNIX program, but it will return an %ERRORLEVEL% so check that or you will be bamboozled. It is noisy when it succeeds and sometimes even noisier when it fails (except when it’s silent).
Secedit silently failed in many confusing ways if either the security database .sdb or the configuration .ini was located on my z: drive, which in this case was a VMware shared folder on a Mac OS X system. Move stuff to a C: temp dir, then clean up afterwards, because hey, writing xcopy lines in batch files is fun.
The configuration .ini files are in full on, utf-16 format. Two fucking bytes per character. Nice.
If you try to create a brand-new configuration .ini file without reference to anything, you do not get a listing of the default settings, but rather an unhelpful, nearly-empty file that informs you that Description=Default Security Settings. (Windows Server).
If you try to look up the values for the various sections, you just plain can’t get them anywhere. If you go to this horrible javascript monstrosity of a reference site and click Technical Reference (for Windows Server Group Policy), you can get a giagantic, unstructured spreadsheet that has relatively lengthy (but non-technical) prose about the various settings. But it won’t tell you which sections they go under in the .ini file, nor the requirements for each field, some of which are registry settings and some of which are not. If you want to see something that was apparently done as a class project by a charity course taught for retarded non-native English speaking remedial computer science students by the generous and distinguished engineers of Microsoft (who are clearly working on better and more interesting problems than, oh, say, making sure the OS’s core security API is sensical and internally consistent), you can look at this horrifying jumble of shittiness, which can’t search for shit but mollifies you with funny Engrish when it fails (I am not kidding: “We probably hit search limit. Try to redefine your search string.”) and as a bonus demonstrates the sloth of Azure serving AJAX (because, you know, actually putting the documents into an html page where anyone’s browser “find” function could speedily search for it would lack the pedagogical value to the retard-children-programmers).
You can maybe stay sane if you learn that the registry values are prepended by an integer and a comma, where that int seems to specify the data type of the reg value (4=integer, 7=text, 1=some other kind of text).
Specifically in the [Event Audit] section, there are values that are not registry values. They are ints that appear to be bitmask math fanciness. (Remember setting options on visual basic windows back in the ’90s, where you got to add up powers of 2? ). It so happens that they all have two bits, the first one being “log successes” and the second being “log failures.” So 0 is neither, 1 is successes, 2 is failures, 3 is both. But this isn’t, as far as I can tell, anywhere on MSFT’s site and it’s sure as fuck not in the giant unstructured spreadsheet reference.
Much of the configuration .ini file can be omitted (so you can just overlay the parts you want). But you MUST include the [Version] and [Unicode] sections or it will barf. Use secedit /validate to check it. However, “validate” does not mean that it will actually round-trip and work right; it doesn’t check the security identifiers in the [Privilege Rights] section so it’s quite possible to have a valid cock-up (see round-trip gotcha below).
Biggest one: secedit CANNOT ROUND-TRIP. The security policy “export” may will (and does for me) produce an output with entries in the [Privilege Rights] section that refer to “Classic .NET AppPool” among others. If you try to import and configure with this, you’ll get “No mapping between account names and security IDs was done” in the error log. Turns out you have to manually fix this by adding “IIS AppPool\” before the names of these AppPool entities. (Hat tip) If you want to actually find out whether that, or some other hackery, fixes it to something that can be mapped to an SID, find yourself the PSTools download and test the name with PSGetSID.exe. Awesome.
The “configure” option only really needs a .sdb database specified by /db. If you give it an additional /cfg parameter, it will muddy up the .sdb with the contents of the specified config ini. There is no benefit to using this, ever, other than skipping a step that could result in you keeping a sanity-preserving intermediate state backup.
The “overwrite” option doesn’t do what you think it does. Especially with “configure.” Just don’t use it, unless you are planning on destroying what is in your .sdb file(s). The .ini configuration already wins in a tie.
The “configure” option is NOT ATOMIC, and it will happily set your system’s security policy partially to be what was in the file you indicated, and partially not (for example, with the broken round-tripping of IIS AppPool names). There’s no way to find out whether or not the configuration will succeed, except to “suck it and see.” And once it does partially, non-atomically make a goulash out of the then-current and database-specified settings, there’s no way to tell what succeeded or failed, except by reading the log, which is formatted in an unparseable mess. Fantastic.