Thursday, September 13, 2007

HowTo: Enum Citrix Server License using LMSTAT

Our PS4 server seems to fail to execute the license information scripts from Citrix.Com (Dependency on SDK).

So instead of relying on it, I decided to develop a script using LMSTAT and a short vb script to parse the output file and write it to a .CSV file for better viewing (Data Filtering and such...)

First I piped the result of lmstat -a to a text file then I used the script below to parse the contents then write it to a .CSV file

Code Snippet:

Parse the source file (lmstat output file): srcfile

  1. Sub GetData(srcfile)
  2. Set f = fso.GetFile(srcfile)
  3. Set ts = f.OpenAsTextStream(ForReading, TristateUseDefault)
  4. Do While ts.AtEndOfStream <> True
  5. readResults = Trim(UCase(ts.ReadLine))
  6. If InStr(readResults, "/27000") Then
  7. mps = split(readResults, Chr(32))
  8. msg = mps(1) & "," & mps(3) &amp; "," & mps(4) &amp;amp; "," & mps(5) & mps(6) & mps(8) &amp;amp; " " & mps(9) &amp;amp; " " & mps(10)
  9. WriteToCSV msg, license_out
  10. End If
  11. Loop
  12. End Sub

Write to CSV function: oCsv(Output File), msg(parsed ReadLine results)


  1. Function WriteToCSV(oCsv,msg)
  2. If Not fso.FileExists(oCsv) Then fso.CreateTextFile(oCsv)
  3. Set f = fso.GetFile(oCsv)
  4. Set ts = f.OpenAsTextStream(ForAppending, TristateUseDefault)
  5. ts.Write msg & vbCrlf
  6. msg = ""
  7. ts.Close
  8. End Function
If at first you fail, call it version 1.0

Wednesday, September 12, 2007

Event Log

Event Log Manipulations:

1. Reading the Event Log
2. Clearing the Event Log
3. Creating backup of the Event Log

Code Snippet #1:

  1. strComputer = "."
  2. Set objWMIService = GetObject("winmgmts:" _
  3. & "{impersonationLevel=impersonate}!\\" _
  4. & strComputer & "\root\cimv2")
  5. Set colLoggedEvents = objWMIService.ExecQuery _
  6. ("Select * from Win32_NTLogEvent " _
  7. & "Where Logfile = 'System'")
  8. For Each objEvent in colLoggedEvents
  9. Wscript.Echo "Category: " &amp; objEvent.Category & VBNewLine _
  10. &amp;amp; "Computer Name: " & objEvent.ComputerName & VBNewLine _
  11. & "Event Code: " & objEvent.EventCode & VBNewLine _
  12. & "Message: " & objEvent.Message & VBNewLine _
  13. & "Record Number: " & objEvent.RecordNumber & VBNewLine _
  14. & "Source Name: " & objEvent.SourceName & VBNewLine _
  15. & "Time Written: " & objEvent.TimeWritten & VBNewLine _
  16. &amp;amp; "Event Type: " & objEvent.Type & VBNewLine _
  17. & "User: " & objEvent.User
  18. Next


Code Snippet #2:

  1. strComputer = "."
  2. Set objWMIService = GetObject("winmgmts:" _
  3. & "{impersonationLevel=impersonate,(Backup)}!\\" & _
  4. strComputer & "\root\cimv2")
  5. Set colLogFiles = objWMIService.ExecQuery _
  6. ("Select * from Win32_NTEventLogFile " _
  7. & "Where LogFileName='Application'")
  8. For Each objLogfile in colLogFiles
  9. objLogFile.ClearEventLog()
  10. WScript.Echo "Cleared application event log file"
  11. Next

Code Snippet #3:


  1. strComputer = "."
  2. Set objWMIService = GetObject("winmgmts:" _
  3. & "{impersonationLevel=impersonate,(Backup)}!\\" & _
  4. strComputer & "\root\cimv2")
  5. Set colLogFiles = objWMIService.ExecQuery _
  6. ("Select * from Win32_NTEventLogFile " _
  7. & "Where LogFileName='Application'")
  8. For Each objLogfile in colLogFiles
  9. errBackupLog = objLogFile.BackupEventLog( _
  10. "c:\scripts\application.evt")
  11. WScript.Echo "File saved as c:\scripts\applications.evt"
  12. Next
If at first you fail, call it version 1.0

Friday, July 13, 2007

MFCOM: Farm Session Count

Another day of Citrix Administration, a simple MFCOM script to view Active Farm Sessions.

Code Snippet:

  1. Const cMetaFrameWinFarmObject = 1
  2. Const MFSessionStateActive = 1
  3. Set theFarm = CreateObject("MetaFrameCOM.MetaFrameFarm")
  4. theFarm.Initialize(cMetaFrameWinFarmObject)
  5. intSessionCount = 0
  6. intActiveCount = 0
  7. For Each oSession In theFarm.Sessions
  8. intSessionCount = intSessionCount + 1
  9. If (oSession.SessionState = MFSessionStateActive) and (oSession.SessionName <> "Console") Then
  10. intActiveCount = intActiveCount + 1
  11. WScript.Echo vbcrlf & "*****************************"
  12. WScript.Echo "User Name: " & oSession.UserName
  13. WScript.Echo "IP Address: " & oSession.ClientAddress
  14. WScript.Echo "Server: " & oSession.ServerName
  15. WScript.Echo "Application: " & oSession.AppName
  16. WScript.Echo "Logon Time: " & oSession.ConnectedTime
  17. End If
  18. Next
  19. WScript.Echo "Total Session Count = " & intSessionCount & vbcrlf & _
  20. "Active Session Count = " & intActiveCount


If at first you fail, call it version 1.0

MFCOM: Connection licenses and usage count

Yet Another Citrix Administrator Task, monitor the connection licenses and usage count in the farm...

Feel like a hill billy...

Code Snippet:

  1. Dim fso
  2. Set fso = CreateObject("Scripting.FileSystemObject")
  3. If not fso.FolderExists("c:\liclog" ) then
  4. Set MyFolder = fso.createFolder("c:\liclog" )
  5. else
  6. End if
  7. if not fso.FileExists("c:\liclog\licCount.log" ) then
  8. Set MyFile= fso.createTextFile("c:\liclog\licCount.log")
  9. MyFile.writeline "Date " & " Time " & "Lic Type " & "Used"
  10. MyFile.close
  11. else
  12. end if
  13. Const ForAppending = 8
  14. Set MyFile= fso.OpenTextFile("c:\liclog\licCount.log", ForAppending,True)
  15. Dim theFarm, aLicense
  16. Set theFarm = CreateObject("MetaFrameCOM.MetaFrameFarm")
  17. ' Initialize the farm object.
  18. theFarm.Initialize(MetaFrameWinFarmObject)
  19. For Each aLicense In theFarm.LicenseSets(MFLIcenseClassConnection)
  20. if aLicense.LicenseID = "0000000000000003" then
  21. MyFile.WriteLine date & "," & time & "," & aLicense.Name &amp;amp; "," & aLicense.pooledinuse("")
  22. else
  23. end if
  24. next
  25. MyFile.Close


If at first you fail, call it version 1.0

Monday, July 09, 2007

Merlin the great!

Imagine how amazed your users will be when they login to the domain and Merlin greets them...

You can call Merlin using Agent Control and make do the moves while you perform you login scripts in the background...

You can load information about the logged on user either using ADSI scripts or just by reading on the environment variable table...

Take note of the length of the messages or actions you throw at Merlin, you might need to make use of the Sleep method, otherwise the sentences or the animation will overlap...

Code Snippet:


  1. strAgentName = "Merlin"
  2. strAgentPath = "Msagent\Chars\" & strAgentName &amp;amp; ".acs"
  3. Set objAgent = CreateObject("Agent.Control.2")
  4. objAgent.Connected = True
  5. objAgent.Characters.Load strAgentName, strAgentPath
  6. Set merlin_d_great = objAgent.Characters.Character(strAgentName)
  7. With merlin_d_great
  8. .Show
  9. Set objRequest = .MoveTo(500,400)
  10. Set objRequest = .Play("Announce")
  11. Set objRequest = .Play("Explain")
  12. Set objRequest = .Speak("Hi ")
  13. Set objRequest = .Play("Read")
  14. wscript.sleep 2000
  15. Set objRequest = .Speak("Today is " & Now() & "...")
  16. Set objRequest = .Play("ReadContinued")
  17. wscript.sleep 2000
  18. Set objRequest = .Speak("and the time is " &amp; Time() & "...")
  19. wscript.sleep 2000
  20. Set objRequest = .Play("ReadReturn")
  21. wscript.sleep 2000
  22. Set objRequest = .MoveTo(750, 450)
  23. Set objRequest = .Play("Pleased")
  24. wscript.sleep 5000
  25. Set objRequest = .Speak("I will be back shortly...")
  26. wscript.sleep 5000
  27. Set objRequest = .Play("Wave")
  28. wscript.sleep 5000
  29. .Hide
  30. End With

Have a blast with Merlin, and oh... you can use other characters aswell...

If at first you fail, call it version 1.0

Radia Command Lines

There are few documents available on Radia troubleshooting and knowledgebase so I decided to post

Q. What is Radia?
A. Radia is Software Deployment\Management Solution (formerly Novadigm EDM\Radia) that was bought by HP.

Q. What is RCS?
A.

Q. What is RPM?
A.

Q. What is RPX\RPS?
A.

Q. What is RMS?
A.



  1. nvdkit objdump
  2. nvdkit.exe objdump zconfig.edm | FIND /I
  3. nvdkit eval nvd::init; set radexe "[exec $::NVDSYS/RADNTFYC.EXE RADCONCT.EXE mode=discovery]"
  4. nvdkit tpping -host
  5. nvdkit sync

  6. If at first you fail, call it version 1.0

    KD Memory.dmp debugging

    One of our Citrix server encountered a BSOD, luckily we had RSA and managed to hard reboot the server.

    I've gathered the memory dump to view the cause of BSOD and found the Symantec Antivirus has caused a module error on the NIC driver.

    We have then disabled the Network Drives in the File System Auto Protect and it had not experienced the same ever since.

    Did not find any help from Symantec regarding the root cause other than it's a known issue.

    Below are some steps that you could use for debbuging:

    1. Launch windbg passing it the location of the symbol files, the source files (i386 directory) and the dump file. Example: windbg -y dump\symbols -i SRC\i386 -z dump\Memory.dmp

    2. At the bottom of the Command window there is a kd> prompt.

    3. The commands are entered into that prompt: kd>!analyze -v

    4. Two things to look for in the results: the memory referenced and the FAULTING_IP

    5. The command: kd>lm - will produce a listing of modules and their memory location.

    6. Look to see which module's memory the memory referenced identified above falls in.

    7. That usually indicates the process that caused the crashed and will probably match the FAULTING_IP if listed.

    8. Also informative: kd>.reload –v

    If at first you fail, call it version 1.0

    Thursday, June 28, 2007

    HowTo: Add cmd.exe to right click context menu

    If you want the command prompt to be available whenever you right click on objects on your desktop or explorer, you can opt to create the keys in the registry:

    • HKEY_CLASSES_ROOT\Folder\shell\MenuText\Command

    Change the (Default) value to cmd.exe /k cd "%1"

    Or you can script it!

    Code Snippet:
    1. Const HKEY_CLASSES_ROOT = &H80000000
    2. Const HKEY_CURRENT_USER = &H80000001
    3. Dim WSHShell, objWMIService, strComputer, lcValue1
    4. strComputer = "."
    5. Set objWMIService = GetObject("winmgmts:\\" & strComputer &amp;amp; "\root\cimv2")
    6. Set objWSHShell = WScript.CreateObject("WScript.Shell")
    7. Set objRegObj = WScript.CreateObject("RegObj.Registry")
    8. objWSHShell.Popup "This will enable CMD with explorer options for the Current User"
    9. objWSHShell.RegWrite "HKCR\Folder\Shell\MenuText\Command\", "cmd.exe /k cd " & chr(34) & "%1" & chr(34)
    10. objWSHShell.RegWrite "HKCR\Folder\Shell\MenuText\", "Launch CMD"
    11. tmp = objWSHShell.RegRead("HKCR\Folder\Shell\MenuText\")
    12. objWSHShell.Popup ("Current Value: " + tmp)

    If at first you fail, call it version 1.0

    HowTo: Enable disabled services

    If you want to automate startups on services that might be disabled by GPO, you can use Win32_Service class and change properties like the startup (Automatic\Manual\Disabled) or start\stop the service.

    In my case, I prefer to use themes on my XP machine at work but our GPO disables them so our machines look like NT desktops... it sucks ain't it?

    So to overcome this, I placed the script in my startup to enable the Themes and start the service.

    Code Snippet:

    1. strComputer = "."
    2. Set objWMIService = GetObject("winmgmts:" _
    3. & "{impersonationLevel=impersonate}!\\" & _
    4. strComputer & "\root\cimv2")
    5. Set colServiceList = objWMIService.ExecQuery _
    6. ("Select * from Win32_Service where Name = 'Themes'")
    7. For Each objService in colServiceList
    8. 'Wscript.Echo objService.Name
    9. errReturnCode = objService.Change( , , , , "Automatic")
    10. If objService.State <> "Running" Then
    11. objService.StartService()
    12. Else
    13. objService.StopService()
    14. Wscript.Echo "Stopping..."
    15. Wscript.Sleep 5000
    16. objService.StartService()
    17. Wscript.Echo "Applying Themes"
    18. Wscript.Sleep 5000
    19. End If
    20. Next
    Change line #6 value to any services that you want to enable (my case it's Name = 'Themes').

    I prefer to use Cscript when executing any vbs scripts to avoid having to click on message prompts whenever you Echo.

    If at first you fail, call it version 1.0

    Bytes Converter Function

    A simple function that converts Bytes to GB, MB or KB.

    Code Snippet:

    1. Function SetBytes(Bytes,fKB)
    2. if fKB=True then Bytes = Bytes * 1024
    3. If Bytes >= 1073741824 Then
    4. SetBytes = FormatNumber((Bytes / 1024 / 1024 / 1024),2,,-1,-1) & " GB"
    5. ElseIf Bytes >= 1048576 Then
    6. SetBytes = FormatNumber((Bytes / 1024 / 1024),2,,-1,-1) & " MB"
    7. ElseIf Bytes >= 1024 Then
    8. SetBytes = FormatNumber((Bytes / 1024),2,,-1,-1) & " KB"
    9. ElseIf Bytes < 1024 Then
    10. SetBytes = Bytes & " Bytes"
    11. End If
    12. End Function

    Usage: SetBytes(Size,true\false)

    If at first you fail, call it version 1.0

    Tuesday, June 26, 2007

    Kix Copy script with GUI (Kixtart UDF)

    Another KIXtart UDF, well the title says it all...

    Dependencies:
    KiX 4.02 (or higher)
    Shell32.dll version 4.71 or later. (Included with: Windows 2000, Windows NT 4.0 with Internet Explorer 4.0, Windows 98, Windows 95 with Internet Explorer 4.0.)

    Usage:
    GUICopy("source", "destination", "optional flag", "optional flag")
    @ERROR " : " @SERROR ?

    Optional Flags:
    4 - Do not display a progress dialog box.
    8 - Give the file being operated on a new name in a move, copy, or rename
    operation if a file with the target name already exists.
    16 - Respond with "Yes to All" for any dialog box that is displayed.
    64 - Preserve undo information, if possible.
    128 - Perform the operation on files only if a wildcard file name (*.*) is
    specified.
    256 - Display a progress dialog box but do not show the file names.
    512 - Do not confirm the creation of a new directory if the operation requires
    one to be created.
    1024 - Do not display a user interface if an error occurs.
    2048 - Version 4.71. Do not copy the security attributes of the file.
    4096 - Only operate in the local directory. Don't operate recursively into
    subdirectories.
    8192 - Version 5.0. Do not copy connected files as a group. Only copy the
    specified files.


    Returns The exitcode of the command in the @ERROR macro.
    @ERROR = 0 The operation completed successfully.
    @ERROR = 2 The system cannot find the file specified. (Refers to Source file.)
    @ERROR = 3 The system cannot find the path specified. (Bad destination path.)
    @ERROR = 9 The storage control block address is invalid. (Most likely cancelled copy.)
    @ERROR = 10 The environment is incorrect. (Incorrect Shell32.dll version.)
    @ERROR = 87 The parameter is incorrect. (Use 0 or 1 to specify Copy or Move.)

    Code Snippet:

    1. Function GUICopy($sSrc, $sDest, OPTIONAL $lFlags, OPTIONAL $bMove)
    2. Dim $sVer,$objShell,$objFldr
    3. If Not Exist($sSrc) Exit 2 Endif
    4. If Not Exist($sDest) Exit 3 Endif
    5. If @INWIN=1
    6. $sVer=GetFileVersion(%WINDIR%+"\System32\Shell32.dll","FileVersion")
    7. Else
    8. $sVer=GetFileVersion(%WINDIR%+"\System\Shell32.dll","FileVersion")
    9. Endif
    10. If $sVer<"4.71" Exit 10 Endif
    11. $objShell=CreateObject("Shell.Application")
    12. $objFldr=$objShell.NameSpace($sDest)
    13. If @ERROR<0 Exit VAL("&"+Right(DecToHex(@ERROR),4)) EndIf
    14. Select
    15. Case $bMove=1 $objFldr.MoveHere($sSrc,$lFlags)
    16. Case $bMove=0 $objFldr.CopyHere($sSrc,$lFlags)
    17. Case 1 Exit 87
    18. EndSelect
    19. If @ERROR<0 Exit VAL("&"+Right(DecToHex(@ERROR),4)) EndIf
    20. Exit @ERROR
    21. EndFunction

    If at first you fail, call it version 1.0

    Kix FTP (Kixtart UDF)

    FTP via Kix? Yes!!!

    Using Microsoft.XMLHTTP and ADODB.Stream.

    Usage:

    FTPget("ftp_address", "target_dest_drive", "id", "password")

    Code Snippet:

    1. Function FTPget($sURL, $sTargetFile, optional $sUser, optional $sPass)
    2. Dim $oFTP, $oStream $sUser=""+$sUser
    3. $oFTP = CreateObject("Microsoft.XMLHTTP")
    4. if @error
    5. $ftpget=1
    6. exit 1
    7. endif
    8. $oStream = CreateObject("ADODB.Stream")
    9. if @error
    10. $ftpget=2
    11. exit 2
    12. endif
    13. if $sUser
    14. $oFTP.Open("GET", $sURL, not 1, $sUser, $sPass)
    15. else
    16. $oFTP.Open("GET", $sURL, not 1)
    17. endif
    18. if @error
    19. $ftpget=3
    20. exit 3
    21. endif
    22. $oFTP.Send
    23. $oStream.Type = 1
    24. $oStream.Mode = 3
    25. $oStream.open
    26. $oStream.Write($oFTP.responseBody)
    27. if @error
    28. $ftpget=4
    29. exit 4
    30. endif
    31. $oStream.SaveToFile($sTargetFile, 2)
    32. if @error
    33. $ftpget=5
    34. exit 5
    35. endif
    36. $oStream.Close
    37. EndFunction


    If at first you fail, call it version 1.0

    Perl SMTP

    IIS6 requires an Application Pool (like Sharepoint or Exchange) other than Default Application Pool for your Web or Virtual Directory for .Net mail sending via your webpage or else CDONTS library will throw Access Denied errors In Yer Face!

    Well thanks to Perl's MIME-Lite and Net-SMTP you are likely to bypass this.

    Code Snippet:

    1. use MIME::Lite;
    2. use Net::SMTP;
    3. # This debug flag will print debugging code to your browser,
    4. # depending on its value
    5. # Set this to 1 to send debug code to your browser.
    6. # Set it to 0 to turn it off.
    7. my $DEBUG = 1;
    8. if($DEBUG)
    9. {
    10. $| = 1;
    11. open(STDERR, ">&STDOUT");
    12. }
    13. # Set this variable to your smtp server name
    14. # my $ServerName = "YourSMTPServer";
    15. # Creat a new SMTP object
    16. #$smtp = Net::SMTP->new($ServerName, Debug => 1);
    17. # If you can't connect, don't proceed with the rest of the script
    18. #die "Couldn't connect to server" unless $smtp;
    19. ### Adjust Sender & Recepient email address
    20. my $from_address = '';
    21. my $to_address = '';
    22. my $cc_address = '';
    23. my $mime_type = 'multipart/mixed';
    24. ### Adjust subject and body message
    25. my $subject = '';
    26. my $message_body = "";
    27. ### Adjust the file to attach
    28. my $filename1 = '';
    29. my $recommended_filename1 = '';
    30. ### Creat the initial text of the message
    31. my $mime_msg = MIME::Lite->new(
    32. From => $from_address,
    33. To => $to_address,
    34. Cc => $cc_address,
    35. Subject => $subject,
    36. Type => $mime_type,
    37. )
    38. or die "Error creating MIME body: $!\n";
    39. ### Add the text message
    40. $mime_msg->attach(
    41. Type => 'TEXT',
    42. Data => $message_body
    43. ) or die "Error adding the text message part: $!\n";
    44. ### Attach the attachmnet file
    45. $mime_msg->attach(
    46. Type => 'application/txt',
    47. Path => $filename1,
    48. Filename => $recommended_filename1,
    49. Disposition => 'attachment',
    50. )
    51. or die "Error attaching test file: $!\n";
    52. my $message_body = $mime_msg->body_as_string();
    53. ### Set this variable to your smtp server name
    54. my $ServerName = "";
    55. ### Creat a new SMTP object
    56. $smtp = Net::SMTP->new($ServerName, Debug => 1);
    57. ### If you can't connect, don't proceed with the rest of the script
    58. die "Couldn't connect to server" unless $smtp;
    59. MIME::Lite->send('smtp', $ServerName, Timeout=>60);
    60. $mime_msg->send;
    61. ### Close the connection
    62. $smtp->quit();

    If at first you fail, call it version 1.0

    WMI Ping (Win32_PingStatus)

    The code below is an example in how to use Win32_PingStatus class in WMI to check a remote machine's status on the network.

    Code Snippet:

    1. Function PingHost(sTarget)
    2. Set cPingResults = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _
    3. sHost & "/root/cimv2"). ExecQuery("SELECT * FROM Win32_PingStatus " & _
    4. "WHERE Address = '" + sTarget + "'")
    5. For Each oPingResult In cPingResults
    6. If oPingResult.StatusCode = 0 Then
    7. If LCase(sTarget) = oPingResult.ProtocolAddress Then
    8. WScript.Echo sTarget & " is responding"
    9. Else
    10. WScript.Echo sTarget & "(" & oPingResult.ProtocolAddress &amp; ") is responding"
    11. End If
    12. Wscript.Echo "Bytes = " & vbTab & oPingResult.BufferSize & _
    13. vbTab & "Time (ms) = " & vbTab & oPingResult.ResponseTime & _
    14. vbTab & "TTL (s) = " & vbTab & oPingResult.ResponseTimeToLive & _
    15. vbTab & "Hostname = " & vbTab & oPingResult.ProtocolAddressResolved
    16. Else
    17. WScript.Echo sTarget & " is not responding"
    18. WScript.Echo "Status code is " & oPingResult.StatusCode
    19. WScript.Echo "*********************************"
    20. End If
    21. Next
    22. End Function

    If at first you fail, call it version 1.0

    How to: Enable Reply to All?

    Did your company disabled the reply to all option on your Outlook?
    And even deployed a noreplyall.dll to remove the icon?

    It sucks ain't it? Copying all the address from the previous email instead of just clicking on the Replyall button...

    You could delete these two (2) keys in the registry then restart your Outlook.
    Customize your Toolbar , search for the Actions category and enable the ReplytoAll button.

    • HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\11.0\Outlook\DisabledCmdBarItemsList
    • HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\11.0\Outlook\DisabledShortcutKeysList

    If you have GPO applied, this settings will not be retained after you logoff or reboot your machine...

    Well a short NT script on your startup can bring it back...


    Code Snippet:
    1. @Echo Off
    2. > "%Temp%.\EnableRep2All.reg" Echo Windows Registry Editor Version 5.00
    3. >> "%Temp%.\EnableRep2All.reg" Echo
    4. >> "%Temp%.\EnableRep2All.reg" Echo [-HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\11.0\Outlook\DisabledCmdBarItemsList]
    5. >> "%Temp%.\EnableRep2All.reg" Echo [-HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\11.0\Outlook\DisabledShortcutKeysList]
    6. >> "%Temp%.\EnableRep2All.reg" Echo
    7. START /WAIT REGEDIT.EXE /S "%Temp%.\EnableRep2All.reg"
    8. DEL "%Temp%.\EnableRep2All.reg"
    9. Exit



    If at first you fail, call it version 1.0

    OS Performance monitoring (PowerShell)




    Another useful powershell code snippet, monitoring the OS performance...


    Code Snippet:

    1. $computer = "."
    2. $perf = get-wmiobject -class "Win32_PerfFormattedData_PerfOS_System" -computer $computer
    3. $uptime=$perf.SystemUpTime/3600
    4. write-host "Performance Stats: "
    5. write-host "Processes", $perf.Processes
    6. write-host "Threads", $perf.Threads
    7. write-host "System Up Time `(hours`)", $uptime.tostring("00.0")
    8. write-host "Alignment Fixups/sec", $perf.AlignmentFixupsPersec.tostring("###,##0.0")
    9. write-host "Context Switches/sec", $perf.ContextSwitchesPersec.tostring("###,##0.0")
    10. write-host "Exception Dispatches/sec", $perf.ExceptionDispatchesPersec.tostring("###,##0.0")
    11. write-host "File Control Bytes/sec", $perf.FileControlBytesPersec.tostring("###,##0.0")
    12. write-host "File Control Operations/sec", $perf.FileControlOperationsPersec.tostring("###,##0.0")
    13. write-host "File Data OperationsPersec", $perf.FileDataOperationsPersec.tostring("###,##0.0")
    14. write-host "File Read Bytes/sec", $perf.FileReadBytesPersec.tostring("###,##0.0")
    15. write-host "File Read Operations/sec", $perf.FileReadOperationsPersec.tostring("###,##0.0")
    16. write-host "File Write Bytes/sec", $perf.FileWriteBytesPersec.tostring("###,##0.0")
    17. write-host "File Write Operations/sec", $perf.FileWriteOperationsPersec.tostring("###,##0.0")
    18. write-host "Floating Emulations/rsec", $perf.FloatingEmulationsPersec.tostring("###,##0.0")
    19. write-host "Percent Registry Quota Used", $($perf.PercentRegistryQuotaInUse/100).tostring("P")
    20. write-host "Processor Queue Length", $perf.ProcessorQueueLength
    21. write-host "System Calls Persec", $perf.SystemCallsPersec
    22. write-host ""


    Sample Output:
    Performance Stats:
    Processes 66
    Threads 573
    System Up Time (hours) 24.8
    Alignment Fixups/sec 0.0
    Context Switches/sec 9,857.0
    Exception Dispatches/sec 0.0
    File Control Bytes/sec 0.0
    File Control Operations/sec 0.0
    File Data OperationsPersec 1,232.0
    File Read Bytes/sec 3,943,044.0
    File Read Operations/sec 1,232.0
    File Write Bytes/sec 0.0
    File Write Operations/sec 0.0
    Floating Emulations/rsec 0.0
    Percent Registry Quota Used 9.00 %
    Processor Queue Length 0
    System Calls Persec 51752



    If at first you fail, call it version 1.0

    Software Inventory in a jiffy (Powershell)

    WMIC and WSH are good enough to perform software inventory collection... but the coding's just a little bit longer...

    Well to query wmi is not a big task, it's formatting the output that will get your code extra few lines of unnecessary vbtab's and vbcrlf's.

    Install Windows Power Shell, then it will take only three (3) lines of codes to get it running and the output is as lovely as a well defined tabular echo's on your console.

    Code Snippet:

    1. #Software Inventory
    2. $computer = "."
    3. $prod = Get-WmiObject -class "win32_product" -computer $computer
    4. $prod | sort name | ft Name, Version, Vendor, Installdate -a
    Just save it as *.ps1 then execute it with powershell...

    If at first you fail, call it version 1.0

    Monday, June 18, 2007

    ADSI Kixtart UDF for Citrix login

    Having a mixed mode environment gave us a lot of hassle when logging in to NT and querying group membership in AD... Specially in our case, we have nested OU's...

    Ifmember.exe is useful for this problem but it does cause a slight delay in the login process and the users are complaining on the slow login session, some couldn't wait and cancels the connection... catastrophic experience ends up as a global complain... hmmm... some people are just impatient...

    So to be able to execute an ADSI query through kix login script the function below can be inserted anywhere in the login script to perform InGroup query... or this can fully replace the built in InGroup function in kixtart.


    Code Snippet:

    1. Function fnInGroupAD($sGroup,Optional $bComputer)
    2. Dim $objSys,$objTarget,$aMemberOf,$sMemberOf
    3. $objSys = CreateObject("ADSystemInfo")
    4. $objTarget = GetObject("LDAP://"+Iif($bComputer,$objSys.ComputerName,$objSys.UserName))
    5. $aMemberOf = $objTarget.GetEx("memberOf")
    6. For Each $sMemberOf in $aMemberOf
    7. If InStr($sMemberOf,"CN="+$sGroup+",")
    8. $fnInGroupAD = Not 0
    9. Exit
    10. EndIf
    11. Next
    12. $fnInGroupAD = NOT 1
    13. EndFunction

    If at first you fail, call it version 1.0

    Saturday, June 16, 2007

    Windows Management Instrumentation Command-line (WMIC) tool

    I previously posted an article regarding wbemtest that can be utilized in performing wmi query.

    I recently visited M$oft and found an article on wmi command-line.

    It was a good read and I was pleased to know that it provides you a simple command-line interface to Windows Management Instrumentation (WMI).

    If you’ve never used WMIC, open a command prompt and type: WMIC

    You should get a brief installation message followed by a WMIC prompt. You can type exit to return to the command prompt. WMIC has an interactive mode like NSLOOKUP or you can access it directly from the command line.

    For example, run "wmic os get caption,csdversion", then you should get something like this:

    Caption CSDVersion
    Microsoft Windows XP Professional Service Pack 2


    Type WMIC /? to view more info.

    Note:
    Use the /RECORD global switch to redirect WMIC output to a file.


    If at first you fail, call it version 1.0

    Double System State Backup

    We have a scheduled System State backup running on our Web Server.

    To save the extra cost of software and hardware backups, I wrote a script that copies the System State backup to folders named after the date the backup was performed.

    With this, it's easier for us to restore backups for particular days without having too much hassels.

    Code Snippet:

    '---------------------------------------------
    ' System State Backup Configuration
    ' Logfile naming, Source and Destination folders
    '---------------------------------------------

    1. Const ForReading = 1, ForWriting = 2, ForAppending = 8
    2. Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0
    3. Dim SysBakName, CurDate, SysBakSrc, SysBakRoot, mssg
    4. Dim hTime, mTime, sTime, nTime
    5. 'System State Backup Filename
    6. SysBakName = ""
    7. 'System State Backup Source Path
    8. SysBakSrc = ""
    9. 'System State Backup Destination Root
    10. SysBakRoot = ""
    11. 'System State Log File
    12. SysBakLog = ""
    13. hTime = Hour(Time)
    14. mTime = Minute(Time)
    15. sTime = Second(Time)
    16. if hTime < 10 then
    17. hTime = "0" & hTime
    18. end if
    19. if hTime = "00" then
    20. hTime = "24"
    21. end if
    22. if mTime < 10 then
    23. mTime = "0" & mTime
    24. end if
    25. if sTime < 10 then
    26. sTime = "0" & sTime
    27. end if
    28. nTime = hrs & hTime & ":" & mTime & ":" & sTime


    '----------------------------------------
    ' System State Backup Modules
    '----------------------------------------


    1. Sub BackDest(CurDate)
    2. Select Case CurDate
    3. Case "MON"
    4. BakDestination = "Monday"
    5. Case "TUE"
    6. BakDestination = "Tuesday"
    7. Case "WED"
    8. BakDestination = "Wednesday"
    9. Case "THU"
    10. BakDestination = "Thursday"
    11. Case "FRI"
    12. BakDestination = "Friday"
    13. Case "SAT"
    14. BakDestination = "Saturday"
    15. Case "SUN"
    16. BakDestination = "Sunday"
    17. Case Else
    18. mssg = "Unable to determine backup destination path!"
    19. WriteMssg mssg
    20. End Select
    21. CopyBak BakDestination
    22. End Sub

    Start the backup process:

    1. Sub StartBackup()
    2. CurDate = (FormatDateTime(Date(),1))
    3. CurDate = UCase(Trim(CurDate))
    4. CurDate = Left(CurDate, "3")
    5. BackDest CurDate
    6. End Sub
    7. Sub CopyBak(BakDestination)
    8. Dim filesys, SysBakFile, SysBakSrcFull
    9. SysBakSrcFull = SysBakSrc & "\" & SysBakName
    10. Set filesys = CreateObject("Scripting.FileSystemObject")
    11. Set SysBakFile = filesys.GetFile(SysBakSrcFull)
    12. BakDestination = SysBakRoot & "\" & BakDestination &amp; "\"
    13. SysBakFile.Copy(BakDestination)
    14. mssg = SysBakSrcFull & " copied to " & _
    15. BakDestination & SysBakName &amp;amp;amp;amp;amp; _
    16. " - " & nTime
    17. WriteMssg mssg
    18. End Sub
    Write the process into a log file:
    1. Sub WriteMssg(mssg)
    2. Dim fso, f, ts
    3. Set fso = CreateObject("Scripting.FileSystemObject")
    4. If Not fso.FileExists(SysBaklog) then
    5. fso.CreateTextFile SysBakLog
    6. End If
    7. Set f = fso.GetFile(SysBakLog)
    8. Set ts = f.OpenAsTextStream(ForAppending, TristateUseDefault)
    9. ts.WriteLine mssg
    10. ts.Close
    11. 'mssg = ""
    12. End Sub
    13. Sub StartLog()
    14. Dim TimeNow
    15. TimeNow = (FormatDateTime(Date(),1))
    16. mssg = "System State Backup started on " & _
    17. TimeNow & " - " & nTime
    18. WriteMssg mssg
    19. End Sub

    If at first you fail, call it version 1.0

    PHP HTTP_X_FORWARDED_FOR versus WPAD

    I was working on one of our company's website running on Apache with PHP and MySQL.

    I seems that when users are accessing the site thru our company's proxy server, the updates fail to reflect on the MySQL database (IE really sucks!).

    So I decided to write a 2 part php function that captures the client's IP Adress and Referrer if the traffic originated from a proxy server and compares it against known Proxy server IP's and Hostname and disallow the clients from accessing the site and prompts a message to remind the user to disable the IE's proxy server settings when accessing to the site.


    Code Snippet:

    1. function GetIP()
    2. {
    3. if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
    4. $ip = getenv("HTTP_CLIENT_IP");
    5. else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
    6. $ip = getenv("HTTP_X_FORWARDED_FOR");
    7. else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
    8. $ip = getenv("REMOTE_ADDR");
    9. else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] &amp;& strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
    10. $ip = $_SERVER['REMOTE_ADDR'];
    11. else
    12. $ip = "unknown";
    13. return($ip);
    14. }
    15. $badreferer=$CompanyProxyServer;
    16. $referer=GetIP();
    17. if ($referer==$badreferer)
    18. {
    19. echo "<br>";
    20. echo "<center><h4>Disable your proxy server settings and clear your IE cache, then return to this page.</h4></center>";
    21. exit;
    22. }


    Well, you know... users will be users...

    Although the site prompts a reminder to remove the proxy settings when accessing the pages, most of them still find it difficult to click Tools -> Internet Options -> Conenctions Tab -> LAN Settings and un-tick the use proxy server options.

    So to put a permanent fix, I relied on WPAD and permanently excluded the site from utilizing the proxy server when accessing the site via the MatchDirect function:

    if (MatchDIRECT(host))
    {
    return "DIRECT";
    }

    I also added an extra entry to treat the site as Local Intranet Site, since the security settings only allows ActiveX to be installed and executed from Trusted Sites and Local Intranet Sites.

    This also helps in another problem that our company's domain is the same as our public internet domain name.

    function FindProxy(host, intranet, internet)
    {
    if (MatchInternet(host))
    {
    return internet;
    }
    else if (dnsDomainIs(host, ".ourcompanyname.com")|
    (isPlainHostName(host))|
    (MatchIntranetIpRange(host))|
    (dnsDomainIs(host, ".ourcompanyname.net")))
    {
    return intranet;
    }
    else
    {
    return internet;
    }
    }


    Now all I needed was a GPO that pushes the Automatic Configuration script (http://OurWebServer/WPAD.dat) to the machines.

    House the WPAD script on a central Web Server and Voila!

    If at first you fail, call it version 1.0

    Friday, June 15, 2007

    Keyword search trick

    Searching your Blogs made easy...

    A two function javascript that allows your visitors to query the web with any keywords from your page.

    The first function checks if the item you double clicked on the document is a text then it passes it to the second function that appends the text value to your specified query string.

    You can opt for the result to be displayed on the same page by using:

    document.getElementById("<$id$>").innerHtml = ""

    Or Pop up a new window:

    window.open("<$variables$>")

    Or redirect the page:

    this.document.location=("" + "")

    Code Snippet:

    1. function searchmySite() {
    2. if (navigator.appName!='Microsoft Internet Explorer') {
    3. var mykeywords = document.getSelection();
    4. omg(mykeywords);
    5. }
    6. else {
    7. var mykeywords = document.selection.createRange();
    8. if(document.selection.type == 'Text' && mykeywords .text>'') {
    9. document.selection.empty();
    10. omg(mykeywords.text);}
    11. }
    12. function omg(mykeywords ) {
    13. var searchStr = "<Put your search string here>"
    14. while (mykeywords.substr(mykeywords.length-1,1)==' ')
    15. mykeywords=mykeywords.substr(0,mykeywords.length-1)
    16. while (mykeywords.substr(0,1)==' ')
    17. mykeywords=mykeywords.substr(1)
    18. if (mykeywords) document.location=(searchStr + mykeywords);
    19. }
    20. }
    21. document.ondblclick=searchmySite


    If at first you fail, call it version 1.0

    Wednesday, June 13, 2007

    String manipulation in NT scripts

    I was working on a Citrix Login script and found out most clients are not able to perform WMI queries to get session information from the server or just simple evironment variable expansion... or is it just our GPO is just too tight?

    Instead of using vbscript for the string manipulation, I opted to the old school NT scripting, since the built in usrlogon script in PS4 is native to NT.

    So I searched the help files and the net for old DOS commands for string manipulation as my goal for this script is to get the first 2 characters from the environment variable %CLIENTNAME%. If the machine name's first 2 characters are "UK", then a certain drive is required to be mapped.

    Now, It is possible to retrieve specific characters from a string variable.

    Syntax:
    %variable:~num_chars_to_skip%
    %variable:~num_chars_to_skip,num_chars_to_keep%

    This can include negative numbers:
    %variable:~num_chars_to_skip, -num_chars_to_skip%
    %variable:~-num_chars_to_skip,num_chars_to_keep%

    A negative number will count backwards from the end of the string. In Windows NT 4 the syntax for negative numbers was not supported.

    Examples:
    The variable _test is used for all the following examples:

    SET _test=123456789abcdef0

    ::Extract only the first 5 characters

    SET _result=%_test:~0,5%
    ECHO %_result% =12345

    ::Skip 7 characters and then extract the next 5

    SET _result=%_test:~7,5%
    ECHO %_result% =89abc

    ::Skip 7 characters and then extract everything else

    SET _result=%_test:~7%
    ECHO %_result% =89abcdef0

    ::Extract only the last 7 characters

    SET _result=%_test:~-7%
    ECHO %_result% =abcdef0

    ::Extract everything BUT the last 7 characters

    SET _result=%_test:~0,-7%
    ECHO %_result% =123456789

    ::Extract between 7 from the front and 5 from the end

    SET _result=%_test:~7,-5%
    ECHO %_result% =89ab

    ::Go back 7 from the end then extract 5 towards the end

    SET _result=%_test:~-7,5%
    ECHO %_result% =abcde

    ::Extract between 7 from the end and 5 from the end

    SET _result=%_test:~-7,-5%
    ECHO %_result% =ab

    And this is the final script:
    SET _CNAME=%CLIENTNAME%
    CALL SET _ORIGIN=%_CNAME:~-0,2%

    IF %_ORIGIN% EQU UK (
    NET USE R: \\UKFILSERVER\CITRIX$
    ) ELSE (
    GOTO Done
    )

    :Done

    If at first you fail, call it version 1.0

    Monday, June 11, 2007

    Viral detection on multiple page loads

    Aside from having too much page loads detected as being viral, too much query from a single point of origin is also detected as viral... now this is the time that when the search results will prompt you for message that this query format is detected as virus and will ask you to key in the confirmation code to confirm that it was a valid search query.

    Anyway, since ie will just crash your machine when performing too much page load and queries, I have written another scriptlet that utilizes MSXML2.ServerXMLHTTP.4.0 instead, so no api calls are made to unreliable but wonderfully obedient ie.

    Set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP.4.0")

    '::::: Set your proxy here, comment it if not required


    xmlhttp.setProxy 2,"10.1.1.1:8080"

    '::::: Open the url using http Get

    xmlhttp.open "GET", purl, false

    You may use the following as part of your query URL:

    InURL:Index.Of?mp3 InText:Index.Of?mp3 InTitle:Index.Of?mp3 InURL:Top Keywords InText:Top Keywords InTitle:Top Keywords InURL:scripts InText:scripts InTitle:scripts InURL:niche InText:niche InTitle:niche InURL:adsense InText:adsense InTitle:adsense InURL:income InText:income InTitle:income InURL:3gp InText:3gp InTitle:3gp InURL:hotel InText:hotel InTitle:hotel InURL:travel InText:travel InTitle:travel InURL:medicine InText:medicine InTitle:medicine InURL:new InText:new InTitle:new InURL:best InText:best InTitle:best InURL:rare InText:rare InTitle:rare InURL:free InText:free InTitle:free InURL:finance InText:finance InTitle:finance InURL:movie InText:movie InTitle:movie InURL:download InText:download InTitle:download InURL:source InText:source InTitle:source InURL:game InText:game InTitle:game InURL:music InText:music InTitle:music InURL:audio InText:audio InTitle:audio InURL:film InText:film InTitle:film InURL:digital InText:digital InTitle:digital InURL:flight InText:flight InTitle:flight InURL:school


    ':::::: Make sure you define your Browser Agent or else queries will not be allowed and will prompt you for blocks of code that you might need to submit to rectify the malformed query.

    xmlhttp.setRequestHeader "User-Agent","Microsoft Internet Explorer"


    xmlhttp.send()


    ':::::: You can do anything with the search results, follow the links, blah
    WScript.Echo xmlhttp.responseText

    set xmlhttp = nothing


    If at first you fail, call it version 1.0

    Why Click it, If you can script it?

    While 10,000 ecpm can earn you $0.40, one wonders how much it takes to actually earn...

    A sequel to my previous post on my recent fascination on ecpm, page loads doesn't mean much if either the page loads are in millisecond and no links in the pages are clicked or the search option was utilized...

    Adding an extra function allows the page loads to have a little extra sense as not only page loads will be peformed, but hey... even the search option is populated with a query string (maybe from an array, etc...)... and an added trick to perform the click to actually perform the query...

    To fill up the input for the search utility:
    .Document.All.tags("INPUT")("q").Value = searchKey

    To Click the search button:
    Set sButt = .Document.getElementsByTagName("INPUT")
    For Each Butt in
    sButt
    If LCase(Butt.getAttribute("value")) = "search" Then
    Butt.Click
    Exit For
    End If
    Next

    If this makes sense and actually is acceptable, why not click on all the links in the result page to add up to your ecpm queries...

    Set xLinx = .Document.getElementsByTagName("a")
    For Each Linx In xLinx
    Linx.Click
    Next

    Note: Make sure that your site setting is to load the results in the same page, rather than popping up new windows... or else you will flood your screen with tons of ie windows... hahaha... (this, even if .visible=0)

    A terminate process will help in getting rid of all the unwanted window popups:

    Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    Set colProcessList = objWMIService.ExecQuery _
    ("SELECT * FROM Win32_Process WHERE Name = 'Iexplore.exe'")
    For Each objProcess in colProcessList
    objProcess.Terminate()
    Next

    Note: Do this after each page finishes loading after the click.

    A draw back is that all your cookies and such are tracked, hence after numerous reloads and queries it might be detected as a viral activity, solution... clear your tracks...

    First, get you cache path from your registry:
    CachePath = WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Cache\Paths\Directory")

    Then parse through the folders to delete all cache:
    Set rootFolder = fso.GetFolder(CachePath)
    Set subFolders = rootFolder.SubFolders
    For Each folder in subFolders
    fso.DeleteFolder(folder)
    Next

    You may reuse the same to delete the remaining files in the rootfolder. Just replace .SubFolders to .Files.

    There you go...

    As easy as it looks like and as cool as it may seem, this will not guarantee that you will actually earn anything based on pageloads and queries... ecpm is not as easily attainable although your site is now generating billions of pageloads\month...

    And knowing how M$oft Internet Explorer sucks bigtime, you know that it will crash alot if you execute this like 10,000 times????

    Anyway, I use Opera and Firefox 50/50... I only use IE to test my scripts to see how long it will take to crash it...

    Good luck!

    If your first attempt fails, call it version 1.0