The Multifunctioning DBA

Oct 31 2009   3:00PM GMT

Happy Haloween



Posted by: Colin Smith
Fun

Happy Halloween from Hawaii everyone. I saw this and thought that I would share with you as well. I would love to go to one of the houses in this video. I love Tech and these are using plenty of it.

Cool Stuff

Have fun and be safe.

Oct 29 2009   8:00PM GMT

Windows 7



Posted by: Colin Smith
Microsoft Windows, Windows, Media Streaming, Media

I have played with one of the preview releases and I liked it just fine. I just read some good info on Engadget that leads me to believe that I will like Windows 7 just because of the media center upgrades that have been done.

I am excited to hear about media center starting to play nice with DLNA devices and not just Media Extenders. This means that I will be able to use my PS3 to stream music via windows media center and no longer have to use a third party app. Not that I mind using a third party app to do so but I think that everyone needs to get along and talk to each other when it comes to media sharing. I think that most media will be online soon and I think that the more devices that can talk nicely together the better off we will be.

Based on just that I can not wait to get my hands on Windows 7 and get the install complete.


Oct 28 2009   8:00AM GMT

Vacation



Posted by: Colin Smith

Well I am very close to heading out on a nice 10 day vacation to Hawaii. I have been looking forward to this for about 6 months and it is finally here. I fly out on Wednesday morning and I will not return until the following Friday. I may post while I am on vacation of I see anything or do anything extra cool. Right now I know that we will be doing some snooba diving, going to the blacksand beaches, and checking out the lava on the big island. I will have pictures and post some of the better ones up here for all to see.


Oct 27 2009   3:30AM GMT

Active, Active, Active



Posted by: Colin Smith
MSSQL, MSSQL Administration, MSSQL Install, MSSQL Server, SQL Server 2008, Cluster

Last week I got the chance to work on an Active, Active, Active SQL Server 2008 Cluster install. This was new to me and very fun. We have three physical hosts all using SQL Server 2008 Enterprise Edition. The Servers are also running Windows Server 2008 Enterprise Edition. I worked with one of our windows admins to do the install. First the windows admin set up the windows cluster and assigned all of the storage to the cluster but did not assign it to an application or service. Once that was done we had to set up the Distributed Transaction Coordinator and give it its storage. Now we started the install of SQL Server 2008. Since all of the storage was owned by one server we installed all three instances, one for each node, of SQL Server on that server and that created the different cluster applications for us. Then on each of the other servers we added a node three times, again once for each instance. Now that is complete we can fail over the resources for any instance to any of the physical nodes. Very cool.


Oct 26 2009   4:26PM GMT

Databases not accessible



Posted by: Colin Smith
SQL Server 2005, MS SQL Admin, MS SQL Troubleshooting, MS SQL Server, MSSQL Administration

Just got a call that three databases on an instance where many reside were not accessible. Users were getting errors about not enough disk, memory, or the files were inaccessible. I logged into the server and found that the databases were not offline but could not be accessed. I looked into the errorlog and found the following error:

‘The transaction log for database ‘database_name’ is full. To find out why space in the log cannot be reused, see the log_reuse_wait_desc column in sys.databases’

Well I looked around and I did not find anything wrong. Disk were logs are kept had just under 100 Gigs free and the ldf files were not in a read-only state. Based on that I offlined the databases and then attempted to bring them back online. SQL found the MDF and the LDF files, went through recovery, found no issues and brought the databases back online.

Still not sure exactly what happened. It is strange also since all the databases use the simple recovery model. Based on that I am not sure how the log was full but there you go.


Oct 22 2009   10:00AM GMT

MCTS Exam



Posted by: Colin Smith
Certification, Study, MSSQL, MS SQL Server

So Like I said before I did take the MCTS Exam and I did pass. I can not go into any detail about the test as you have to agree to an NDA before you take it. The test was, in my opinion, not as hard as the study material. I think that MS did a great job with the study material for this test. I was not sure if I was really ready for the test but it turns out I was more than ready.
I finished the test very early. I had about 40 minutes left when I completed the question portion and still over 1 hour left when I completed the simulation portion of the Exam. To study I purchased the following kit and I am about to start on the second book to prepare for the second of the three tests required for the MCITP:DBA certification. Think I will start hitting that hard when I return from Hawaii.

 http://www.amazon.com/gp/product/0735623…

Read the book and spend time doing the practices and questions in the book and definitely take the practice tests. You will do well if you do all that.


Oct 21 2009   4:00PM GMT

Sprint HTC Hero



Posted by: Colin Smith
Android, Phone, Exchange

One reason that I was so excited to get this phone was that it supports Exchange Active Sync out of the box. This is great for me since I would like to consolidate down to one phone and get rid of my employer provided device that I am not so fond of. Well I was very disappointed when it did not work. I brought the Hero in and sat down with a mail administrator and we set it all up. Come to find out that the built in sync does not support ssl passwords. Well what is the point then? No IT department is going to allow device syncing without securing the password that is flying in the air in packets that could be sniffed out by anyone. This is, after all, my domain log in password and that is a huge security hole.Thank fully I found Touchdown by NitroDesk. This is a great application. I downloaded the trial installed it and off I went. Very simple setup and it just works and with PUSH email I get my email on the device quickly, sometimes before Outlook gets it. Synced my Calander and Contacts as well. Love it and I say it is well worth the $20.00 that the license costs. I got mine for $10.00 due to some special pricing that they had going on at the time. Check it out if you are on Android. It is great.


Oct 21 2009   10:00AM GMT

AD Audit all together



Posted by: Colin Smith
Powershell, AD, AD Managment, AD Administration, Scripting

Here is the full script so you can copy and paste it. Remember that you will need to make some modifications to the script to fit your environment. Let me know if you have any questions at all.

Thanks




###########################################################################
## Script Name: 90-180.ps1
## Written by: Colin Smith
## Date: 9/15/09
###########################################################################
## ChangeLog
###########################################################################
###########################################################################
## This Script will enumerate all accounts in the your domain
## and disable all accounts that have not been logged in with in
## over 90 days, unless the account is one of the Protected OU's.
## This script will also delete all accounts that are disabled
## and have not been loged in with in over 180 Days.
## This script will not search accounts that reside in defined
## exception containers. This will also find the users H: Drive
## folder and move it to \\someserver\_term to await deletion.
## This script will also remove all group memberships from accounts
## before deletion of the account. This will avoid Hashes in Groups
## this replaces the 90-180 Visual Basic Script.
###########################################################################
###########################################################################
## Requirments for this script are Powershell V1 installed as well as
## Quest Active Directory Management Snapin
###########################################################################

#######################################################
## This Function Gets a listing of all user account
## and last logon times and created dates for
## all users on the your domain that are not in
## Excluded OU's
#######################################################
function get_users
{
	foreach($company in $companies)
		{
#Echo "Company is $company"
			Clear-Content "c:\90-180\$company.csv"
			Clear-Content "c:\90-180\$company.disabled.txt"
			echo "enabled, LogonName, firstname, lastname, dn, lastlogon, createddate" >> "c:\90-180\$company.csv"

			$dcs = Get-QADComputer -ComputerRole DomainController

			$users = Get-QADUser -SizeLimit 0 -searchroot "Some.root.com/$company/Users" | where{(($_.dn -notlike "*disabled*") -and ($_.dn -notlike "*Generic*") -and ($_.dn -notlike "*Vendors*") -and ($_.dn -notlike "*mail-in*") -and ($_.dn -notlike "*shared calendars*"))}

			foreach($user in $users)
				{
					$lastlogon = $null
					foreach($dc in $dcs)
					{
						$dclogon = Get-QADUser -Service $dc.Name -SamAccountName $user.samaccountname | select lastlogon
						$dclogon = $dclogon.lastlogon.value

						if ($dclogon -ne $null)
							{
								if($lastlogon -lt $dclogon)
									{
										$lastlogon = $dclogon
									}
							}
					}
					if ($lastlogon -eq $Null)
						{
							$lastlogon = [datetime]::Now.AddDays(-500000)
						}

					$o = New-Object PSObject
					$o | Add-Member NoteProperty "User" $user.Name
					$o | Add-Member NoteProperty "LastLogin" $lastlogon
					$o | Add-Member NoteProperty "DisplayName" $user.DisplayName
					$o | Add-Member NoteProperty "Disabled" $user.accountisdisabled
					$o | Add-Member NoteProperty "DistinguishedName" $user.DN
					$o | Add-Member NoteProperty "Created" $user.CreationDate
					$o | Add-Member NoteProperty "SamAccountName" $user.SamAccountName
					$o | Add-Member NoteProperty "LastName" $user.LastName
					$o | Add-Member NoteProperty "FirstName" $user.FirstName

					if($o.disabled -eq "False")
						{			$enabled = "DISABLED"}
					else
						{			$enabled = "ENABLED"}
					$Fname = $o.FirstName
					$lname = $o.LastName
					$lastlogon = $o.LastLogin
					$created = $o.Created
					$samname = $o.samaccountname
					$dn = $o.DistinguishedName
					$dn = $dn.replace(",", ":")

					echo "$enabled, $samname, $fname, $lname, $DN, $lastlogon, $created" >> "c:\90-180\$company.csv"

				}

		}
}

##########################################################
## Function Disable_Accounts
## Find all accounts that need to be disabled
## Disable the account
## Move the account to the appropriate disabled OU
## Log the account that has been disabled and moved
##########################################################
function Disable_Accounts
{
	foreach($company in $companies)
		{
			$listedusers = Import-Csv "c:\90-180\$company.csv"
			foreach($listeduser in $listedusers)
			{
				$fname = $listeduser.Firstname
				$lname = $listeduser.LastName
				$dn = $listeduser.dn
				$dn = $dn.replace(":", ",")
				$enabled = $listeduser.enabled
				$logon = $listeduser.lastlogon
				$logonname = $listeduser.logonname
				$created = $listeduser.createddate

##########################################################
## Check for accounts in Holding OU that are still
## disabled and beyond the 30 holding limit and
## move them to the disabled OU
##########################################################
				if(($enabled -eq "DISABLED") -and ($created -lt $holdingdate) -and ($dn -like "*holding*"))
					{
						$logonname | Move-QADObject -NewParentContainer "pni.us.ad.gannett.com/$company/Users/Disabled" -WhatIf
						echo "$fname $lname $logonname" >> "c:\90-180\$company.disabled.txt"
					}

##########################################################
## Find any accounts that are disabled and not in the
## Holding OU and move them to the disabled OU
## This cleans up any accounts that have been disabled
## by hand and not moved to the disabled OU.
##########################################################
				if(($enabled -eq "DISABLED")-and ($dn -notlike "*holding*"))
					{
						$logonname | Move-QADObject -NewParentContainer 'some.root.com/$company/Users/Disabled' -WhatIf
						echo "$fname $lname $logonname" >> "c:\90-180\$company.disabled.txt"
					}

##########################################################
## Check for accounts not in holding OU that are beyond
## the 90 day limit for login and create date
## and disable them and move them to the disabled OU.
##########################################################
				if(($enabled -eq "ENABLED") -and ($logon -lt $disabledate) -and ($created -lt $disabledate) -and ($dn -notlike "*Holding*"))
					{
						$logonname | Disable-QADUser -WhatIf
						$logonname | Move-QADObject -NewParentContainer "some.root.com/$company/Users/Disabled" -WhatIf
						echo "$fname $lname $logonname" >> "c:\90-180\$company.disabled.txt"
					}

			}
		}
}

##########################################################
## function Get_Disabled_Accounts
## Search only the disabled OU for all disabled accounts
## Get the Last Login time and the Created Date so we
## can determine if the account should be removed from
## the domain.
##########################################################
function Get_Disabled_Accounts
{

foreach($company in $companies)
{
Clear-Content "c:\90-180\$company.disabledou.csv"
echo "enabled, LogonName, firstname, lastname, dn, lastlogon, createddate" >> "c:\90-180\$company.disabledou.csv"

			$dcs = Get-QADComputer -ComputerRole DomainController

			$users = Get-QADUser -SizeLimit 0 -searchroot "some.root.com/$company/Users/Disabled"

			foreach($user in $users)
				{
					$lastlogon = $null
					foreach($dc in $dcs)
					{
						$dclogon = Get-QADUser -Service $dc.Name -SamAccountName $user.samaccountname | select lastlogon
						$dclogon = $dclogon.lastlogon.value

						if ($dclogon -ne $null)
							{
								if($lastlogon -lt $dclogon)
									{
										$lastlogon = $dclogon
									}
							}
					}
					if ($lastlogon -eq $Null)
						{
							$lastlogon = [datetime]::Now.AddDays(-500000)
						}

					$o = New-Object PSObject
					$o | Add-Member NoteProperty "User" $user.Name
					$o | Add-Member NoteProperty "LastLogin" $lastlogon
					$o | Add-Member NoteProperty "DisplayName" $user.DisplayName
					$o | Add-Member NoteProperty "Disabled" $user.accountisdisabled
					$o | Add-Member NoteProperty "DistinguishedName" $user.DN
					$o | Add-Member NoteProperty "Created" $user.CreationDate
					$o | Add-Member NoteProperty "SamAccountName" $user.SamAccountName
					$o | Add-Member NoteProperty "LastName" $user.LastName
					$o | Add-Member NoteProperty "FirstName" $user.FirstName
					$o | Add-Member NoteProperty "Groups" $user.MemberOf

					if($o.disabled -eq "False")
						{			$enabled = "DISABLED"}
					else
						{			$enabled = "ENABLED"}
					$Fname = $o.FirstName
					$lname = $o.LastName
					$lastlogon = $o.LastLogin
					$created = $o.Created
					$samname = $o.samaccountname
					$dn = $o.DistinguishedName
					$dn = $dn.replace(",", ":")
					$groups = $o.groups

					echo "$enabled, $samname, $fname, $lname, $DN, $lastlogon, $created" >> "c:\90-180\$company.disabledou.csv"
					if($groups -ne $null)
						{
							if(($lastlogon -lt $deletedate) -and ($created -lt $deletedate))
								{
									echo $groups >> "c:\90-180\$samname.groups.txt"
								}
						}

				}

		}
}
##########################################################
## Function Delete_Accounts
## Find all acounts that are in the disabled OU's and
## determine what accounts have not been loged in with
## in over 180 days and also were created over 180 days
## ago. Once the accounts have been identified capture
## Users login name so that we can remove all groups
## from that user as well as move the users H: Drive
## folder to the K drive to await deletion.
##########################################################
function Delete_Accounts
{
	foreach($company in $companies)
		{
		Echo "Delete accounts for $company"
			$listedusers = Import-Csv "c:\90-180\$company.disabledou.csv"
			Clear-Content "c:\90-18\$company.deleted.txt"
			foreach($listeduser in $listedusers)
			{
				$fname = $listeduser.Firstname
				$lname = $listeduser.LastName
				$dn = $listeduser.dn
				$dn = $dn.replace(":", ",")
				$enabled = $listeduser.enabled
				$logon = $listeduser.lastlogon
				$logonname = $listeduser.logonname
				$created = $listeduser.createddate

##########################################################
## Check for accounts that have not been used and were
## created more than 180 days ago. If found then remove
## all groups, remove from domain, log removal from
## domain and move H: Drive to holding area.
##########################################################
				if(($created -lt $deletedate) -and ($logon -lt $deletedate))
					{
##########################################################
## Gather all groups that the user is a member of
## and loop thru all groups to remove the user.
##########################################################
						if(Test-Path "c:\90-180\$logonname.groups.txt")
						{
							$groups = Get-Content "c:\90-180\$logonname.groups.txt"
							foreach($group in $groups)
							{
								Remove-QADGroupMember -Identity $group -Member $logonname -whatif
							}
							#rm "c:\90-180\$logonname.groups.txt"
						}

##########################################################
## Remove the User Object and log the removal
##########################################################
						Remove-QADObject $logonname -whatif
						echo "$fname $lname $logonname" >> "c:\90-180\$company.deleted.txt"

##########################################################
## Check to see if the user has an H: Drive
## If the folder exists then move it to the K: Drive
## to hold until the time limit to delete the folder
##########################################################
						if(Test-Path "\\someserver\yourhomedrives\$logonname")
						{
							move-item -literalPath "\\someserver\yourhomedrives\$logonname" -destination "\\someserver\_term\$logonname" -whatIf
							Echo "Moved \\someserver\yourhomedrives\$logonname to \\pni-pcfs01\data\common\_term\$logonname" >> "c:\90-180\homedirs.txt"
						}
						else
						{
							Echo "NO H Drive found for $logonname" >> "c:\90-180\homedirs.txt"
						}
					}

				}
			}
}
##########################################################
## Email all Log files about disabled and deleted
## accounts to  someaccount at domain.com
##########################################################
function Mail
{
$file1 = "c:\90-180\file1.Disabled.txt"
$file2 = "c:\90-180\file2.Disabled.txt"
$file3 = "c:\90-180\file3.Disabled.txt"
$file4 = "c:\90-180\file1.Deleted.txt"
$file5 = "c:\90-180\file2.Deleted.txt"
$file6 = "c:\90-180\file3.Deleted.txt"

$smtpServer = "somemailhost"
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$msg = New-Object Net.Mail.MailMessage

##########################################################
## Test for Attachment files. If the file is not
## available then do not create the attachment object
##########################################################
if(Test-Path $file1)
{$att1 = New-Object Net.Mail.Attachment($file1)}
if(Test-Path $file2)
{$att2 = New-Object Net.Mail.Attachment($file2)}
if(Test-Path $file3)
{$att3 = New-Object Net.Mail.Attachment($file3)}
if(Test-Path $file4)
{$att4 = New-Object Net.Mail.Attachment($file4)}
if(Test-Path $file5)
{$att5 = New-Object Net.Mail.Attachment($file5)}
if(Test-Path $file6)
{$att6 = New-Object Net.Mail.Attachment($file6)}

$msg.From = "90-180Audit@pni.com"
$msg.To.Add("somemail@domain.com")
$msg.Subject = "Disabled and Deleted Domain Accounts"
$msg.Body = "Attached are files with names of disabled and deleted accounts."

##########################################################
## Test if the file is available again. If so then
## create the attachment.
##########################################################
if(Test-Path $file1)
{$msg.Attachments.Add($att1)}
if(Test-Path $file2)
{$msg.Attachments.Add($att2)}
if(Test-Path $file3)
{$msg.Attachments.Add($att3)}
if(Test-Path $file4)
{$msg.Attachments.Add($att4)}
if(Test-Path $file5)
{$msg.Attachments.Add($att5)}
if(Test-Path $file6)
{$msg.Attachments.Add($att6)}

$smtp.Send($msg)
$att1.Dispose()
$att2.Dispose()
$att3.Dispose()
$att4.Dispose()
$att5.Dispose()
$att6.Dispose()
}

##########################################################
## Main
## Set up variables and call functions of script.
##########################################################
$ErrorActionPreference = "SilentlyContinue"
$starttime = [datetime]::Now
echo "Start 90-180 Script run at $starttime" >> "c:\90-180\90-180.log"
$holdingdays = -30
$disabledays = -90
$deletedays = -180
$disabledate = [datetime]::Now.AddDays($disabledays)
$deletedate = [datetime]::Now.AddDays($deletedays)
$holdingdate = [datetime]::Now.AddDays($holdingdays)
$companies = "PNI", "AMG", "GPP"
clear-content "c:\90-180\homedirs.txt"
#echo "calling Get_Users"
Get_Users
#echo "calling Disable_Acconts"
Disable_Accounts
#Echo "Calling Get Disabled Accounts"
Get_Disabled_Accounts
#Echo "Calling Delete_Accounts"
Delete_Accounts
#Echo "Calling Mail"
Mail
$endtime = [datetime]::Now
echo "End 90-180 Script run at $endtime" >> "c:\90-180\90-180.log"
echo "#################################`n" >> "c:\90-180\90-180.log"


Oct 20 2009   6:48PM GMT

AD Audit Script Q and A



Posted by: Colin Smith
Powershell, Q and A, AD, AD Administration, AD Managment, Scripting

I got the following comment on Part 3 of the script.
RobDolfijn

Hi Colin,

This is just what I need so I’m looking forward to the whole script!
I’m getting stuc on Get_Users because it is not recognized as a cmdlet, please help me?

So I am not sure how you have it set up but I think I have an idea of what is going on. One of two things.

1. You have the function below the main part of the script that calls the function. The function has to be before the main part of the script so that Powershell knows about the function.

2. The other thing is that you do not have the function defined in the {} brackets.

My assumption here is that the first thing is the issue. The Powershell ‘Engine’ looks for the function definitions before the function is called. It seems strange but that is how it works in many languages. So just make sure that you put all the functions above the function call and you should be good. Hope that this helps. Please let me know if you have any issues.


Oct 20 2009   4:45PM GMT

AD Audit in Powershell Script Part 6



Posted by: Colin Smith
Powershell, AD Administration, AD, AD Managment, Scripting

As i recall, in Part 5 we had gathered all the account information, parsed that, disabled accounts that needed to be disabled, gathered information on all the disabled accounts, and removed the accounts from the domain that needed to be as well as documented that we did so. Now that leaves me with needing to accomplish one more thing. My business would like to have certain people notified about the account changes that have taken place. This is where the Mail function comes into play. Below is the code that I execute to send email when needed.



function Mail { $file1 = "c:\90-180\file1.Disabled.txt" $file2 = "c:\90-180\file2.Disabled.txt" $file3 = "c:\90-180\file3.Disabled.txt" $file4 = "c:\90-180\file1.Deleted.txt" $file5 = "c:\90-180\file2.Deleted.txt" $file6 = "c:\90-180\file3.Deleted.txt" $smtpServer = "mailhost" $smtp = New-Object Net.Mail.SmtpClient($smtpServer) $msg = New-Object Net.Mail.MailMessage ########################################################## ## Test for Attachment files. If the file is not ## available then do not create the attachment object ########################################################## if(Test-Path $file1) {$att1 = New-Object Net.Mail.Attachment($file1)} if(Test-Path $file2) {$att2 = New-Object Net.Mail.Attachment($file2)} if(Test-Path $file3) {$att3 = New-Object Net.Mail.Attachment($file3)} if(Test-Path $file4) {$att4 = New-Object Net.Mail.Attachment($file4)} if(Test-Path $file5) {$att5 = New-Object Net.Mail.Attachment($file5)} if(Test-Path $file6) {$att6 = New-Object Net.Mail.Attachment($file6)} $msg.From = "90-180Audit@pni.com" $msg.To.Add("somemail@host.com") $msg.Subject = "Disabled and Deleted Domain Accounts" $msg.Body = "Attached are files with names of disabled and deleted accounts." ########################################################## ## Test if the file is available again. If so then ## create the attachment. ########################################################## if(Test-Path $file1) {$msg.Attachments.Add($att1)} if(Test-Path $file2) {$msg.Attachments.Add($att2)} if(Test-Path $file3) {$msg.Attachments.Add($att3)} if(Test-Path $file4) {$msg.Attachments.Add($att4)} if(Test-Path $file5) {$msg.Attachments.Add($att5)} if(Test-Path $file6) {$msg.Attachments.Add($att6)} $smtp.Send($msg) $att1.Dispose() $att2.Dispose() $att3.Dispose() $att4.Dispose() $att5.Dispose() $att6.Dispose() }

first I define all 6 of the files that I may or may not want to attach to the email. Then I set up the SMTPserver and the mail objects. Now I test for each of the files that I may or may not want to attach. I only want to attach the file if the file exists. This way I do not get errors about files not being on the filesystem and I am not sending blank files to the people that need the information.
I then define who the message is from, who it is to, subject, and the body. Now that we have that I have to start attaching the files. After attaching the files that are needed I send the message and then close all the attachments just to make sure that no handles keep the files open. I want to be able to delete the files later.

Well that is it. Next post will have the script in its entirety so that you do not have to cut and paste so much. Hope all this helps you out. Let me know if you have any questions about any part of this script.