Monday, 12 July 2010

Simple Database Source Control

Got into a pickle the other day because of a stored procedure that was changed but as a result messed a few things up. Had backups so I could retrieve the data , but what if I didn’t??? This got me thinking to a way to store down all the changes I make on database procedures so I could revert should something go horribly wrong. So without further a do….
First off we need a database and a table to hold the list of changes.

CREATE DATABASE SQLSourceSafe
GO

USE SQLSourceSafe
GO

CREATE TABLE dbo.ProcedureChanges
(
    [ID] uniqueidentifier NOT NULL ROWGUIDCOL,
    [Server] VARCHAR(64),
    IP_Address VARCHAR(32),
    [Database] NVARCHAR(255),
    [Schema] NVARCHAR(255),
    [Object] NVARCHAR(255),
    [Date] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    [Type] NVARCHAR(64),
    ProcName NVARCHAR(255),
    SourceCode NVARCHAR(MAX),
    SourceCodeXML XML,
    UserName    NVARCHAR(255)
)

ALTER TABLE dbo.ProcedureChanges ADD CONSTRAINT ProcedureChanges_ID DEFAULT (newid()) FOR ID

ALTER TABLE dbo.ProcedureChanges ADD CONSTRAINT ProcedureChanges_PK_ID PRIMARY KEY CLUSTERED ( ID )
 WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

So now we have our table we can get a current list of all the procedures in the databases that we want to start auditing. We can easily do this by looking in the sys.procedures table, this holds all the data on the current procedures in the database. So from YOUR database, run the following code.

INSERT INTO SQLSourceSafe.dbo.ProcedureChanges
( [Type],[SourceCode],[Database],[Schema],[Object],[UserName] )
SELECT 'CREATE_PROCEDURE', OBJECT_DEFINITION([object_id]), DB_NAME(), OBJECT_SCHEMA_NAME([object_id]), OBJECT_NAME([object_id]), 'Stewart Millward'
FROM sys.procedures

Notice I use the actual procedure and schema names? I prefer to be able to see the names of the procuedures rather than run around trying to find them. Anywho that’s all the information on the current look of the database now it’s time to record the changes made to the database from now on, for this we chall use a trigger on the events we know change a procedure and then just shove similar code to above in there.

CREATE TRIGGER SourceSafe_ProcedureTrigger
ON DATABASE FOR CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE, ALTER_SCHEMA, RENAME
AS
BEGIN
SET NOCOUNT ON
DECLARE @EventData XML = EVENTDATA()
DECLARE @ip VARCHAR(32) = (SELECT client_net_address FROM sys.dm_exec_connections WHERE session_id = @@SPID)

INSERT INTO SQLSourceSafe.dbo.ProcedureChanges
( [Type], [SourceCode], [SourceCodeXML], [Database], [Schema], [Object], [Server], [IP_Address], [ProcName], [UserName] )
SELECT @EventData.value('(/EVENT_INSTANCE/EventType)[1]',   'NVARCHAR(100)'), 
@EventData.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'NVARCHAR(MAX)'),
@EventData,
DB_NAME(),
@EventData.value('(/EVENT_INSTANCE/SchemaName)[1]',  'NVARCHAR(255)'), 
@EventData.value('(/EVENT_INSTANCE/ObjectName)[1]',  'NVARCHAR(255)'),
HOST_NAME(),
@ip,
PROGRAM_NAME(),
SUSER_SNAME()
END
GO

And that’s that it will start logging the changes in the database for you and you can then always go back should a mistake be made… huzzar!
Just some notes, RENAME is a 2008 event only so you may get an error on a 2005 machine, also if you want to disable the trigger you can use the following code.

DISABLE TRIGGER [SourceSafe_ProcedureTrigger] ON DATABASE

That’s That.

Sunday, 11 July 2010

LSASS.exe error and bye bye domain?

Had the following error pop up the other day on a customers domain, it stop the server and clients from logging onto the machine

lsass.exe - System Error : Security Accounts Manager initialization failed because of the following error: Directory Service cannot start. Error Status: 0xc00002e1. Please click OK to shutdown this system and reboot into Directory Services Restore Mode, check the event log for more detailed information.

Directory Services Restore Mode??? I though this must be pretty bad, and I was right.. the Active Directory database was corrupt, I thought OK I'll get them to restore the system state from last nights backup.... They don't do backups, after a few harsh words with them I knew I'd have to do it the hard way.  I have actually done this before a few years back with 2000 Server but this is 2008, luckily the same procedure but it took me a while to remember what i needed to do so here's the general jist for future reference.

On startup press F8 and enter the system via the "Active Directory Restore" option.


When asked for the Username and password enter "Administrator" and the Active Directory Restore Password, this should be listed in the password file and would have been set up when the domain controller was first promoted.

Step 1
  • Once the system has booted, go to start -> Run and type "cmd" to go to the command prompt
  • In the Command Prompt type "ntdsutil.exe" and press enter to go into the Active Directory Restore program.
  • Type "Files" and press enter then type "Info" and press enter this will give you the current location of the NTDS Datastore and should read something like "C:\Windows\NTDS\"
  • On the file list given make sure that the following files are present
  • NTDS.dit, DSADATA.bak, res2.log res1.log, and edb.log
  • Find the file edb.chk under the file path given and rename it to edb.old reboot the machine and see if it boots, if not go to step 2
Step 2
  • Boot back into Active Directory Restore mode (as above) and open up another command prompt window (Start->Run->cmd)
  • Type the following command to repair any corrupted database files
  • ESENTUTL /g \ntds\NTDS.dit /!10240 /8 /v /x /o Exchange the for whatever the NTDS folder was displayed as previously, e.g. ESENTUTL /g C:\windows\ntds\NTDS.dit /!10240 /8 /v /x /o
  • If you recieve a "jet_error" or a "database corrupt" error then go back into the NTDSUtil program to repair it as follow
  • From the command prompt type
    • NTDSUtil
    • Type "Files" and press enter
    • Type "recover" and press enter
  • This will repair and damaged files in the Active Directory, after this type "Quit" and press enter then "Quit" and press enter again.
  • Use the ESENTUTL again to attempt to repair the database again e.g.
    ESENTUTL /g \ntds\NTDS.dit /!10240 /8 /v /x /o
  • If you still recieve an error goto Step 3 otherwise reboot and try again.
Step 3
  • Move all of the .log files from the NTDS folder to a seperate folder (you can delete this later if it works)
  • Go to the command prompt and enter the NTDSUtil again
    • Type "Files" and press Enter
    • Type "integrity" and press Enter
  • This will attempt to repair the database without any of the previous transactions stored in the log files (it's probably whatever is in the log file is corrupting the database)
  • Type "Quit" and press enter
  • Type "Semantic Database Analysis" and press enter
  • Type "Go" and press enter, this will give a quick check of the files again
  • If errors still occur at this stage then type "Go Fix" and press enter
  • Type "Go" and press enter again, this should now have no errors
  • Reboot the system and it should now work.
If you ever have to go through this process then you really need to double think your backup procedures.

Thursday, 1 July 2010

Connection Details

ohhh look you can retrieve connection details using the sys.dm_exec_connections table linked to the connected users session ID @@SPID :)

SELECT * FROM sys.dm_exec_connections WHERE session_id = @@SPID