Retrieving Password from Application Pool

I came across an undoc­u­ment­ed app the oth­er day. For a num­ber of rea­sons, we need­ed to restore the pass­word but it was­n’t doc­u­ment­ed any­where. Luck­i­ly, the ser­vice account was set­up in an app pool. In IIS 7.0 or 7.5, APPCMD can be used to recov­er the pass­word. In 6.0, adsutil.vbs can be used.

cscript.exe /nologo adsutil.vbs GET W3SVC/AppPools/AppPoolName/WAMUserPass

How­ev­er, I want­ed to write my own lit­tle script. Hav­ing a lit­tle tid­bit makes it easy to reuse lat­er for oth­er clients. For exam­ple, I could search AD for SPNs start­ing with “HTTP”, loop through each of their app pools and doc­u­ment the user­name and pass­words for all ser­vice accounts used in this fash­ion. So, here is the lit­tle tid­bit I threw togeth­er.

Option Explicit

Call GetAppPoolUserAndPass("localhost", "ApplicationPoolName")

Private Sub GetAppPoolUserAndPass (byVal strComputer, byVal strAppPool)
	Dim appPool
	On Error Resume Next
	Set appPool = GetObject("IIS://" & strComputer & "/w3svc/AppPools/" & strAppPool)
	If Err Then
		wscript.echo "Error connecting to " & chr(34) & strAppPool & chr(34) & " on " & strComputer
	Else
		wscript.echo strAppPool & vbTab & appPool.WAMUserName & vbTab & appPool.WAMUserPass
	End If
	On Error GoTo 0
End Sub

Here is an exam­ple of just what I men­tioned above. YMMV but this should dis­cov­er IIS box­es and report all the accounts used in their app pools. Note: Pools using built-in accounts will show up with blank pass­words; this is nor­mal; the pass­word isn’t actu­al­ly blank.

Option Explicit

' Determine DNS domain name.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")

' Determine DNS domain name.
Dim objRootDSE, strDNSDomain
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")

' Use ADO to search Active Directory.
Dim adoCommand, adoConnection
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection

' Build Query
Dim strBase, strFilter, strAttributes, strQuery
strBase = ""
strFilter = "(servicePrincipalName=HTTP*)" 'Search for SPN starting w/ HTTP (case insensitive)
strAttributes = "name"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False

Dim adoRecordset
Set adoRecordset = adoCommand.Execute

If (adoRecordset.EOF = True) Then
    Wscript.Echo "No SPNs Found matching HTTP*"
    Wscript.Quit
End If

Wscript.Echo "Computer Name" & vbTab & "AppPool Name" & vbTab & "User Name" & vbTab & "User Password"

Do Until adoRecordset.EOF
    Call GetApplicationPools(adoRecordset.Fields("name").Value & "." & strDNSDomain)
    adoRecordset.MoveNext
Loop
adoRecordset.Close

' Clean up.
adoConnection.Close

Private Sub GetApplicationPools (byVal strComputer)
	Dim objWMIService, colItems, objItem
	
	On Error Resume Next
	Set objWMIService = GetObject("winmgmts:{authenticationLevel=pktPrivacy}\" & strComputer & "rootmicrosoftiisv2")
	Set colItems = objWMIService.ExecQuery("Select * from IIsApplicationPoolSetting")
	If Err Then
		wscript.echo "Error connecting to " & strComputer
	Else
		For Each objItem in colItems
			Wscript.Echo strComputer & vbTab & objItem.Name & vbTab & objItem.WAMUserName & vbTab & objItem.WAMUserPass
		Next
	End If
End Sub

The Power of Scripting: Finding Morto.A

Here I go on anoth­er vbScript tuto­r­i­al.  You might ask why I’m not doing this in pow­er­shell yet and it is sim­ple: I still run into 2003 and XP envi­ron­ments. Oh yeah, and this works. I don’t care what script­ing lan­guage I’m writ­ing in if it gets the job done; you should­n’t either. My $0.02. If you want to down­load this script, click here: Morto.A Detec­tion Script.

A had to do a lit­tle cleanup on a net­work from the Morto.A worm.  The first thing I want­ed to do was find out how bad things were.  They were report­ing a DDOS across their LAN (most­ly 3389) and a lot of oth­er issues.  It as obvi­ous we were going to need to rebuild a few sys­tems but we want­ed to get a grasp out of what the dam­age was.  This were gen­er­al­ly work­ing: logons, shares, etc.

I’m not going to go over what we did on the fire­wall or local net­work but dis­cuss a quick script I threw togeth­er to scan the net­work for infect­ed sys­tems.  The trick was this net­work had mul­ti­ple domains and sev­er­al com­put­ers that weren’t even domain joined.

So, I put my automa­tion hat on and threw togeth­er a script I will out­line below.  I split this into sec­tions to help you see how you can use script­ing to piece togeth­er a com­pli­cat­ed job in sim­ple tasks.  It is pret­ty basic.  I start by defin­ing what I want to do:

Prob­lem state­ment: I need to check every com­put­er in each domain for infec­tion of the Morto.A worm.  I can split this into three dis­tinct steps:

  1. For Each Domain
  2. Get Each Com­put­er
  3. Check for Morto.A

For Each Domain

This is pret­ty sim­ple.  There are advanced tech­niques for find­ing all the domains in a for­est or read­ing from a text file or even a spread­sheet.  I like to keep it sim­ple and just cre­ate an array.

Dim arrDomains
arrDomains = Array("domain1.domain.local", "domain2.domain.local", "domain3.domain.local")
For Each Domain in arrDomains
	Call ComputersAll(Domain)
Next

Get Each Computer

Now, I need to build the “Com­put­er­sAll” sub-rou­tine.  I call this in the domain script by pass­ing each domain in DNS for­mat.  I used DNS domains in my exam­ple on pur­pose (you could use the Dis­tin­guished­Name for­mat “dc=domain1,dc=domain,dc=local” but I pre­fer DNS names for this pur­pose).  By default, each com­put­er in that domain is going to reg­is­ter itself in DNS (assum­ing you set it up prop­er­ly).  I want to get the com­put­er name out of AD and append the dns domain name.  Once that is done, I want to use my “IsCon­nectible” script to check and make sure it is online.  If it pings, I should be able to car­ry out my busi­ness and find out if it is infect­ed.

The real mag­ic is in the lines: str­Base, strAt­trs and str­Fil­ter.  str­Base sets the search base to the domain you sent the sub-rou­tine.  It isn’t going to go out­side this domain for its search but it will search the whole domain due to its use of sub­tree.  The search a spe­cif­ic OU, you have to use the DN for­mat and that is out of scope of this arti­cle.  The strAt­trs is pret­ty straight for­ward.  This is an array of attrib­ut­es you want returned.  You could do DNS­Do­main­Name but some clients set this improp­er­ly.  It is safe to assume (in most cas­es) that the name and the domain name com­prise the DNS domain name.  The str­Fil­ter isn’t doing much but may look com­plex.  Basi­cal­ly, it is look­ing for com­put­ers in AD that aren’t dis­abled.

The oth­er things to pay atten­tion to is the line after

Do Until ADORecordSet.EOF

.  This checks first if the com­put­er is on the net­work through my “IsCon­nectible” script.  It pass­es the FQDN by append­ing “.” and the domain name to the name attribute from the query.

Const adUseClient = 3
Private Sub ComputersAll(byVal strDomain)
	Set adoCommand = CreateObject("ADODB.Command")
	Set adoConnection = CreateObject("ADODB.Connection")
	adoConnection.Provider = "ADsDSOObject"
	adoConnection.cursorLocation = adUseClient
	adoConnection.Open "Active Directory Provider"
	adoCommand.ActiveConnection = adoConnection

	strBase   =  ";"
	strFilter = "(&(objectClass=computer)(!userAccountControl:1.2.840.113556.1.4.803:=2));"
	strAttrs  = "name;"
	strScope  = "subtree"
	strQuery = strBase & strFilter & strAttrs & strScope
	adoCommand.CommandText = strQuery
	adoCommand.Properties("Page Size") = 5000
	adoCommand.Properties("Timeout") = 30
	adoCommand.Properties("Cache Results") = False

	Set adoRecordset = adoCommand.Execute

	If adoRecordset.RecordCount > 0 Then
		' wscript.echo "Computers for " & strDomain & ": " & adoRecordset.RecordCount
		' Loop through every single computer in the domain
		adoRecordset.MoveFirst
		Do Until adoRecordset.EOF
			If IsConnectible(adoRecordset.Fields("name").Value & "." & strDomain) = "Online" Then Call DetectMorto(adoRecordset.Fields("name").Value & "." & strDomain)
			adoRecordset.MoveNext
		Loop
	End If
	adoRecordset.Close
	adoConnection.Close
End Sub

Check For Morto.A

This is the tricky part. I used sev­er­al sources and found two dis­tict char­ac­ter­isitcs of this work:

  1. C:windowssystem32sens32.dll
  2. HKLM­Sys­temW­PA
    1. Key: sr
    2. Val­ue: Sens

So, I need to check and see if a file and reg­istry key exists in order to detect if the machine is infect­ed.  There are a cou­ple of caveats with this: 1) when check­ing if a file exists, the default response is true on error, 2) you need local admin rights to query the c$ share, and 2) the reg­istry check relies on the remote reg­istry ser­vice.  To over­come these caveats, we put error check­ing in.  If an error occurs, it assumes a man­u­al check is need­ed.  We do this to err on the side of cau­tion.  Of course, on a large net­work, this isn’t desir­able.  Feel free to con­tact me if you need more advanced help.  Here is the sub-rou­tine I came up with to do all of the above.  It is mean and nasty and isn’t exact­ly the kind of finesse I pre­fer but, it works…

First, I try writ­ing a temp file (and delet­ing it if it suc­ceeds). If that works, I should be able to detect if the file exists and con­nect to the remote reg­istry. How­ev­er, per­haps you are an admin that is para­noid and dis­ables the remote reg­istry ser­vice. Well, it will still detect an error and tell you to check man­u­al­ly. Of course, if you don’t have admin rights, it will also tell you to check remote­ly.

Private Sub DetectMorto(byVal strComputer)
	' Detects morto via several methods...
	Dim blnInfected : blnInfected = False
	
	
	' Requires admin rights to properly detect. Check for rights
	Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
	On Error Resume Next
	Dim TempFile : Set TempFile = objFSO.CreateTextFile("\" & strComputer & "c$WINDOWStempfile.deleteme", True)
	TempFile.WriteLine("This is a test.")
	TempFile.Close
	Set TempFile = Nothing
	objFSO.DeleteFile("\" & strComputer & "c$WINDOWStempfile.deleteme")	
	If Err Then bnlInfected = "Error"
	Err.Clear
	On Error GoTo 0
	
	' Check for registry key placed by Morto...
	Dim strKeyPath, strEntryName, objReg, strValue
	strKeyPath = "SYSTEMWPA"
	strEntryName = "sr"
	On Error Resume Next
	Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\" & strComputer & "rootdefault:StdRegProv")
	objReg.GetStringValue HKEY_LOCAL_COMPUTER, strKeyPath, strEntryName, strValue

	If Err Then blnInfected = "Error"
	If strValue = "Sens" Then blnInfected = True
	
	' Check for file indicating morto infection
	Dim strMortoSens32
	strMortoSens32 = "\" & strComputer & "c$WINDOWSsystem32Sens32.dll"
	If objFSO.FileExists(strMortoSens32) Then blnInfected = True
	
	' If the Infected flag is set, it is infected...
	If blnInfected = True Then
		wscript.echo "*******MORTO INFECTION: " & strComputer
	ElseIf blnInfected = "Error" Then
		wscript.echo "Error (Check Manually): " & strComputer
	Else
		wscript.echo "Clean: " & strComputer
	End If
End Sub

Conclusion

So, I have tak­en sev­er­al scripts and thrown them togeth­er to find a solu­tion. I can reuse this for any­thing. Per­haps I want to use vbscript to find com­put­ers with a cer­tain file on their hard dri­ve. I can reuse this by just tweak­ing the Mor­to sub-rou­tine.

IsConnectible: My vbScript Ping Method

When­ev­er I am doing large sweeps of the net­work that require con­nect­ing to a large num­ber of work­sta­tions (e.g. file copy, wmi query, etc.), I pre­fer to check to see if I can even see the sys­tem. This avoids wait­ing for (WMI) time­outs and also aids in trou­bleshoot­ing fail­ures. If the file copy failed, why? Well, if I can’t ping it or it can’t be resolved, I would like to know right away and move on to the next host.

Of course, there are a cou­ple down­sides to this method. It does add over­head to the script because it too has a time­out. How­ev­er, depend­ing on the pur­pose of the script, this may be accept­able for the flex­i­bil­i­ty you gain. The oth­er caveat is that the sys­tems you run this against must allow ICMP on their local fire­wall or the script will just ignore them and move on to the next host.

There are sev­er­al meth­ods for ping­ing hosts but I’ve found this to be the most reli­able since it works against any sys­tem that allows ICMP, even Lin­ux or Macs. This is adapt­ed from Richard Mueller’s ping script. This method will return three pos­si­ble val­ues: “Online”, “No Ping Reply”, or “No DNS/WINS Entry”. You can also tweak the ping com­mand options to your lik­ing.

Here is an exam­ple of how to call the func­tion:

Dim computers(2), computer, pingable
computers(0) = "pc-100.domain.local"
computers(1) = "pc-200.domain.local"
comptuers(2) = "pc-300.domain.local"
For Each computer In computers
	Select Case IsConnectible(computer)
		Case "Online"
			wscript.echo computer & " is online"
		Case "No Ping Reply"
			wscript.echo computer & " is offline or firewall blocks ICMP"
		Case "No DNS/WINS Entry"
			wscript.echo computer & " cannot be found in DNS/WINS"
		Case "Host Unreachable"
			wscript.echo computer & " is unreachable"
	End Select
Next

Here is the func­tion:

Private Function IsConnectible(ByVal strComputer)
	' Uses ping.exe to check if computer is online and connectible.
	' Adapted from http://www.rlmueller.net/Programs/Ping1.txt
	Dim objShell, objExecObject, strText
	Set objShell = CreateObject("Wscript.Shell")
	
	' use ping /? to find additional values for ping command; see -n and -w
	Set objExecObject = objShell.Exec("%comspec% /c ping -n 2 -w 750 " & strComputer)
	Do While Not objExecObject.StdOut.AtEndOfStream
		strText = strText & objExecObject.StdOut.ReadLine()
	Loop
	
	If InStr(strText,"could not find host") > 0 Then
		IsConnectible = "No DNS/WINS Entry"
	ElseIf (InStr(strText,"Reply from ") > 0) And (InStr(strText,": bytes=") > 0) Then
		IsConnectible = "Online"
	ElseIf InStr(strText,"Destination host unreachable") > 0 Then
		IsConnectible = "Host Unreachable"		
	Else
		IsConnectible = "No Ping Reply"
	End If
End Function

vbScript: Adding and Removing a Domain Group to a Local Group

Yes, I still use vbscript. Some­day, I’ll get to work in an envi­ron­ment where every­thing is upgrad­ed. Until then, I have to rely on the tried and true vbscript.

One of the most com­mon uses of a Group Pol­i­cy start­up script is for adding users to the local admin group. Just google it and you will find hun­dreds of scripts doing just that, batch files, posh, vbscript, perl, etc. I wrote the script below because I want­ed the flex­i­bil­i­ty to reuse this script at any client and for any group (not just Admin­is­tra­tors but Remote Desk­top Users or Pow­er Users).

The con­fig sec­tion takes three argue­ments: Action, str­Local­Group, str­Do­main­Group.

  • Action: Can be either “Add” or “Remove”. It will either add the domain group to the local group or remove it.
  • str­Local­Group: The name of the local group (e.g. Admin­is­tra­tors, Pow­er Users, etc.). I test­ed w/ all the stan­dard built-in groups.
  • str­Do­main­Group: The name of the domain group to add to the local group. Note: The work­sta­tion has to be a mem­ber of the same domain the group resides in.

Down­load the script (zipped): add-remove-domain-group-to-local-group

'======================================================
' VBScript Source File
' NAME: Add/Remove Domain Group to Local Group
' AUTHOR: Andrew J Healey
' DATE  : 2011.07.08
' COMMENT: Will add or remove the domain group specified 
'	  to/from the local group specified.
' USAGE: Modify the config section to match your env. 
'	The "Action" can be "Remove" or "Add"
'======================================================

Option Explicit
Dim strDomainGroup, strLocalGroup, Action

'--------- START CONFIG SECTION ---------
Action = "Add" ' or Remove
strLocalGroup = "Administrators"
strDomainGroup = "Local-Workstation-Admins"
'--------- END CONFIG SECTION ---------

' Enable error handling routine to ensure startup
' script doesn't throw error at users
On Error Resume Next

Dim strDomain, strComputer
Dim objNetwork, objLocalGroup, objDomainGroup

Set objNetwork = CreateObject("WScript.Network") 
strDomain = objNetwork.UserDomain
strComputer = objNetwork.ComputerName

Set objLocalGroup = GetObject("WinNT://" & _
		 strComputer & "/" & strLocalGroup) 
Set objDomainGroup = GetObject("WinNT://" & _
		 strDomain & "/" & strDomainGroup)

' Do Work
Select Case Action
	Case "Remove"
		objLocalGroup.Remove(objDomainGroup.ADsPath)
	Case "Add"
		objLocalGroup.Add(objDomainGroup.ADsPath)
End Select

' Clean up objects
Set objDomainGroup = Nothing
Set objLocalGroup = Nothing 
Set objNetwork = Nothing

vbScript: Tweaking Power Settings (disabling hibernate and standby)

As is often the case in IT, when you need to push out that soft­ware pack­age or migrate that com­put­er to a new domain, it isn’t on the net­work.  This has come up sev­er­al times in the past year and I want­ed to share my solu­tion.  Now, this isn’t the “green­est” solu­tion because this will ensure your clients nev­er go into a pow­er sav­ing mode.  How­ev­er, it can be a tem­po­rary fix for a project.  It can also be adapt­ed to force stand­by or hiber­nate at spe­cif­ic thresh­olds.

While Win­dows 7 and Vista make this task sim­ple, XP is still a real­i­ty in most enter­pris­es and SMB’s and there­fore, must be tak­en into account.  The script below does just that.  Some addi­tion­al exam­ples can be found at the US Gov­ern­men­t’s Ener­gy Star web­site.

Note: Copy­ing the script from the web­page may cause for­mat­ting issues.  You can down­load the script here: tweak-power-settings.vbs
Read More

.Net Classes within VBScript: Doing Randomness and Arrays the Easy Way

.Net and VBScript can play togeth­er
Back in 2007, the Microsoft Script­ing Guys post­ed a arti­cle titled “Hey, Script­ing Guy! Be Care­ful What You Say.” This arti­cle changed every­thing in the way I script­ed because it should how sim­ply you can access some .Net class­es through COM callable wrap­pers. The two they focus on are “System.Random” and “System.Collections.ArrayList”.
Set objRandom = CreateObject("System.Random")
Set objArrList = CreateObject("System.Collections.ArrayList")

Read More

vbScript: Quickly determine architecture

I’ve been using a rou­tine to deter­mine 64-bit v 32-bit work­sta­tions for some time check­ing the reg­istry for the PROCESSOR_ARCHITECTURE in the HKLM­SYS­TEM­Cur­rent­Con­trolSet­Con­trolSes­sion Man­agerEn­vi­ron­ment path. How­ev­er, this was prov­ing to be error prone. So, I just gave up that method alto­geth­er since all Win­dows x64 edi­tions have a “%SystemDrive%Program Files (x86)” direc­to­ry. This makes it just a quick and easy call the folderex­ists method of the filesys­te­mob­ject.

The only down­side is that can’t be used remote­ly but since most of my scripts are used in local poli­cies, this should­n’t be an issue.

Cheers!

Private Function is64bit()
	Dim filesys : Set filesys = CreateObject("Scripting.FileSystemObject")
	Dim bln64bit : bln64bit = False
	If filesys.FolderExists("C:Program Files (x86)") then bln64bit = True
	is64bit = bln64bit
End Function

Installing Java via Script and Group Policy

Due to some soft­ware require­ments, there was a need to get JRE 1.5.0_09 rolled out across our enter­prise. The require­ments were pret­ty straight for­ward:

  • Only install on client oper­at­ing sys­tems (Win­dows 2000, Win­dows XP, Win­dows Vista and Win­dows 7)
  • Detect the ver­sions of Java installed. If 1.5.0_09 is installed, exit.  If 1.5.0_08 or less was installed, install this ver­sion.  If it has a new­er ver­sion, do noth­ing.

The best way of deter­min­ing the Java ver­sions is to look in %pro­gram files%.  On 64-bit machines, this is “C:program files (x86)Java”.  On 32-bit, this is “C:program files­Ja­va”.  The script accounts for this.

I want­ed to post this because sev­er­al of the func­tions used are very use­ful.  The share host­ing the jre run­time needs to have wide open read-only access so the Local Sys­tem account can access share (Domain Com­put­ers).  This script can then be applied to machine accounts in group pol­i­cy as a start­up script.  If you want to test this, just com­ment out line 111.

Cheers!
Down­load Com­pressed (.zip) script

'======================================================
' VBScript Source File
' NAME: Java Runtime Environment Installation
' AUTHOR: Andrew J Healey
' DATE  : 2010.07.15
' COMMENT: This script will install the jre references based on processor, existing 
' 				   installations, and operating system.  This script is to be run at startup
'				   under the Local System account. No user interaction is required for 
'				   this script to work properly.
'======================================================

Option Explicit

If isClientOperatingSystem = False Then wscript.quit

Dim jreVerMajor, jreVerMinor
Dim strCommand, strPathToInstall, strInstallFile, strArguments

'============== BEGIN CONFIGURATION SECTION =================
jreVerMajor = "jre1.5.0_" 'As string
jreVerMinor = 9 'As Integer for > operations
strPathToInstall = "\servernameSoftwareJava" 'Point to share \servernamesharefolder
strInstallFile = "jre-1_5_0_09-windows-i586-p.exe"
strArguments = "/s /v /qn ADDLOCAL=jrecore,extra IEXPLORER=1 REBOOT=Suppress JAVAUPDATE=0 SYSTRAY=0 WEBSTARTICON=0"
strCommand = strPathToInstall & strInstallFile & " " & strArguments
'============== END CONFIGURATION SECTION =================

If checkForJRE(jreVerMajor, jreVerMinor) = False Then
	Call InstallJava(strCommand)
End If

Private Function checkForJRE(ByVal jreVerMajor, ByVal jreVerMinor)
	Dim jrePath
	Dim blnMajorFound : blnMajorFound = False
	Dim blnMinorFound : blnMinorFound = False
	
	If is32bit Then
		jrePath = "C:Program FilesJava"
	Else
		jrePath = "C:Program Files (x86)Java"
	End If
	
	On Error Resume Next
		Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
		Dim objFolder : Set objFolder = objFSO.GetFolder(jrePath)
		Dim colSubfolders : Set colSubfolders = objFolder.Subfolders
		Dim objSubfolder
		
		For Each objSubfolder in colSubfolders
			If Left(objSubfolder.Name,Len(jreVerMajor)) = jreVerMajor Then
				blnMajorFound = True
				If CInt(Right(objSubfolder.Name,2)) >= jreVerMinor Then
					blnMinorFound = True
				End If
			End If
		Next
		
		If Err.Number > 0 Then
			chechForJRE = True
			Exit Function
		End If
		
		If blnMajorFound = False And blnMinorFound = False Then
			checkForJRE = False
		Else
			checkForJRE = True
		End If
	On Error GoTo 0
	
	Set objSubfolder = Nothing
	Set colSubfolders = Nothing
	Set objFolder = Nothing
	Set objFSO = Nothing
	jrePath = Empty
	blnMajorFound = Null
	blnMinorFound = Null
	jreVerMajor = Empty
	jreVerMinor = Empty
End Function 

Private Function is32bit()
	'Get processor architecture; do not use remotely
	const HKEY_LOCAL_MACHINE = &H80000002
	Dim oReg,strKeyPath,strValueName
	Dim strValue
	On Error Resume Next
		Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\.rootdefault:StdRegProv")

		strKeyPath = "SYSTEMCurrentControlSetControlSession ManagerEnvironment"
		strValueName = "PROCESSOR_ARCHITECTURE"
		oReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue

		If Err.Number > 0 or strValue = "x86" Then
			is32bit = True
		Else
			is32bit = False
		End If
		Err.Clear
	On Error GoTo 0
	
	Set oReg = Nothing
	strKeyPath = Empty
	strValueName = Empty
End Function 

Private Function InstallJava(ByVal strCommand)
	On Error Resume Next
		Dim objWshShell, intRC

		Set objWshShell = WScript.CreateObject("WScript.Shell")
		intRC = objWshShell.Run(strCommand, 0, True)

		If intRC > 0 Or Err.Number > 0 Then
			InstallJava = "Failed"
		Else
			InstallJava = "Success"
		End If
	On Error GoTo 0
	Set objWshShell = Nothing
	intRC = Empty
End Function 

Private Function isClientOperatingSystem()
	Dim objWMIService, objItem, colItems
	Dim strOS

	On Error Resume Next
		' WMI Connection to the object in the CIM namespace
		Set objWMIService = GetObject("winmgmts:\.rootcimv2")

		' WMI Query to the Win32_OperatingSystem
		Set colItems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")

		' For Each... In Loop (Next at the very end)
		For Each objItem in colItems
			strOS = objItem.Caption
		Next
		
		If InStr(strOS,"Windows 7") > 0 Or InStr(strOS,"XP") > 0 Or InStr(strOS,"2000 Professional") > 0 Or InStr(strOS,"Vista") > 0 Then
			isClientOperatingSystem = True
		Else
			isClientOperatingSystem = False
		End If
		
		If Err.Number > 0 Then isClientOperatingSystem = False
		
		strOS = Empty
		Set objItem = Nothing
		Set colItems = Nothing
		Set objWMIService = Nothing
	On Error GoTo 0
End Function 

Part 1: Blocking Bad Hosts - Finding Them, Easily

Down­load Script: get-bad-hosts.zip

While trou­bleshoot­ing some issues on an OWA Front-End serv­er, I went over to the secu­ri­ty log to see if the authen­ti­ca­tion attempts were get­ting past this box. The prob­lem I found was the log was so full of failed logon attempts it was dif­fi­cult to fil­ter out what I was look­ing for. In a twelve hour peri­od, there were thou­sands of 529 events in the secu­ri­ty log. Now, I know this is noth­ing new, but I found a few pat­terns. I man­u­al­ly export­ed the log to a CSV, parsed out all the source ip address­es and opened it up in Excel. What I found was that 98.7% of failed logon attempts were made by just four dif­fer­ent ip address­es.  (I rec­om­mend using Max­Mind’s GeoIP Address Loca­tor for help in deter­min­ing where the source address­es are locat­ed.) Read More

Logon Script: Move Local PST Files To Network Share

Down­load Script: move-pst-to-network.zip

So, my bud­dy (and for­mer co-work­er) called me yes­ter­day for some help with a script he put togeth­er.  His script checked the local pro­file in Out­look for any PST files that were stored local­ly.  If it found any, it would them move them to the users home space.  We tried and tried to get the script to work prop­er­ly but it nev­er seemed to work 100%.  Being that he is a good friend and this would be use­ful at work, I decid­ed to take the work he had put in and get the thing work­ing. Read More