Monday, August 22, 2016

802.1x WiFi Profile for the AppleTV (3rd Generation)

Finally figured out the profile requirements to get an AppleTV (3rd gen) working with 802.1x wireless authentication. We employ an Aruba ClearPass (which does the authentication checking to Windows Active Directory). We did this as of 15 Aug 2016.

Requirements: 
  • Apple computer with Apple Configurator 2 installed (we used v2.2.1 (3C72))
  • Apple TV (3rd gen)
  • USB cable (normal-end to micro-end)
 Steps
  • Plug the micro-usb into the AppleTV and open the Apple Configurator 2 application on the Apple computer
  • Create a new profile and use the screenshots in the PDF below
  • Push the profile to the AppleTV
  • Test
Notes:
  • Observe we had to use "MSCHAPv2" after choosing  "TTLS" on the WiFi profile
  • Observe you probably only need your Root CA and Intermediate CA certificate (in our case DigiCert)
    • As a precaution, I included our local AD root CA and our ClearPass certificate
  • Many forums I read stated you need your Root CA *and* your Intermediate CA (to complete the trust chain)
References:
Apple 802.1x White Paper:
http://training.apple.com/pdf/WP_8021X_Authentication.pdf

Apple Configurator 2:
https://itunes.apple.com/us/app/apple-configurator-2/id1037126344?mt=12

Identify your Apple TV model:
https://support.apple.com/en-us/HT200008 


PDF of profile screenshots here:
https://drive.google.com/file/d/0B5ttjkGSReNeVEZqb1BheVczQ3c/view?usp=sharing


Sunday, February 14, 2016

Separate DNS Servers for Network Groups at Home - Working DHCP Conf File

I needed a way to have OpenDNS distributed to my kid's devices to filter their limited Internet usage.

Using an OpenSUSE Leap Linux VM on an ESXi chassis, I created a DHCP scope that does just this.

Only "known-clients" are given 8.8.8.8 for DNS. Known-clients are those with static mac-address entries in the conf file. "Unknown-clients" include everyone else (not listed with static mac-addresses).

Note: I had to use the "allow" and "deny" statements (in both pools) to get this work.

Note: The firewall only allows certain devices to get to any public DNS. The children's devices are limited to DNS queries to OpenDNS only (even if a static IP is assigned).

option domain-name "home";
option routers 10.12.14.16;
option ntp-servers 0.pool.ntp.org;
default-lease-time 345600;
ddns-update-style none;
subnet 10.12.14.0 netmask 255.255.255.0 {
  default-lease-time 345600;
  max-lease-time 604800;
  host iPhone {
    option domain-name-servers 8.8.8.8, 8.8.4.4;
    hardware ethernet xx:xx:xx:xx:xx:xx;
    fixed-address 10.12.14.2;
  }
  pool { # id="LowRange"
    option domain-name-servers 8.8.8.8, 8.8.4.4;
    range 10.12.14.2 10.12.14.24;
    deny unknown-clients;
    allow known-clients;
  }
  pool { # id="highRange"
    option domain-name-servers 208.67.222.222, 208.67.220.220;
    allow unknown-clients;
    range 10.12.14.25 10.12.14.240;
    deny known-clients;
  }
  host IBMETH {
    hardware ethernet xx:xx:xx:xx:xx:xx;
  }
  host JiPad {
    hardware ethernet xx:xx:xx:xx:xx:xx;
  }
}

Friday, June 12, 2015

Martin Pro Software to iPhone App Connectivity Issue

I recently got a call from my Church asking for some help with a networking issue. Packet captures to the rescue!

Background
A Windows PC running Martin-Pro Lighting Console Software can be controlled using an iPhone/iPad app call "M-Series Remote" (aka MaxRemote). This app can remotely control various aspects of the lighting software (over the wireless network).

Problem
When connected to the same VLAN over the Ruckus AP and through a Cisco Catalyst 2960X switch, the app would *not* connect. However, going through a small Linksys WiFi router, the app connection was working just fine (see network layout below).

Fix
After running a packet capture on the PC, I noticed the Martin software was advertising a multicast stream (waiting for remote clients to connect). A quick search yielded that Cisco switches have IGMP Snooping enabled by default. Easily turned off with "no ip igmp snooping". After turning that off and restarting the lighting software, the iPhone app connected without problem!

Technical Details
It looks like the MaxRemote listens for multicast traffic (using UDP) on port 32480. The iPhone connects to the controller using the multicast stream over this same port. You can see this in the packet capture screenshot below.

10.12.14.82 = controller
10.12.14.83 = iPhone running the MaxRemote app.
  • In line #151 below, the source (iPhone) is touching the multicast address (230.255.255.180) for the first time.
  • The controller is responding to the iPhone in line #157 (after a successful ARP reply in line #156).
  • The connection is successful in lines #173 & #179 (iPhone successfully joins the multicast group).
Multicast is much more efficient than broadcasts (especially considering the marriage of A/V and networking), so I applaud the Martin Software Engineers for forward-thinking!





Friday, June 05, 2015

Copy File from Bootflash to Subdirectory

Bootflash with "/37subs" as a subdirectory.

copy clientlib-28445_R0-0.log 37subs/

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Copy from subdirectory to bootflash (root):

copy tracelogs/clientlib-28445_R0-0.log bootflash: 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

go up one level:

cd

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

request platform software package expand file bootflash:37subs/asr1001-universalk9.03.07.06.S.152-4.S6.bin

http://www.cisco.com/c/en/us/td/docs/routers/asr1000/configuration/guide/chassis/asrswcfg/issu.html#pgfId-1150636



Wednesday, June 03, 2015

VACL Working Config


Goal: Allow PC1 to talk with anything on the local LAN (10.12.14.0/24) but block PC1 from accessing the Internet. Only allow PC2 to access the Internet. Block everything else.

Note: 3750 layer-2 switch (ip routing disabled), running "c3750-ipservicesk9-mz.122-50.SE4.bin"

Note: For some reason, I had to use wildcard masks instead of "host" (it wasn't working, troubleshot, but gave up).


PC1: 10.12.14.134/24 (on port f1/0/5)

PC2: 10.12.14.133/24 (on port f1/0/7)

Internet Connection: (on port f1/0/9)


##############################################################
!
mac access-list extended permitARP
 permit any any 0x806 0x0
!
ip access-list extended LocalOnlyACL
 permit ip 10.12.14.0 0.0.0.255 10.12.14.0 0.0.0.255
!
ip access-list extended InternetOnlyACL
 permit ip 10.12.14.133 0.0.0.0 any
 permit ip any 10.12.14.133 0.0.0.0
!
!
vlan access-map myVACLMap 10
 action forward
 match ip address LocalOnlyACL   
!
vlan access-map myVACLMap 11
 action forward
 match ip address InternetOnlyACL 

!
vlan access-map myVACLMap 15
 action forward
 match mac address permitARP      

!
vlan access-map myVACLMap 20
 action drop                     
!
!
vlan filter 123 vlan-list 44
!
!
interface FastEthernet1/0/5
 switchport access vlan 44
 switchport mode access
 spanning-tree portfast
!
interface FastEthernet1/0/7
 switchport access vlan 44
 switchport mode access
 spanning-tree portfast
!
interface FastEthernet1/0/9
 switchport access vlan 44
 switchport mode access
 spanning-tree portfast
!
end

##############################################################

Wednesday, May 20, 2015

Test Excel VBS - Working code using Sub Routines

Dim arrFileLines()

'##############################################################################
Set fso = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")

Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True

userDesktopPath = objShell.SpecialFolders("Desktop")
userDesktopFullPath = userDesktopPath & "\test.xlsx"

Set objWorkbook = objExcel.Workbooks.Open(userDesktopFullPath)
Set objWorksheet = objWorkbook.Worksheets(1)
'###################################################################|



' Start main section of code
'~~~~~~~~~~~~~~~|||~~~~~~~~~~~~~~~~~
t = 0

readSpreadsheet

firstB = True

'~~~~~~~~~~~~~~~|||~~~~~~~~~~~~~~~~~
' End main section of code




' Read Excel spreadsheet, insert cell values into script
'##############################################################################
Sub readSpreadsheet

If (fso.FileExists(userDesktopFullPath)) Then
' MsgBox userDesktopFullPath
Else
MsgBox "You are Missing the Router List Text File", 48, "Start Over"
WScript.Quit
End If


intRow = 1

Do Until objExcel.Cells(intRow,1).Value = ""
netName = Trim(objExcel.Cells(intRow,1).Value)
blah33 netName,intRow
intRow = intRow + 1
Loop

j=1
For Each word In arrFileLines
MsgBox word & vbCrLf & "This is the final array"
objExcel.Cells(j,2).Value = word
j = j + 1
Next


End Sub
'###################################################################|



'##############################################################################
Sub blah33 (xx, yy)

myVar = objExcel.Cells(yy,1).Value
buildArray myVar, t

End Sub
'###################################################################|



'##############################################################################
Sub buildArray (zz,tt)

ReDim Preserve arrFileLines(tt)
arrFileLines(tt) = zz
MsgBox arrFileLines(tt) & vbCrLf & tt
tt = tt+1

End Sub
'###################################################################|

Saturday, April 04, 2015

Using VMware ESXi 5.5 for Virtual Networking Labs

Spent the past few weeks putting this together. Wanted to pull all the disjointed silos of information together into a single document.

Enjoy.

PDF (25 MB)
ESXi 5.5 Setup How To (Signed).pdf

Wednesday, August 27, 2014

The Worst Thing You Can Do For Your Grandma is Convince Her to Get an Android Phone

I have a plea for all of those people out there who love their Android phones. For the love of Pete, *DO NOT* convince your elderly Grandmother to get an Android phone!

As some of you are aware, I've been providing small-time tech support since about 2001 (as a side-business to my main job as a Network Engineer). I cannot begin to count the number of times I've been on the phone with an elderly person troubleshooting an Android phone problem. Don't even get me started on the issue of Android fragmentation. :|

I'm no Apple FanBoi (I hate that word), but I can say that I've seen the elderly handle the iPhone's iOS with ease. Downloading apps? Easy. Setting up email? Easy. Texting, sending a photo over SMS, taking a picture, making new contacts? All easy on the iPhone. 

I *challenge* anyone with any modicum of technical skill to watch a senior citizen try to do *any* of the above on an Android phone. You will cringe, you will cry. I *dare* you to try to do any of that over the phone... You'll want to strangle Android. 

You'll want to strangle the person who convinced Grandma to get an Android phone.

Monday, July 14, 2014

Sapphire Glass -- Ending the Need for Screen Protectors?

The iPhone 6 is rumored to have Sapphire Glass as a screen. Could this new technology end the need for screen protectors?





Saturday, June 28, 2014

The Law of the Cheap Tool vs the Expensive Tool

So often, I've been at a fork in the road. There I stand, in the aisle of some store staring at a section of tools. These tools have run the gamut... weed trimmers, electrical tools, cabling tools, etc. You name it, I've been there.

In the (long ago) past, I made my decision based on price. Inevitably, that low-cost tool either broke or made me rage in frustration at the poor engineering and difficulty in use. If you've ever used a cheap pair of RJ45 crimpers or punch-down tools, you know what I mean.

My mind would vacillate between the trade-off of the cheaply priced item versus the obvious high-grade material, better engineering, and good "feel" of the more expensive item. I used to think to myself, "Eh, I'm only going to use this a few times, no big deal." 
!! ( insert The Price is Right fail-horns here ) !!

Eventually, I learned the same painful lesson over and over and over until I stopped making that mistake... and here it is:

The Law of the Cheap Tool vs the Expensive Tool:
If given a choice, and you choose the cheaper tool, eventually, you'll have to go back to buy the same tool (the first one broke, failed, frustrated you, etc). You'll purchase the more expensive one the 2nd time around. In the end, you've spent more than twice the amount of money than had you purchased the more expensive tool in the first place!

Friday, June 13, 2014

Using a Cell Phone Jammer? You Will Eventually Get Caught!

April 2014

A Florida man was finally caught after using a cell phone jammer in his car for at least 16 months.

MetroPCS noticed one of their cell phone towers had failures every morning and evening around the same time every day (presumably only on the days when this guy was driving by).

They reported it to the FCC and a bandwidth stakeout ensued. We can only assume a demure FCC vehicle roamed the roadways in question scanning for rogue transmissions. Sure enough, they found this man's blue Toyota Highlander transmitting "strong wideband emissions."

The FCC fined him $48,000. 

The jammer probably cost him less than $150.

Not worth it, for sure.

Story Here:
http://www.cnet.com/news/man-put-cell-phone-jammer-in-car-to-stop-driver-calls-fcc-says/

Saturday, May 24, 2014

I Can't Ping the Internet

Customer technicians at a site contacted me recently about not being able to ping anything on the Internet. I asked them to describe the cabling layout and this was the result...


Online Speedtest Results Will Vary

Recently, I worked with a customer installing a new 50M ethernet WAN circuit. This customer already had an existing 50M ethernet circuit through another carrier; however, this existing service was much more expensive. The new circuit was going to be a significant cost savings.

After a few unsuccessful attempts at turn-up (VLAN, speed, & duplex mismatches), we finally arrived at the point of expected success. That is, until the customer opened up a web browser to perform a speed test on the new circuit.

The default server the speedtest chose (based on their location) gave them 50M download, 30M upload. On the old circuit, the default server the speedtest chose consistently gave them 50M download and 50M upload. Hard to argue with what appears to be gospel to the customer.

The truth came out after we chose different speedtest servers. From the same location, using only a test laptop (directly connected to the WAN router) and no other traffic on the new line, the results were wildly different as you can see below.

Eventually, the customer was convinced that the 50M circuit was going to be fine (given the fact that 3 different servers indicated 50M for down & up speeds). We had also ruled out config mismatches, packet drops, and physical layer problems. The end-to-end circuit was very clean.

Link to download the PDF below:
https://drive.google.com/file/d/0B5ttjkGSReNeMTlBancwT093ZzA/edit?usp=sharing








Monday, May 06, 2013

Auto Reboot Server 2012

http://www.servicefirst.com/KB/a156/how-do-i-schedule-my-server-to-automatically-reboot.aspx

Windows Server 2003

Navigate to Start -> All Programs -> Accessories -> System Tools -> Scheduled Tasks.

Click on "Add Scheduled Task".

You should now see the Add Scheduled Task Wizard. Click Next.

Disregard the list of programs, and click the Browse button.

By default, the browse button will bring you to the root of the C: drive. Navigate to WINDOWS -> system32 and locate the file named ‘shutdown.exe’. Highlight it, and click Open.

Enter your desired name for this task (such as "Auto Reboot"). Next, choose how often you would like your server to reboot, whether it is daily, weekly, or monthly.

Next you can select the time and date of the month you would like the server to automatically reboot.  Click Next

Type in the password for the user you would like this task to run under. If you are setting this task to run under your ‘ServerAdmin’ login, enter the ‘ServerAdmin’ password. Once entered, click Next.

Place a check-mark in the option for 'Open advanced properties for this task when I click Finish'.  Click Finish.

Add the following line in the Run field:

C:\windows\system32\shutdown.exe -r -t 00

You will need to enter your ‘ServerAdmin’ password to confirm the changes. Once entered, click OK.

You have now set Windows to automatically reboot as the time you have specified.

Windows 2008

Navigate to Start > Administrative Tools > Task Scheduler

Name the task to reflect the nature of the request.  Click Next

The next two screens will allow you to set the frequency of the task.  Do so then click Next as you are ready

Select "Start a program", then click Next

In the "Program/Script" box enter in "C:\Windows\system32\shutdown.exe."  If this is a x64 bit operating system, you will want to use "C:\Windows\SysWOW64\shutdown.exe".  Click Next when finished

The last screen will allow you to view the settings before creating the task.  When ready, click Finish.

Map Drive with Domain Password Masked (Windows XP)

'#############################################################
'Author: Scot Geer //
'Script Purpose: Script to map a drive
'Script Reason: Issue with end-users connecting to VPN that
'               cannot connect to an "already" mapped drive
'               on an active directory domain. The fix is
'               to manually map the drive (issue with cached
'               credentials?)
'Script Date: Aug 2006
'Script Updated: April 2008
'Script Actions: Prompts user for username/password, then
'                maps the drive to the domain share. It also
'                has error-handling built-in (checks for
'                network, bad password, etc.) and informs the
'                user as such.
'                *Observe the password is masked when the
'                user types it in*
'Script Requirements:
'         1. XP or above is required (thanks to
'            "ScriptPW.Password", it will *not* work
'            on Win2k or below). FYI, this does *not* work in Vista

'            or Windows 7 due to the lack of the scriptpw.dll file.
'            It *might* work if you copy over that file from an XP
'            machine
'         2. This script must be run in a command line
'            window (with the 'cscript' parameter):
'            "cscript scriptName.vbs"
'         3. To automate this script, create a batch
'            file with the line:
'            "start cmd /k cscript /nologo scriptName.vbs"
'            Batch file and vbs script should reside
'            in the same folder
'         4. Technician will have to edit parameters
'            "drvLetter", "ShareDir", & "domain" in
'            order for this script to work
'

'#############################################################
Option Explicit

Dim objShell,objNetwork,objPassword
Dim drvLetter,shareDir,domain,userName,userPswd
Dim driveAlreadyMapped,errorNOS
Dim error001,error002,error003

Set objShell = WScript.CreateObject("Wscript.Shell")
Set objNetwork = WScript.CreateObject("WScript.Network")
Set objPassword = CreateObject("ScriptPW.Password")

driveAlreadyMapped = False
errorNOS = False

drvLetter = "S:"    'change to any drive letter desire
shareDir = "\\serverName\shareName"   'change to your server share
domain = "domainName\"            'keep the backslash

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WScript.StdOut.Write "Please enter your username:"
userName = WScript.StdIn.ReadLine
WScript.Echo

If userName = "" Then
    WScript.Echo
    Wscript.StdOut.WriteLine String(60, "#")
    Wscript.Echo "No Username Entered or User Cancelled"
    quitscript
End If

Wscript.StdOut.Write "Please enter your password:"
userPswd = objPassword.GetPassword()
Wscript.Echo
WScript.Echo

mapDrive drvLetter,shareDir,domain,userName,userPswd
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


'Maps drive w/username, pswd. Invokes error handler if drive is already mapped
'******************************************************************************
Sub mapDrive(drv,share,dom,usr,pswd)

    On Error Resume Next

    objNetwork.MapNetworkDrive drv, share, "false", dom & usr, pswd

    errorHandler_mapDrive

    If Not(driveAlreadyMapped) And Not(errorNOS) Then
        WScript.Echo
        Wscript.StdOut.WriteLine String(60, "#")
        Wscript.StdOut.WriteLine "Success!"
        WScript.Echo
        Wscript.StdOut.WriteLine "You may now open your ""Shared"" files"
        Wscript.StdOut.WriteLine String(60, "#")
    End If

End Sub
'*******************************************************************|

'Notifies user if drive is already mapped, bad username/pswd, or off network
'******************************************************************************
Sub errorHandler_mapDrive

    If Err.Number<>0 Then

        error001 = InStr(1,Err.Description,"already",1)
        error002 = InStr(1,Err.Description,"found",1)
        error003 = InStr(1,Err.Description,"password",1)

        If (error001) Then
            driveAlreadyMapped = True
            WScript.Echo
            Wscript.StdOut.WriteLine String(60, "#")
            Wscript.StdOut.WriteLine "Your ""Shared"" drive is already mapped"
            WScript.Echo
                WScript.StdOut.WriteLine "Open your ""Shared"" files as normal"
                WScript.Echo
                WScript.StdOut.WriteLine "Notice001"
                Wscript.StdOut.WriteLine String(60, "#")
        ElseIf (error002) Then
            errorNOS = True
            WScript.Echo
            Wscript.StdOut.WriteLine String(60, "#")
            Wscript.StdOut.WriteLine "The path to the drive could not be found"
            WScript.Echo
            WScript.StdOut.WriteLine "Drive = " & shareDir
            WScript.Echo
            Wscript.StdOut.WriteLine "Check your network connection to ensure " _
                & "you are connected to the Internet"
            WScript.Echo
            Wscript.StdOut.WriteLine "Make sure you are connected to the VPN"
            WScript.Echo
            Wscript.StdOut.WriteLine "Notice002"
            Wscript.StdOut.WriteLine String(60, "#")
        ElseIf (error003) Then
            errorNOS = True
            WScript.Echo
            Wscript.StdOut.WriteLine String(60, "#")
            Wscript.StdOut.WriteLine "Wrong username or password"
            WScript.Echo
            Wscript.StdOut.WriteLine "Run this script again"
            WScript.Echo
            WScript.StdOut.WriteLine "Ensure you are typing your username " _
                & "& password correctly"
            WScript.Echo
            WScript.StdOut.WriteLine "Check your CAPS LOCK"
            WScript.Echo
            Wscript.StdOut.WriteLine "Notice003"
            Wscript.StdOut.WriteLine String(60, "#")
        End If

          Err.Clear

    End If

End Sub
'*******************************************************************|

'Ends Script with a notification to the user
'******************************************************************************
Sub quitscript

    WScript.Echo
    WScript.Echo "Quitting Now"
    Wscript.StdOut.WriteLine String(60, "#")
    Wscript.Quit

End Sub
'*******************************************************************|

Sunday, October 03, 2010

Server Scheduled Tasks Script

'Author: Scot Geer ()
'Purpose: Reads all scheduled tasks listed, compiles their last run, last result, etc.
'         & then sends it to specified recipient(s) via text email
'Date Created: 07 Oct 2008
'Instructions: Modify only the parameters in the "modify" section below
'Tips: If this script cannot send an email to the SMTP server, it will fail silently
'      & write to the Event Log. Put a bad ip address in there, then run it, then check
'      your event log (application, ERROR, WSH)
'##########################################################################################

Option Explicit

Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

Set objShell = WScript.CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")

Dim objFSO, objDocument, objShell
Dim commandsArr, schTasksArr(), groupedTasksArr()
Dim myCmd, x, fullCommand, totalTaskLinesRequested
Dim reqSchTasksLinesArr, myTimeDateNow

myCmd = "cmd /c "


'                                 !!! Modify this section only !!!
'##########################################################################################
'commandsArr is an array of command line commands
'CLI Scheduled Tasks reference found here:
'http://technet.microsoft.com/en-us/library/cc772785.aspx
commandsArr = Array("schtasks /query /fo LIST /v")

'run this CLI command "schtasks /query /fo LIST /v" and pick which lines you want here:
reqSchTasksLinesArr = Array("TaskName:","Next Run Time:","Last Run Time:","Last Result:")

'Modify this section only for the 'sendEmail' function
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Dim eFrom,eTo,eSubject,eBody,eAttachment,eUsername,ePassword
Dim eSmtpServer,eSmtpPort,eSmtpUseSSL

Const eNetworkType = 1 'use '1' if script will run on machine with SMTP installed
'Const eNetworkType = 2 'use '2' if script will run on SMTP box somewhere on network

eFrom = "s@some-domain.com"
eTo = "me@some-email.com"
eSubject = "Daily Scheduled Tasks Report (Server-Name - 10.12.14.21)"
eBody = ""
'Type in full path and filename with extension here if you want an attachment
eAttachment = "%homepath%\Local Settings\Application Data\Microsoft\Windows NT\NTBackup\data\backup01.log"
'Note: use domain\username if going to exchange server
'Note: use username@domain.com if going to public Internet SMTP server
'Note: only use username/password if SMTP server is on separate machine
eUsername = "" 
ePassword = "" 
eSmtpServer = "Name-of-SMTP-Server"
eSmtpPort = 25
eSmtpUseSSL = False
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'##########################################################################################
'                                  !!! Modify this section only !!!


totalTaskLinesRequested = ((UBound(reqSchTasksLinesArr))+1)




'Main Code
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
myTimeDateNow = FormatDateTime(Time,0) & ", " & Date

For x=0 To UBound(commandsArr)
fullCommand = myCmd & commandsArr(x)
'replace Null with fullPath if writing to file
runCommands fullCommand, Null 
Next

groupTaskResults

eBody = prettyUpResults 'builds results into body of email

sendEmail eFrom,eTo,eSubject,eBody,eAttachment,eUsername,ePassword, _
eNetworkType,eSmtpServer,eSmtpPort,eSmtpUseSSL
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~





'Action: runs commands via command line, reads each line or reads all
'Dependencies: 'appendTextToFile()' (only if you want to write to file)
'              global declaration of schTasksArr to enter results
'           global declaration of totalTaskLinesRequested
'              'groupTaskResults()' 
'Parameters: 'pCommand' --> command line (ex: "schtasks /query /fo LIST /v") 
'            'pPath' --> fullPath of text file to write info to (if applicable)
'Returns: Nothing
'******************************************************************************
Sub runCommands(pCommand,pPath)

Dim objExecObject, strLine, y, w

Set objShell = WScript.CreateObject("WScript.Shell")
Set objExecObject = objShell.Exec(pCommand)
y = 0

Do Until objExecObject.StdOut.AtEndOfStream
   strLine = objExecObject.StdOut.ReadLine
   For w=0 To UBound(reqSchTasksLinesArr)
   If InStr(strLine, reqSchTasksLinesArr(w)) Then
    ReDim Preserve schTasksArr(y)
    schTasksArr(y) = strLine
' appendTextToFile pPath,schTasksArr(y) 'write to text file
    y=y+1
   End If
Next
Loop
End Sub
'********************************************************************|


'Action: pulls 3 specific lines from the 'schTasksArr' array and groups them
'        into their own sections for easy display or printing to a file
'Dependencies: 'schTasksArr' --> lines from --> "schtasks /query /fo LIST /v"
'              global declaration of 'totalTaskLinesRequested'
'              'totalTaskLinesRequested' = # of lines wanted from schtasks cmd
'Parameters: none
'Returns: nothing returned but it does build the global groupedTasksArr array
'******************************************************************************
Function groupTaskResults

'making info into groups of 3 lines 
'we want 3 specific lines from each sch task
Dim m, w, groupedTasks, groupedTaskResults, tempPlaceHolder
w = 0
'get number of total task lines, divide by totalTaskLinesRequested 
'to get # of sections needed
groupedTasks = (UBound(schTasksArr) + 1)/totalTaskLinesRequested
'don't forget to subtract 1 (starts at zero)
For x=0 To groupedTasks - 1
'grouping each scheduled task sections
'don't forget to subtract 1 (starts at zero)
For m=0 To totalTaskLinesRequested - 1
tempPlaceHolder = tempPlaceHolder & schTasksArr(w) & vbCrLf
w = w + 1
Next
groupedTaskResults = tempPlaceHolder
tempPlaceHolder = Null 

ReDim Preserve groupedTasksArr(x)
groupedTasksArr(x) = groupedTaskResults
'Keep this echo line here for testing purposes
' WScript.Echo groupedTasksArr(x) & vbTab & "This is the grouped tasks"
Next

End Function
'*******************************************************************|


'Action: formats array results into a readable/printable form
'Dependencies: globally declared array of some kind
'Parameters: none
'Returns: 'myPrettyPrint' --> properly formatted results
'******************************************************************************
Function prettyUpResults

Dim myPrettyPrint
For x=0 To UBound(groupedTasksArr)
myPrettyPrint = myPrettyPrint & groupedTasksArr(x) _
& vbCrLf & "Current System Time" _
& String(9, ".") & myTimeDateNow _
& vbCrLf & String(40, "#") & vbCrLf & vbCrLf
Next

prettyUpResults = myPrettyPrint

End Function
'*******************************************************************|


'Action: sends email & attachment (attachment optional)
'Dependencies: global declaration of "modify" section below
'Parameters: see "modify" section below
'Returns: nothing
'******************************************************************************
Function sendEmail(pFr,pTo,pSu,pTe,pAtt,eUser,ePswd,pType,pSmtp,ePort,eSSL)

'Modify this section only for the 'sendEmail' function 
'Put this section in the global declaration section of this script
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' Dim eFrom,eTo,eSubject,eBody,eAttachment,eUsername,ePassword
' Dim eSmtpServer,eSmtpPort,eSmtpUseSSL

'Const eNetworkType = 1 'use '1' if script will run on machine with SMTP installed
'Const eNetworkType = 2 'use '2' if script will run on SMTP box somewhere on network

' eFrom = "username@domain.com"
' eTo = "recipient@domain.com"
' eSubject = "Subject Message"
' eBody = "Body of email"
'Type in full path and filename with extension here if you want an attachment
' eAttachment = "c:\temp\logs\backup01.log"
'Note: use domain\username if going to exchange server
'Note: use username@domain.com if going to public Internet SMTP server
' eUsername = "domain\username" 'don't use this line if eNetworkType=1 
' ePassword = "password"        'don't use this line if eNetworkType=1
' eSmtpServer = "serverName or IP address"
' eSmtpPort = 25
' eSmtpUseSSL = False
'
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

On Error Resume Next

Dim objEmail, extraMessages

Set objEmail = CreateObject("CDO.Message")
extraMessages = "Check the parameters in the 'email modify' section" _
& " of the script" _
& vbCrLf & "Rob I. is a Hottie!  :D"
objEmail.From = pFr
objEmail.To = pTo
objEmail.Subject = pSu
objEmail.Textbody = pTe
objEmail.AddAttachment(pAtt)
objEmail.Configuration.Fields.Item _
   ("http://schemas.microsoft.com/cdo/configuration/sendusing") = pType
objEmail.Configuration.Fields.Item _
   ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = pSmtp 
objEmail.Configuration.Fields.Item _
   ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = ePort

'Only use this section if running this script from a non-SMTP server, such as a 
'workstation. Simply remove the apostrophe's at the beginning of each line.
'##############################################################################
' objEmail.Configuration.Fields.Item _
'    ("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1 
' objEmail.Configuration.Fields.Item _
'    ("http://schemas.microsoft.com/cdo/configuration/sendusername") = eUser
' objEmail.Configuration.Fields.Item _ 
'    ("http://schemas.microsoft.com/cdo/configuration/sendpassword") = ePswd
' objEmail.Configuration.Fields.Item _
'    ("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = eSSL
' objEmail.Configuration.Fields.Item _
'    ("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60
'##############################################################################

objEmail.Configuration.Fields.Update
objEmail.Send
myErrHandler(extraMessages)
End Function
'*******************************************************************|


'Action: generic error handler module that writes to the system event log
'Dependencies: global declaration of 'objShell'
'Parameters: 'pMsg' = extra message you want written to the event log
'Returns: nothing
'******************************************************************************
Sub myErrHandler(pMsg)

Dim errMessage, eventLogMessage
If Err.Number<>0 Then
errMessage = Err.Description
eventLogMessage = WScript.ScriptFullName _
& vbCrLf & vbCrLf & errMessage _
& vbCrLf & pMsg
' WScript.Echo eventLogMessage
objShell.LogEvent 1, eventLogMessage
End If
Err.Clear

End Sub
'*******************************************************************|


'Action: quits the script and prompts the user "Quitting Now"
'Dependencies: none
'Parameters: nothing
'Returns: nothing
'******************************************************************************
Sub quitScript

WScript.Echo "Quitting Now"
Wscript.Quit

End Sub
'*******************************************************************|