Welcome, guest | Sign In | My Account | Store | Cart
# machine.py
# ==========

import wmi
import win32net
import win32com.client
from BeautifulSoup import BeautifulSoup
from string import replace, digits, ascii_letters
import urllib, urllib2

DELL_SVCTAG_URI
= 'http://support.dell.com/support/topics/global.aspx/support/my_systems_info/en/details?c=us'
DELL_SVCTAG_PARTS_URI
= DELL_SVCTAG_URI + '&l=en&s=gen&~tab=2&~wsf=tabs'
DELL_UA
= [('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')]

class InvalidServiceTagException(Exception): pass

def machines_in_default_domain():
    domain_controller
= win32net.NetGetDCName(None, None)
    domain_name
= win32net.NetUserModalsGet(domain_controller, 2)['domain_name']
   
return machines_in_domain(domain_name)

def machines_in_domain(domain_name):
    adsi
= win32com.client.Dispatch("ADsNameSpaces")
    nt
= adsi.GetObject('', 'WinNT:')
    result
= nt.OpenDSObject('WinNT://%s' % domain_name, '', '', 0)
    result
.Filter = ['computer']
   
for machine in result:
       
yield machine.Name

class Machine(object):

   
def __init__(self, machine_name):
       
self.machine = machine_name
       
try:
           
self.wmi_conn = wmi.WMI(self.machine)
           
self.active = True
       
except:
           
self.active = False

   
def __safe_encode(self, val):
       
return ''.join([c for c in val if (c in digits or c in ascii_letters)])
   
   
@property
   
def _enclosure(self):
       
if not hasattr(self, '__enclosure_query'):
           
self.__enclosure_query = self.wmi_conn.query('Select * from Win32_SystemEnclosure')
       
return self.__enclosure_query

   
@property
   
def _system(self):
       
if not hasattr(self, '__system_query'):
           
self.__system_query = self.wmi_conn.query('Select * from Win32_ComputerSystem')
       
return self.__system_query

   
def query_results(self, query):
       
return self.wmi_conn.query(query)
   
   
@property
   
def service_tags(self):
        tags
= [self.__safe_encode(e.SerialNumber.strip()) for e in self._enclosure]
       
if not tags:
           
return None
       
return tags

   
@property
   
def model(self):
        m
= [self.__safe_encode(c.Model.strip()) for c in self._system]
       
if not m:
           
return None
       
return m[0]

   
@property
   
def manufacturer(self):
        mfs
= [self.__safe_encode(e.Manufacturer.strip()) for e in self._enclosure]
       
if not mfs:
           
return None
       
return mfs[0]

   
@property
   
def name(self):
       
return self.machine
       
   
@property
   
def is_dell(self):
       
return 'dell' in self.manufacturer.lower()

   
@property
   
def has_valid_dell_service_tags(self):
        tag
= self.service_tags[0]
       
if len(tag) == 7:
           
return True

   
def __normalize_dell_charset(self, page_content):
        page_content
= replace(page_content, "<sc'+'ript", '')
        page_content
= replace(page_content, "</sc'+'ript", '')
        t
= ''.join(map(chr, range(256)))
        d
= ''.join(map(chr, range(128, 256)))
        page_content
= page_content.translate(t, d)
       
return page_content
   
   
def __retrieve_tag_information(self):
       
if not self.has_valid_dell_service_tags:
           
raise InvalidServiceTagException
       
if not hasattr(self, '_dell_connection'):
           
self._dell_cookie_jar = urllib2.HTTPCookieProcessor()
           
self._dell_connection = urllib2.build_opener(self._dell_cookie_jar)
           
self._dell_connection.addheaders = DELL_UA
            urllib2
.install_opener(self._dell_connection)
       
params = urllib.urlencode({'ServiceTag': self.service_tags[0]})
        f
= self._dell_connection.open(DELL_SVCTAG_URI, params)
        page_content
= f.read()
       
# clean up the page
        soup
= BeautifulSoup(self.__normalize_dell_charset(page_content))
       
# Determine if we're still under warranty
       
self._service_contracts = []
       
for _contract in soup.find('table', {'class': 'contract_table'}).findAll('tr'):
           
try:
                parts
= _contract.findAll('td')
               
if any([('contract_header' in m['class']) for m in parts]):
                   
continue
               
self._service_contracts.append({
                   
'name': parts[0].first().string,
                   
'provider': parts[1].string,
                   
'start_date': parts[2].string,
                   
'end_date': parts[3].string,
                   
'days_remaining': int(parts[4].find(text=True)),
               
})
           
except:
               
pass
       
       
# Determine original parts
        f
= self._dell_connection.open(DELL_SVCTAG_PARTS_URI)
        page_content
= self.__normalize_dell_charset(f.read())
        soup
= BeautifulSoup(page_content)
       
self._parts = []
       
for _part in soup.find('a', {'name': 'grid_1'}).nextSibling:
           
try:
                fields
= _part.findAll('td')
               
if any([('gridTitle' in m['class']) for m in fields]):
                   
continue
               
self._parts.append({
                   
'quantity': int(fields[0].string),
                   
'part_number': fields[1].string,
                   
'description': fields[2].string,
               
})
           
except:
               
pass

   
@property
   
def service_contracts(self):
       
if self.is_dell and not hasattr(self, '_service_contracts'):
           
self.__retrieve_tag_information()
       
return self._service_contracts

   
@property
   
def parts(self):
       
if self.is_dell and not hasattr(self, '_parts'):
           
self.__retrieve_tag_information()
       
return self._parts
   
   
@property
   
def is_under_warranty(self):
       
if self.is_dell:
           
return any([(m['days_remaining'] > 0) for m in self.service_contracts])
       
return None

# warranty_report.py

import csv
from machine import Machine, InvalidServiceTagException, machines_in_default_domain

class MachineNotDell(Exception):pass
class MachineNotActive(Exception):pass

BASE_INDENT
= 4

def validate_machine(m):
   
"""
    We're only searching for Dell machines, so filter
    everything else out.
    """

   
if not m.active:
       
raise MachineNotActive
   
elif not m.is_dell:
       
raise MachineNotDell
   
else:
       
return m

def indent(spaces, text):
   
return ' ' * BASE_INDENT + text

def main():
    output_writer
= csv.writer(open('MachinesList.csv', 'w'))

   
# write header
    output_writer
.writerow([
       
'Machine Name',
       
'Model',
       
'Service Tag(s)',
       
'Under Warranty?',
       
'Contract days remaining',
   
])

   
for hostname in machines_in_default_domain():
       
try:
           
# Print Identification
           
print 'Retrieving machine information for host: %s' % hostname
            m
= validate_machine(Machine(hostname))
           
print indent(1, '%s (%s) discovered.' % (m.model, ', '.join(m.service_tags)))

           
# Print Service Contracts
           
print indent(1, 'Found %d service contracts:' % len(m.service_contracts))
           
for contract in m.service_contracts:
               
print indent(2, '> %s (%d days remain)' % (contract['name'], contract['days_remaining']))

           
# Prettify (put newline after each record)
           
print ''

           
# Write Output to CSV
            output_writer
.writerow([
                hostname
,
                m
.model,
               
', '.join(m.service_tags),
               
['N','Y'][int(m.is_under_warranty)],
                max
([c['days_remaining'] for c in m.service_contracts])
           
])

       
# handle failures
       
except MachineNotActive:
           
print indent(1, 'No WMI response from %s. Continuing.\n' % hostname)
           
continue
       
except MachineNotDell:
           
print indent(1, 'Machine was not manufactured by Dell. Continuing.\n')
           
continue
       
except InvalidServiceTagException:
           
print indent(1, 'Machine provided an invalid service tag.')
           
print indent(1, 'Unable to retrieve details. Continuing.\n')
           
continue

   
print 'Network scan complete.'

if __name__ == '__main__':
    main
()

History