Got some things working. Incorporating RDP will have to wait but I can still grab other useful information, like pings.
Progress is slow
Browsing AD with Isotope
I hate using the default interface in Windows management so I wanted a better way to visualize computers listed in AD.
Some pretty long code, but it combines a custom server app via cherrypy with the jQuery plugin Isotope for some fancy graphical views.
Because I don’t have LDAP access directly I use a rather hack way to get the computer listings, but it works and if I can integrate automatic RDP functionality it will be pretty awesome for using here at work.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | import cherrypy import os class OnePage(object): def index(self): return "one page!" index.exposed = True class searchForm(object): #creates the form page def index(self): return """ <form action="resultpage" method="post"> <p>Computername</p> <input type="text" name="computername" value="" size="15" maxlength="40"/> <p><input type="submit" value="Login"/></p> <p><input type="reset" value="Clear"/></p> </form> """ index.exposed = True #runs the query using the most ghetto method and outputs the results def resultpage(self, computername=None): #include header of page h = open('header.html','r') #include the footer f = open('footer.html','r') contentone = """ <div class="element even"> <h2 class="computername"> """ contentodd = """ <div class="element odd"> <h2 class="computername"> """ contenttwo = """ </h2> </div>""" names = self.query(computername) page = '' count = 1 for pc in names: self.create_rdp(pc) if count%2 == 0: page += contentone + '<a href="rdp/' + pc + '.rdp">' + pc + '<a/>' + contenttwo else: page += contentodd + '<a href="rdp/' + pc + '.rdp">' + pc + '<a/>' + contenttwo count+=1 return h.read() + page + f.read() resultpage.exposed = True #does the computername query work and formatting, returns proper html line #returns array of computernames def query(self, computername): query = "dsquery computer -name " + str(computername) + '*' tmp = os.popen(query).read() tmp = tmp.split('\n') names = [] for line in tmp: if line == '': break else: newline = line.split(',') names.append(newline[0].replace('"CN=','')) return names #pings a computer to determine if it is awake def is_up(self, computername): x = os.popen('ping -n 1 ' + computername).read() if 'could not' in x: return False else: return True def create_rdp(self,computername): filename = computername + '.rdp' command = 'full address:s:' + computername f = open('rdps/' + filename,'w') f.write(command) f.close() return True #main server page class Root(object): onepage = OnePage() form = searchForm() def index(self): return "hello world" index.exposed = True #must include config here cherrypy.quickstart(Root(),'/','prod.conf') |
Obtuse Solution of the Day
So in my never ending quest to get Microsoft’s USMT tool to run remotely without me having to log in as the user, I have succeeded with a bizarre method that allows me to simply target a machine and enter a password.
Its a python script that moves a bat file from the host machine to the target machine. Then I use psexec from PSTools to open a command line and run said bat file. This works because of the cmd /c function which lets you open the terminal and run a command.
Then it saves the profiles to my machine or wherever I want and I can restore from there to the new device. Works great. Edited to remove specific content.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | from shutil import copy import os import argparse #this moves USMT files to the Temp directory of the target machine. parser = argparse.ArgumentParser(description='Do a thing.', add_help=True) parser.add_argument('machine', help='source file') #parser.add_argument('user', help='destination file') args = parser.parse_args() #machinename = raw_input('Enter the machine name to mount: ') #user = raw_input('Enter the comit id for the account: ') machinename = args.machine #user = args.user print "Clearing existing Q Drive..." os.system('net use q: /d') print "Mounting new machine C drive to Q..." os.system('net use q: \\\\' + machinename + '\c$') #copy bat file to run stuff copy('C:/Everyone/USMT/go.bat','q:/Temp/go.bat') #cleanup os.system('net use q: /d') #now execute the batch file remotely command = 'psexec -u domain\user \\\\' + machinename + ' cmd /c c:\\Temp\\go.bat ' + machinename os.system(command) |
And in case you wondered what is in the batch file, its pretty simple. Also edited for specific content.
1 2 3 | net use q: \\d154tec00g001\Everyone\USMT q:\bin\scanstate q:\Profiles\%1 /i:migapp.xml /i:miguser.xml /i:migsys.xml /i:migCUSTOMXML.xml /i:migPrintNet.xml /i:miglinks.xml /targetxp /localonly /o /ue:SPECIALDOMAINACC /ue:administrator /uel:30 net use q: /d |
Cygwin: The Undiscovered Country
I’m trying to sort all these files on a Windows machine and pull every file of a certain type from numerous subdirectories. Looking up the DOS commands was tedious and not consistent.
So I just installed cygwin and did mv */*.pdf myfolder/
Windows would be perfect if it used Unix standards for terminals. It really would.
Problem 59 Project Euler
I had trouble with this problem but then I stole the solution from this result of a google search http://blog.mycila.com/2009/08/project-euler-problem-59.html.
I know the problem asks to brute force it, but the frequency analysis method never occurred to me. Basically, you have a 3 character key that cycles through the document to encrypt it. Without the key, its hard to read.
But we can guess at the key because spaces make up the most common character in formatted text. So the most 3 common numbers in the document must be spaces which we can then backwards XOR to figure out the encryption word.
Then just make a loop to decode the document using the key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #ascii range lowercase 97,122 #uppercase (65-90) #32-47 various symbols #euler problem 59 import collections cipher = open("cipher1.txt", "rb") cipherlist = [] tmp = cipher.read() for num in tmp.split(','): cipherlist.append(int(num)) counts = collections.Counter() for num in cipherlist: counts[num] += 1 print counts.most_common(3) # these are probably space characters cracktext = '' key = [103, 111, 100] count= 0 #total ascii value asked for by problem total = 0 for num in cipherlist: decrypt = num ^ key[count] total += decrypt decrypt = chr(decrypt) #debugging #print decrypt, num, key[count] cracktext += decrypt count +=1 if count == 3: count = 0 print cracktext print total |
More Copying
I already sort of completed the copying a single file portion. Now I can move on to doing an entire recursive directory.
Python has high level ways of copying directories, but I wanted to keep using my file copy function and maintain the verbose options of showing the file progress for each file.
But the trick to copying a whole directory is that the destination has to exist. I did some research into good ways to do this and using part of the os module seemed the best bet using os.walk().
First, I step through the source directory and make note of the folders and then recreate them in the target directory. Then I do the same thing again but copy the files I find into the now existing copied directories.
The below copies the directory structure and every file within, provided you use the right argument flag when you run the program.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | import argparse import os import sys parser = argparse.ArgumentParser(description='Do a thing.', add_help=True) parser.add_argument('source', help='source file') parser.add_argument('destination', help='destination file') parser.add_argument('-r',action='store_true',help='recursive directory') parser.add_argument('-v',action='store_true',help='verbose') args = parser.parse_args() def single_directory(sourcefile,destination,args): source_size = os.stat(sourcefile).st_size target = open(destination, 'wb') source = open(sourcefile,'rb') chunksize = source_size/100 copied = 0 while True: chunk = source.read(chunksize) if not chunk: break target.write(chunk) copied += len(chunk) if args.v: print ' \r' + str((copied * 100 / source_size)) + '% ' + sourcefile, if args.v: print source.close() target.close() def directory_copy(args): #copies entire directory and subfolders/files #create directory structure first directorysize = directory_size(args.source) for path, dirs, files in os.walk(args.source): folder = path.split(args.source)[1] if folder != '': os.mkdir(args.destination + folder) #now copy the files copiedsize = 0 for path, dirs, files in os.walk(args.source): for file in files: filename = os.path.join(path, file) newfile = filename.split(args.source)[1] single_directory(filename,args.destination + newfile,args) copiedsize += os.stat(filename).st_size #print args.source + ' \r%02d%% ' % (copiedsize * 100 /directorysize), if args.r: directory_copy(args) else: single_file(args) |
Recreating Unix utilities in Python
I get bored sometimes and I end up having to do a lot of copying/support on Windows machines. But the DOS command line is annoying (I don’t really have a great reason) and I am more familiar with the Unix set. So I took up trying to recreate basic Unix commands in Python, that are run the same way from a command line with options.
My first attempt is with “cp”. Â Copying a file is pretty easy in Python, but I wanted to have verbose modes, recursive directory copies and progress indicators.
So the first step is to create a single file copy function. For modules, I used argparse to make it easy to have command line options and not have to deal with writing a parser of my own. One of the great things about Python is that there are a lot of modules in the standard library to help you do common programming tasks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import argparse import os import sys parser = argparse.ArgumentParser(description='Do a thing.', add_help=True) parser.add_argument('source', help='source file') parser.add_argument('destination', help='destination file') parser.add_argument('-r',action='store_true',help='recursive directory') args = parser.parse_args() def single_file(args): source_size = os.stat(args.source).st_size target = open(args.destination, 'wb') source = open(args.source,'rb') chunksize = source_size/100 copied = 0 while True: chunk = source.read(chunksize) if not chunk: break target.write(chunk) copied += len(chunk) print args.source + ' \r%02d%% ' % (copied * 100 / source_size), source.close() target.close() single_file(args) |
Currently, the file copy function prints a progress bar by default. I will add an option for it eventually. Argparse provides the arguments so you should be able to run this in Python 2.7 using something like “cp.py sourcefile.txt newfile.txt”. The “-r” is part of a recursive directory function that I will detail later.
But to get the progress bar, I partially stole some helpful code from a Google search and changed it a bit to account for varying file sizes. The original function held the chunk size at 32kb. This is great but for huge files it has to do more reads and writes to copy the file. I tested balancing speed with the progress bar by comparing just a straight copy (without chunk processing) to various chunk sizes. In the end,I found a good compromise between processing speed and information was to simply make the chunk size 1 percent of the total file size.
Therefore, when run you can see the percentage go up to 100 on larger files. On very small files it goes too fast to be relevant. All in all not a bad start, and its pretty interesting how simple it is to make this function. But I haven’t gotten into the more extensive options and error handling in the Unix equivalent, yet.