Friday, January 06, 2006

Windows VBS Automated Maintenance Scripts

I had a need to automate a number of tasks for remote administration, and used Visual Basic Scripting and Windows Scripting Host Objects, since I am fairly comfortable with VB/VBA.

This is an automated defragmentation script that uses dirms.exe, a defragmentation utility found here.

Option Explicit

Dim FSO, Drive, oShell, WshShell, BtnCode, rtn, hd, stComp
Set WshShell = WScript.CreateObject("WScript.Shell")
Set FSO = CreateObject("Scripting.FileSystemObject")

Set oShell = WScript.CreateObject ("WScript.shell")
'''' ''''''''''''''''''' DIRMS.EXE USAGE
' dirms c -q : Do free space evaluation, defragment, and quickly move files to the front of the drive
' dirms c DEFRAG -q : Defragment files only
' dirms c CoMpAcT -q : C ompact only
' dirms c COMFRAG -q : Perform partial compaction (quickly) on all fragmented files
' dirms c COMFRAG c:\filename.exe : Perform partial compaction on one file
' dirms c move date -q : Move files according to modification dates, and do it quickly

' dirms c move lcn : Try to free space at the bottom of the drive (moves files toward the front of the drive)
'''''''''''''''''''''''''''''''''''''''''''''''

' This sets the drive type to look for to Fixed

Const constFixed = 2
' enumerate all drives

For Each Drive in FSO.Drives

If Drive.DriveType = constFixed Then
hd = LCase(Left(Drive, 1))
stComp = StrComp("M", hd, 1) ' Returns 0 if the M drive.
' Only run if not the IFS drive

If stComp = 1 Then
' Ask the user nicely...

BtnCode = WshShell.PopUp("pcTech needs to degragment your " & Drive & " hard drive[s]. Is that OK?", 60, "pcTech", 4 + 32)
Select Case BtnCode
' Show an OK (1) or Cancel (2) button
Case 6 rtn = WshShell.PopUp("Thanks, please don't turn your PC off for 24 hours.", 5, "pcTech", 1)
If rtn = 1 Then

'do nothing
ElseIf rtn = 2 Then
Exit For
MsgBox "Defrag cancelled", 0, "pcTech"
End If
Case 7 rtn = WshShell.PopUp("Ok, we'll wait until the next time.", 5, "pcTech", 0)

End Select

Select Case ShowFileSystemType(Drive)
Case "NTFS"
' Run NTFS defrag
oShell.run "cmd /c c:\temp\dirms.exe " & hd & " -q > c:\temp\defrag_" & hd & "_hdd.txt", 0

Case "FAT"
' Run FAT defrag, yes I know, it's the same command, but I was hoping
' to find a win95 cli defrag util to use in it's place...
oShell.run "cmd /c c:\temp\dirms.exe " & hd & " -q > c:\temp\defrag_" & hd & "_hdd.txt", 0
Case "CDFS"

' Do nothing, it's a CD
Case Else
' Shit, can't defrag? We should never get this far...
BtnCode = WshShell.Popup("pcTech found no drives to defragment.", 15, "pcTech", 0 + 16)
End Select
'end of stComp check

End If

' end of Fixed Drive check
End If
Next

Set oShell = Nothing
Set FSO = Nothing
Set WshShell = Nothing

Function ShowFileSystemType(drvspec)
Dim FSO,d

Set FSO = CreateObject("Scripting.FileSystemObject")
Set d = FSO.GetDrive(drvspec)
ShowFileSystemType = d.FileSystem
End Function

This is a script that uses SpyBot to remove spyware. There was an ability to retrieve the Stats.ini file from the machine, and populate a SQL db for reporting purposes.

Option Explicit

Set objFSO = CreateObject("Scripting.FileSystemObject")

' Set the type of file access
Const ForReading = 1, ForWriting = 2, ForAppending = 8

' Set our input file
'Determine what our OS version is, since it is dependant on gathering statistics and placement of files
' Per this page that says our configuration.ini file is found in different places as noted below.
' http://www.spybot.info/pt/faq/23.html
'For Windows 95/98, the file is located in C:\Windows\Application Data\Spybot - Search & Destroy\.
'For Windows ME, the file is located in C:\Windows\All Users\Application Data\Spybot - Search & Destroy\.
'For Windows NT/2000/XP, you will find it in C:\Documents and Settings\All Users\Application Data\Spybot - Search & Destroy\.


Select Case GetOS
Case "0"
objINFile = "C:\Windows\Application Data\Spybot - Search & Destroy\Statistics.ini "
Case "4.9"
objINFile = "C:\Windows\All Users\Application Data\Spybot - Search & Destroy\Statistics.ini"
Case Else
objINFile = "C:\Documents and Settings\All Users\Application Data\Spybot - Search & Destroy\Statistics.ini"
End Select

' Set our output file and it's location
objOUTFile = "C:\Temp\Stats.ini"

' If our output file doesn't exist, create it, if it does, delete and create
If Not objFSO.FileExists(objOUTFile) Then
Set fso = CreateObject("Scripting.FileSystemObject")
Set f1 = fso.CreateTextFile(objOUTFile, True)
Set fso = Nothing
Set f1 = Nothing
ElseIf objFSO.FileExists(objOutFile) Then
Set fso = CreateObject("Scripting.FileSystemObject")
fso.DeleteFile objOUTFile
Set f1 = fso.CreateTextFile(objOUTFile, True)
Set fso = Nothing
Set f1 = Nothing
End If

' Move our configuration.ini file to it's proper location
Select Case GetOS
Case "0"
objConfPath = "C:\Windows\Application Data\Spybot - Search & Destroy\"
Case "4.9"
objConfPath = "C:\Windows\All Users\Application Data\Spybot - Search & Destroy\"
Case Else
objConfPath = "C:\Documents and Settings\All Users\Application Data\Spybot - Search & Destroy\"
End Select

' Now that our configuration path is set, copy the configuration.ini to it
' Use Error handling to ignore the absence of a configuration.ini

On Error Resume Next
FileSystemObject.CopyFile "C:\temp\Configuration.ini", objConfPath, True

'Open file for reading
Set objIFile = objFSO.OpenTextFile(objINFile, 1)

' Open file for writing
Set objOFile = objFSO.OpenTextFile(objOUTFile, 8)

Do Until objIFile.AtEndOfStream
strNextLine = objIFile.Readline
'grab the first charachter on the line

strFinder = Left(strNextLine, 1)

If strFinder = "[" Then 'we found our header descriptor
strDescription = Left(strNextLine, Len(strNextLine))

' decend into the list
'we know this one is LastFound date, and we don't care
strLastFound = objIFile.Readline

'we know this one is CountFound, again we don't care for this script
strCountFound = objIFile.Readline

'this one could be blank, or could be LastRemoved, which we need to know
strLastRemoved = objIFile.Readline

If strLastRemoved = "" Then
' This is a blank line, and we need to go throught the loop again
' so do nothing

Else
' it's not a blank line, it's our LastRemoved line and we don't care
' but we need to get to the next line
strCountRemoved = objIFile.Readline

intLen = Len(strCountRemoved)
intEq = InStr(strCountRemoved, "=")
intData = intLen - intEq
intTotal = Right(strCountRemoved, intData)

strLine = strDescription & "=" & intTotal & vbCrlf
'WScript.Echo strLine

objOFile.WriteLine strLine
End If

End If
Loop


objIFile.Close
objOFile.Close
'now delete our original statistics.ini

Set fso = CreateObject("Scripting.FileSystemObject")
fso.CreateTextFile objINFile
Set fso = Nothing


Function GetOS()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Determines OS by reading reg val & comparing to known values
' OS version number returned as:
' Windows 9X: 0
' Windows NT4: 4
' Windows ME: 4.9

' Windows 2k: 5
' Windows XP: 5.1
' Windows 2003: 5.2
' Windows x: >5.2
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim oShell, sOStype, sOSversion, GetOsVersionNumberReg
Set oShell = CreateObject("Wscript.Shell")


'On Error Resume Next

sOStype = oShell.RegRead(_
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ProductOptions\ProductType")
If Err.Number<>0 Then
' Hex(Err.Number)="80070002"
' - Could not find this key, OS must be Win9x
Err.Clear
GetOsVersionNumber = 0
Exit Function

End If


GetOsVersionNumberReg = oShell.RegRead(_
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentVersion")
If Err.Number<>0 Then
GetOsVersionNumber = "Unknown NTx"
' Could not determine NT version
Exit Function

End If

SetLocale "en-us" ' do not remove
GetOsVersionNumber = CSng(GetOsVersionNumberReg)
If GetOsVersionNumber > 49 Then
GetOsVersionNumber = CSng(Replace(GetOsVersionNumberReg, ".", ","))
End If

GetOS=GetOsVersionNumber
End Function

This was a quickie script to run executable files silently, so as not to alert the user.

'///////////////////////////////////////////////////
'
' Use this script to hide any .exe, .com, .bat, etc.
' from popping up a cmd window. Run in the same directory
' as the executable does not require passing a path.
'
' Keep in mind that if you DO have to pass a path, that
' you enclose ANY spaces in quotations, or use old
' skool DOS charachters to represent Long FileNames,
' like progra~1 for Program Files...
'
'///////////////////////////////////////////////////

Dim oShell
Set oShell = WScript.CreateObject ("WScript.shell")

Set colNamedArguments = WScript.Arguments.Named

If Not colNamedArguments.Exists("FileName") Then
Wscript.Echo "Usage: RunCmdFile /FileName: is required."
Wscript.Quit
End If

oShell.run("%comspec% /c " & FileName),0

Set oShell = Nothing

This is a script to change a service account that a group of consultants use for administering domains.

' Create the user. If it exists, change the password
' Object Class Naming attribute
' user cn (Common Name)
' group cn (Common Name)
' computer cn (Common Name)
' container cn (Common Name)
' organizational unit ou (Organizational Unit)

' domain dc (Domain Component)
' --------------------------------------------------------------'
Option Explicit
Dim oOU, oUser, oRoot, oContainer, oSContainer, oContents, oGroup
Dim sContainer, sDomain, sPassword, bFound, sUser, oMyBusiness

sPassword = "mYwAcKyPaSs"
sUser = "consultant"
bFound = "no"
' Bind to Active Directory Domain

On Error Resume Next
Set oRoot = GetObject("LDAP://RootDSE")
If Err.Number <> 0 Then

On Error GoTo 0
' WScript.Echo "No domain found, this is a workstation."

Dim oShell
Set oShell = WScript.CreateObject ("WSCript.shell")
oShell.Run "net user techworks " & sPassword & " /ADD", 0
oShell.Run "net localgroup Administrators techworks /ADD", 0

Set oShell = Nothing

WScript.Quit
End If

sDomain = oRoot.Get("DefaultNamingContext")



Set oContents = GetObject("LDAP://" & sDomain)

For Each oContainer in oContents
' WScript.Echo oContainer.Name
'see if this is an SBS box

If oContainer.Name = "OU=MyBusiness" Then
' WScript.Echo "This might be an SBS box.."

Set oMyBusiness = GetObject("LDAP://" & oContainer.Name & "," & sDomain)
For Each oSContainer in oMyBusiness
If oSContainer.Name = "OU=Users" Then
sSContainer = "OU=SBSUsers,OU=Users,OU=MyBusiness," & sDomain

Set oOu = GetObject("LDAP://" & sSContainer)
For Each oUser in oOU
If oUser.Name = "CN=consultant" Then
bFound = "yes"
' WScript.Echo "Found techworks in " & sSContainer

oUser.SetPassword sPassword
oUser.SetInfo
WScript.Quit
End If
Next
End If
Next
End If


If "CN=Users" Then
' WScript.Echo "This is not an SBS box."
sContainer=oContainer.Name
Set oOU = GetObject("LDAP://" & sContainer & ", " & sDomain)
For Each oUser in oOU

If oUser.Name = "CN=consultant" Then
bFound = "yes"
' WScript.Echo "Found user in " & sContainer
oUser.SetPassword sPassword
oUser.SetInfo
WScript.Quit
End If
Next
End If

Next

Set oOU = Nothing
Set oContents = Nothing

If bFound = "no" Then

Set oContainer = GetObject("LDAP://CN=Users," & sDomain)
' Build the actual User.
Set oUser = oContainer.Create("User", "CN=" & sUser)
Set oGroup = GetObject("LDAP://CN=Administrators,CN=Builtin," & sDomain)
oUser.Put "sAMAccountName", sUser
oUser.Put "userPrincipalName", sUser
' This will trap an error if the user exists somewhere we
' didn't check

On Error Resume Next
oUser.SetInfo
If Err.Number <> 0 Then
On Error GoTo 0

' debug
' WScript.Echo "This user exists somewhere outside normal CN containers."
' WScript.Echo "You will have to find it and change it manually."
WScript.Quit
End If

' re-use this variable to store the user path, and set the password

Set oUser = Nothing

Set oUser = GetObject("LDAP://CN=" & sUser & ",CN=Users," & sDomain)
oUser.SetPassword sPassword
oGroup.Add(oUser.ADsPath)

' give him info

oUser.Put "givenName", "Consultant"
oUser.Put "sn", "INC"
oUser.Put "displayName", "Consultant Group, INC"
oUser.Put "telephoneNumber", "(555) 555-5555"
oUser.Put "mail", "info@consultantgroup.com"
oUser.Put "wWWHomePage", "http://www.consultantgroup.com"
' enable the account

oUser.AccountDisabled = FALSE
oUser.SetInfo

End If

WScript.Quit

No comments: