Thursday, 17 December 2009

VBA - checking for open applications/documents

This was a tricky one to find this but got there in the end.

Basically I wanted Excel/VBA to take a look and see if a PDF file was currently open and if so give me the document title. Code can be easily modified to look for anything. Original code modified from VB from http://www.freevbcode.com/ShowCode.Asp?ID=920

Note that the code below only looks for the first match then backs out - check the VB code above for the structure to continually recurse through until all matches are found.


Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As Any, _
ByVal lpWindowName As Any) As Long
Private Declare Function GetWindow Lib "user32.dll" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetWindowText Lib "user32.dll" Alias "GetWindowTextA" (ByVal hwnd As Long, _
ByVal lpString As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetParent Lib "user32.dll" (ByVal hwnd As Long) As Long

Dim hwndapp As Long
Dim nret As Long
Dim hwndtmp As Long
Dim titletmp As String
gw_hwndnext = 2
titlepart = "WHAT YOU ARE LOOKING FOR OR LEAVE BLANK MAYBE? I WAS GOING FOR PDF"
titlepart = UCase(titlepart)
hwndtmp = FindWindow(0&, 0&)
Do Until hwndtmp = 0
If GetParent(hwndtmp) = 0 Then
titletmp = Space(256)
nret = GetWindowText(hwndtmp, titletmp, Len(titletmp))
If nret Then
titletmp = UCase(Left(titletmp, nret))
If InStr(titletmp, titlepart) Then
Exit Do
End If
End If
End If
hwndtmp = GetWindow(hwndtmp, gw_hwndnext)
Loop
Title = titletmp ' so title gives you the app/window title you were looking for

Thursday, 30 July 2009

SNMP for CDP Trawling of Cisco devices

The SNMP voyage continued today with a script to discover CDP neighbours via SNMP and then go get their CDP neighbour info and so on (although not too far!). Basically an intelligent network mapping. Couldn't do this via expect or anything due to a SecID front end on logins to the devices, so had to drop back to SNMP.

Obviously all Cisco based stuff, specifically switches but it's fairly generic.

Key things here are the SNMP IDs for the useful information:
1.3.6.1.4.1.9.2.1.3: Device name
1.3.6.1.2.1.47.1.1.1.1.13.1: Model number

To actually get the rest of the CDP data, it all gets a bit messy. Firstly you need the CDP table. This is started with a dump of IDs to uniquely identify each table entry. These can be obtained with an SNMP get of the following ID:

1.3.6.1.4.1.9.9.23.1.2.1.1.3

The bit you need is the last two numbers - The first number represents the local port ID (as a number) and the second represents a unique ID that we can use to get more info.

So once we have these (lets call them our_port and table_ID) we can use:

1.3.6.1.2.1.2.2.1.2.our_port
to get the local port name

and then for your cdp info:
1.3.6.1.4.1.9.9.23.1.2.1.1.4.table_id to get IP address (in hex)
1.3.6.1.4.1.9.9.23.1.2.1.1.6.table_id to get Name
1.3.6.1.4.1.9.9.23.1.2.1.1.7.table_id to get Remote port
1.3.6.1.4.1.9.9.23.1.2.1.1.8.table_id to get Device type

There is other stuff too - best take a look at the SNMP browser on Cisco for more info (see link in previous post).

Tuesday, 23 June 2009

Cisco AP - getting AP transmit power using SNMP

Someone asked me this question and I thought, well simple. Just ask the box.

Then finding the right part of the tree was somewhat harder.

Did find this, which is a bit handy...

http://tools.cisco.com/Support/SNMP/public.jsp

Then I found the most useful tree entries for me to be:
1.3.6.1.4.1.14179.2.6.3.42
and
1.3.6.1.4.1.9.9.272.1.1.2.14.1.6

that's it. I used SNMPGET on a solaris platform to get the info - this isn't necessarily the built in one, I seem to remember downloading it as a standalone binary some time ago but the tree is the key bit for this post.

Cisco deliberately annoying customers

This really made me giggle:




and a screenshot because they are bound to change it......


Wednesday, 17 June 2009

Create a temporary file (automatic name/path generation) in VB.net

Love this one:

myfilename = System.IO.Path.GetTempFileNameSystem.IO.Path.GetTempFileName()

Brilliant.

Spawning an executable from VB.net (using file type association)

Right, this one took longer than it should.

Wanted to:
  • Open webpage using default browser (not necessarily IE)
  • Open a CSV file using Excel

So it should be simple. filename stores "c:\mycsv.csv" or http://www.nowhere.com)

Option 1: Shell(filename)
Didn't work. End of.

Option 2: ShellExecute(0, vbNullString, filename, vbNullString, vbNullString, vbNormalFocus)
Works great on Vista, no good on XP. Didn't do anything.

Option 3: System.Diagnostics.Process.Start(filename)
Works fine on both. Brilliant. Job done.

Wednesday, 27 May 2009

Using registry from VB.net/express

Simple this:

to write:

SaveSetting("yourappname", "section", "key", value)

and to read:

myvar=getsetting("yourappname", "section", "key")

Don't forget to error handle (on error resume next) in case it can't find the app or key or value.

Write stuff best placed in myform.FormClosing.

Textbox handling control-C copy/paste

Another nice easy bit of code for this:

Private Sub outputbox_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles outputbox.KeyPress
If e.KeyChar = Convert.ToChar(1) Then
DirectCast(sender, TextBox).SelectAll()
e.Handled = True
End If
End Sub

Tuesday, 19 May 2009

Multiline Textbox update with autoscroll and less flashing in VB

I'll never remember this one, so here's the scenario.

Flaky code reading single bytes from a network stream, want a multiline textbox to show the output live. Problem is the cursor is at the top and text appends to the bottom. If I force the cursor to the bottom with textbox.scrolltocaret it's well flashy. Simple answer, don't add to the textbox.text, append to the box itself thus:

BAD
textbox.text=textbox.text & "stuff"
textbox.refresh
textbox.scrolltocaret

BETTER
textbox.SelectionStart = outputbox.TextLength
textbox.SelectedText = "stuff"

VB (.net/2008 express) Telnet to SUN Solaris - done! (with code)

Right, for anyone who read the previous post below, an update - the code now works!

It seems that when writing the stream, something was getting a bit carried away. With some assistance from Wireshark I got there in the end! Firstly, the first write request (IAC) was sending two bytes - FF and 00, even though the byte stream only had FF in it. Having tracked this down and forced it to 1 byte we got the IAC ok. Things then got worse as the second byte (IAC_COMMAND) was sending a 4k fragmented packet and the final byte (IAC_OPTION) was sending an 8k fragmented packet. Ouch! Forcing each response to a length of 1 got the right messages through (although I did notice it cocks the odd one up). Happily though it works fine with the Solaris box I am trying to get to and I get a "login:" prompt.

Remember this is not for a fully blown standards compliant Telnet type thing - just a rough job to get us logged into something and get some data back.

Hope this helps all those out there that were struggling!

So (pre-tidyup) the code now looks like (apologies for blog removing my indents):

Imports System.Net
Imports System.Net.Sockets

Public IAC As Integer = 255
Public IAC_WILL As Integer = 251
Public IAC_WONT As Integer = 252
Public IAC_DO As Integer = 253
Public IAC_DONT As Integer = 254

Dim returndata As String = Encoding.Unicode.GetString(bytes) ' data that comes back
Dim threebits As String = Chr(255) & Chr(255) & Chr(255) ' variable to keep track of the last three bytes
Dim command As Integer ' variable to store the IAC Command (well the integer equiv for CHR)
command = 0
' now a nasty while - basically we are saying that if any byte in the last three is a control byte
' (i.e. above 250) or any byte is a stream of 0's (found this needed trapping for reasons beyond me)
' we keep reading data and treating this as negotiation
While (Asc(Mid(threebits, 1, 1)) > 250 Or Asc(Mid(threebits, 2, 1)) > 250 Or Asc(Mid(threebits, 3, 1)) > 250) Or _
(Asc(Mid(threebits, 1, 1)) = 0 Or Asc(Mid(threebits, 2, 1)) = 0 Or Asc(Mid(threebits, 3, 1)) = 0)
Try ' just try it - if it fails, we'll handle it
networkStream.ReadTimeout = 1000 ' 1 second timeout (can skip this if you like but it
' does allow for interaction with the user
networkStream.Read(bytes, 0, 1) ' read 1 byte
returndata = Encoding.Unicode.GetString(bytes) ' store the byte as a string
threebits = Mid(threebits & returndata, 2, 3) ' sort out the three bytes
Catch
returndata = Chr(1) ' if we didn't get any data then let's call it chr(1)
End Try
Application.DoEvents() ' give the user some control
' I have a button called get_data that initiates the get. when it is clicked it
' changes it's text to "Stop". before any of this runs, when the user clicks it it checks
' to see what it's current text is and changs it to the inverse. So if it says
' get data, it changes it to stop and vice versa. Here in the loop (and in any other
' collection loop) we check to see if it has been changed to "get data" - if it has the
' user must have clicked stop - therefore we exit the sub
If get_data.Text = "Get data" Then
Exit Sub
End If
' now we decide on actions - basically act dumb - say no to everything!
Select Case Asc(returndata)
Case IAC_WILL ' will
command = IAC_WILL
Case IAC_WONT ' won't
command = IAC_WONT
Case IAC_DO ' do
command = IAC_WONT
Case IAC_DONT ' don't
command = IAC_WONT
Case IAC ' control req.
command = IAC
Case 1 ' this is our dummy case - ie no data read
Case Else ' traps the option value case, or plain text case
If command > 0 Then ' make sure we have a command to reply to - if not its just text
sendBytes = Encoding.Unicode.GetBytes(Chr(IAC)) ' IAC
networkStream.Write(sendBytes, 0, 1) ' 1 byte!
sendBytes = Encoding.Unicode.GetBytes(Chr(command)) ' command
networkStream.Write(sendBytes, 0, 1) ' 1 byte
sendBytes = Encoding.Unicode.GetBytes(returndata) ' return the option sent
networkStream.Write(sendBytes, 0, 1)
End If
command = 0
End Select
End While ' and loop but exit if we get three bytes of normal data



' that's the end of telnet negotiation (in the initial instance anyhow)
' and your code goes here, loop reading the data 1 byte (or more at a time) and do what you will.
' something like below might help
dim usernamedone as system.boolean = false
Do Until jobdone = True
Application.DoEvents()
If get_data.Text = "Get data" Then
Exit Sub
End If
Dim returndata As String = Encoding.Unicode.GetString(bytes)
Try
networkStream.ReadTimeout = 1000
networkStream.Read(bytes, 0, 1)
returndata = Encoding.Unicode.GetString(bytes)
Catch
returndata = ""
End Try
' outputbox is a multi-line text box on my form - shows the user the interaction in progress
' more for my diagnostics than anything else!
outputbox.Text = outputbox.Text & returndata
' note that username_prompt and password_prompt are textboxes on my form
If InStr(outputbox.Text, username_prompt.Text) and not usernamedone Then
! NOTE CHANGE TO ASCII ENCODE
sendBytes = Encoding.ASCII.GetBytes(username.Text & vbCrLf)
networkStream.Write(sendBytes, 0, sendBytes.Length)
usernamedone=true
statusupdate("Username sent")
End If
If InStr(outputbox.Text, Password_prompt.Text) Then
sendBytes = Encoding.ASCII.GetBytes(password.Text & vbCrLf)
networkStream.Write(sendBytes, 0, sendBytes.Length)
statusupdate("Password sent")
jobdone = True
End If
Loop

Monday, 18 May 2009

VB (2008/.net but anything really)- Telnet

(Update! This code fixed here:
http://myhead-online.blogspot.com/2009/05/vb-net2008-express-telnet-to-sun.html)

Ok, so I'm still distracted by VB. It's all just so easy to get great results, that's the problem!

Anyhow this week's project is Cisco device output collation into useful stuff. Got some great stuff going for switches to collate MAC/Port/VLAN/ARP/CDP information into a single sheet from multiple (or single) log files of a terminal session but then I thought, why not automate the Telnet portion? So off we go.

Now some things to note:

Telnet is not as simple as we would like
Negotiation of options may be required
Devices I want to access are a hop that requires logon (or more complex operations) away from my client PC, on different networks
I have no control over the clinet PC build and I have to assume nothing.

If you are anything like me then the first thing is to just steam headlong into it and see what breaks. So my approach is to open a socket and start reading/writing as required.

Dim tcpClient As New System.Net.Sockets.TcpClient()
tcpClient.Connect(host_ip.Text, IPport.Text)
Dim networkStream As NetworkStream = tcpClient.GetStream()
Dim sendBytes As [Byte]()
Dim returndata As String
Dim bytes(tcpClient.ReceiveBufferSize) As Byte
If networkStream.CanWrite And networkStream.CanRead Then ' check a ok
' read data
networkStream.Read(bytes, 0, 1)
returndata = Encoding.Unicode.GetString(bytes)
' write data
sendBytes = Encoding.Unicode.GetBytes(command & returndata)
networkStream.Write(sendBytes, 0, sendBytes.Length)
End If
tcpClient.Close()

Great, now I can read and write and do what I want - or so I thought. Actually, no - the code will work with many Cisco type products (and many others) but is unlikely to work with IBM/UNIX/Msoft/anything else, specifically anything that adheres to thet Telnet standard. So we need some tweaks.

Now I stop here to say that Telnet negotiation is an arse and it would be great to just say bugger it and keep away. Unfortunately the Telnet server has a different opinion and will sit waiting for you to negotiate with it if you just ignore the problem. Net result being no session.

So first thing is to take a look at how to negotiate. I'm not going into this but you need to know that every command starts with IAC (chr(255)).

KEYPOINT! Do not encode response as/with ASCII - there aren't enough bits to represent 255. Hence Unicode in code above. ASCII coding will result in a load of CHR(63)'s responding. Took me bloody ages to work that out - couldn't get why I was geting 63s when I was expecting 255s!

So basically we get a whole stream of

IAC - WILL/WONT/DO/DONT - OPTIONS

In text this will show as gibberish but it is critical! What you need to know is the following codes:
251 - WILL
252 - WONT
253 - DO
254 - DONT

Then there are stacks of others for the options. Look elsewhere for these. So what I want to do is to look at what comes in and basically say bugger off, I'm stupid. So comms go:

Server sends Client Sends
DO (option) WONT (option)
DONT (option) WONT (option)
WILL (option) DONT (option)
WONT (option) WONT (option)

But we don't know what we are going to have to negotiate so we need code that will handle any of this. this can all happen multiple times too. Great news is that the commands (at this level) are always sequences of 3 bytes. So basically get three bytes then respond (or as below get any command things, then when we get a non command option, send a response). Some code:

Public IAC As Integer = 255
Public IAC_WILL As Integer = 251
Public IAC_WONT As Integer = 252
Public IAC_DO As Integer = 253
Public IAC_DONT As Integer = 254
Select Case Asc(returndata)
Case IAC_WILL ' will
command = Chr(IAC_DONT)
Case IAC_WONT ' won't
command = Chr(IAC_WONT)
Case IAC_DO ' do
command = Chr(IAC_WONT)
Case IAC_DONT ' don't
command = Chr(IAC_WONT)
Case IAC ' control req.
command = command & Chr(IAC)
Case Else
sendBytes = Encoding.Unicode.GetBytes(command & returndata) ' return sent byte
statusupdate(status_line.Text & "IAC Response sent")
networkStream.Write(sendBytes, 0, sendBytes.Length)
command = ""
End Select

So now we can run a loop with the code in and send 'stupid' responses. Problem I have is that the response being sent is not being understood. A network capture shows that when I say send IAC & IAC_DONT, (option) it may or may not send something but it won't be the net result I want. Not sure whay but otherwise the theory is ok (I think!). Same holds for all bytes I send. Hmmm.....

Monday, 11 May 2009

Sourceforge - how to upload web pages to a project (finally!)

OK, this did my head in. It is a case of RTFM (very carefully) but with the exception that you have to be a mind reader and also ignore some contradictions in the existing docs.

Key points:

Server name is different from file access

web.sourceforge.net NOT frs.sourceforge.net

Username is different, use:
username,projectname NOT username

Then put your gumf in htdocs folder as per usual.....

Phew! That took blooming ages to diagnose!

Friday, 1 May 2009

Todays challenge - learning C or C++ or something

Right well I know a bit about programming, with a history of Visual Basic, VBA, PERL, shell script, TCL and a few others but I don't know jack about C or C++ so I have decided to learn something about them.

First port of call from a google search was here: http://www.programmingtutorials.com/c.aspx, nice easy tutorials. Head for the C++ one first but that assumes some knowledge of C so redirect to the C tutorials.

Ahh just what I need. Now, first I know I need a compiler so I go to find a free one. Stumble across this useful post http://www.codeproject.com/KB/cpp/altvcc.aspx

So I go to get GCC from here: http://gcc.gnu.org/ and end up here: http://www.mingw.org/. Right I now have a compiler installed.

Next stage, I reckon a GUI would be good, I'm assuming that it's a bit necessary for a good ol Windows app design. Everything points me to wxWidgets from here: http://www.wxwidgets.org/, then some things say install MSYS (no idea what that is) so I do that. Then I can download and install visualwx from here:http://visualwx.altervista.org/

Ok, all downloaded. Where to start?? Hmm. Fire up visualwx - crashes, can't find python25.dll. Ok, hmm, python. Right well find python for download, http://www.python.org/download/releases/3.0.1/.

Ok, so in the install I notice it also installs TCL hmm, so now I have C compilers, TCL and Python but still not started yet!

Right, back to python to get python 2.5. Can't find 2.5 but got a 2.5.4 - that must be close enough. And no, it still doesn't run, can't find python25.dll. Odd, I can, it's sitting in system32. Copy file to \windows and then the same folder as the .exe and no results, same error. Right, I quit on that one. Python uninstall and visualwx uninstall and back to google.

A bit of searching throws up something called QT - looks like it's worth a stab. Nice big download too.

Arrgh no idea where to start here, chucked in some basic C++ code and all of the build options are greyed out - no idea why and the help is about as useful as a wet fish.

Ok, now in my travels I did spot that there is Visual C available for free in an 'express' version. Now I am familiar with visual basic so maybe this is my way forwards.....
Welcome to my head - online!

This is basically what is going on in my head. Not of any intertest to most but at least I'll be able to remember what was in my head a few days ago!