Ryan Adams Blog

SQL, Active Directory, Scripting

Browsing Posts in SQL Server

The North Texas SQL Server User Group currently has an open position on their board of directors.  I am eager to serve the SQL community and very excited to have the opportunity to run in this election.  If you follow my blog I need your support.  Below is a little information on my involvement in the SQL community, why I want to be on the BoD, and most importantly how you can vote for me!

Community Involvement

I have been an active NTSSUG participant for about 2.5 years.  I was a core team member for SQLSaturday 35 and handled the coordination of benefits for our sponsors after Jennifer McCown (Blog|Twitter) brought them on board.  I also organized all of the volunteers for the day of the event.  I post all of our meetings on communitymegaphone.com so they get listed in the MSDN newsletter.  I have also created and maintain a LinkedIn group for NTSSUG and post our meetings on the DFWITProfessionals.com website to help increase our exposure and expand our group.  In addition, I actively blog and participate with the online community through Twitter, Facebook, and LinkedIn.  Most recently I am serving on the core team for SQLSaturday BI Edition, and I am also serving on the organizing committee for SQLSaturday Houston.  As a follow-up to SQL Saturday 35 I setup Confio to be our sponsor for the month of August.  Lastly as another follow-up to my involvement with SQL Saturday 35 I secured a very special speaker for our January meeting.  I can tell you that you will not want to miss this meeting so clear your calendar now.  For more hints of what’s coming see Tim Mitchell’s (Blog|Twitter) blog post HERE.  If you are interested in my professional background you can view my BIO on my About Me page.

Why

I would be honored to be on the NTSSUG board.  This group has helped me and my career in many ways from meeting professional contacts to top notch technical training.  I want to give back to the group by being instrumental in providing others all the things this group has afforded me.  I am a firm believer in the SQL community where there is no comparison for professionalism, a network of people willing to lend a hand, and a comradeship that cannot be matched.  I believe I would be a great board member as I am highly motivated, extremely organized, and very passionate about the SQL community.  I want to search out opportunities and ways to grow our group into a premier chapter of SQLPass.

How to Vote

We’ve had some issues with our mailing list lately so here is the email with instructions on how you can vote.

Dear Members,

Thank you all for participating in this important process to elect another Member to the North Texas SQL Server User Group Board.

If you are hearing about this election for the first time, information on this special election can be found here.

http://northtexas.sqlpass.org/NTSSUGBoardVacancy/tabid/3031/Default.aspx

Voting Procedures

1.      You must be a North Texas SQL Server User Group Member, else your vote will be invalidated.  Click on the link below to join the North Texas SQL Server User Group distribution list which will automatically make you a member.

http://northtexas.sqlpass.org/DistributionList/tabid/364/Default.aspx

2.     Only 1 vote per member.

3.     Send email to vote@ntssug.com with the last name of the candidate of your choice in the subject line.

The North Texas SQL Server User Group is trying out a new format for the August 19th, 2010 meeting.  The first part of the meeting will be a presentation from Janis Griffin of Confio software.  She will be presenting, “Tuna Helper – Proven Process for Tuning SQL.”  The second half of the meeting is the new part.  We will be breaking up into small discussion groups to talk about various topics.  Each group will have a moderator to help facilitate the discussion.  I think this is a really great idea and I hope it works well.  My hat is off to the NTSSUG board of directors for this idea!  NTSSUG is a very large group and we all know how powerful and beneficial networking with other professionals can be, but networking in a large group can also be a challenge.  The NTSSUG board was very forward thinking in recognizing this challenge and trying something new to help the situation.  I really think this idea will help those who are not so outgoing get to know others in the group in a smaller and less intimidating setting.  SQL server has many different facets (PBM pun intended) and most professionals seem to specialize or gravitate toward a select few of those facets.  I believe this format will help connect like-minded individuals to each other, but still maintain the broad scope of interests with the standard main presentation.  I am hopeful that this will create strong bonds by connecting members to each other and connecting members to the SQL community.  May the connections spread like wild fire and our plates overrun with bacon!

As a side note I will be moderating the discussion on, “How do I get a job as <job title> without experience?”  Here is the list of topics:

  • How do you keep current with a training budget of zero?
  • How do I get a job as <job title> without experience?
  • Using blog, Twitter, and Facebook for professional networking and career improvement.
  • What benefits do you get from being part of a user group, and how could NTSSUG be a better resource for your professional development?

Also a new position has opened up on the NTSSUG board of directors and the candidates will each have a short speech during the meeting.  If you are interested in joining this awesome leadership then check out the NTSSUG website for more details, HERE.  As you can see this is a meeting you will not want to miss.  Here is what some others have posted.

Jennifer McCown (MidnightDBA)

Tim Mitchell

Lately the organizer team for SQLSaturday #35 in Dallas has had several requests from other SQLSaturday organizers about how to get sponsors and handle the sponsorships.  For us Jen McCown (Blog|Twitter) did an unbelievable job of finding sponsors and getting them involved in sponsoring the event.  In fact, she did such a wonderful job that it quickly became overwhelming and more than one person could handle.  That’s where I came in to help, but before you finish reading this post you need to read her blog on how she found the sponsors, contacted them, and defined the sponsorship levels. READ HERE.

My part was to handle the coordination of benefits with each of our sponsors to ensure they each got what their sponsorship level entitled them to.  Fortunately for me I am a very organized person, which was a benefit to me.  You have to be organized and able to communicate well.  You have to think ahead about all the small things you need to ask them in addition to their benefits.  Things like how many people are they sending, do any of them require a vegetarian lunch (we provided lunch for all sponsors and volunteers), do they require power, and how many items are they wanting to raffle.  You also need to make a list of things they simply need to be informed about like how big the table sizes are, as they might be bringing a table cloth.  Clear communication is paramount.  I sent each sponsor an email with a bulleted list of their benefits and the status of each item.  I also included a seperate list for the questions we needed answered that did not pertain to the sponsor benefits, and finally an ending paragraph of the informational things we wanted them to be aware of.  Getting everything possible in a single easy to read format avoids sending tons of emails about every little thing as you think of it.  This will save you time (which you will need), and help prevent you from annoying the sponsor with tons of email.  Remember you not only want them to sponsor this event, but also events in the future.  Make it easy for them and yourself by only including action items in follow up emails, and be as accomodating as you can while being strict with the rules of what their sponsorship level allows.  Sometimes this means doing some of the leg work yourself like picking up flyers for event bags, having them send stuff to you for their table and making sure it is ready for them that morning, and mailing back anything they have left over after the event.

The other thing you absolutely need is a good spreadsheat to track progress with each sponsor.  Make sure to include each benefit for their level, the answers to your questions not specific to their sponsorship, and the items they need to be informed about so nothing gets through the cracks.  You have to use your best judgement on the frequency of follow up emails concerning outstanding action items.  You don’t want to be that obsessive and pesky guy.  Do you really need to follow up with them every week when the event is three months away? No.  Three to four weeks on the other hand, you probably need to if those items are regarding them getting things mailed to you.

The bottom line is that you need to be organized and communicate clearly.  Make sure you thank them in your communications, and certainly be sure to thank them in person at the event.  Again you want them to sponsor future SQLSaturdays, so make sure they know how much you value their sponsorship.  Remember that sponsorships are great targeted business for the sponsors and great for our community!

Every so often I get a call from a user saying he is trying to access some reports I wrote for him in SSRS 2005 and he gets the following error:

Cannot find or load System.EnterpriseServices.dll version=2.0.0

I’m not a .NET expert so the first thing I do is Boogle it.  You will get a ton of hits on this error, but none of them talk about the solution or cause I found.  Most of them tell you to copy c:\windows\microsoft.net\framework\v2.0subversion\system.enterpriseservices.dll to c:\windows\assembly.  All this does is register the missing DLL and put it back into the GAC (Global Assembly Cache).  The good news is that this method can save you from having to re-install the .Net Framework.  If you find that you do need to re-install, then I would suggest to first try re-applying the latest .Net Framework service pack first.

Although this may fix the issue, it did not explain why it kept happening on this system and at no defined interval.  What I finally figured out is that it happens every time Windows Update has downloaded a .NET Framework Service Pack and is ready to install it.  I still cannot explain how or why this would unregister the DDL from the GAC, but once I install the updates, Bingo!

How did I get here?  Most of my career has been spent with Windows administration, architecture, and design.  Several years ago I started to see the writing on the wall with Microsoft using SQL Server as the backend of all their new product lines.  I have a passion for technology and a pension for learning so I dove right into the SQL pool.  After a couple of SQL certifications and a Microsoft SQL Server Launch event, I discovered the North Texas SQL Server User Group.  I still have not found a community geared toward Active Directory and Windows architecture, so finding a group and community dedicated to my new passion; I knew right away this was my new home.  After all the friends and free monthly training, it was only natural that I wanted to jump in and help wherever I could when the group announced holding a Dallas SQL Saturday.

I volunteered and ended up organizing the volunteers and also coordinating with all of the sponsors.  Jen McCown (Blog|Twitter) of MidnightDBA started the sponsor process, but had too much on her plate with other SQL Saturday volunteer responsibilities, moving her family to a new home, and being a speaker.  I’m pretty sure she got all of two hours sleep the entire week of SQL Saturday Dallas.  Thanks Jen for everything you did, you are a true SQL Superstar!

I won’t even delve into all the pre-planning activities, but start with Thursday of that week.  We hold NTSSUG meetings at the Microsoft campus in Irving, TX on the third Thursday of every month.  Since I do not live or work nearby, I office out of one of my company’s other buildings on NTSSUG meeting days to avoid traffic.  That also means I start my day at about 5:30am.  The night before, I loaded my truck (both the bed and cab) with sponsor SWAG and material.  After my regular work day, I headed over to the Microsoft campus for our monthly NTSSUG meeting where Brad McGehee (Blog|Twitter) was speaking on PAL.  After the meeting we asked for volunteers to help us stuff the attendee bags and actually got it done in about an hour.  With my truck re-packed and even fuller than before, I managed to get home around 11pm.

I was up early again on Friday, but this time to be at the Dallas Stars annual warehouse sale.  My wife and I are huge fans and this event means we can actually afford some Stars gear.  Fast forward to 4pm I arrive at the venue to unload my truck and start preparing.  My first task was to make sure all the sponsor tables were setup, along with anything any of them sent me for their setups.  We had 18 sponsors including the facility and 11 of them had tables and 4 of them had lunch sessions.  After getting all of that setup and determining where the lunch sessions would be held it was now time to work on making sure I was prepared for organizing all of the volunteers.  Early in the week I realized there was no way the morning of the event that I could handle a volunteer orientation and the sponsors as they showed up.  I had Andy Eggers, one of the NTSSUG volunteers, help me out.  That night I walked him through the room and equipment setup, and how everything needed to run the following morning.  Thank you Andy, you saved my life!  After everything was setup we headed over to the speaker party for some awesome networking.

Saturday morning I arrived at the venue at 6:15am.  I am not a morning person and do not function well without sleep, and the late night/early morning patterns were starting to catch up to me.  Fortunately I have a little one at home and have had recent training in the art of little sleep, and I knew some coffee would fix me right up.  I am a very organized person and had everything printed up, check lists ready and a pen in hand.  The event was great, even though my volunteer duties prevented me from sitting in on the entirety of any of my desired sessions.  We provided breakfast for free, lunch at a low cost, free afternoon snacks, and even free ice cream!  Every session I attended was top notch.  We ended the day with sponsor give aways and various other SWAG that included top end SQL software, XBOX360, 1.5TB hard drives, iPOD shuffles, and an iPAD.  We can’t thank our sponsors enough for their support!  After some cleanup we headed out to the after party which was an incredible time of networking.

Did I mention we had a photographer?  Thanks go out to Emad Kamel and the link for pictures is HERE

This event was so great you should take the time to read what others are saying.  Here is a list of those that have blogged about SQL Saturday Dallas so far.

Bill Fellows (Blog|Twitterhttp://bit.ly/b7q7HC

Wes Brown (Blog|Twitterhttp://bit.ly/9orJXc

David Stein (Blog|Twitterhttp://bit.ly/aFb3Yw

AJ Mendo  (Blog|Twitterhttp://bit.ly/bPptxb

Jonathan Gardner (Blog|Twitterhttp://bit.ly/a9VQh0

Allen Kinsel (Blog|Twitterhttp://bit.ly/aJ3pkB

Jennifer McCown (Blog|Twitterhttp://bit.ly/9ihxAA

Stuart Ainsworth (Blog|Twitterhttp://bit.ly/daoEzE

Here is a list of the sponsors that helped make this such a great event.

I am very excited to be a part of the core planning committee for SQLSaturday 35 in Dallas on May 22nd, 2010.  The Dallas area is a technology hot spot and we have quite a local SQL community.  The North Texas SQL Server User Group averages 80 people every month.  If Sean McCown (Twitter|Blog)  is teaching a class before the meeting we rarely have under 100 people.  SQLSaturday is no exception, and current registrations put those numbers to shame.  This is our first time to hold a SQLSaturday in Dallas and planning an event this size is quite an under-taking.  I’m only handling two things and that is almost a full time job itself.  The planning committee has done quite a bang up job and this event will NOT disappoint.

There’s even a RUMOR that ice cream will be provided! I know what you are thinking, “Where do I signup?”  Well I’m sorry to tell you that you missed the bandwagon, but also excited to say that we are full and at capacity.  We have over 500 registrations with 50 people on the waitlist!  This is going to be one big event.

If you are already registered you can verify your registration and lunch paid status HERE.

I ran across something a couple years back and I just ran across this sweetness again.  I had a database populated by a VBScript that inventoried specific things on our servers with a web front end.  I wanted to make it easy for users to see if a server was still under warranty at a glance and not have to do the “datediff” in their head.  My table had a column that contained the warranty expiration date so I could have written this logic into the web page, but it would have to process it for every page load.  By doing this in SQL the computation only has to be done once.  The problem is that I wanted a string returned based on a date calculation and not just the result of some calculation on a column or two.  I discovered a cool way to do this was to write a user defined function because you can use UDFs in your computed column definitions.  Here is the UDF I created:

USE [MyDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create function [dbo].[udf_warrantystatusupdate]
(
 @expdate datetime
)
returns char(8)
as
begin
 declare @status char(8)
 set @status = case
  when @expdate > getdate() then ‘Active’
  when @expdate < getdate() then ‘Expired’
  else null
 end
return(@status)
end

Here is my column definition in my table:

[WarrantyStatus]  AS ([dbo].[udf_warrantystatusupdate]([warrantyexpdate]))

Awhile back I was tasked with designing and implementing a disaster recovery solution for one of our production application’s databases.  I decided to take a very simple approach for a couple of reasons.  I chose to simply create SQLAgent backup jobs on the production box that backup to a share on the DR box.  Why not use mirroring or log shipping? I took this route for the following reasons:

  1. We have very large pipes between our data centers, so keeping the data in small chunks with mirroring or log shipping is not necessary.  Also the DBs are small.
  2. This gives me point in time (full recovery model) backups in a remote location.  Another group handles server and application backups and the last time I needed a restore they “forgot” to setup the backups.
  3. Security over the wire is not an issue since our security team is like a cast iron chastity belt.  Seriously….we got bought 5 years ago and they still block traffic from the company that bought us even though that company has opened its firewalls to us.  Hey guys we are all the same company, let’s play nice.
  4. The required uptime for this application allows some leniency.  Besides, I can have the DBs restored long before the developer can change his code to point to the new location and DNS to replicate.

 

I’m a big believer in automation, because less is more.  I was also itching to write some VBScript, so I decided to script the restoration of the DBs.  This script makes some assumptions on how you design your backup job schedules so it will not work in every situation.  This script assumes that you take a full backup sometime in the AM and a differential sometime in the PM.  We are restoring these backups onto a different server than where the backups were taken.  This means we do not have local access to the SQL MSDB for backup information unless we remotely query the source server.  Since the backup files are local and SQL can’t tell us the difference between a full and differential backup (Please comment and correct me if you know a way) there is no need to query MSDB for any information anyway.  I bring this up because if we could query SQL to find the last full and differential backups, then it would not matter how we scheduled our backups and no assumptions would need to be made.   As far as I have ever known SQL only shows backups as one of two types, either a data file backup or a log file backup.  Since full and differentials are both data file backups there does not appear to be a way to differentiate between the two.  The last assumption is that you do not backup multiple databases in a single folder.  Things get messy if you do, so I suggest avoiding that as a general rule.   Here is where you can specify separate folders for each database while creating a maintenance plan within the “Backup Database Task”.

Backup Database Task

We start off declaring some variables and then initialize the ones that define the name of the DB we are restoring, the local drive letter where the backups are located, and the full path to the backup folder on that drive.  Now we create a connection to the local SQL server that will use the credentials under which the script is run.  We also create a connection to WMI and create a log file to record the name of each DB file that got restored.  Note that the log file will get overwritten every time the script is run.  You can change this to simply append, but make sure you also insert the date and time.  Alternately you could also build a log table and store it all in SQL.

Dim strComputer, strDrive, strPath, strDBName, colDBFilePath, colLogFilePath
Dim colDBName, strSQLRestore, colLogName, strSQLFixUser
strDBName = “MyRestoreDB”
‘This is the drive letter where your back files are located on the local machine
strDrive = “D:”
‘This is the path where your back files are located on the local machine
strPath = “\\MyBackupFolder\\” & strDBName & “\\” ‘WMI requires double backslashes in its path names
strComputer = “.”

‘=========================== SQL Connection =====================================================
Set objSQLConnection = CreateObject(“ADODB.Connection”)

objSQLConnection.Open _
    “Driver={SQL Server};Server=localhost;” & _
        “Trusted_Connection=No;database=master;”
‘================================================================================================

‘=========================== WMI Connection =====================================================
Set objWMIService = GetObject(“winmgmts:” _
    & “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2″)
‘================================================================================================   

‘=========================== Output Log Creation ================================================
Set objFSO = CreateObject(“Scripting.FileSystemObject”)
Set objTextFile = objFSO.CreateTextFile(“c:\Scripts\DBRestoreLog.txt”,True)
‘================================================================================================   

Now we need to get the file name and location where SQL tells us it is storing the DB, so we have that for the restore.  We’ll also need a list of all the backup “BAK” files in the backup directory to determine which full backup is the most recent and if there was a differential taken after it.  In order to do all that we query WMI for the list of files and store them in a recordset where we can sort them by their last modified date.  Since we know we do a full in the AM and a differential in the PM, we know if the last modified date of the most recent file is in the AM then all we have to restore is that full backup.  If the most recent backup file is in the PM then we know it was a differential and we have to restore the file before it since that will be the most recent full and then restore the differential.

‘=============================================================================================================================
‘FULL AND DIFFERENTIAL FILES
‘=============================================================================================================================

colDBFilePath = objSQLConnection.Execute(“Select filename from sys.sysaltfiles where dbid = db_id(‘” & strDBName & “‘) and fileid=’1′”)
colLogFilePath = objSQLConnection.Execute(“Select filename from sys.sysaltfiles where dbid = db_id(‘” & strDBName & “‘) and fileid=’2′”)
colDBName = objSQLConnection.Execute(“Select name from sys.sysaltfiles where dbid = db_id(‘” & strDBName & “‘) and fileid=’1′”)
colLogName = objSQLConnection.Execute(“Select name from sys.sysaltfiles where dbid = db_id(‘” & strDBName & “‘) and fileid=’2′”)

Set colFiles = objWMIService.execquery _
    (“Select * from CIM_DataFile where Path = ‘” & strPath & “‘” _
     & “And Drive = ‘” & strDrive & “‘ and Extension = ‘bak’”)

Set rsBackup = CreateObject(“ADODB.Recordset”)
rsBackup.Fields.Append “strFileName”, 200, 255
rsBackup.Fields.Append “strFileDate”, 7
rsBackup.Open

For Each objFile in colFiles
    rsBackup.AddNew
    rsBackup(“strFileName”) = objFile.Name
    rsBackup(“strFileDate”) = WMIDateStringToDate(objFile.lastmodified)
    rsBackup.Update
Next

rsBackup.Sort=”strfiledate”
rsBackup.MoveLast
If ucase(Right(rsBackup.Fields.Item(“strFileDate”),2)) = “AM” Then
 ’Restore Full
 objTextFile.WriteLine(rsBackup.Fields.Item(“strfilename”) & vbTab & rsBackup.Fields.Item(“strfiledate”) & VbCrLf)
 strStartDate = rsBackup.Fields.Item(“strfiledate”)
 strSQLRestore = “RESTORE DATABASE [" & strDBName & "] FROM  DISK = N’” & rsBackup.Fields.Item(“strfilename”) & _
 ”‘ WITH  FILE = 1,  MOVE N’” & colDBName(0) & “‘ TO N’” & colDBFilePath(0) & “‘,  MOVE N’” & colLogName(0) & “‘ TO N’” & colLogFilePath(0) & “‘,  NORECOVERY,  REPLACE”
 objSQLConnection.Execute(strSQLRestore)
Else
 ’Restore Full
 rsBackup.MovePrevious
 objTextFile.WriteLine(rsBackup.Fields.Item(“strfilename”) & vbTab & rsBackup.Fields.Item(“strfiledate”))
 strSQLRestore = “RESTORE DATABASE [" & strDBName & "] FROM  DISK = N’” & rsBackup.Fields.Item(“strfilename”) & _
 ”‘ WITH  FILE = 1,  MOVE N’” & colDBName(0) & “‘ TO N’” & colDBFilePath(0) & “‘,  MOVE N’” & colLogName(0) & “‘ TO N’” & colLogFilePath(0) & “‘,  NORECOVERY,  REPLACE”
 objSQLConnection.Execute(strSQLRestore)

 ’Restore Differential
 rsBackup.MoveNext
 objTextFile.Writeline(rsBackup.Fields.Item(“strfilename”) & vbTab & rsBackup.Fields.Item(“strfiledate”) & VbCrLf)
 strSQLRestore = “RESTORE DATABASE [" & strDBName & "] FROM  DISK = N’” & rsBackup.Fields.Item(“strfilename”) & _
 ”‘ WITH  FILE = 1,  MOVE N’” & colDBName(0) & “‘ TO N’” & colDBFilePath(0) & “‘,  MOVE N’” & colLogName(0) & “‘ TO N’” & colLogFilePath(0) & “‘,  NORECOVERY, REPLACE”
 objSQLConnection.Execute(strSQLRestore)
 strStartDate = rsBackup.Fields.Item(“strfiledate”)
End If

The last thing we need to do is find and restore all the transaction log files.  We use the same method of querying WMI for all the files in our backup folder that have an extension of “TRN”.  We then save them in a recordset so we can sort them by date.  In the previous section of code you’ll notice we stored the date of that last backup file we restored in a variable called “strStartDate”.  That allows us to compare it to the current transaction log date and skip restoring any log backups that were taken prior to the last full or differential backup we just restored.  As we iterate through the files in the recordset the other condition we have to check for is whether or not it is the last record in the set.  We do this because we have to specify “norecovery” in our TSQL restore command until we restore the last log file. At that point we remove ”norecovery” from our TSQL restore command (or you can change it to “recovery”, which is the default) so SQL can rollback any uncommitted transactions and make the DB available again.

‘=============================================================================================================================
‘TRANSACTION FILES
‘=============================================================================================================================

Set colFiles = objWMIService.ExecQuery _
 (“Select * from CIM_DataFile where Path = ‘” & strPath & “‘” _
  & “And Drive = ‘” & strDrive & “‘ and Extension = ‘trn’”)

Set rsTran = CreateObject(“ADODB.Recordset”)
rsTran.Fields.Append “strFileName”, 200, 255
rsTran.Fields.Append “strFileDate”, 7
rsTran.Open

For Each objFile in colFiles
    rsTran.AddNew
    rsTran(“strFileName”) = objFile.Name
    rsTran(“strFileDate”) = WMIDateStringToDate(objFile.lastmodified)
    rsTran.Update
Next

rsTran.Sort=”strfiledate”
rsTran.MoveFirst
Do Until rsTran.EOF
 If rsTran.Fields.Item(“strfiledate”) < strStartDate Then
  rsTran.MoveNext
 Else
  objTextFile.WriteLine(rsTran.Fields.Item(“strfilename”) & vbTab & rsTran.Fields.Item(“strfiledate”))
  If rsTran.AbsolutePosition <> rsTran.RecordCount Then
   strSQLRestore = “RESTORE LOG [" & strDBName & "] FROM  DISK = N’” & rsTran.Fields.Item(“strfilename”) & _
   ”‘ WITH  FILE = 1,  NORECOVERY”
   objSQLConnection.Execute(strSQLRestore)
  Else
   strSQLRestore = “RESTORE LOG [" & strDBName & "] FROM  DISK = N’” & rsTran.Fields.Item(“strfilename”) & _
   ”‘ WITH  FILE = 1″
   objSQLConnection.Execute(strSQLRestore)
  End If
  rsTran.MoveNext
 End If
Loop

This last piece of the script just closes the text file we opened to log our actions and includes a function that converts the WMI date format to something more familiar.  For more details on the WMI date conversion function, visit this article in the Microsoft Script Center that was written by the ScriptingGuys.  Now we have successfully restored our database on our DR server and hopefully the crisis is averted.  Of course now you have to go fix the production system…..Good luck!

objTextFile.Close

Function WMIDateStringToDate(dtmInstallDate)
    WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) & “/” & _
        Mid(dtmInstallDate, 7, 2) & “/” & Left(dtmInstallDate, 4) _
            & ” ” & Mid (dtmInstallDate, 9, 2) & “:” & _
                Mid(dtmInstallDate, 11, 2) & “:” & Mid(dtmInstallDate, _
                    13, 2))
End Function

I discovered this little catch back when SQL 2005 released, but it took me awhile to notice it was not working.  One of the cool new things in the 2005 release was database mail.  Finally we didn’t have to setup mail profiles and install Outlook, which meant additional patching for Microsoft Office and possible reboots.  We also no longer had to use an extended stored procedure to send email alerts from the database.

The group I worked in used Microsoft Operations Manager to monitor our environment, which included much more than just our SQL servers.  One day I got an alert from MOM that one of my SQLAgent jobs failed on a job step.  However, I never got an email alert from SQL server that the job had failed.  I had already setup database mail and had even run my code in SSMS, which ran fine and sent email via msdb.dbo.sp_send_dbmail.  In fact, I had even recently received an email from that job and verified that kicking off the job manually resulted in success.  So I started wondering what could be the problem since I knew database mail was working and verified it both by executing code in SSMS and via SQLAgent job.  I also started wondering why I had not noticed this before when it dawned on me that my jobs were set to only send email in the event of a failure.  Well, I would like to think it was skill and not luck that I had not had any job failures up until then.  I’m glad we were using MOM or who knows when I would have noticed the job failures.  This server was a development server that rarely got paid any attention.

After some troubleshooting I started to search the internet to see if anyone else had run across this issue.  My hours of searching turned up nothing so I went back to the troubleshooting drawing board.  Keep in mind this was right after SQL 2005 released so there very well may be plenty of search results for it now.  What I discovered was that the SQLAgent itself has to be mail enabled and assigned to a database mail profile.  The fix was quite simple.  In SSMS right click SQL Server Agent and select properties.  In the left hand pane select the Alert System page.  Next we need to check off “Enable Mail Profile”.  Next we select the mail system from the drop down box and select Database Mail.  If you are still using SQLMail you can also select that, but I highly recommend you start migrating your jobs and any code over to Database Mail.  Lastly we select which mail profile setup in Database Mail that we want to use for sending job messages from SQL Server Agent.

SQLAgent Mail Config

Configuring DBMail for SQLAgent Alerts

In part 1 we looked at how “Run As” works in Windows XP and in part 2 we looked at how it works in Windows Vista.  Now let’s see how it works in Windows 7.

 GUI

Vista Run As Context Menu

Vista Run As Context Menu

In Windows 7 you can hold down the shift key and right click ADUC to get the full context menu.  Here you will see two options called “Run as Administrator” and “Run as Different User”.  The “Run as Administrator” option makes use of the new User Account Control (UAC) security feature.  The good news is if you are logged in with a privileged account and simply run ADUC without any options, the application only has user access to the local machine.  This applies even if the account is in the local administrators group.  If you run it with the “Run As Administrator” option, UAC elevates the account by combining the second part of the SID with the first part of the SID (SID filtering).  The first part describes the regular user account and the second part describes the elevated privileges.  This works exactly as it did in Windows Vista.  This is Microsoft’s way of solving the issue of companies making every day knowledge workers administrators on their machine and reducing the attack surface.  If you select the Run as Administrator option, Windows 7 runs the application using the entire account SID so that the process (and only that process) now has local administrator permissions.

Although user account control was probably the most persecuted new feature after Windows Vista launched, it was actually a really good thing.  In my opinion it certainly has a place in the corporate world, but proved to be a daunting inconvenience in the home user world.  If you still think UAC is a bad thing and too inconvenient go google “linux +sudo”.  Microsoft is not the only one to implement such features.  Microsoft has gone to great lengths to keep this security feature in Windows 7, but greatly reduce the annoyance factor of multiple “Allow or Deny” prompts.

The problem is that “Run as Administrator” is a UAC function and should not be used as a “Run As” replacement.  Although you can set the “Run as Adminstrator” option to prompt for alternate credentials, that application will run as a local administrator and under the supplied alternate credential.  See part 2 of this series for more information.  What we really want is for the application to run under the locally logged on non-privileged account and only pass the alternate credentials to the remote application.  This where “Run as Different User” comes in.  This is the “Run As” replacement and uses the secondary logon service.  The issue here as that it works exactly as it did in Windows XP where it uses the supplied alternate credentials to run the local application. Once again we are left without a secure option in the GUI.

CLI

Executing “Run As” from the CLI is exactly the same in Windows 7 as it was in Windows Vista (see Part 2).  Again it requires elevating the account using UAC, so you might as well just use “Run As Administrator” from the GUI.

The sad part is that although the SysInternals add-on that gave us exactly what we needed in Vista installs in Win 7, it still acts like it did in XP.  The application will run under the supplied alternate credentials on the local box instead of just supplying them to the remote application.

Conclusion

My suggestion for the most secure option for each OS would be…

XP – Use “Run As” from the command line and supply the /netonly switch

Vista – Download the SysInternals add-on called Shellrunas.  Use it from the GUI and always select the one labeled “netonly”.

Windows 7 – Use the “Run As Different” user option from the GUI.  It is the worst option of the 3 but the only viable one.  Let’s cross our fingers that MS will put out another Shellrunas add-on through SysInternals.