DNS Records Disappearing

February 26th, 2010

This post is a little confusing, but it may help someone out there.  In a recent security audit, we were told to disable several services on our servers, one of which was DHCP.  Before disabling it on each server, I verified they were manually configured.  We have some that are set by DHCP with a static.  I then proceeded to disable DHCP on all of the servers with manually configured NICs.

After a couple hours, we had 1 server that could no longer be reached.  of course it was a fairly critical web server.  After investigating, we could reach it in our Indianapolis location, but not Albuquerque.  The server was physically in ABQ.  I started thinking it was a network issue.  Also, the external users that access it from outside our firewall could still reach it.

After looking through the network and trying to see what changed, we realized the server no longer had any records in DNS in ABQ.  How does one record get removed from DNS like that, I thought?  After getting DNS back to how it should be, we started investigating what caused the DNS change.

Finally, we realized the server was using dynamically updated DNS, instead of a manually entered static record…  Never ever did it cross any of our minds that DHCP was keeping the DNS record updated, but it was.  The DHCP service on Windows machines automatically registers with DNS regularly.  This I knew, but I didn’t know that DHCP will register with DNS even if none of the interfaces on the machine are obtaining an address from DHCP.  Interesting.

So, before you disable that service, make sure your DNS records are manual entries and didn’t just come from DHCP’s dynamic updates.

Find Tables Missing Indexes and Create Clustered Indexes for Them

February 24th, 2010

**Update at bottom**

OK, so we had a SQL 2005 database that we migrated from another company.  The application that uses it as a backend was having some terrible performance issues.  We had limited information on the previous configuration, so we bumped the Application up to a newer server since it seemed most of the load issues were with that part.  Afterwards, there were still performance issues and timeouts.  SQL was queuing up commands and taking too long to process them.  So we got the senior DBA involved to help us see what kind of performance increases we could get on the SQL server.  Unfortunately, I did not note all of the changes, but this was the biggest improvement.

We found out that the previous company also had performance issues.  When looking at the tables, we noticed many did not have indexes.  This little query was a lifesaver.  It shows you which tables are without an index, how many reads/writes and if things are queuing.

SELECT

migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (migs.user_seeks + migs.user_scans) AS improvement_measure,

‘CREATE INDEX [missing_index_' + CONVERT (varchar, mig.index_group_handle) + '_' + CONVERT (varchar, mid.index_handle)

+ '_' + LEFT (PARSENAME(mid.statement, 1), 32) + ']‘

+ ‘ ON ‘ + mid.statement

+ ‘ (’ + ISNULL (mid.equality_columns,”)

+ CASE WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL THEN ‘,’ ELSE ” END

+ ISNULL (mid.inequality_columns, ”)

+ ‘)’

+ ISNULL (’ INCLUDE (’ + mid.included_columns + ‘)’, ”) AS create_index_statement,

migs.*, mid.database_id, mid.[object_id]

FROM sys.dm_db_missing_index_groups mig

INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle

INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle

WHERE migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (migs.user_seeks + migs.user_scans) > 10

ORDER BY migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans) DESC

The second column is a query string generated by the first query that will create indexes based on what is needed.  A note though, that query only creates standard indexes.  I recommend to change it to create clustered indexes.  They are considerably faster.  Here are the commands I used to create our indexes.

CREATE CLUSTERED INDEX cix_MASTER1_HISTORY on MASTER1_HISTORY(mrID)

CREATE CLUSTERED INDEX cix_MASTER1_DESCRIPTIONS on MASTER1_DESCRIPTIONS(mrID)

CREATE CLUSTERED INDEX cix_MASTER1_TIMETRACKING on MASTER1_TIMETRACKING(mrID)

CREATE CLUSTERED INDEX cix_MASTER2_HISTORY on MASTER2_HISTORY(mrID)

Hopefully this helps some of you out there

**Updated 3/1/2010

This query to find indexes is dynamic.  it doesn’t actually find all tables missing indexes, it finds tables that are CURRENTLY being searched without indexes and ranks them based on the performance problems they are causing.  So run this query when your SQL starts getting backed up.

How To Seize FSMO Roles and Clean Up Failed Domain Controllers In Active Directory

December 18th, 2009

Alright, so I think at some point, every SysAdmin will have a domain controller fail.  Every SysAdmin should also know that unless you run dcpromo.exe to demote a domain controller before removing it from AD, you can have some issues.  From FSMO to DFRS, it’s just not a good situation.  Here is a summary guide on how to clean up AD after one of your Domain Controllers fail.  Also, this looks long, but it’s all very simple, just putting it into step-by-step sort of drags it out, so no worries, this should be about a 30 minute process.

USE CAUTION: Improperly using ntdsutil may result in partial or complete loss of Active Directory functionality… Don’t go exploring without doing your research.

STEP 1:

Finding Current FSMO Role Masters

First, We need to know whether that particular server was holding any of the FSMO roles.  To check this, we have a couple options, Either via the GUI(1), or via ntdsutil(2).  Personally, I prefer to do it via ntdsutil, as I always feel that there is more power in the command line.  Also, I just hate using a mouse. There are other options, but these two are all that I will cover in this post. For more you can look into “netdom” or “replmon” tools from microsoft, these are not included in windows by default, so I will overlook them for now.  (NOTE: For this, I definitely recommend ntdsutil, as in step 2, I will expect it to already be open and connected.  the GUI Method, is more for information.)

Method 1:

Open AD Users and Computers.

Right-click the name of the domain you are wanting to look at, then select Operations Masters.

FindFSMO1

From this view, you can determine the current Domain-Specific RID Master, PDC Emulator, and Infrastructure Master FSMO Roles.

Now, open AD Domains and Trusts,

Right-click the AD Domains and Trusts in the nav. pane and go to Operations Masters.  This will show you the Domain Naming Master Role.

Finally, to find the Schema Master, you will have an extra step.   You will need to register the Schmmgmt.dll library first.

Goto: Start>Run and type:

regsvr32 schmmgmt.dll

Hit Enter, you should see a success message.

Now, that should allow you to open a new console: AD Schema.  To open it, goto: Start>Run, type:

mmc

hit enter.  Now, in the management console, goto File>Add/Remove Snap-in> click Add.  Double Click Active Directory Schema and close the add/remove dialog windows.

Now, right-click the AD Schema icon and goto Operations Masters.

Method 2:

To check the FSMO Roles via the command line using ntdsutil, we will need to do the following.

Alright, let’s open up a command prompt, then type

ntdsutil

and hit enter.

at the ntdsutil prompt, you will type

roles

hit enter.

Now, you should see a screen that says “fsmo maintenance”.  type

connections

and hit enter again. Here you will connect to the server you want to become the FSMO master(localhost works, if thats what you want). So type:

connect to server

and hit enter again. now you will leave the server connections page and go back to fsmo maintenance. Type:

q

Now we should be back in fsmo maintenance, type

select operation target

Hit Enter. Then type:

list roles

Once you hit enter, it should show you the servers that hold each role.
FindFSMO2

Type “q” to get back to fsmo maintenance, but stay at this screen for the next step.

STEP 2:

Seizing FSMO Roles From Dead Server

OK, so this step is optional.  based on the results of your last step.  You only need to seize the roles if the FSMO master is no longer operational.  To do this step we will use ntdsutil.

Now, we need to seize the roles that are on our dead server.  You should know what roles your dead server holds from the last step, so only do this command for those.  Remember, I had you connect to the server that will receive the FSMO role(s).  A quick way to see the syntax for seizing is just type “?” and it will show you how to transfer/seize, it is basically:

seize <role>

as in:

seize schema master

or for transfers(only to be done if current master is still live/active)

transfer <role>

To verify the roles transferred(ignore the errors you get at first, you are guaranteed to have one since the current master is unavailable), put in

select operation target

then the same way we found the masters before:

list roles for connected server

Now, we’re almost done, we have transferred the FSMO roles(the biggest potential problem), and just need to cleanup the AD metadata and sites/services.

STEP 3:

Metadata Cleanup

For the next step, we will go back to the first ntdsutil prompt.  type “q” and hit enter until your prompt says “ntdsutil:”.  Type

metadata cleanup

hit enter. You should still be connected to a domain controller, but if you closed ntdsutil and reopened it, you will need to put in

connections

then

connect to server <servername>

then type quit back to the metadata cleanup prompt (”q”). Now, we will pick our target for cleanup. Type:

select operation target

At this point, if you only have 1 domain, or within the domain you pick, only 1 site, you can skip some steps. Your domain number, site number will be “0″(zero) if there is only one. For the sake of thoroughness, I will show you how to find the index anyway. To find the domain, type:

list domains

Now, find the domain you want to work with, and type:

select domain <number>

Now, we find the site within the domain where the domain controller used to reside.

list sites

put in the site you want:

select site <number>

To find the servers within that site, type:

list servers in site

then we will select the inactive server by typing:

select server <number>

Now, type enter “q” to quit back to metadata cleanup prompt. The final command to cleanup all metadata for that server is:

remove selected

You will receive a warning, but if you’re positive that server is down and will need rebuilt, you should be safe to hit Yes.  You should get a message saying it was removed successfully.  If you receive an error that the object could not be found, it was probably already removed from the domain controller.  Open up AD Users and Computers to verify the server is gone from the Domain Controllers OU.  Alright, we’re almost done, just another 5 minutes of work, at the most.

Step 4:

Remove The Server From Sites & Services

This will be done via the AD Sites & Services Snap-in.  Just expand the site where the server was located, and delete the object for the failed server… This step is done.

Step 5:

Remove The Server From DNS

This step depends a lot on how you have your DNS set up, I am assuming the DNS is run on a Windows server, and hopefully a DC.  It doesn’t have to be, that’s just how i prefer it.  Unfortunately, where I work, The DNS servers are separate and I have no access to them… such a pain.  Anyway, open up your DNS Management Console.  I hope you know this, but it’s:
Start>run> type “mmc”, hit enter. Goto File>Add/Remove Snap-in>hit Add>double-click DNS>Close>Close.
Now, expand the zone where the server used to be(probably Forward Lookup Zones>domain.local), and delete the A record(also called a host record) for the server. Remove the CNAME record in the _msdcs.root domain of forest zone in DNS. If you have reverse lookup zones, also remove the server from these zones. If you have anywhere else the server is referenced, or are unsure, you might want to check for these now.

You’re Done!  Now, you should be good to go.  Let me know if any of you have issues with this guide, notice anything wrong, or just have errors/questions.  I will be glad to help, and I know I have some pretty atrocious grammar/spelling at times.

Error Logging in VB and C#

December 17th, 2009

Alright, so lately I have been working on a couple of ASP.NET(C#) projects.  One thing I have seen is nothing is as useful as having a good error logger.  Now, since I am still in the learning phases of .NET programming, I have been looking to a coworker, Joe Young, sort of as a mentor.  He provided me with some code that has just immensely helped me.  I have attached 2 files.  one in VB, on in C#, they are Joe’s code.  These are your App_Code files.  They will create a detailed log of any errors in a file in a directory you specify.  You specify the file in the attached files.  To use them, you will insert the following code. (For the below VB examples, I used a website to convert it from my C#, as I was being lazy)

C#:

private void LogError(Exception errMessage)
{
errorlogger objLog = new errorlogger();
objLog.logerror(errMessage);
}

VB:

Private Sub LogError(ByVal errMessage As Exception)
Dim objLog As New errorlogger()
objLog.logerror(errMessage)
End Sub

This allows you to call the external errorlogger.

Now, to call it. The most useful place I have put these are in SQL connections/procedure calls. Here is an example from one of my programs.

C#

try
{
string strSQLSetCheckedOut = “exec CP_setCheckedOutTrue ” + HttpContext.Current.Session["sName"].ToString();
SqlCommand conSQLCommand = new SqlCommand(strSQLSetCheckedOut, conSQLConnection);
conSQLCommand.CommandTimeout = 120;
conSQLConnection.Open();
conSQLCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
LogError(ex);
}
finally
{
conSQLConnection.Close();
}

VB:

Try
Dim strSQLSetCheckedOut As String = “exec CP_setCheckedOutTrue ” & HttpContext.Current.Session(”sName”).ToString()
Dim conSQLCommand As New SqlCommand(strSQLSetCheckedOut, conSQLConnection)
conSQLCommand.CommandTimeout = 120
conSQLConnection.Open()
conSQLCommand.ExecuteNonQuery()
Catch ex As Exception
LogError(ex)
Finally
conSQLConnection.Close()
End Try

Hopefully this little bit of code out there will help someone else out.

C# ErrorLogger Code

VB ErrorLogger Code

Moving

November 3rd, 2009

Just to let everyone know, I am moving my blog off to my own server. The new address will be blog.christophermichaelwebb.com. I had resisted for quite a while as wordpress has some powerful clout on the search engines, but I feel it’s for the best as I like to have full control over my sites. Hope to see you all there.

Burnt Out?

November 2nd, 2009

You know, I think my main reason for going into IT was that it is constantly changing and there is so much to learn that it seems constantly new. I started in consulting and loved it. Everyday somewhere new, a new task with new technologies. After a while, I grew curious of what it would be like to work in a dedicated environment. This period coincided with a time of downsizing at the consulting firm I was with. I took the opportunity to hop on at a data center with Lockheed Martin. At first, I thought it would be exciting, learning about clustering and the different issues that are involved with large enterprise environments. Honestly, though, it’s pretty boring. At our office, we have no senior systems administrators, so there isn’t really anyone to observe or learn from. I’m not saying that the guys I work with aren’t smart, not by any means. We just all lack that experience and the other benefits that come with it. The environment we are in is pretty stale, it has been running for a couple years now and is 90% stable and with everything being redundant, there never seems to be an emergency. Really, this is what most companies want and something that I would love to set up, but i feel no connection to the environment as I had no part in the installation or configuration of any of it.

One thing that has made my time with Lockheed wonderful is the scripting. I got to really dive in and learn scripting and WMI and how AD works because there are constantly large, mundane tasks that need done across the network. I started doing a lot of scripting. I think that my big debate right now is “Where do I want to go with my career?” I like the consulting work and administration when there is opportunity for change, but really, i feel like my true passion for IT comes with the idea of creation. I loved setting up networks from scratch, from the routers, to switches, to deciding which servers, desktops, and OS’s to use. There was a lot of control there, but I don’t think the control is the main thing that made me love it. I have been studying up on Visual Basic and .NET 3.5 lately, to try to get into application development. I would like to move to C++, but already have a fairly solid knowledge of VB to start there. My thought is creating versus maintaining, obviously creating is more exciting(at least to me). I guess I’m not sure what I want, I just feel a bit burnt out and can’t seem to focus today. There hasn’t been anything too exciting for me to post lately, either, so I thought I would just throw my thoughts up as an update.

How to Set Folders View in Explorer Bar Permanently

October 27th, 2009

I have always hated that i need to go to View>Explorer Bar>Folders every time I need to get the folder view on the left, or even right-click>Explore. I want it there all the time. This little trick I learned from a colleague really helped me out.

First open My Computer
GoTo View>Explorer Bar>Folders
Here’s the trick to make it stick:
Now, goto Tools>Folder Options>File Types
Find the entry that is a folder icon with (none) next to it.
Click it, goto Advanced.
Click Explore
Then click Set Default

Voila! Now, every time you open an explorer window, the folder view will be on the left.

Killing Processes on Server 2000 from VBScript

October 8th, 2009

Alright, so we have a report server that has a massive SQL database and is running Server 2000 SP4. I honestly don’t know too much about it, because we have a DBA who does pretty much 90% of the maintenance/admin work on this server and the reports have nothing to do with the programs I work with. Anyway, the reports that are run export the SQL data to Excel spreadsheets. Once the report is run, the Excel process is left running. This server is already extremely old and bogged down as is, so having over a hundred instances of Excel running on it wasn’t helping. I wrote a script to check for all processes named “excel” and see how long they have been running, then kill the ones that were running for what seem to be too long of time. I had some issues, because Server 2000 does not have all of the capabilies as 2003, obviously. This script requires that you download pskill, part of the PSTools suite from SysInternals(now Microsoft). Now, while the script requires PSKill, it is able to run on server 2000/2003/2008(and 2000/xp/vista/7), so hopefully it is still useful to someone else out there. The script is below and I tried to make sure it was well-commented to help you out. Feel free to leave any suggestions/questions below. Enjoy.


''''This script requires pskill, part of the PSTools suite from SysInternals(now Microsoft). This script is assuming pskill is in your path for cmd line(generally, c:\windows(winnt on 2000/nt)\system32\)

Option Explicit
Dim strComputer, objWMIService, colProcessList, objProcess, PDate, Days, Hrs, Min, Sec, objSWbemLocator, WshShell
strComputer = "."
Set WshShell = CreateObject("wscript.shell")
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where Name = 'Excel.exe'") ' Replace Excel with whatever the process is you're looking for.
Do
If colProcessList.Count = 0 Then ' This kills the script if the process we are looking for is not running.(also ties with last commented line for looping)
Exit Do
Else
For Each objProcess in colProcessList
If objProcess.CreationDate "" Then
PDate = Left(objProcess.CreationDate,14) ' pulls the date process started in format: yyyymmddhhmmss
Days = DateDiff("d",DateSerial(Left(PDate,4),Mid(PDate,5,2),Mid(PDate,7,2)),Date) ' find how many days process has been running
Hrs = Hour(Now) - Mid(PDate,9,2) ' find how many hours process was running, if started same day
Min = Minute(Now) - Mid(PDate,11,2) ' same but for minutes
Sec = Second(Now) - Mid(Pdate,13,2) ' same but for seconds
If Hrs > 6 Then ' This is where you specify how long the process has to have been running in order for it to be killed, so you don't kill active jobs. Change it from "Hrs" to "Min" or "Sec" for minutes or seconds. Change 6 to whatever number of units.(currently set to kill processes over 6 hours old)
WshShell.Run "pskill -t " & objProcess.ProcessId, 0, False
Else
If Days > 0 Then ' This is a failsafe to the previous "If". Since it only detects how many hours process was running, if started same day. This guarantees that it kills anything over a day old.
WshShell.Run "pskill -t " & objProcess.ProcessId, 0, False
End If
End If
End If
Next
WScript.Sleep 1000 ' wait before trying again
Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where Name = 'Excel.exe'") ' Recheck for processes ' This makes the script keep looking until there aren't any active processes. i.e. a report is being run now, we will wait until it is done to kill the process and the script.
End If
Loop

Login Script for Everyone

September 21st, 2009

UPDATED 12/23/09: The script on the bottom is the original.  I have made a few changes to log all errors and to fix a couple glitches that come up in some environments.  Changed the syntax of the addWindowsPrinterConnection command, and made it set default printer.  Here is the new script(the original post is below):


Option Explicit
Const ADS_PROPERTY_APPEND = 3 'sets the variable to Append
Const ADS_UF_NORMAL_ACCOUNT = 512
Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
CONST HKEY_LOCAL_MACHINE = &H80000002
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

Dim WshShell : Set WshShell = CreateObject(”wscript.shell”)
Dim strContainer, strUser, i, objRootDSE, strDisplayName, ObjFSO, objInFile, objContainer, strLine, strName, objOU, objGroup, objUser, objFile, objFile2, varDomainNC, objRoot, strText, FirstLine, arrMemberOf, Group, strFirstName, strLastName, strLine2, objOU2, objNetwork, strGroup, objConnection, objCommand, objRecordSet, objErrorLog, strComputer, colItems, objWMIService, colInstalledPrinters, strComputer2
Set objOU2 = GetObject(”LDAP://CN=users,DC=twic,DC=local”)
Set objOU = GetObject(”LDAP://ou=users,ou=indianapolis,DC=twic,DC=local”)
ObjOU.Filter= Array(”user”)
Set objGroup = objOU2.Getobject(”group”, “cn=CSRs”)
Set objFSO = CreateObject(”Scripting.FileSystemObject”)
Set objNetwork = WScript.CreateObject(”Wscript.Network”)
Set objRootDSE = GetObject(”LDAP://rootDSE”)
strComputer2 = “.”
Dim CRLF
CRLF = Chr(13) & Chr(10)

‘*************(Global Scripting) this section applies to all computers no matter what group users are in.

”default lockheed banner script
Function Ask(strAction)

Dim intButton
intButton = MsgBox(strAction, _
vbQuestion + vbYesNo, _
L_Welcome_MsgBox_Title_Text )
Ask = intButton = vbYes

End Function

MsgBox “This system is the property of this Corporation, and is intended for” & CRLF & _
“the use of authorized users only. All activities of individuals using this computer” & CRLF & _
“with or without authority, or in excess of their authority, may be monitored and recorded” & CRLF & _
“by system personnel. If any such monitoring reveals evidence of criminal activity or is in” & CRLF & _
“violation of foreign or U.S. state or federal law, such evidence may be provided to law” & CRLF & _
“enforcement officials and/or used for further legal action by this Corporation and/or the” & CRLF & _
“organization’s Information Protection group. Unauthorized use of this system is prohibited” & CRLF & _
“and may result in revocation of access, disciplinary action and/or legal action. The” & CRLF & _
“company reserves the right to monitor and review user activity, files and electronic messages.” & CRLF & _
“REMINDER: Information transmitted to a foreign person on this network may be subject ” & CRLF & _
“to applicable Export Control laws. Contact your Export Coordinator for assistance.” & CRLF & _
“(This machine is not authorized for classified processing)”, _
vbOKOnly, _
“SYSTEM USE MONITORING NOTICE – IPM-003 Banner Statement”

WshShell.Run “net use s: /delete”, 0, False
WshShell.Run “Net use s: \\indtwicfile01\shared /persistent:yes”, 0, False

‘*************End of global scripting

”pull local computer name for loggin info.
strComputer = objNetwork.ComputerName

”pull logon id
strUser = objNetwork.UserName

”turn logon id into container name for LDAP queries

Set objConnection = CreateObject(”ADODB.Connection”)
objConnection.Open “Provider=ADsDSOObject;”
Set objCommand = CreateObject(”ADODB.Command”)
objCommand.ActiveConnection = objConnection
objCommand.CommandText = “;(&(objectCategory=User)(samAccountName=” & strUser & “));name;subtree”
Set objRecordSet = objCommand.Execute
On Error Resume Next
strUser = objRecordSet.Fields(”name”)
On Error GoTo 0
objConnection.Close
Set objRecordSet = Nothing
Set objCommand = Nothing
Set objConnection = Nothing
strUser = Replace(strUser, “,”, “\,”)

‘’set user to have LDAP queries run
ON ERROR RESUME NEXT
Set objUser = GetObject(”LDAP://cn=” & strUser & “,ou=users,ou=indianapolis,dc=twic,dc=local”)
If Err.Number = 0 Then

”\/\/\/\/\/\/Determine Group memberships. PLEASE NOTE: group names must be in UPPER case and the “Left(strGroup, X)”
‘ X must be the number of characters in the group name.
‘\/\/\/\/\/\/\/

arrMemberOf = objUser.GetEx(”memberOf”)

If Err.Number <> E_ADS_PROPERTY_NOT_FOUND Then
For Each Group in arrMemberOf
strGroup = UCase(Group)
strGroup = Right(strGroup, Len(strGroup) – 3)
If Left(strGroup, 2) = “IT” Then
‘*****IT group scripting

‘’set Z:IT drive
WshShell.Run “net use z: /delete”, 0, False
WshShell.Run “Net use z: \\indtwicfile01\it /persistent:yes”, 0, False

”Prepare to set printers
Set objWMIService = GetObject(”winmgmts:\\” & strComputer & “\root\cimv2″)

”This prevents script from stopping when mapping network printers on the server where they
”are shared from
ON ERROR RESUME NEXT

”Add Printers

objNetwork.AddWindowsPrinterConnection “\\indtwicfile01\Xerox WorkCentre 5675 PS”
objNetwork.SetDefaultPrinter “\\indtwicfile01\Xerox WorkCentre 5675 PS”

‘*****End of IT
Else
If Left(strGroup, 4) = “CSRS” Then
‘*****CSR group scripting

‘*****End of CSR
Else
If Left(strGroup, 10) = “MANAGEMENT” Then
‘*****Management group scripting – NOTE: all managers are members of “Team Leads” group

‘*****End of Management
Else
If Left(strGroup, 7) = “Quality” Then
‘*****Quality scripting – NOTE: all quality are members of “TeamLeads” group

‘*****End of Quality
Else
If Left(strGroup, 10) = “TEAMLEADS” Then
‘*****Team Lead scripting

”Prepare to set printers
Set objWMIService = GetObject(”winmgmts:\\” & strComputer & “\root\cimv2″)

”This prevents script from stopping when mapping network printers on the server
”where they are shared from
ON ERROR RESUME NEXT

”Add Printers
objNetwork.AddWindowsPrinterConnection “\\indtwicfile01\Xerox WorkCentre 5675 PS”

‘*****End of Team Lead
End If
End If
End If
End If
End If
Next
Else
‘*****Create Error Log if groups could not be determined

Set objErrorLog = objFSO.OpenTextFile(”\\indtwicdc01\errors\signonerrors.txt”, ForAppending, True)
objErrorLog.WriteLine strUser & ” on ” & strComputer & ” could not be found in Active Directory on ” & Date
objErrorLog.WriteLine “The error code is ” & Err.Number
Err.Clear
End If
Else
‘*****Create Error Log for all other errors
Set objErrorLog = objFSO.OpenTextFile(”\\indtwicdc01\errors\signonerrors.txt”, ForAppending, True)
objErrorLog.WriteLine strUser & ” on ” & strComputer & ” had the following error: ” & Err.Number & ” on ” & Date
Err.Clear
End If

ORIGINAL POST: We have a new program in with a new domain. On our other networks, there are seperate logon scripts for pretty much every security group and they all call other scripts. With this network, i wanted to keep things simple, so this script connects to AD and checks their group membership before running the apropriate commands for each group. This particular network does not have any shares yet, and isn’t very complex, but here is the base of it. Let me know if you want to know how to add anything more to it.

Option Explicit
Const ADS_PROPERTY_APPEND = 3 'sets the variable to Append
Const ADS_UF_NORMAL_ACCOUNT = 512
Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
CONST HKEY_LOCAL_MACHINE = &H80000002
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

Dim WshShell : Set WshShell = CreateObject(”wscript.shell”)
Dim strContainer, strUser, i, objRootDSE, strDisplayName, ObjFSO, objInFile, objContainer, strLine, strName, objOU, objGroup, objUser, objFile, objFile2, varDomainNC, objRoot, strText, FirstLine, arrMemberOf, Group, strFirstName, strLastName, strLine2, objOU2, objNetwork, strGroup, objConnection, objCommand, objRecordSet, objErrorLog, strComputer, colItems, objWMIService, colInstalledPrinters, strComputer2
Set objOU2 = GetObject(”LDAP://CN=users,DC=arra,DC=local”)
Set objOU = GetObject(”LDAP://OU=arra-users,DC=arra,DC=local”)
ObjOU.Filter= Array(”user”)
Set objGroup = objOU2.Getobject(”group”, “cn=CSRs”)
Set objFSO = CreateObject(”Scripting.FileSystemObject”)
Set objNetwork = WScript.CreateObject(”Wscript.Network”)
Set objRootDSE = GetObject(”LDAP://rootDSE”)
strComputer2 = “.”
Dim CRLF
CRLF = Chr(13) & Chr(10)

‘*************(Global Scripting) this section applies to all computers no matter what group users are in.

”default lockheed banner script
Function Ask(strAction)

Dim intButton
intButton = MsgBox(strAction, _
vbQuestion + vbYesNo, _
L_Welcome_MsgBox_Title_Text )
Ask = intButton = vbYes

End Function

MsgBox “This system is the property of this Corporation, and is intended for” & CRLF & _
“the use of authorized users only. All activities of individuals using this computer” & CRLF & _
“with or without authority, or in excess of their authority, may be monitored and recorded” & CRLF & _
“by system personnel. If any such monitoring reveals evidence of criminal activity or is in” & CRLF & _
“violation of foreign or U.S. state or federal law, such evidence may be provided to law” & CRLF & _
“enforcement officials and/or used for further legal action by this Corporation and/or the” & CRLF & _
“organization’s Information Protection group. Unauthorized use of this system is prohibited” & CRLF & _
“and may result in revocation of access, disciplinary action and/or legal action. The” & CRLF & _
“company reserves the right to monitor and review user activity, files and electronic messages.” & CRLF & _
“REMINDER: Information transmitted to a foreign person on this network may be subject ” & CRLF & _
“to applicable Export Control laws. Contact your Export Coordinator for assistance.” & CRLF & _
“(This machine is not authorized for classified processing)”, _
vbOKOnly, _
“SYSTEM USE MONITORING NOTICE – IPM-003 Banner Statement”

‘*************End of global scripting

”pull local computer name for loggin info.
strComputer = objNetwork.ComputerName

”pull logon id
strUser = objNetwork.UserName

”turn logon id into container name for LDAP queries

Set objConnection = CreateObject(”ADODB.Connection”)
objConnection.Open “Provider=ADsDSOObject;”
Set objCommand = CreateObject(”ADODB.Command”)
objCommand.ActiveConnection = objConnection
objCommand.CommandText = “;(&(objectCategory=User)(samAccountName=” & strUser & “));name;subtree”
Set objRecordSet = objCommand.Execute
On Error Resume Next
strUser = objRecordSet.Fields(”name”)
On Error GoTo 0
objConnection.Close
Set objRecordSet = Nothing
Set objCommand = Nothing
Set objConnection = Nothing

‘’set user to have LDAP queries run
Set objUser = GetObject(”LDAP://cn=” & strUser & “,ou=arra-users,dc=arra,dc=local”)

”\/\/\/\/\/\/Determine Group memberships. PLEASE NOTE: group names must be in UPPER case and the “Left(strGroup, X)”
‘ X must be the number of characters in the group name.
‘\/\/\/\/\/\/\/

arrMemberOf = objUser.GetEx(”memberOf”)

If Err.Number E_ADS_PROPERTY_NOT_FOUND Then
For Each Group in arrMemberOf
strGroup = UCase(Group)
strGroup = Right(strGroup, Len(strGroup) – 3)
If Left(strGroup, 2) = “IT” Then
‘*****IT group scripting

‘’set Z:IT drive
WshShell.Run “net use z: /delete”, 0, False
WshShell.Run “Net use z: \\indarradc04\it”, 0, False

”Prepare to set printers
Set objWMIService = GetObject(”winmgmts:\\” & strComputer & “\root\cimv2″)

”This prevents script from stopping when mapping network printers on the server where they
”are shared from
ON ERROR RESUME NEXT

”Add Printers
objNetwork.AddWindowsPrinterConnection(”\\indarradc03\Xerox WorkCentre 5675 PS”)

‘*****End of IT
Else
If Left(strGroup, 4) = “CSRS” Then
‘*****CSR group scripting

‘*****End of CSR
Else
If Left(strGroup, 10) = “MANAGEMENT” Then
‘*****Management group scripting – NOTE: all managers are members of “Team Leads” group

‘*****End of Management
Else
If Left(strGroup, 10) = “TEAM LEADS” Then
‘*****Team Lead scripting

”Prepare to set printers
Set objWMIService = GetObject(”winmgmts:\\” & strComputer & “\root\cimv2″)

”This prevents script from stopping when mapping network printers on the server
”where they are shared from
ON ERROR RESUME NEXT

”Add Printers
objNetwork.AddWindowsPrinterConnection(”\\indarradc03\Xerox WorkCentre 5675 PS”)

‘*****End of Team Lead
End If
End If
End If
End If
Next
Else
‘*****Create Error Log if groups could not be determined

Set objErrorLog = objFSO.OpenTextFile(”\\indarradc04\errors\signonerrors.txt”, ForAppending, True)
objErrorLog.WriteLine strUser & ” on ” & strComputer & ” could not be found in Active Directory on ” & Date
Err.Clear
End If

Again, let me know if you need help modifying/adding anything for your own use.

**UPDATE(9/25)**

Changed the
WshShell.Exec(”net use…”)
lines to
WshShell.Run “net use…”, 0, False

This allows us(and does it already) to set any outside commands or scripts(in this case mapping drives, but can call bat files or whatever) to run invisibly(the 0), and “False” says to continue with the rest of the script immediately, True would mean to wait for the outside command to complete before continuing. This site has the details.

Run Method(Windows Script Host)

Bulk Add of Users to Active Directory – vbscript

September 21st, 2009

This script is fairly basic. We have a temporary(7-12 month) program coming in and they need their own domain. They won’t have exchange or really need AD for anything except authentication and GPOs. This was made for server 2008, but everything works on 2000/2003. We got a list of 85 names for user accounts in a text file, so this is how i used them for input. anyway, here it is:

Option Explicit
Const ADS_PROPERTY_APPEND = 3 'sets the variable to Append
Const ADS_UF_NORMAL_ACCOUNT = 512
Const ForReading = 1
Dim strcontainer, strUser, i, objRootDSE, strDisplayName, ObjFSO, objInFile, objContainer, strLine, strName, objOU, objGroup, objUser, objFile, objFile2, varDomainNC, objRoot, strText, FirstLine, strFirstName, strLastName, strLine2, objOU2
Set objOU2 = GetObject("LDAP://CN=users,DC=arra,DC=local")
Set objOU = GetObject("LDAP://OU=arra-users,DC=arra,DC=local")
Set objGroup = objOU2.Getobject("group", "cn=CSRs")
strContainer = "ou=Arra-Users"
Set objFSO = CreateObject("Scripting.FileSystemObject")

'***********************************************
'* Connect to a container *
'***********************************************
Set objRootDSE = GetObject("LDAP://rootDSE")
If strContainer = "" Then
Set objContainer = GetObject("LDAP://" & _
objRootDSE.Get("defaultNamingContext"))
Else
Set objContainer = GetObject("LDAP://" & strContainer & "," & _
objRootDSE.Get("defaultNamingContext"))
End If
'***********************************************
'* End connect to a container *
'***********************************************

Set objInFile = objFSO.OpenTextFile("C:\Users\webbc\Desktop\Users.txt", ForReading)
Do until objInFile.AtEndOfStream
strLine2 = objInFile.ReadLine
FirstLine = 0

strText = Replace(strLine2, " ", "§§")
Dim arrText : arrText = Split(strText, "§§")

For Each strLine In arrText
If FirstLine 1 Then
FirstLine = FirstLine + 1
strLine = Replace(strLine, "§§", "")
strFirstName = strLine
Else
strLine = Replace(strLine, "§§", "")
strLastName = strLine
End If
Next

strUser = Left(strFirstName, 1) & strLastName
strDisplayName = strFirstName & " " & strLastName

Set objUser = objContainer.Create("User", "cn =" & strDisplayName)
objUser.Put "displayName", strDisplayName
objUser.Put "description", strLastName & ", " & strFirstName
objUser.Put "sAMAccountName", strUser
objUser.Put "givenName", strFirstName
objUser.Put "sn", strLastName
objUser.Put "userPrincipalName", strUser & "@arra.local"
objUser.Put "Homedrive", "h"
objUser.Put "scriptPath", "login.bat"
objUser.Put "HomeDirectory", "\\indarradc03\Home\" & strUser
objUser.SetInfo

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateFolder("\\indarradc03\Home" & "\" & strUser)

objUser.AccountDisabled = FALSE
objUser.Put "pwdLastSet", 0

'* edit the password to suit

objUser.SetPassword("NewPassword1")
objUser.SetInfo

objGroup.PutEx ADS_PROPERTY_APPEND, "member", Array("cn=" & strDisplayName & ",OU=arra-users,dc=arra,dc=local")
objGroup.SetInfo
Loop

Let me know if you have any questions.