I know most people have heard of Moore’s Law that is named after Gordon Moore, but have you ever heard of Bob’s law? Bob was the senior network administrator when I first became an IT pro, and he created what he called Bob’s Law. Briefly stated it says this: “A user’s demand for storage space will always expand to meet the available storage space, plus 10 percent.” In other words, we can never have too much disk space for users.
Well, at work, we are currently being ravaged by Bob’s Law; our users are constantly running out of disk space on their work stations, their laptops, and even their Windows smart phones. I go into some offices, and they have USB sticks stuck in every available port on their laptops, and some users have even gone so far as to buy external USB hubs and stick stuff in there as well. The things look like some kind of infernal terminator porcupine. I know we cannot suspend Bob`s Law, but I need a script that I can run remotely that will tell me how much free disk space a user has. Can you help me?
– EC
Hi EC,
So your users say they do not have enough free disk space? Tell them to open Windows PowerShell and type Format c…just kidding. That command will delete all their files. That is an old IT joke, about as old as Bob’s law.
This week is Desktop Week—a rather vague series of loosely connected articles that may or may not be related to desktops. But the articles were written on a desktop, so maybe that counts. If you want to see some VBScript examples of Desktop Management scripts, check out these scripts in the Script Center Script Repository. The Community-Submitted Scripts Center also has a collection of scripts related to desktop management. In addition, there is the Desktop Management archive of “Hey Scripting Guy!” articles, which include scripts and explanations as well. The scripts this week will be using Windows PowerShell. To download Windows PowerShell and to find getting started information, see the Windows PowerShell hub. |
To aid you in managing your users’ incessant demands for disk space, it might be useful to be able to retrieve the amount of free disk space from a remote computer before it becomes a crisis. We can use the Win32_LogicalDisk WMI class with the Get-WmiObject cmdlet from Windows PowerShell. An example of doing this is seen in the GetFreeDiskSpace.ps1 script.
Get-FreeDiskSpace.ps1
Function Get-FreeDiskSpace($drive,$computer) { $driveData = Get-WmiObject -class win32_LogicalDisk ` -computername $computer -filter "Name = '$drive'" "$computer free disk space on drive $drive" "{0:n2}" -f ($driveData.FreeSpace/1MB) + " MegaBytes" } Get-FreeDiskSpace -drive "C:" -computer "vista"
The first thing we do in the Get-FreeDiskSpace.ps1 script is to create a function. To create a function that uses multiple input parameters we use the Function keyword, specify the name of the function, use variables for each input parameter, and define the script block within the curly brackets.
The Get-FreeDiskSpace.ps1 script begins with the Function keyword, the name of the function, and the two input parameters. The first input parameter is the drive name, and the second is the name of the computer. The input parameters are placed inside smooth parentheses with a variable used to hold the data that comes in when the function is called:
Function Get-FreeDiskSpace($drive,$computer) {
Inside the curly brackets the Get-FreeDiskSpace function uses the Get-WmiObject cmdlet to query the Win32_LogicalDisk WMI class. It connects to the computer specified in the $computer parameter, and it filters out only the drive that is specified in the $drive parameter. When the function is called, the parameters are specified as –drive and –computer. In the function definition, the variables $drive and $computer are used to hold the values supplied to the parameters.
The –filter parameter from the Get-WmiObject cmdlet is used to limit the number of instances that are returned by the WMI query. The filter takes the place of the whereclause from VBScript WMI Query Language (WQL) statements. The filter in our script limits the number of instances that are returned to only the one specified in the $drive variable. Here is our filter:
-filter "Name = '$drive'
The thing that is perhaps surprising is that the value contained in the $drive variable still gets read. You may recall from previous “Hey, Scriting Guy!” articles that I went on and on at great length about the difference between literal quotation marks and expanding quotation marks. We also have this documented as a Windows PowerShell tip. Well, you can forget that here. When you are working with the filter parameter of the Get-WmiObject cmdlet, you are using WQL syntax, not Windows PowerShell syntax. This is why you use the equal sign instead of –eq. It is also why the single quotation mark is not a literal quotation mark, so we still have access to the value of the $drive variable.
An excellent reference for learning WMI is the Microsoft Press book, Microsoft Windows Scripting with WMI: Self-Paced Learning Guide. While the examples are all written in VBScript, WMI technology is still the same.
If we were to use the Get-WmiObject cmdlet by itself and query the Win32_Logicaldisk WMI class, we would see an output similar to this:
There is more data returned from the WMI query than that which is displayed in the preceding image. Windows PowerShell creates s a nice display of information that is considered to be most useful to the network administrator. If you want to see more information, you can easily obtain it by using either the methods or properties seen in Table 1.
After the data from WMI is retrieved, it is stored in the $driveData variable. The data that is stored in the $driveData variable is an instance of the Win32_LogicalDisk. This variable contains a complete instance of the class. The members of this class are seen in Table 1.
Table 1 Members of the Win32_LogicalDisk class
Name | Member Type | Definition |
Chkdsk |
Method |
System.Management.ManagementBaseObject Chkdsk(System.Boolean FixErrors, System.Boolean VigorousIndexCheck, System.Boolean SkipFolderCycle, System.Boolean ForceDismount, System.Boolean RecoverBadSectors, System.Boolean OkToRunAtBootUp) |
Reset |
Method |
System.Management.ManagementBaseObject Reset() |
SetPowerState |
Method |
System.Management.ManagementBaseObject SetPowerState(System.UInt16 PowerState, System.String Time) |
Access |
Property |
System.UInt16 Access {get;set;} |
Availability |
Property |
System.UInt16 Availability {get;set;} |
BlockSize |
Property |
System.UInt64 BlockSize {get;set;} |
Caption |
Property |
System.String Caption {get;set;} |
Compressed |
Property |
System.Boolean Compressed {get;set;} |
ConfigManagerErrorCode |
Property |
System.UInt32 ConfigManagerErrorCode {get;set;} |
ConfigManagerUserConfig |
Property |
System.Boolean ConfigManagerUserConfig {get;set;} |
CreationClassName |
Property |
System.String CreationClassName {get;set;} |
Description |
Property |
System.String Description {get;set;} |
DeviceID |
Property |
System.String DeviceID {get;set;} |
DriveType |
Property |
System.UInt32 DriveType {get;set;} |
ErrorCleared |
Property |
System.Boolean ErrorCleared {get;set;} |
ErrorDescription |
Property |
System.String ErrorDescription {get;set;} |
ErrorMethodology |
Property |
System.String ErrorMethodology {get;set;} |
FileSystem |
Property |
System.String FileSystem {get;set;} |
FreeSpace |
Property |
System.UInt64 FreeSpace {get;set;} |
InstallDate |
Property |
System.String InstallDate {get;set;} |
LastErrorCode |
Property |
System.UInt32 LastErrorCode {get;set;} |
MaximumComponentLength |
Property |
System.UInt32 MaximumComponentLength {get;set;} |
MediaType |
Property |
System.UInt32 MediaType {get;set;} |
Name |
Property |
System.String Name {get;set;} |
NumberOfBlocks |
Property |
System.UInt64 NumberOfBlocks {get;set;} |
PNPDeviceID |
Property |
System.String PNPDeviceID {get;set;} |
PowerManagementCapabilities |
Property |
System.UInt16[] PowerManagementCapabilities {get;set;} |
PowerManagementSupported |
Property |
System.Boolean PowerManagementSupported {get;set;} |
ProviderName |
Property |
System.String ProviderName {get;set;} |
Purpose |
Property |
System.String Purpose {get;set;} |
QuotasDisabled |
Property |
System.Boolean QuotasDisabled {get;set;} |
QuotasIncomplete |
Property |
System.Boolean QuotasIncomplete {get;set;} |
QuotasRebuilding |
Property |
System.Boolean QuotasRebuilding {get;set;} |
Size |
Property |
System.UInt64 Size {get;set;} |
Status |
Property |
System.String Status {get;set;} |
StatusInfo |
Property |
System.UInt16 StatusInfo {get;set;} |
SupportsDiskQuotas |
Property |
System.Boolean SupportsDiskQuotas {get;set;} |
SupportsFileBasedCompression |
Property |
System.Boolean SupportsFileBasedCompression {get;set;} |
SystemCreationClassName |
Property |
System.String SystemCreationClassName {get;set;} |
SystemName |
Property |
System.String SystemName {get;set;} |
VolumeDirty |
Property |
System.Boolean VolumeDirty {get;set;} |
VolumeName |
Property |
System.String VolumeName {get;set;} |
VolumeSerialNumber |
Property |
System.String VolumeSerialNumber {get;set;} |
__CLASS |
Property |
System.String __CLASS {get;set;} |
__DERIVATION |
Property |
System.String[] __DERIVATION {get;set;} |
__DYNASTY |
Property |
System.String __DYNASTY {get;set;} |
__GENUS |
Property |
System.Int32 __GENUS {get;set;} |
__NAMESPACE |
Property |
System.String __NAMESPACE {get;set;} |
__PATH |
Property |
System.String __PATH {get;set;} |
__PROPERTY_COUNT |
Property |
System.Int32 __PROPERTY_COUNT {get;set;} |
__RELPATH |
Property |
System.String __RELPATH {get;set;} |
__SERVER |
Property |
System.String __SERVER {get;set;} |
__SUPERCLASS |
Property |
System.String __SUPERCLASS {get;set;} |
PSStatus |
PropertySet |
PSStatus {Status, Availability, DeviceID, StatusInfo} |
ConvertFromDateTime |
ScriptMethod |
System.Object ConvertFromDateTime(); |
ConvertToDateTime |
ScriptMethod |
System.Object ConvertToDateTime(); |
After you have the data stored in the $driveData variable, you will want to print out some information to the user of the script. The first thing to do is print out the name of the computer and the name of the drive. To do this, you can place the variables inside double quotation marks. Double quotation marks are expanding strings, and variables placed inside double quotation marks emit their value, not their name. This is seen here:
"$computer free disk space on drive $drive"
The next thing you will want to do is to format the data that is returned. To do this, use the .NET Framework format strings to specify two decimal places. We will need to use smooth parentheses to force the evaluation of the free disk space prior to formatting it to two decimal places. This is seen here:
"{0:n2}" -f ($driveData.FreeSpace/1MB) + " MegaBytes"
When you run the script you see the name of the computer, the name of the drive, and the amount of free disk space expressed in megabytes:
office free disk space on drive C: 54,108.36 MegaBytes
Well, EC, that is about it for using WMI to obtain free disk space. Join us tomorrow as Desktop Week continues. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments