Showing posts with label System Admin. Show all posts
Showing posts with label System Admin. Show all posts

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!

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.

Tuesday, 12 June 2012

Python: Preventing an application from exiting.

I overheard somebody complaining that a program needs to be "Always open" and that the "Stinkin' Users" always close it causing issues down the line...

This can be really easy to fix... create a watcher with the WMI module for python and when the event is triggered, open the program again... then call the 'def' again recursively so the watcher program stays open all the time...  I don't think that's very clear to them, so I just said I could make something for them.

Heres what it looks like:

'''
Created on Feb 13, 2012
@author: rcummins
'''
import wmi
import subprocess
def ohnoyoudidnt():
    c = wmi.WMI()
    watcher = c.watch_for (
                               notification_type="Deletion",
                               wmi_class="Win32_Process",
                               delay_secs=1,
                               Name="application.exe"
                               )
    watcher ()
    exe_path = r'C:\Program Files\application.exe'
    subprocess.Popen(exe_path)
    ohnoyoudidnt()
if __name__ == '__main__':
    ohnoyoudidnt()
Now you need to get yourself the WMI Module here: http://timgolden.me.uk/python/wmi/index.html
It's a really awesome module and I have seen Tim Golden's posts around the web; very helpful.

the Subprocess module is standard so theres nothing to download there...

Hope it helps you out!
       
 

Monday, 11 June 2012

VBScript: Alert system for certificates that will expire in 'n' days.

One day, an individual was called at... oh lets say 3 in the morning, because some certificates which were not set to auto renew and the outlook reminder was never set to tell him or her that the certificates were going to expire.


This could have been avoided by preparing a scheduled task to help alert the Computer System Technician of the upcoming demise and prompt them to take action 5, 10, 30, 60 days before the certs expired. 

I did a bit of research to help the person out... no it was not me called at 3am, thankfully! 

Breaking the VBScript into parts helps out a lot... portability is key when it comes to any scripting language.  I do not have any formal education when it comes to programming, however I do have a lot of confidence in two things... Trial and Error... and Google.

One part of this overall task is the alerting piece.... yes, standard email will do the trick.  I already had something I had used this for anyhow and its a pretty standard piece of code that sys admins should have readily available.  The below code is derived from http://www.paulsadowski.com/wsh/cdo.htm

Sub EMAIL(mailto,txtbody)
    Set objMessage = CreateObject("CDO.Message")
    objMessage.Subject = "Certificates are expiring soon..."
    objMessage.From = "CertificateAuthorityExpirations@work.com"
    objMessage.To = mailto
    objMessage.TextBody = txtbody

    objMessage.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2

    objMessage.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "exchange.server.dot.com"

    objMessage.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25

    objMessage.Configuration.Fields.Update
    objMessage.Send
END SUB
The next part is derived from http://blogs.msdn.com/b/spatdsg/archive/2007/07/19/notify-users-of-cert-expiration.aspx  and modified to meet my needs...  so you can add any arguments you want like number of days to check for... also maybe who you want the email to go to.  Like I mentioned before portability is a sys admins best friend.  Along with documentation... but... like I said, I don't have any formal programming education, so that's my excuse for not commenting my code enough ;)

Const CV_OUT_BASE64 = &H1
Const DUMMY_CERT = "modifiable cert to exclude"  '<== I used this part to skip common certs that all desktops use, because they auto renew anyways and nothing will go down if they are expired

' Setup arguments if there are any....
SET Args = WScript.Arguments

If WScript.Arguments.Count = 1 Then    ' This part can be modified to something hard coded
    mailto = Args.Item(0)                         ' definitely up to you though.
    limit = 60
else
    limit = 60   ' <-- number of days to check for...
    mailto = "system_admin@work.com"
End if
'Log it...
Set objFSO = CreateObject("Scripting.FileSystemObject")
SET writeFile = objFSO.OpenTextFile("Certificates.log", 2, True)  '<-- just creates a new log every time... you can set it to append if you want.

'THIS IS THE <Machinename>\CAName
CAName = "domain_controller.work.int\WORK"     '=======>> CHANGE THIS TO THE CORRECT MACHINE\CA==

'create the CAView object
set oCAView = CreateObject("CertificateAuthority.View")


'open the connection to the Machine\CA
oCAView.OpenConnection (CAName)

'retrieve specific columns from DB  (This part took me awhile to figure out the field names...)
oCAView.SetResultColumnCount(4)
Index0 = oCAView.GetColumnIndex(False, "CommonName") 
Index1 = oCAView.GetColumnIndex(False, "NotAfter")
Index2 = oCAView.GetColumnIndex(False, "SerialNumber")
Index3 = oCAView.GetColumnIndex(False, "CertificateTemplate")
oCAView.SetResultColumn (Index0)
oCAView.SetResultColumn (Index1)
oCAView.SetResultColumn (Index2)
oCAView.SetResultColumn (Index3)
'open the view
Set RowObj= oCAView.OpenView

txtbody = ""

on error resume next
Do Until RowObj.Next = -1

   Set ColObj = RowObj.EnumCertViewColumn()
        x = ""
        Do Until ColObj.Next = -1
            x = x + Cstr(ColObj.GetValue(CV_OUT_BASE64))+","
        Loop
        if Left(x, 1) <> " " then
            items = split(x,",")
            Machine = items(0)
            Expires = items(1)
            Subject = items(2)
            Info = items(3)
            if Info <> DUMMY_CERT then
                edate = cdate(Expires)
                odate = Date
                blarg = DateDiff("y", edate, odate)
                if blarg < 0 then
                    if abs(blarg) < limit then
                        difference = Abs(DateDiff("y", edate, odate)) & " Days until it expires!"
                        writeFile.writeline(Machine & "," & difference & ",SerialNumber: " & Subject & ",CertificateTemplate: " & Info)
                        txtbody = txtbody + "Certificate for: "& Machine & "      Has Only: " & difference & vbcrlf & vbcrlf & _
                        "CA Details;" & vbcrlf & "SerialNumber: " & Subject & vbcrlf & "CertificateTemplate: " & Info & _
                        vbcrlf & "=======================" & vbcrlf & vbcrlf
                    end if
                end if
            end if
        end if
  Set ColObj = Nothing

Loop
call EMAIL(mailto,txtbody)   '<-- this is the SUB i mentioned earlier... cdo send method
writeFile.Close
There is a lot going on it there, but its not hard to pick out what needs to change.  The domain controller
I found from the command line using the certutil exe found in system32...  I don't recall the actual command, but I'm sure its not hard to find on the msdn site...

Hopefully this has been informative and takes you all less time than it took me ;)

Happy testing/fixing/administering

Thursday, 7 June 2012

PowerShell: Email me my EventLog, Please.

Today at work I decided to try my hand at PowerShell a little bit.

I DO like it... it's a little tricky to learn any new language, but it is really powerful.

I have a Server (Windows Server 2003...) and occasionally something happens when a process crashes.  Based on that... I thought maybe I could setup some sort of means for reporting to my email (which coincidently, I get my work email on my phone... so voila..)


Heres what I used..  and its all under 15 lines of code... some good potential here

----------------------------
$FROM = "SERVER@work.com"
$TO = "RCUMMINS@WORK.COM" 
$SMTP_Server = "Exchange.Dot.Com"
$smtp = New-Object Net.Mail.SmtpClient($SMTP_Server)
$SUBJECT = "Server Health Report"

$x = Get-EventLog "Application" -EntryType 'Error' -After (Get-Date).addHours(-1) | 
    Where-Object {$_.Source -eq 'Application Hang'}

if($x)
{
    $xx = $x | select TimeGenerated, Message | Out-String
    $smtp.Send($FROM, $TO, $SUBJECT, $xx)
}
---------------------------

So to setup the scheduled task... I just had to do a quick google for the hidden window option...

---------------------------

C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle "Hidden" -Command ".'C:\Path\To\Scripts\Process Checking.ps1'"
---------------------------

That was enjoyable.