Wednesday, 4 July 2012

DOS: Disconnect from ALL Citrix sessions with one batch file

I am pretty happy with myself for coming up with this.  It did take awhile, but it's working.

First let me start off by saying that we are concerned with the security aspect with keeping information safe but we need to also provide a suitable workflow to help facilitate others with ease of use and help broaden the functionality of the tools they already use.

Here is the Batch file contents.
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for /f %%A in ('QFARM ^| find "*"') DO (
        SET curSERVER=%%A
        SET curSERVER=!curSERVER:~0,-1!)
for /f %%A in ('QFARM ^| find "CITRIX"') DO (
        SET SERVER=%%A
        SET lastCHAR=!SERVER:~-1!
        IF NOT !lastCHAR! == * for /f "skip=1 tokens=2" %%B in ('QUSER %USERNAME% /SERVER:!SERVER!') DO (
        tsdiscon %%B /SERVER:!SERVER!
         )
)
for /f "skip=1 tokens=2" %%A in ('QUSER %USERNAME%') do (
        tsdiscon %%A /SERVER:%curSERVER%)
An important note:  This is run from within Citrix... I found that when using the QUERY command locally you don't have access to the QFARM command, but in a Citrix context you do.  We also needed to run this within Citrix because we have generic logins in some locations that act as thin clients, so the %USERNAME% variable would not be effective in this case.

tsdiscon is a great tool that was overlooked initially.

Firstly we wanted to find out what the current server we are on is.  This was necessary because if you end up disconnecting from the server you are running this from, it stops.

Secondly... we loop through the output of the QFARM command finding "CITRIX"... if you have different naming conventions, you just have to massage that a little and it's good to go.

QFARM by itself spit output with the citrix servers and one of the servers has an asterisk at the end... this is one that we want to skip over until the end...  its the %curSERVER% variable.

From there on you can see... we loop through the servers finding the ica-tcp#... sessions and use that to disconnect from each of the servers.

I hope this is informative and helps you out!

Wednesday, 20 June 2012

Python: Let Domain User's manage themselves

Not sure if that's a great idea ;)

I am always trying to find ways to help the 1st level support guys, they get lots of calls and when the calls pile up, I remember it being quite annoying.

So here is what I created.  Hope you enjoy!  Now obviously you need to make a few changes to make it work for you, but this little tool allows domain users with little access the ability to Add/ Remove users from groups that they are managers of. 




Heres what you need:

Active Directory;
User account; must be a member of the group as well as selected in the Managed By tab, check the box that says Manager can update the group and you are set.

*note I have images in the current directory, so be sure to change those around as well.
'''
Created on Jun 14, 2012

@author: rcummins
'''
import active_directory as AD
from Tkinter import *
from os import environ
import ttk
import win32com, win32com.client
import pythoncom
import tkMessageBox
from PIL import Image, ImageTk

login = environ["USERNAME"]
manager = []
 
LOGIN = AD.find_user(login)
grps = {}
for group in LOGIN.memberOf:
    GROUP = AD.AD_object(group)
    if str(LOGIN)[7:] == str(GROUP.managedby):
        GRP = AD.AD_object(group)
        grps[GRP.cn] = GRP.distinguishedName
        manager.append(str(GRP.cn))
   
root = Tk()
root.title("Manager Console")

root.wm_iconbitmap('mgmt.ico')


master = PanedWindow(orient=VERTICAL)
master.pack(fill=BOTH, expand=1)

userframe = LabelFrame(master, text='Groups Managed By: %s'%(LOGIN.cn))

fr = Frame(userframe)
userinfo = Label(fr, text='Manager of: ')
userinfo.pack(side=LEFT, padx=5, pady=10)
usergroups = ttk.Combobox(fr, values=manager, width=30)
usergroups.pack(side=LEFT, fill=X, expand=1, padx=5)

type=None
if(len(manager)>0):
    usergroups.set(manager[0])
    ggrp = AD.find_group(manager[0])
    type = AD.AD_object(ggrp)
grouptype = Label(userframe, text="No group(s) found..")
if(type):
    grouptype = Label(userframe, text="Description: %s"%(ggrp.description))
fr.pack(side=TOP)
grouptype.pack(side=TOP, padx=5)
master.add(userframe)

groupframe = LabelFrame(master, text='Group Detail and Modification')
groupinfo = Listbox(groupframe, height=20, width=30)
groupinfo.pack(side=LEFT, padx=5, pady=10)
controlframe = Frame(groupframe)
controlframe.pack(side=LEFT, padx=5, fill=BOTH)

master.add(groupframe)
def ADDUser(event=None):
    geo = root.winfo_pointerxy()
    xx = geo[0]
    yy = geo[1]
   
   
    TOPr = Toplevel()
    TOPr.title("Add a user to this group")
    TOPr.geometry("+%d+%d"%(xx,yy))
   
    x = Label(TOPr, text="Enter username:")
    x.pack(side=TOP, fill=X, padx=10)
    f = Frame(TOPr)
    em = Label(f, text="@WORK.com")
    em.pack(side=RIGHT)
    uname = Entry(f, width=15)
    uname.pack(side=RIGHT)
    f.pack(side=TOP, padx=10)
       
    def plusONE(event=None):
        if len(str(uname.get()))>0:
            usr = AD.find_user(str(uname.get()).strip())
            grp = AD.find_group(str(usergroups.get()).strip())
            uLDAP = "LDAP://%s"%(str(usr.distinguishedName))
            gLDAP = "LDAP://%s"%(str(grp.distinguishedName))
            try:
                grp_obj = win32com.client.GetObject(gLDAP)
                grp_obj.Add(uLDAP)
                #grp_obj.Remove(uLDAP)
                grp_obj.SetInfo()
                groupinfo.insert(END, usr.cn)
            except pythoncom.com_error,( hr,msg,exc,arg ):
                print "Error adding user %s to group %s..." % (usr.cn, grp.cn)
                print hr, msg, exc, arg
            #http://code.activestate.com/recipes/511447-add-account-to-group-in-active-directory/
    addButton = Button(TOPr, text='Add User', command=plusONE)
    addButton.image = photo
   
    addButton.pack(side=TOP, fill=X)
    root.update()
    TOPr.mainloop()

img = Image.open(r"business_user.png")
photo = ImageTk.PhotoImage(img)
addBTN = Button(groupframe, compound=TOP, image=photo, text='Add User', command=ADDUser)
addBTN.pack(side=TOP)


def DELUser(event=None):
    usr = AD.find_user(str(groupinfo.selection_get()).strip())
    grp = AD.find_group(str(usergroups.get()).strip())
    uLDAP = "LDAP://%s"%(str(usr.distinguishedName))
    gLDAP = "LDAP://%s"%(str(grp.distinguishedName))
    try:
        grp_obj = win32com.client.GetObject(gLDAP)
        #grp_obj.Add(uLDAP)
        xray = tkMessageBox.askokcancel("Delete User from Group", "Are you sure you want to delete: %s from %s"%(usr.cn, grp.cn))
        print xray
        if(xray):
            grp_obj.Remove(uLDAP)
            grp_obj.SetInfo()
    except pythoncom.com_error,( hr,msg,exc,arg ):
        print "Error adding user %s to group %s..." % (usr.cn, grp.cn)
        print hr, msg, exc, arg
        #http://code.activestate.com/recipes/511447-add-account-to-group-in-active-directory/
    root.update()
    groupname = usergroups.get()
    usrs = []
    for groupmbr in AD.find_group(groupname).member:
        usrs.append(str(groupmbr.cn))
    usrs.sort()
    groupinfo.delete(0, END)
    for usrer in usrs:
        if usrer != usr.displayName:
            groupinfo.insert(END, usrer)
    return

img2 = Image.open(r"business_user_delete.png")
photo2 = ImageTk.PhotoImage(img2)
delBTN = Button(groupframe, compound=TOP, image=photo2, text='Remove User', command=DELUser)
delBTN.pack(side=TOP)

master.add(groupframe)

def SelectDropdown(event=None):
    if(usergroups.get()):
        groupname = usergroups.get()
        usrs = []
        for groupmbr in AD.find_group(groupname).member:
            usrs.append(str(groupmbr.cn))
        usrs.sort()
        groupinfo.delete(0, END)
        for usrer in usrs:
            groupinfo.insert(END, usrer)
        root.update()
usergroups.bind("<<ComboboxSelected>>", SelectDropdown)
SelectDropdown()
root.mainloop()

As always, I accept constructive feedback, so if it could be cleaner, please let me know! always looking for feedback.

Monday, 18 June 2012

Python: Backup your data on the fly

I have been bitten before, and so to prevent any unforeseen loss of data, I set out to create something of the sort.

I did it.  And I am quite proud of it.  Even though its not perfect... the concept is pretty rad.

Things you will need.

  1. Python [Modules] - wmi, shutil, os, sys, winpaths(optional....)
  2. TaskScheduler
  3. USB or SD card, need to change its name to eBackup, instead of "Removable Disk"
The basic idea is to:
  • have a scheduled task run when the system is on idle...
  • only runs when a drive is present that is labeled eBackup
  • copy directories, specified in a cfg file.
Here is the code for this project:

'''
Created on Apr 30, 2012
@author: rcummins
'''
import wmi
import shutil
import os
import winpaths
import sys
def getDrive(computer=None):
    c = wmi.WMI(computer)
    host_info = c.Win32_LogicalDisk(VolumeName='EBACKUP')
    return host_info[0].Name
def fileChange(source):
    drive = getDrive()
    for dirs in os.listdir(source):
        path = source+'\\'+dirs
        dest = path.replace("C:\\", drive[0]+":\\")
        if os.path.getmtime(dest) - os.path.getmtime(path) < 0:
            shutil.copytree(path, dest)
if __name__ == '__main__':
    computer = ''
    logfile = ''
    x = getDrive(computer)
    try:
        logfile = str(sys.argv[1]).strip()
    except:
        logfile = 'eBrake.cfg'
    if os.path.exists(logfile):
        f = open(logfile,'r')
        for q in f.readlines():
            source = q.strip()
            for(path, dirs, files) in os.walk(source):
                for filez in files:
                    src = os.path.join(path, filez)
                    dst = str(os.path.join(path, filez)).replace("C:\\",x[0]+":\\")
                    if str(src).find(".metadata") < 0:
                        try:
                            if os.path.getmtime(dst) - os.path.getmtime(src) < 0:
                                print "Overwriting >> " + dst
                                shutil.copy(src, dst)
                        except:
                            print "Created: " + dst
                            if not os.path.exists(dst): os.makedirs(dst)
                            try:
                                shutil.copytree(src, dst)
                            except: shutil.copy(src, dst)
    else:              
        print "Create file: %s \n\n Enter paths to backup on SD card\n\ncard needs to be named 'EBACKUP'"%(logfile)
        pass                   
I hope this has either inspired you or saved your data.  Enjoy!

Thursday, 14 June 2012

Python: Breaking apart large files into smaller chunks

Something that I find really neat with Python is its flexibility and strong support in the online community.  I found a really good example somewhere on how to do this and I adapted it to my own needs...  like most programmers ;)
import os
def UnpileFile(src, outPATH, parts):
    if not os.path.isdir(outPATH): os.mkdir(outPATH)
    f = open(src, 'rb')
    data = f.read()
    f.close()
    byts = len(data)
    inc = (byts+4)/int(parts)
    filenames = []
    for i in range(0, byts+1, inc):
        fn1 = outPATH + "\\file %s" % i
        filenames.append(fn1)
        f = open(fn1, 'wb')
        f.write(data[i:i+inc])
        f.close()
def CompileFile(srcPATH, outFILE):
    if not os.path.isdir(srcPATH): os.mkdir(srcPATH)
    dataList = []
    for root, dirs, files in os.walk(srcPATH):
        for fn in files:
            f = open(str(root+'\\'+fn), 'rb')
            dataList.append(f.read())
            f.close()
    f = open(outFILE, 'wb')
    for data in dataList:
        f.write(data)
    f.close()
if __name__ == '__main__':
    pass
There's not much to import which is a plus... ;)

So say you had an ISO image... you only have 2 2gb usb drives?  no problem... break these guys up into 2 parts by saying;
src = the path to the ISO you want to break up
outPATH = the directory you want to save the broken pieces to
parts = the number of parts you want the files split into
UnpileFile(src, outPATH, parts)


















And to put humpty dumpty back together again... so to speak... you just say:

srcPATH = the directory that has the broken files
outFILE = the name you want to give your patched up ISO...
CompileFile(srcPATH, outFILE)
*NOTE... I am pretty sure I specified mkdir and not makedirs, there is a difference...

http://docs.python.org/library/os.html?highlight=os.mkdir#os.mkdir

Android: Learning to walk... and then programmatically add TableRows to a TableLayout

I have had some long spent nights trying to learn developing for Android... LayoutParams... oh you light of my life, LayoutParams...

One recent problem I have been facing is the TableRow widget I intend on populating with data scraped from the web...  store it in a ArrayList<String> and pop it into the TableRow as necessary.

I did buy an idiots guide to Android Development... and I gently set it aside and started Google-ing how to accomplish what I wanted an android app to do.  If you are struggling, Google is your friend...  and just like real life... some friends take you down the wrong path, and others have just what you need.

http://stackoverflow.com/questions/3200691/dynamically-add-tablerow-to-tablelayout

import android.widget.TableRow.LayoutParams;
//import android.widget.RelativeLayout.LayoutParams; 

Just like dfetter88 mentions in his/her answer... ensure you are importing the right thing.

So the background, before getting into the gritty for loop, is that I have scraped data from the web and stored it into an arraylist.  So here's my scratch;
ArrayList<String> prices = getPrice (doc);
for(int i =0; i<prices.size(); i++)
{
    Log.d("PRINT", prices.get(i));
    //RelativeLayout RLay = new RelativeLayout(getParent());
    TableRow TR = new TableRow(getApplicationContext());
    TR.setId(10);
    TR.setLayoutParams(lp);
    TextView price = new TextView(getApplicationContext());
    price.setId(20);
    price.setLayoutParams(lp);
    price.setText(prices.get(i));
    TR.addView(price);
    TLay.addView(TR, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
I had a difficult time wrapping my head around the context argument.  Because this for-loop was triggered by a button click, the context was changed and you couldn't use the term THIS...  which refers to the current object...  and the current object in that situation is BUTTON...  so you can't very well create a new TableRow within the Button context, so I had to use getApplicationContext()...

I think that is explained right, but then again... I really SHOULD read the Android Developer book.

Another really cool trick I learned is to import the Log "module"
import android.util.Log;
This will help you troubleshoot issues while you are testing.  you use it like this;

Log.d("LEVEL1","about to go through the loop... buckle up.");
 LEVEL1 is just the Tag you can assign to the log...  makes it really handy.  Eclipse is a super powerful tool that you definitely need to have if you want to explore android development... There are at least a gajillion resources at your disposal.

Here's where you go to get started: http://developer.android.com/guide/index.html  Do it up.





Wednesday, 13 June 2012

VBScript: XP only!: Find Computer by User Name

When I was working for "The helpdesk" a long time ago... I would always forget to write down the computer name and it seemed to be taking more time than it should just to get that info back... I sometimes called the end user... I was looking online and actually didn't find anything until I ran into an old classmate who had a huge script that he sent me, it was really awesome, filled with SUBS and whatnot.

Here's the bare necessity:

Dim inputStr, UserName, Domain, splitInput, sName, oArgs, Session
Dim oUser, userFullName, userHome, fService, LoggedOn, q, ss
'On Error Resume Next
q = Chr(34)
Domain = "Domain"
username = inputbox("Enter username: ")
Set oUser = GetObject("WinNT://" & Domain & "/" & UserName & ",user")

userFullName = oUser.FullName
userHome = oUser.HomeDirectory
sName = Split(userHome, "\")

Set fService = GetObject("WinNT://" & Domain & "/" & sName(2) & "/LanmanServer")
Set ss = fService.Sessions
For Each Session In ss
If LCase(Session.User) = LCase(UserName) Then
LoggedOn = LoggedOn & vbcr & Session.Computer
End If
Next
If LoggedOn = "" then
msgbox "User " & q & UserName & q & " (" & userFullName & ") is not logged on.", 64, "Query:"
Else
MsgBox "User " & q & UserName & q & " (" & userFullName & ") logged on to the following workstations: " & vbcr & vbcr & LoggedOn, , "Query:"
End If

One of the cool things about this script is that it doesn't return the first one it finds, it returns a list of them.

So you may find a bunch of Citrix Servers.  I have found it to be flaky at times and have never been able to get this to work with Windows 7...  I think because of the LanmanServer part.

Anyways, enjoy!

VBScript: Shutdown / Reboot workarounds

Every now and then I find myself trying to script the silliest things.

I was really annoyed at how when you are using Remote Desktop to connect to a workstation, the Shutdown / Reboot option is replaced by the Disconnect option... I think it's probably a safe guard, which is nice to have, but I like to have the option.

I created a VBScript on my desktop called Shutdown.vbs; its remarkably simple.

Set OpSysSet = GetObject("winmgmts:{(Shutdown)}//./root/cimv2").ExecQuery("select * from Win32_OperatingSystem where Primary=true")
for each OpSys in OpSysSet
x = InputBox("Reboot or Shutdown?", "Reboot or Shutdown?", "Shutdown")
if Left(x, 1) = "R" Then
OpSys.Reboot()
end if
if Left(x, 1) = "S" Then
OpSys.Shutdown()
end if
next
the section that contains
x = InputBox("Reboot or Shutdown?", "Reboot or Shutdown?", "Shutdown")
can be modified; if you change the last parameter, you can set it to "Reboot"

like I mentioned, its not overly complicated, but I found it annoying to keep typing
shutdown -s -t 1 or shutdown -r -t 1

*Note... when showing this to people from a remote location, be sure you really want to shutdown... otherwise you risk taking the walk of shame and force yourself to either call somebody there to turn it back on or do what every System Admin hates doing... get up and do it yourself.