with

Writing lists to a file

After creating my list from the previous post I needed to save this to a text file to send back to the person who had requested the information. I just wrote a standard loop over the list but this got me thinking about a better way to do this as it’s a common task. As it turns out not really but it did bring up a few titbits worth mentioning.

If you are from a PERL background you might be tempted to use a single write and a join to turn the list into a string as follows

file.write("\n".join(mylist))

Don’t. This creates a new string in memory from the list and then writes that. Ok if it is a small list but a huge waste of memory for larger ones.

For the more experienced Python user, using a generator produces arguably a cleaner syntax and saves a line of typing. As with all generators, you can make it conditonal by adding an if clause to the end.

with open(r'x:\path\to\file.txt','w') as txtfile:
  txtfile.writelines( "%s\n" % item for item in mylist )

That covers off the text file, but there may be a better option depending upon what is going to be done with the resulting file. I’ll finish the following couple of examples.

# if the file is going to Excel, maybe a CSV file
import csv
with open(r'x:\path\to\file.csv','w') as csvfile:
  csv = csv.writer(csvfile)
  for item in mylist:
    csv.writerow([item])

# or how about json if it is going to another program
import json # Python 2.5 use simplejson
with open(r'x:\path\to\file.json','w') as jsonfile:
  json.dump(mylist,jsonfile)

See the Python docs for the csv module and json module.

Advertisements

Network WMI queries

I have already covered searching AD and running a WMI query on remote computers. It is easy to combine the two for a flexible tool that can run the same query on all computers that meet a certain criteria.

To achieve this I wrote the function adwmiquery. It does a lot considering it is only really 4 lines of code.

I originally wanted to see the amount of free space of all the drive on all of the servers. This is still the default behavior if you just run the netquery.py directly. As an added bonus you can run any wmi query against all servers simply by entering the select statement on the command line as so.

python netquery.py Select Name,DriverName,PortName From Win32_Printer

The function takes 3 optional arguments as follows
WMI Query: self explanatory (defaults to drive space)
AD Query: specifies the computers to run the WMI Query on (defaults to servers)
Filter Function: a function which gets the result of the WMI query

The last argument is a function that accepts two arguments, the name of the computer and the result of the WMI query as a list. This can be used to format the output or store the result. You can also use this to add additional filtering, maybe you only want to see drives with less than 10% free space.

As an example the following lists all printers on the server (so used the default AD query) and writes them to a CSV file.

import csv,sys

# if netquery.py is not in you path you need the following line
# sys.path.append(r"C:\Path\To\File")
from netquery import adwmiquery

with open(r"C:\Temp\printers.csv","w") as csvfile:
    out = csv.writer(csvfile)
    out.writerow(['Server','Printer Name','Driver (Make & Model','Port'])

    def prnwrite ( compname , prnlist ):
        "writes the printer details to the CSV file"
        for prn in prnlist:
            out.writerow([compname,prn.Name,prn.DriverName,prn.PortName])

    # run the wmi query on all servers (default) using above fn to output to csv
    adwmiquery(wql = "Select Name,DriverName,PortName From Win32_Printer",
               filterfn = prnwrite)