Check disk space with Powershell

Need to monitor disk space on multiple servers? Then make the job easy with this Powershell script. To configure this script just create a file called serverlist.txt in your user profile folder, C:\Users\Rhys on my laptop. The $percentWarning variable allows you to control at what percentage level you will be warned about free disk space. If disk space is less than this then the text will be coloured red to draw your attention to it. The script will also output a datetime stamped csv file in your user folder containing similar data.

?View Code POWERSHELL
# Issue warning if % free disk space is less 
$percentWarning = 15;
# Get server list
$servers = Get-Content "$Env:USERPROFILE\serverlist.txt";
$datetime = Get-Date -Format "yyyyMMddHHmmss";
 
# Add headers to log file
Add-Content "$Env:USERPROFILE\server disks $datetime.txt" "server,deviceID,size,freespace,percentFree";
 
foreach($server in $servers)
{
	# Get fixed drive info
	$disks = Get-WmiObject -ComputerName $server -Class Win32_LogicalDisk -Filter "DriveType = 3";
 
	foreach($disk in $disks)
	{
		$deviceID = $disk.DeviceID;
		[float]$size = $disk.Size;
		[float]$freespace = $disk.FreeSpace;
 
		$percentFree = [Math]::Round(($freespace / $size) * 100, 2);
		$sizeGB = [Math]::Round($size / 1073741824, 2);
		$freeSpaceGB = [Math]::Round($freespace / 1073741824, 2);
 
		$colour = "Green";
		if($percentFree -lt $percentWarning)
		{
			$colour = "Red";
		}
		Write-Host -ForegroundColor $colour "$server $deviceID percentage free space = $percentFree";
		Add-Content "$Env:USERPROFILE\server disks $datetime.txt" "$server,$deviceID,$sizeGB,$freeSpaceGB,$percentFree";
	}
}

cid image001 png01c9f0dc thumb1 Check disk space with Powershell


51 Comments

  1. […] a PowerShell script here: Check disk space with Powershell | youdidwhatwithtsql.com Takes the servers from a TXT, outputs to screen and […]

  2. Eriko Oliveira says:

    Hello Guy,

    thank you so much… really this command or why not tool is awsome!

    Thanks
    EFO

  3. Jelly says:

    I copied, and modified this script. Very well written. I’m a big Fan of Rhys

  4. Aron says:

    Hey Thanks for script!

    This is almost exactly what I’m trying to do, except I need it to output the result of the script to the body of an email. I think what I need it to make the output into a variable I can call in the body of the email, in my example below I called it $DriveSpace.

    $SmtpClient = new-object system.net.mail.smtpClient
    $SmtpServer = “MAILSERVER”
    $SmtpClient.host =
    $SmtpServer

    $From = “USER ”
    $To = “ADDRESS@DOMAIN.COM”
    $Title = “Email Title”
    $Body = $DriveSpace
    $msg.IsBodyHTML = $true
    $SmtpClient.Send($from,$to,$title,$Body)

    I’m pretty new to Powershell and this is my first attempt at scripting, any advice would be appreciated :)

  5. Rhys says:

    Hi Aron,

    I also write the output into a text file so you can read the contents of this into a variable with the Get-Content cmdlet. Something like this should do it…
    $DriveSpace = Get-Content "$Env:USERPROFILE\server disks $datetime.txt";

    Cheers,

    Rhys

  6. Nathan says:

    Hey there, Rhys… awesome script, thank you!

    About your last comment… I’m a total beginner to PS, so could you explain a bit on how to put that $DriveSpace variable into the script properly in order to output all the results into a text file? I’ve tried it myself a couple of times, but I’m not having a lot of luck. My text file generates, but ends up with just “server,deviceID,size,freespace,percentFree” in it.

    Your assistance is much appreciated. Thanks!

    -Nathan

  7. Rhys says:

    Hi Nathan,

    Welcome to the awesome world of Powershell!

    The original script generates a text file so you don’t need to worry about that. The $DriveSpace variable was just a suggestion to get the content into an email. If you run the original script do you have a text file in your user directory called “server disks yyyymmddhhmiss.txt”? I’ve retested the script and it works fine for me. Try the original script and check your user folder for the file.

    Cheers,

    Rhys

  8. TJ says:

    I keep getting the error below for one of my servers. Any idea why?

    Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESS
    DENIED))
    At C:\server_check.ps1:12 char:24
    + $disks = Get-WmiObject <<<< -ComputerName $server -Class Win32_LogicalDisk -Filter "DriveType = 3";

  9. Rhys says:

    Hi TJ,

    Looks like a permissions issue to me so check this on the server in question.

    Cheers,

    Rhys

  10. Stuart says:

    Great code. One issue: I’m getting NaN as a result for one of the logical drives. When I check manually on the server, I can see this drive’s usage (110 GB used out of 500 GB).

    Not sure why I’m getting a non-number result.

  11. Rhys says:

    Hi Stuart,
    Mmm, I’d output the variables in the calculation. NaN…

    “The value of this constant is the result of dividing zero by zero.” ref

    Perhaps it’s having trouble getting the values for this drive.

    Cheers,

    Rhys

  12. ErwinvA says:

    Great script, thanks for sharing.

    Erwin

  13. Jeff says:

    Thanks for the script. I was looking for something like this to monitor a server that fills up on occasion. You saved me a lot of time by publishing this script.

    Cheers.

    Jeff

  14. Anton says:

    Hi, I was wondering if I can apply this script to my exchange mailbox moves.
    As I move a lot of mailboxes my concern is space. Can I somehow nest forloops to say that for every mailbox that I am moving I want to check if there is enough space available on the local server.
    The way I am moving mailboxes is through powershell, the code I have been using is this:

    get-content c:\moves.txt | get-mailbox | move-mailbox -baditemlimit 5 -targetdatabase ‘MYEXCHSERV\First Storage Group\MailboxDB’ -maxthreads 5 -Confirm:$False

    Thank you in advance!

  15. Rhys says:

    Hi Anton,

    I don’t work with Exchange anymore (thank God) so I can’t really give you any specifics but I guess you could use the Get-MailboxStatistics cmdlet to get the mailbox size and then cross-check this with the available free disk space.

    Cheers,

    Rhys

  16. Anton says:

    Rhys, thanks for the quick update.
    I took what you had here and created a scrippy which looks like this;

    #issue warning if disk space is less than XX%
    $percentWarning = 20;

    #list of mailboxes
    $mailboxes = get-content “c:mymbmoves.txt”
    #what server is this on
    $server = gc env:computername
    #partition variable
    $partition = “S:”;

    #display current data
    Write-Host -F Gray “`nPartition to check free space on: $partition”;
    Write-Host -F Gray “`nFree Space Threshold is $percentWarning”;
    Write-Host -F Gray “`nNumber of mailboxes to move:” $mailboxes.length;
    Write-Host -F Gray “`nList of mailboxes to move:”;
    Write-Host -F Gray “$Mailboxes”;

    #Perform the following actions for every mailbox in the $mailboxes array
    foreach($mailbox in $mailboxes)
    {

    #Create the $disks array
    $disks = Get-WmiObject -ComputerName “.” -Class Win32_LogicalDisk -Filter “DeviceID = ‘$partition'”

    #Check the diskspace of each disk in the $disks array so that we know if its safe to proceed
    foreach($disk in $disks)
    {
    Write-Host -F Gray “`nChecking free space on`n $disk ….”;

    #Calculate free space of the disk we are working on
    $deviceID = $disk.DeviceID;
    [float]$size = $disk.Size;
    [float]$freespace = $disk.FreeSpace;

    $percentFree = [Math]::Round(($freespace / $size) * 100, 2);
    $sizeGB = [Math]::Round($size / 1073741824, 2);
    $freeSpaceGB = [Math]::Round($freespace / 1073741824, 2);

    Write-Host -F Gray “`nCurrent free space on`n $disk is ” -NoNewLine;
    Write-Host -F Green $percentFree;

    #Compare the free space to our threshold – if free space is less than threshold, stop the entire script
    if ($percentFree -lt $percentWarning)
    {
    Write-Host -F Gray “`nQuitting at $(Get-Date)”;
    Write-Host -F Red “Stopping moves – free space is too low”;
    EXIT
    }

    }
    I hope this will somebody who is an exchange admin. great site, cheers!

  17. Rhys says:

    Hi Anton,

    Looks good. Thanks for sharing.

    Cheers,

    Rhys

  18. Fish says:

    Hi Rhys,

    I’m tuning this script to fit my own environment, and it seems to be working almost right. The problem is I’m pulling disk info from about 20 servers, and when I see the output it will list all drives from every computer as belonging to the first server in the list.
    For example: my list file contains svr1 svr2 and svr3 all of which have three partitions, the output would look like this
    svr1 C: etc…
    svr1 D: etc…
    svr1 E: etc…
    svr1 C: etc…
    svr1 D: etc…
    svr1 E: etc…
    svr1 C: etc…
    svr1 D: etc…
    svr1 E: etc…

    The second and third sets of drives should be listed as belonging to svr2 and svr3 respectively. Also of note it is returning an error about line 13
    $disks = get-wmiobject -computername (get-content “c:\computers.txt”) win32_logicaldisk -filter “drivetype=3″ ;

    Any help you can offer is appreciated. I’m pretty new to powershell but it seems like a phenomenal tool to automate some redundant tasks.

  19. Fish says:

    No Worries!

    I found that it was an s. 1 “s” made the whole thing screw up. This is why I hate coding.

  20. Rhys says:

    Hehehe, I’m still waiting for someone to invent a computer that does what I mean rather than what I tell it!

    Cheers,

    Rhys

  21. shridevi says:

    Hi Rhys,
    I am facing a challenge in using the above script:
    Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
    is the error,

    Please help me out in this.

  22. Rhys says:

    Hi Shridevi,

    Got to be some type of permissions issue so I would double-check around that. Maybe also check the WMI Service is running on the remote boxes – http://msdn.microsoft.com/en-us/library/windows/desktop/aa826517(v=vs.85).aspx

    Rhys

  23. shridevi says:

    Hi Rhys,

    The script now works without any error, the problem was with providing the user credentials to access the remote servers. I have added “-credentials” parameter to the script and passed in my username ( which prompts up asking for password ).

    The script works awesome, Thanks a lot for the same and also answering my query with such an immediate response.

    I wish to ask some help from you, based on the scenario where I am passing 10 server names in serverlist.txt and each time it is prompting me for entering the password.
    Can I have a better option other than it.

    Thanks a lot again for you help!

  24. Rhys says:

    Use the Get-Credential cmdlet outside of the loop – http://technet.microsoft.com/en-us/library/dd315327.aspx

  25. Rob says:

    Hi Rhys, great script, I’ve combined your script with some email functionality and some scheduled tasks to create an automated solution for our company. For anyone that is interested the script is here: http://randomdotnetnuggets.blogspot.com.au/2012/04/checking-server-disk-space.html

  26. Shridevi says:

    Thanks you Rhys! Its working awesome.

  27. Sravan says:

    i want to check the freespace against a single server and input the servername in a command prompt itself, how do i change the script..

    My need is like, when i run the script , it should ask, ‘enter server name’ and execute the script

    Can u help me please, i m new to PS scripting and not able to do.

  28. Rhys says:

    Hi Sravan,

    See my post on Console input with Powershell. You can modify the above script to accept a computer name.

    Cheers,

    Rhys

  29. Sravan says:

    Thank you Rhys ! I used read-host and is working fine :), thanks so much

  30. Sudipta says:

    Thanks very much for the info… Helped a lot…

  31. Mitch says:

    Thanks very much for the script, is there a way to pull info from a specific instance for a server instead of all instances?

    eg.
    Server1 C:
    server2 E:
    Server2 F:
    server3 G:

  32. Rhys says:

    Hi Mitch,

    Yes, you could add logic based on some condition.Is there a particular type of disk with a specific attribute you’d like to check?

    Cheers,

    Rhys

  33. Mitch says:

    Yes, for example;
    Svr1 instance E and F
    Svr2 instance I and G
    Svr3 instance C
    etc….

    For all instances I’m only interested to see the Local Fixed Disk

  34. Rhys says:

    It already does that with the DriveType property in the filter. See the documentation for the Win32_LogicalDisk.

    Cheers,

    Rhys

  35. Mitch says:

    DriveType will only filter on Local Fixed Disk but how do I further filter on specific instance for multiple servers?
    Below script will create two separate windows but the idea was to have it all in one window and specify for each server which instance I’m interested in.

    Get-WMIObject Win32_LogicalDisk -computername Server1 -filter “DeviceID=’E:’ or DeviceID=’F:'”|
    select __server, Name,Description, DriveType, @{Label=”Size”;Expression={“{0:n0} GB” -f ($_.Size/1024mb)}}, @{Label=”Free Space”;Expression={“{0:n0} GB” -f ($_.FreeSpace/1024mb)}} | out-gridview -Title “Disk Space Scan Results_Mitch”

    Get-WMIObject Win32_LogicalDisk -computername Server2 -filter “DeviceID=’C:'”|
    select __server, Name,Description, DriveType, @{Label=”Size”;Expression={“{0:n0} GB” -f ($_.Size/1024mb)}}, @{Label=”Free Space”;Expression={“{0:n0} GB” -f ($_.FreeSpace/1024mb)}} | out-gridview -Title “Disk Space Scan Results_Mitch”

  36. Rhys says:

    Two separate windows? How are you running this? There’s no reason why what you’ve got can’t be executed in a single window.

    Cheers,

    Rhys

  37. Mitch says:

    It outputs to grid, so if you run both sections as is then you get two windows open; one for the first Server which shows the free space for instance E and F ; and a second window that opens for the second Server which shows free space for drive C

    What I was looking for is one script where I can specify the server name and instances that I am interested in, however different servers have different instances eg. C, D, E, F, G, Y
    I know I can output to xls and then apply filters etc but would’ve been nicer to just have a script

  38. Rhys says:

    OK, so you’re using some sort of powershell ide for this? You probably want to look at Powershell Custom Objects to store all of your data from various servers before displaying it.

  39. Vsh says:

    Rhys ,

    Thanks a lot. its really excellent. It saved me lot of time and unnecessary delays .
    I thought using SSIS and T-SQL code to pull this out but your solution
    is much feasible.

    Keep Rocking ….

  40. Ruth says:

    I’m new to PowerShell. This was very helpful. Thank You!

  41. MARS says:

    Hi Rhys,

    I’m even more of a PS beginner than Nathan is. How do I even launch the script? Do I save it as DiskCheck.txt on the server in question?

    Thanks!
    Mike

  42. Rhys says:

    Hi Mike,

    Here’s a quick guide to running powershell scripts;

    http://technet.microsoft.com/en-us/library/ee176949.aspx

    The traditional extension for powershell script is “ps1″ but the script probably won’t execute due to the default execution policy (which is a good thing) http://technet.microsoft.com/en-us/library/ee176961.aspx

    Powershell scripts have to be signed to run, see here http://www.hanselman.com/blog/SigningPowerShellScripts.aspx

    Although it’s possible to disable this. Only do so if you’re 100% confident. You could also run it interactively by running each line individually in a powershell windows. See here for some stuff to get you started with ps – http://www.youdidwhatwithtsql.com/powershell-nuggets/72

    Hope this helps

    Cheers,

    Rhys

  43. ben says:

    Hi,

    The script is awesome!

    but i’m getting double results.. no idea why..

    p-srv-website C: percentage free space = 32.69 GB vrij = 12.96 GB
    p-srv-website C: percentage free space = 58.87 GB vrij = 58.81 GB
    srvdatabase C: percentage free space = 32.69 GB vrij = 12.96 GB
    srvdatabase C: percentage free space = 58.87 GB vrij = 58.81 GB

    By having a look at the servers the 2nd and 4th line are srvdatabase
    and the 1st and 3rd line are the p-srv-website.

    Any thoughts?
    Regards,
    Ben

  44. Rhys says:

    Hi Ben,

    I can’t see any reason for that to happen from what I’ve posted. Can you post what you’re running?

    Cheers,

    Rhys

  45. William says:

    Rhys,
    Your script is executing without any issues on my end, but I have a quick question. If I’m wanting to output this data into the body of an email via a database column “body”, how could I do so without the output becoming one long string?

    Thanks,
    William

  46. Rhys says:

    Hi William,

    I often use ConvertTo-Html cmdlet to format Powershell output for emails.

    Cheers,

    Rhys

  47. JP Garcia says:

    I have altered a bit your code, since I need to monitor mount points as well, so I used “-class win32_volume” instead of “Win32_LogicalDisk”

    The script is almost the same, just change “size” for “capacity” to get the values and that’s it.

    I hope this also help others too.

    JP

  48. Nicholas says:

    Thank you for this script Rhys

    It run well but I keep running into an issue on a server where I get the free space of the a partition and the disk size of a disk quota. So I tend to end up with a higher free space than capacity. I want to make sure I see the free space of the quota. Any idea on how to do this?

  49. Rhys says:

    Hi Nicholas

    Use the Win32_DiskQuota class.

    Cheers,

    Rhys

  50. Denis says:

    Thank you Rhys,

    Just the script I was looking for.

    Regards,
    Denis

Leave a Reply

Current ye@r *