Showing posts with label xml. Show all posts
Showing posts with label xml. Show all posts

Thursday, March 18, 2010

Query Scheduled Tasks The Hard Way

Because the CIM/WMI model is still an unfinished work in progress, I’ve once again had to resort to making some ugly crap code to work around a giant hole in the model. In this case it’s the lack of a model counterpart to the Scheduled Tasks collection.  This is NOT the same as the Win32_ScheduledJobs or the AT command output.  I’m talking about SCHTASKS.exe and the Windows Scheduled Tasks utility.  Anyhow, the klunky workaround here is to ride the SCHTASKS command like a whipping boy and make it dump a text file, then turn around and do a crude (but effective) string parsing and crank it out in XML form.  Enjoy.
'****************************************************************
' Filename..: xml_scheduled_tasks.vbs
' Author....: David M. Stein
' Date......: 03/18/2010
' Purpose...: query Scheduled Tasks (not WMI/Jobs/AT) --> XML out
'****************************************************************

Const tempfile = "c:\temp\schtasks.txt"
Const computer = ""

Const ForReading = 1
Const ForWriting = 2

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

If computer <> "" Then
cmdstr = "cmd /c schtasks /query /s \\" & computer & " /v /fo list >" & tempfile
Else
cmdstr = "cmd /c schtasks /query /v /fo list >" & tempfile
End If

retval = objShell.Run(cmdstr, 1, True)

If objFSO.FileExists(tempfile) Then
Dim linecount, objFSO, objFile, ln, strLine

linecount = 0
wscript.echo ""

Set objFile = objFSO.OpenTextFile(tempfile, ForReading)
Do Until objFile.AtEndOfStream
strLine = Trim(objFile.Readline)

If Left(strLine, 9) = "HostName:" Then
hostname = Mid(strLine, 39)
wscript.echo vbTab & ""

ElseIf Left(strLine, 9) = "TaskName:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""
wscript.echo vbTab & vbTab & "" & hostname & ""

ElseIf Left(strLine, 15) = "Scheduled Type:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 9) = "Schedule:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 12) = "Task To Run:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 8) = "Comment:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 12) = "Run As User:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 11) = "Start Time:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 11) = "Start Date:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 17) = "Power Management:" Then
wscript.echo vbTab & "
"

End If
linecount = linecount + 1

Loop
objFile.Close
Set objFSO = Nothing

wscript.echo "
"

Else
wscript.echo "fail: file not found"
End If

Thursday, March 4, 2010

VBScript: Enumerate Start Menu Shortcuts into XML

Here's a little script to dump a list of all shortcuts and their internal properties, which exist under the “All Users” profile, in Start Menu\Programs, as well as all sub-folders below that.  The output is basic raw XML.  Not much to it, but I had to crank this out for a special project I worked on a few weeks ago and thought I’d post it here.
'****************************************************************
' Filename..: enum_allusers_shortcuts.vbs
' Author....: skatterbrainz
' Date......: 02/03/2010
' Purpose...: enumerate shortcuts under all-users start menu (xml)
'****************************************************************
Dim objShell, allUsers, allStart, objFSO, oFolder, s

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

allUsers = objShell.ExpandEnvironmentStrings("%AllUsersProfile%")
allStart = allUsers & "\Start Menu\Programs"

Set oFolder = objFSO.GetFolder(allStart)

wscript.echo "<shortcuts>"
For each s in oFolder.SubFolders
ListShortcuts objFSO.GetFolder(allStart & "\" & s.Name)
Next
wscript.echo "</shortcuts>
"

Sub ListShortcuts(objFolder)
Dim objFile, filename
For each objFile in objFolder.Files
filename = objFile.Name
If Right(Lcase(filename),4) = ".lnk" Then
filepath = objFolder.Path & "\" & filename
wscript.echo vbTab & "<shortcut>"
ShortcutProps filepath
wscript.echo vbTab & "</shortcut>
"
End If
Next
End Sub

Sub ShortcutProps(scName)
Dim objShortcut
If objFSO.FileExists(scName) Then
Set objShortcut = objShell.CreateShortcut(scName)
WScript.Echo vbTab & vbTab & "<fullname>" & objShortcut.FullName & "</fullname>"
WScript.Echo vbTab & vbTab & "<arguments>" & objShortcut.Arguments & "</arguments>"
WScript.Echo vbTab & vbTab & "<workingpath>" & objShortcut.WorkingDirectory & "</workingpath>"
WScript.Echo vbTab & vbTab & "<target>" & objShortcut.TargetPath & "</target>"
WScript.Echo vbTab & vbTab & "<icon>" & objShortcut.IconLocation & "</icon>"
WScript.Echo vbTab & vbTab & "<hotkey>" & objShortcut.Hotkey & "</hotkey>"
WScript.Echo vbTab & vbTab & "<windowstyle>" & objShortcut.WindowStyle & "</windowstyle>"
WScript.Echo vbTab & vbTab & "<comment>" & objShortcut.Description & "</comment>"
Set objShortcut = Nothing
Else
wscript.echo "unable to find shortcut"
End If
End Sub

Set oFolder = Nothing
Set objFSO = Nothing
Set objShell = Nothing

Thursday, December 31, 2009

VBScript ADO with XML and CSV Data Files

I was poking around to find a way to read CSV, TXT (various delimiters) through VBScript for use in scripted data migrations, as well as to render the data in ASP, and found some interesting things.  I have to give credit to [http://www.mombu.com/microsoft/scripting-wsh/t-query-xml-file-with-ado-in-wsh-131431.html] for the XML example.  I only modified it slightly to fit in with how I tend to code ADO processes.  I also would like to applaud the efforts of Connection Strings.com for their fantastic reference site for connection information for almost anything that can possibly store information.

Reading XML Data

Const dsn = "Provider=MSDAOSP;Data Source=MSXML2.DSOControl;"
Const adChapter = 136

Dim conn, rs
Dim iLevel : iLevel = 0

Set conn = CreateObject( "ADODB.Connection" )
Set rs = CreateObject( "ADODB.Recordset" )

conn.Open dsn

rs.Open CreateObject( "WScript.Shell" ).CurrentDirectory + _
"\test.xml", conn

WalkHier iLevel, rs

rs.Close
conn.Close

Sub WalkHier(ByVal iLevel, ByVal rs)
iLevel = iLevel + 1
Dim PriorLevel : PriorLevel = iLevel
Dim i, adoChildRS
While Not rs.EOF
For i = 0 To rs.Fields.Count - 1
If rs.Fields(i).Name <> "$Text" Then
If rs.Fields(i).Type = adChapter Then
Set adoChildRS = rs.Fields(i).Value
WalkHier iLevel, adoChildRS
Else
wscript.echo iLevel & ": rs.Fields(" & i & ") = " & _
rs.Fields(i).Name & " = " & rs.Fields(i).Value
End If
End If
Next
rs.MoveNext
Wend
iLevel = PriorLevel
End Sub


Reading CSV Data



dsn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source='s:\scripts\';Extended Properties=""text;HDR=Yes;FMT=Delimited(,);"""

query = "SELECT * FROM test.csv"

Set conn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
Set rs = CreateObject("ADODB.Recordset")

conn.Open dsn

rs.CursorLocation = adUseClient
rs.CursorType = adOpenStatic
rs.LockType = adLockReadOnly

Set cmd.ActiveConnection = conn

cmd.CommandType = adCmdText
cmd.CommandText = query
rs.Open cmd

If Not(rs.BOF And rs.EOF) Then
Do Until rs.EOF
For i = 0 to rs.Fields.Count - 1
wscript.echo rs(i).name & " = " & rs(i).value
Next
rs.MoveNext
Loop
Else
wscript.echo "error: no records found"
End If
rs.Close
conn.Close
Set rs = Nothing
Set cmd = Nothing
Set conn = Nothing

Friday, December 25, 2009

Convert INI to XML with KiXtart

Sometimes you may want/need to read a standard INI data file and output it to an XML format.  There are several ways to do this, but here is just one.  You’ll need KiXtart 4.61 in order to use the Replace() function. Enjoy (and Merry Christmas!)

KiXtart Code

Break ON
; requires KiXtart 4.61 or later!!!
If @kix <= "4.60"
? "this script requires 4.61 or later!"
Exit
EndIf

$strFileName = "s:\scripts\test.ini"

$quote = Chr(34)
$tab = Chr(9)

Dim $linecount, $fHandle, $strLine, $outer, $keyset, $subkeyformat
Dim $name, $value

$subkeyFormat = 1
$fHandle = FreeFileHandle()
$outer = ""

If Open($fHandle, $strFileName) = 0
$strLine = ReadLine($fHandle)
While @error = 0
Select
Case Left($strLine,1) = "["
$outer = Replace(Replace($strLine, "]", ""), "[", "")
? "<$outer>"
Case InStr($strLine, "=") <> 0
$keyset = Split($strLine, "=")
$name = $keyset[0]
$value = $keyset[1]
If $subkeyFormat == 1
? "$tab"
Else
? "$tab<$name>$value</$NAME>"
EndIf
Case 1
If $outer <> ""
? "</$OUTER>"
$outer = ""
EndIf
EndSelect
$strLine = ReadLine($fHandle)
Loop
$=Close($fHandle)
EndIf

Saturday, October 17, 2009

Using Twitter to Control Your Computer

I’ve blogged about this before, but not with a lot of detail.  So here goes.

In my previous post, I explained how to setup a “system” that has your computer sending a DM (Direct Message) Tweet to your Twitter account.  But in this scenario I’m turning it around, so that you will Tweet your computer and have it perform actions based on what you Tweet.

What you do with this is up to you.  Anything you can do with a script is fair game.  Anything.  The script will reside on your computer.  You will send a DM to a Twitter account, which your computer will monitor on a scheduled recurrence.  Your script will read and parse the DM container and look for specific phrases that it is set to recognize and will execute a task accordingly.  Simple enough?  Good.  I thought so.

Ingredients:

  1. A Twitter Account
  2. Another Twitter Account
  3. A List of Things You Intend to Ask Your Computer To Do
  4. A Script
  5. A Scheduled Task

A Twitter Account

This is YOUR Twitter account actually.  You will need this in order to send a DM (Direct Message) Tweet to your computer, which requires…

Another Twitter Account

This is the account your computer will monitor.  Remember to lock it down so only your “other” Twitter account can access it.

A List of Things for Your Computer To Do

You need to sit down and make a list of what specific tasks you want to be able to request of your computer.  Yes, you COULD make it so you Tweet any shell operation and have it blindly execute that, but trust me: THAT IS DANGEROUSLY STUPID.  In fact, so stupid, you should have your balls stomped with ice climbing boots in a rowdy Irish pub just for thinking it.  Need some pointers? Here’s a simple list to get you started:

  • Reboot or Shutdown a computer
  • Disable a User Account
  • Add/Remove A User to/from a Group
  • Start/Stop a Service
  • Start a Batch or Backup Job

For the first example, I’m going to simply have the computer tweet me back.  That way I know the plumbing is working and the toilets flush properly.  To do this, I’m going to make a script that reads my DM list and parses it for a specific phrase.  When that phrase is found, it will simply tweet me back (by DM) to let me know it got it.

A Script

The script I’m using for this example is written in VBscript, but any language/platform will work fine as long as it can invoke the Twitter API.  This script will access my Computer Twitter account, fetch the DM queue, iterate through it for messages containing a specific phrase of “TWEET_ME_BACK @userid” and then simply turn around and send a DM to the “@userid” that sent it (which, in this situation, is me).

'----------------------------------------------
' filename: twitter_monitor.vbs
' author: skatterbrainz
' http://scriptzilla.blogspot.com
' give props, don't rip me off please?
'----------------------------------------------
Const username = "Computer_TwitterName"
Const password = "Computer_TwitterPassword"
Const replyTo = "My_Twitter_Account"

Function Twitter_Get_Direct(strUser,strPass)
wscript.echo "querying for direct messages..."
Dim oXml, strTwitterURL : strTwitterURL = "http://twitter.com/direct_messages.xml"
Set oXml = CreateObject("MSXML2.ServerXMLHTTP.3.0")
oXml.Open "GET", strTwitterURL, False, strUser, strPass
oXml.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oXml.Send()
Twitter_Get_Direct = oXml.responseText
Set oXml = Nothing
End Function

result = Twitter_Get_Direct(username, password)

'----------------------------------------------
' if direct messages were found, iterate them
'----------------------------------------------

If Trim(result) <> "" Then
wscript.echo "direct messages were found!"
Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.async = "false"
xmlDoc.loadXML(result)
For each x in xmlDoc.documentElement.childNodes
msg = x.Text
If InStr(1, Ucase(msg), "TWEET ME BACK") <> 0 Then
id = Left(msg, 9)
wscript.echo id, ": ", Mid(Msg, 20)
wscript.echo "sending tweet-dm..."
TweetBack()
DeleteDM id
End If
Next
End If

'----------------------------------------------
' send tweet via direct-message
'----------------------------------------------

Sub TweetBack()
Dim retval, strMsg : strMsg = "I got your message!"
Dim oXml, strTwitterURL : strTwitterURL = "http://twitter.com/direct_messages/new.xml"
Set oXml = CreateObject("MSXML2.ServerXMLHTTP.3.0")
oXml.Open "POST", strTwitterURL, False, username, password
oXml.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oXml.Send "text=" & strMsg & "&user=" & replyTo
retval = oXml.responseText
Set oXml = Nothing
End Sub

'----------------------------------------------
' delete a direct-message using the id number
'----------------------------------------------

Sub DeleteDM(id)
Dim retval
Dim oXml, strTwitterURL : strTwitterURL = "http://twitter.com/direct_messages/destroy/" & id & ".xml"
Set oXml = CreateObject("MSXML2.ServerXMLHTTP.3.0")
oXml.Open "POST", strTwitterURL, False, username, password
oXml.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oXml.Send()
retval = oXml.responseText
Set oXml = Nothing
End Sub


Note that in the iteration section of code above I invoke the XMLDOM object to parse the direct_message result.  This is because it returns a single XML stream that contains all of the direct messages.



A Scheduled Task



Because your computer needs to read the Twitter account DM queue, it needs to “poll” for it using a recurrent task.  The easiest way to do this is by creating a scheduled task.  Each time the task is initiated, it will execute the script and go back to sleep until it’s scheduled to run again.  I’m using Windows 7 for this example, so here goes…




  1. Click on the Windows button (formerly “Start” button)


  2. Type in SCHED and as soon as “Task Scheduler” appears at the top, press Enter.


  3. Click on Task Scheduler Library in the left-hand panel


  4. Right-click on Task Scheduler Library and select “Create Task


  5. In the Name box, enter “Monitor Twitter Account”


  6. In the Description box, enter “Monitor Twitter account ___ for Direct Messages to parse” (fill-in your computer Twitter account name).


  7. Select “Run whether user is logged on or not”


  8. Click “Change User or Group” button, enter “SYSTEM” and click “Check Names”


  9. Once the name is underlined, click OK.  You should see “NT AUTHORITY\SYSTEM” in the user account name box. (see Fig. 1)


  10. Click the Triggers tab.


  11. Change the “Repeat task every:” to “15 Minutes”


  12. Check “Stop task if it runs longer than:” and set it to “14 Minutes” (see Fig. 2)


  13. Click OK, to return to the Create Task form.


  14. Click the Actions tab, click the New button


  15. Enter “cscript” for the program.  Enter “/nologo c:\scripts\monitor_twitter.vbs” in the arguments box (see Fig. 3, and 4)


  16. Click OK to save the new Task



Figure 1 Fig. 1



Figure 2 Fig. 2



Figure 3 Fig. 3



Figure 4 Fig. 4

Sunday, July 12, 2009

LDAP Query for User Accounts Created Since a Specific Date

Just modify the date string to use the YYYYMMDDHHMMSS.0Z format. So, for June 1, 2009, you would specify "20090601000000.0Z"


(&(objectCategory=user)(whenCreated>=20090601000000.0Z))

LDAP Query for Printers = HP DesignJet Plotters


(&(&
(uncName=*)
(objectCategory=printQueue)
(objectCategory=printQueue)
(driverName=*DesignJet*)
))

LDAP Query for Windows Server 2003 SP1 Computers in AD


(&(&(&(&(&(&(&(&(&(&
(objectCategory=Computer)
(operatingSystem=Windows Server 2003*)
(operatingSystemServicePack=Service Pack 1)
))))))))))