In Windows 2000, Microsoft introduced disk quota policies, with which you can limit the amount of disk space that users consume on NTFS volumes. Disk quota policies also determine how the system responds when a user exceeds his or her quota limit or reaches a predefined warning level.
When you put disk quotas in place, you decide how the system will respond when users attempt to consume more disk space than you've permitted. If a greedy user creates a file that would exceed his or her allotted disk space, the user typically receives an Insufficient disk space error. The system forbids the user to write additional data to the volume without first deleting other files. Disk quotas are based on file ownership and, as such, are independent from the physical location of files on the volume. In other words, if a user simply moves files from one folder to another on the same volume, the overall space usage doesn't change.
Upon reaching his or her quota limit, the user can only delete files or physically move files to another volume that's under the control of another user. From the viewpoint of the quota system, compressing (or decompressing) files doesn't affect the amount of disk space consumed and subsequently doesn't affect the user's space allowance. Disk quotas are based on uncompressed file sizes.
Disk quota limits are transparent to most programs. When a user reaches his or her limit, the volume simply appears full—at which point, programs raise errors and execute error-handling code to recover. Disk quotas are also transparent to the user. When a user asks how much space remains on a particular disk, the system reports only the user's quota availability—whether the user asks through the OS's UI or through a script.
Typically, you use Group Policy Editor (GPE) to set disk quota policies. However, you can manually configure some settings—for example, you can enable or disable disk quota management—without maintaining a policy. You can also use COM components in a script to determine users' quota disk usage and create an HTML-based report.
Manually Configuring Quotas
To manually control quotas without maintaining a policy, you simply open the My Computer folder, right-click the appropriate NTFS volume, and click Properties. On the Quota tab, you can set the various options. You have three approaches for disk quota management:
- You can disable quotas by clearing the Enable quota management check box.
- You can enable but not enforce quotas by selecting the Enable quota management check box and clearing the Deny disk space to users exceeding quota limit check box. If you choose this approach, the system tracks usage but doesn't raise quota error events or reject write operations because of disk quota violations.
- You can enable and enforce quotas by selecting the Enable quota management check box and the Deny disk space to users exceeding quota limit check box.
The Quota tab also includes a mode that lets you track quotas. By clearing the Deny disk space to users exceeding quota limit check box and selecting one of the logging options, you enter quota-tracking mode. This mode essentially permits users to exceed their quota. The system never denies access to a volume; instead, the system regularly monitors and reports on disk-space usage on a per-user basis. In other words, while in quota-tracking mode, the disk quota system limits its actions to log events rather than to blocking operations.
You can also choose to enable quota tracking and quota enforcement simultaneously. To do so, select the Deny disk space to users exceeding quota limit check box, along with one of the logging options. You can configure the system to add an entry to the system log file whenever a user attempts to exceed his or her allotted disk space.
Enabling disk quotas increases server overhead and slightly degrades file-server performance. A good technique for minimizing the effect of disk quotas on system performance is to selectively enable quotas. When quotas are enabled, you can use Win2K's auditing capabilities to monitor and record disk usage. In this way, you can get a precise idea of how users are using the space and decide whether and when to run the system with the quota feature enabled. You can use a common file format such as Microsoft Excel (.xls) files to export auditing output to other applications and managers.
Determining Disk Quotas Programmatically
Let's look at an alternative approach, based on the use of COM components, to selectively extract disk usage information and generate HTML code to create Web-deployable reports. In Win2K and later, the Windows shell provides the DiskQuotaControl object, which lets you manage disk quota properties for a given volume. Using the DiskQuotaControl component, you can programmatically set default quota limits, enable and disable a particular volume's disk quota system, and decide whether to deny or provide extra disk space to users who exceed their limit.
Before you start working with this COM object, you need to ensure that quotas are enabled or that disk quotas have been enabled at least once on the system. If you run a script that uses the DiskQuotaControl component on a disk that has never had quotas enabled, the script will return nothing but a zero. When you enable quota management, the system takes a while to update disk statistics usage per user.
To create an instance of the DiskQuotaControl object, you use VBScript's CreateObject function with the programmatic identifier (ProgID) of Microsoft.DiskQuota.1, as callout A in Listing 1 shows. The first operation you perform with the DiskQuotaControl object is to initialize its quota control object. To do so, use the Initialize method to specify and open a disk volume, as the code at callout A shows. The Initialize method requires two arguments. The first argument is a string value that contains the fully qualified path of the volume you want to initialize. Typically, this string is the root of an NTFS volume drive. The second argument is a Boolean value that specifies the volume's read/write modality. If you pass a value of true, the volume will be available for read/write access; if you pass a value of false, the volume will be available only for read access. After the Initialize method executes, you're connected to the volume's disk quota system.
What you do next depends on your needs. For the purposes of this article, let's look at two techniques you can use to obtain and report disk usage for each user. Listing 1 contains code that determines and displays users' quota disk usage, whereas Listing 2 contains code that determines users' quota disk usage and creates an HTML-based report from that data.
Displaying Disk Quota Usage
The DiskQuotaControl object lets you set global volume properties that apply to all users. To set quota-related properties that pertain to a particular user, and to add or remove users to and from the disk quota system, you use the DIDiskQuotaUser object. This object exposes all users who have a disk quota as elements of a collection. Each member of the collection is a DIDiskQuotaUser object. As with any other COM-based collection, you can use VBScript's For Each...Next statement to enumerate the quota users collection. The code at callout B in Listing 1 iterates each user in the collection and creates a string that contains the name of the user and the amount of space he or she is using. The DIDiskQuotaUser object's LogonName property returns the user's logon account name and is a read-only property. The QuotaUsed property contains the user's current disk usage, expressed in bytes. (The data type of the value returned by this property is Double.) As I mentioned earlier, disk compression doesn't affect the disk quota system. Therefore, the value that QuotaUsed returns always reflects the amount of disk space that uncompressed files require.
If you access quota information for reporting purposes, you probably don't need to know the exact number of bytes that each user is consuming. Thus, the value that QuotaUsed returns goes far beyond your needs and, worse, is hard to read. To arrive at a more readable number, the code at callout B uses VBScript's Round function to convert the number of bytes into the number of megabytes. The Round function uses a specified number of decimal digits (two digits in this sample) to round the number up or down.
The code in Listing 1 is configured to work on an NTFS-formatted C volume. To adapt the code to your system, change the first argument of the Initialize method in the code at callout A so that it reflects the volume you want to work on.
Preparing an HTML Report
Listing 1 provides information about users' disk usage, but you can hardly say that the output is well formatted or pleasant to read. With a little effort, you can write code so that the disk usage information flows seamlessly into an HTML framework. HTML isn't a difficult formatting language, as long as your needs remain relatively simple. The tasks of formatting data into columns and applying some straightforward layout rules are relatively easy and don't require the use of an ad hoc report-generator tool.
The script in Listing 2 queries Win2K for disk-usage information, then formats the data into an HTML file. To create the HTML report more effectively and easily, the code uses the QuotaUsedText property instead of the QuotaUsed property. QuotaUsedText returns a string that expresses the amount of space in gigabytes, megabytes, or kilobytes (e.g., 6.78GB, 443.56MB, 4.89KB). The text returned matches the data that appears in the volume's Quota Entries window's Amount Used column. All the information displayed in the Quota Entries window has a counterpart in the DiskQuotaControl and the DIDiskQuotaUser objects.
The script initializes a string with the HTML header tags necessary to set up a page with a table. As the code at callout A in Listing 2 shows, the code creates a table with a seashell background and border of one pixel in size. The code then creates two columns named Logon Name and Amount Used. If you need to create a third column, just insert a <th>...</th> line before the closing </thead> tag. Note that the <th> elements define only a cell in the table's header. A <th> tag alone doesn't represent a column.
At this point, the HTML page's static infrastructure has been set up. The next task is to simply fill the page with the raw quota information, as the code at callout B in Listing 2 shows. In this code, the script adds a new table row—a new <tr> element—for each user registered in the quota system. The row consists of as many cells—<td> elements—as the header cells previously defined. The Amount Used column, which is the second column in the table, is right aligned because it's made of strings that represent numbers. At the end of the loop, you close the main HTML tags and save the page. The file is now ready for deployment over an intranet and for viewing locally or remotely through a Web browser.
Code a Quota
The DiskQuotaControl component represents the scriptable counterpart of the disk quota system. You can use it to selectively extract the information you need from the quota system. This flexibility provides quota information in ways that are specific to corporate standards or administrator preference. Although Win2K provides powerful built-in auditing subsystems, a simple script like that in Listing 2 can use the same tools that the rest of the system uses to read quota information, then persist the information into HTML or even XML or a comma-separated value (CSV) file. You can now build your own history of user disk usage and create easily readable files.