Solved

Powershell script to get size of shares and freespace of volume

Posted on 2010-08-23
24
4,041 Views
Last Modified: 2012-06-21
I´m trying to build a powershell script, but I have definitely not enough know how about it. So maybe someone could help me with this or provide some information. What I want the script to do is the following:
I have an input-file with UNC-pathes to network shares on different servers. The script should use this file to get me the foldersize of the shares and also provide information about the freespace of the volume where the share exists.
An output like UNC - local Volume - total size - free space - sharesize would be perfect.
I´ve read and testet some scripts which I found here, but I can not get this to work...

At least this has not to be solved with powershell. If someone has a solution in VBS it would be fine also.

Any help would be welcome!

Regards
Steffen
0
Comment
Question by:SSR-IS
  • 10
  • 6
  • 6
  • +2
24 Comments
 
LVL 42

Expert Comment

by:sedgwick
ID: 33500105
can u post an example pf how the unc and shared folder is listed in the file?
0
 

Author Comment

by:SSR-IS
ID: 33500123
Oh, at least it doesn´t matter how the input file should look like. The easiest for would be

\\server1\share1
\\server1\share2
\\server2\share1
...

But I could also provide an input-file without the backslashes...
0
 
LVL 42

Expert Comment

by:sedgwick
ID: 33500311
the script reads from UNC_LIST_FILE (modify it in the script) and expect unc in the format you posted.
for example:

\\s004\temp

the output result is csv, for example:

UNC,FolderPath,FolderSize,DriveSize,DriveFreeSpace
s004,C:\temp,675.42124080658,152624.99609375,101631.92578125

all sizes are in MB.
const UNC_LIST_FILE = "c:\temp\shared_volume.txt"
const LOG_FILE = "c:\temp\output.log"

set objFSO = createobject("scripting.filesystemobject")
set objFile = objFSO.OpenTextFile(UNC_LIST_FILE, 1)

arrVolumes = Split(objFile.ReadAll, vbNewLine)
objFile.Close

set objLogFile = objFSO.CreateTextFile(LOG_FILE, 1)
objLogFile.WriteLine "UNC,FolderPath,FolderSize,DriveSize,DriveFreeSpace"

for each vol in arrVolumes
	
	Set objFolder = objFSO.GetFolder(vol)
	folderSize = (objFolder.Size/1048576)
	tokens = Split(vol, "\")
	name = tokens(UBound(tokens))
	server = tokens(UBound(tokens)-1)
	
	strLogLine = server
	
	Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & server & "\root\cimv2")
	Set colShares = objWMIService.ExecQuery("Select Path from Win32_Share where name = '" & name & "'")

	For each objShare in colShares
		strLogLine = strLogLine & "," & objShare.Path
		drive = Split(objShare.Path,":")(0)
		exit for
	Next

	strLogLine = strLogLine & "," & folderSize
	
	Set objWMIService = GetObject("winmgmts:\\" & server & "\root\cimv2")
	Set colItems = objWMIService.ExecQuery("Select FreeSpace,Size from Win32_LogicalDisk where Name='" & drive & ":'")
	For Each objItem in colItems
		size = (objItem.Size/1048576)
		freeSpace = (objItem.FreeSpace/1048576)
		
		strLogLine = strLogLine & "," & size
		strLogLine = strLogLine & "," & freeSpace
		exit for
	next
	
	objLogFile.WriteLine strLogLine
next

objLogFile.Close
wscript.echo "Done"

Open in new window

0
 

Author Comment

by:SSR-IS
ID: 33500437
Thanks a lot, sedgwick! Yout Script runs really perfect for me!
Do you mind me asking you three more things?

Could we get the sizes in GB?
Could we get the output values seperated by semikolon instead of komma?

And another thing: Would it be a lot of work to get the results in an excel worksheet? Eventually written "live"? - But don´t spent to much time on this, I could even also import it there...

Regards
Steffen
0
 
LVL 42

Expert Comment

by:sedgwick
ID: 33500490
now the script logs GB sizes, and use semikolon instead of comma.
regarding excel, it's gonna take sometime if you can wait...
const UNC_LIST_FILE = "c:\temp\shared_volume.txt"
const LOG_FILE = "c:\temp\output.log"

set objFSO = createobject("scripting.filesystemobject")
set objFile = objFSO.OpenTextFile(UNC_LIST_FILE, 1)

arrVolumes = Split(objFile.ReadAll, vbNewLine)
objFile.Close

set objLogFile = objFSO.CreateTextFile(LOG_FILE, 1)
objLogFile.WriteLine "UNC,FolderPath,FolderSize,DriveSize,DriveFreeSpace"

for each vol in arrVolumes
	
	Set objFolder = objFSO.GetFolder(vol)
	folderSize = (objFolder.Size/1073741824)
	tokens = Split(vol, "\")
	name = tokens(UBound(tokens))
	server = tokens(UBound(tokens)-1)
	
	strLogLine = server
	
	Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & server & "\root\cimv2")
	Set colShares = objWMIService.ExecQuery("Select Path from Win32_Share where name = '" & name & "'")

	For each objShare in colShares
		strLogLine = strLogLine & ";" & objShare.Path
		drive = Split(objShare.Path,":")(0)
		exit for
	Next

	strLogLine = strLogLine & ";" & folderSize
	
	Set objWMIService = GetObject("winmgmts:\\" & server & "\root\cimv2")
	Set colItems = objWMIService.ExecQuery("Select FreeSpace,Size from Win32_LogicalDisk where Name='" & drive & ":'")
	For Each objItem in colItems
		size = (objItem.Size/1073741824)
		freeSpace = (objItem.FreeSpace/1073741824)
		
		strLogLine = strLogLine & ";" & size
		strLogLine = strLogLine & ";" & freeSpace
		exit for
	next
	
	objLogFile.WriteLine strLogLine
next

objLogFile.Close
wscript.echo "Done"

Open in new window

0
 

Author Comment

by:SSR-IS
ID: 33500516
If it´s okay for you to do the coding I could wait a while!
0
 
LVL 42

Expert Comment

by:sedgwick
ID: 33500551
here's output to excel.


const UNC_LIST_FILE = "c:\temp\shared_volume.txt"
const LOG_FILE = "c:\temp\output.log"
const OUTPUT_EXCEL_FILE = "c:\temp\Live.xlsx"
const SHEET_HEADERS = "UNC;FolderPath;FolderSize;DriveSize;DriveFreeSpace"

set objFSO = createobject("scripting.filesystemobject")
set objFile = objFSO.OpenTextFile(UNC_LIST_FILE, 1)

arrVolumes = Split(objFile.ReadAll, vbNewLine)
objFile.Close

Const xlExcel7 = 51

On Error Resume Next
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = false
 
If (Err.Number <> 0) Then
    On Error GoTo 0
    Wscript.Echo "Excel application not found."
    Wscript.Quit
End If
On Error GoTo 0

col=1
row=2

' Create a new workbook.
objExcel.Workbooks.Add

' Bind to worksheet.
Set objSheet = objExcel.ActiveWorkbook.Worksheets(1)

for each header in Split(SHEET_HEADERS,";")
	objSheet.Cells(1, col).Value = header
	col=col+1
next

for each vol in arrVolumes
	
	Set objFolder = objFSO.GetFolder(vol)
	folderSize = (objFolder.Size/1073741824)
	tokens = Split(vol, "\")
	name = tokens(UBound(tokens))
	server = tokens(UBound(tokens)-1)
	path=""	
	size=""
	freeSpace=""
	
	Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & server & "\root\cimv2")
	Set colShares = objWMIService.ExecQuery("Select Path from Win32_Share where name = '" & name & "'")

	For each objShare in colShares
		path = objShare.Path
		drive = Split(objShare.Path,":")(0)
		exit for
	Next
	
	Set objWMIService = GetObject("winmgmts:\\" & server & "\root\cimv2")
	Set colItems = objWMIService.ExecQuery("Select FreeSpace,Size from Win32_LogicalDisk where Name='" & drive & ":'")
	For Each objItem in colItems
		size = (objItem.Size/1073741824)
		freeSpace = (objItem.FreeSpace/1073741824)
		exit for
	next
	
	objSheet.Cells(row, 1).Value = server
	objSheet.Cells(row, 2).Value = path
	objSheet.Cells(row, 3).Value = folderSize
	objSheet.Cells(row, 4).Value = size
	objSheet.Cells(row, 5).Value = freeSpace

	row=row+1
next

objExcel.DisplayAlerts = False
objExcel.ActiveWorkbook.SaveAs OUTPUT_EXCEL_FILE, xlExcel7
objExcel.ActiveWorkbook.Close false

' Quit Excel.
objExcel.Application.Quit

Set objSheet = Nothing
Set objExcel = Nothing

Wscript.Echo "done."

Open in new window

0
 
LVL 13

Expert Comment

by:soostibi
ID: 33500592
Let's try this PowerShell solution. This is raw data, we can format it to any format you like.
$shares = get-content c:\sharelist.txt # "\\server1\share1", "\\server2\share2"

$shares | %{

	if($_ -match "\\\\([^\\]+)\\(.+)$"){

		$server = $matches[1]

		$name = $Matches[2]

		$wmi = Get-WmiObject -ComputerName $server -Class Win32_Share -Filter "name = '$name'"

		$driveletter = if($wmi.path -match "^(\w:)"){$matches[1]}

		$drive = Get-WmiObject -ComputerName $server -Class Win32_logicaldisk -Filter "DeviceID = '$driveletter'"

		$sharesize = (Get-ChildItem $_ -Recurse -ErrorAction SilentlyContinue | ?{!$psiscontainer} | Measure-Object -Property length -Sum).sum

		New-Object -TypeName PSObject -Property @{UNC = $_; volume = $driveletter; size= $drive.size; freespace = $drive.freespace; sharesize = $sharesize}

	}

}

Open in new window

0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 33500761

Just for fun... A PowerShell version.

All sizes are in Gb to two decimal places. Exports to a CSV file at the end, do yell if the comments aren't sufficient.

Chris
# Read the text file
Get-Content Test.txt | ForEach-Object {
  # Get the server name
  $Server = $_ -Replace '^\\\\|\\.*$'

  # Get the share
  $ShareName = $_ -Replace '^.*\\'
  $Share = [WMI]"\\$Server\root\cimv2:Win32_Share.Name='$Sharename'"

  # Get the disk
  $VolumeDeviceID = $Share.Path -Replace '\\.*$'
  $Volume = [WMI]"\\$Server\root\cimv2:Win32_LogicalDisk.DeviceID='$VolumeDeviceID'"

  # Build the output combining everything we found above
  "" | Select-Object `
    @{n='ServerName';e={ $Server }},
    @{n='ShareName';e={ $ShareName }},
    @{n='Path';e={ $Share.Path }},
    @{n='Volume';e={ $Volume.Name }},
    @{n='TotalSize';e={ '{0:N2}' -f ($Volume.Size / 1Gb) }},
    @{n='Freespace';e={ '{0:N2}' -f ($Volume.Freespace / 1Gb) }},
    @{n='ShareSize';e={ '{0:N2}' -f ((Get-ChildItem $_ -Recurse | Measure-Object Length -Sum).Sum / 1Gb) }}

# Export the results to a CSV file
} | Export-Csv File.csv -NoTypeInformation

Open in new window

0
 

Author Comment

by:SSR-IS
ID: 33500836
Thanks a lot guys!
You´re posting faster as I can test the scripts. But I´ll let you know when I managed to do so...
0
 
LVL 42

Expert Comment

by:sedgwick
ID: 33500924
@Chris-Dent

i'm amazed everytime how many lines of code are required to perform a task in vbs as opposed to powershell.
0
 

Author Comment

by:SSR-IS
ID: 33500932
@Chris-Dent:
Something seems to be wrong with building ".sum". Please see my result:
"ServerName","ShareName","Path","Volume","TotalSize","Freespace","ShareSize"
"server01","share01","D:\share01","D:","54,15","9,58","0,01"
"server02","share01","I:\share01","I:","36,84","32,68","0,01"

The ShareSize is the same value for both, but on the server the second share is about 3 GB.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 70

Expert Comment

by:Chris Dent
ID: 33500954

Apologies, I broke it :)

Fixed here.

Chris
# Read the text file
Get-Content Test.txt | ForEach-Object {
  # Get the server name
  $Server = $_ -Replace '^\\\\|\\.*$'

  # Get the share
  $ShareName = $_ -Replace '^.*\\'
  $Share = [WMI]"\\$Server\root\cimv2:Win32_Share.Name='$Sharename'"

  # Get the disk
  $VolumeDeviceID = $Share.Path -Replace '\\.*$'
  $Volume = [WMI]"\\$Server\root\cimv2:Win32_LogicalDisk.DeviceID='$VolumeDeviceID'"

  # Build the output combining everything we found above
  $_ | Select-Object `
    @{n='ServerName';e={ $Server }},
    @{n='ShareName';e={ $ShareName }},
    @{n='Path';e={ $Share.Path }},
    @{n='Volume';e={ $Volume.Name }},
    @{n='TotalSize';e={ '{0:N2}' -f ($Volume.Size / 1Gb) }},
    @{n='Freespace';e={ '{0:N2}' -f ($Volume.Freespace / 1Gb) }},
    @{n='ShareSize';e={ '{0:N2}' -f ((Get-ChildItem $_ -Recurse | Measure-Object Length -Sum).Sum / 1Gb) }}

# Export the results to a CSV file
} | Export-Csv File.csv -NoTypeInformation

Open in new window

0
 

Author Comment

by:SSR-IS
ID: 33501188
Okay, I´ll do some more testing, but for now I can say the following:
Sedgwick´s and Chris-Dent´s scripts are running both very smooth, with not a lot of differences if you want to work with the results in Excel.
It seems to me the the VBS-Solution runs a lot quicker than the powershell version:
VBS --> 6 seconds on the 3 GB testshare
PS --> 59 seconds on the 3 GB testshare

If I calculate this for 500 GB-shares.....
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 33501321

It's the bit that gets the folder size, we have to recurse down the folder structure if we use Get-ChildItem, counting all the files. We can use the same method as VbScript though.

You may find relatively small discrepancies in size, but it's worth a try :)

Chris
# Read the text file
Get-Content Test.txt | ForEach-Object {
  # Get the server name
  $Server = $_ -Replace '^\\\\|\\.*$'

  # Get the share
  $ShareName = $_ -Replace '^.*\\'
  $Share = [WMI]"\\$Server\root\cimv2:Win32_Share.Name='$Sharename'"

  # Get the disk
  $VolumeDeviceID = $Share.Path -Replace '\\.*$'
  $Volume = [WMI]"\\$Server\root\cimv2:Win32_LogicalDisk.DeviceID='$VolumeDeviceID'"

  # Build the output combining everything we found above
  $_ | Select-Object `
    @{n='ServerName';e={ $Server }},
    @{n='ShareName';e={ $ShareName }},
    @{n='Path';e={ $Share.Path }},
    @{n='Volume';e={ $Volume.Name }},
    @{n='TotalSize';e={ '{0:N2}' -f ($Volume.Size / 1Gb) }},
    @{n='Freespace';e={ '{0:N2}' -f ($Volume.Freespace / 1Gb) }},
    @{n='ShareSize';e={ '{0:N2}' -f ((New-Object -ComObject Scripting.FileSystemObject).GetFolder($_).Size / 1Gb) }}

# Export the results to a CSV file
} | Export-Csv File.csv -NoTypeInformation

Open in new window

0
 

Author Comment

by:SSR-IS
ID: 33501472
I understand the changes you made to use filesystem object, but the funny thing ist, that now the powershell script runs faster then vbs.
Maybe I have the opportunity to test the scripts on our larger shares (30 to 800 GB) tomorrow morning.
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 33501501

Good, that's the way it should be ;)

It's quite likely that the WMI pieces are where you get the speed improvement. In the case of mine we're connecting directly to a WMI resource rather than searching for it.

Chris
0
 

Author Comment

by:SSR-IS
ID: 33508792
Okay, I did some testing this morning on our larger shares and everthing worked fine. If yout time allows, there one more thing which would make the script perfect:
Is it possible to implement some kind of status/ progress bar? The script will run for al long time and it would be nice to know if its still alive...

Steffen
0
 
LVL 70

Accepted Solution

by:
Chris Dent earned 500 total points
ID: 33508860

Sure! This uses Write-Progress.

Chris
# Read the text file
Get-Content Test.txt | ForEach-Object {

  Write-Progress -Activity "Scanning shares" -Status $_

  # Get the server name
  $Server = $_ -Replace '^\\\\|\\.*$'

  # Get the share
  $ShareName = $_ -Replace '^.*\\'
  $Share = [WMI]"\\$Server\root\cimv2:Win32_Share.Name='$Sharename'"

  # Get the disk
  $VolumeDeviceID = $Share.Path -Replace '\\.*$'
  $Volume = [WMI]"\\$Server\root\cimv2:Win32_LogicalDisk.DeviceID='$VolumeDeviceID'"

  # Build the output combining everything we found above
  $_ | Select-Object `
    @{n='ServerName';e={ $Server }},
    @{n='ShareName';e={ $ShareName }},
    @{n='Path';e={ $Share.Path }},
    @{n='Volume';e={ $Volume.Name }},
    @{n='TotalSize';e={ '{0:N2}' -f ($Volume.Size / 1Gb) }},
    @{n='Freespace';e={ '{0:N2}' -f ($Volume.Freespace / 1Gb) }},
    @{n='ShareSize';e={ '{0:N2}' -f ((New-Object -ComObject Scripting.FileSystemObject).GetFolder($_).Size / 1Gb) }}

# Export the results to a CSV file
} | Export-Csv File.csv -NoTypeInformation

Open in new window

0
 

Author Comment

by:SSR-IS
ID: 33508918
Thanks again - works nice and does anything I need!
I guess I should learn some powershell stuff, there´s a lot of things which can be done very elegant.

Can you recommend some books or so to get a good entry point?
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 33508968
Yeah, this is a good starting point:

http://powershell.com/Mastering-PowerShell.pdf

Once you start getting through that you can explore some of the resources listed here:

http://social.technet.microsoft.com/wiki/contents/articles/windows-powershell-survival-guide.aspx

And these physical books are highly regarded:

PowerShell Cookbook - http://oreilly.com/catalog/9780596801519
PowerShell in Action - http://www.manning.com/payette/

They have different focus, if you're looking at administrative work the Cookbook may be the best bet (just make sure you get the new edition, 2nd edition).

Chris
0
 

Author Comment

by:SSR-IS
ID: 33508984
So at least all my questions are answered and the results are great!
0
 
LVL 42

Expert Comment

by:sedgwick
ID: 33509182
that's a whole new "project" and not really in this scope.
i've found something that create dynamically htmlfile object and update it but it needs major modification.
check http://www.computing.net/answers/programming/vbscript-show-progress/14186.html

i think you should open new question for it, i'd happily assist you if it wasn't like this.
sorry man.
0
 
LVL 1

Expert Comment

by:jjoz
ID: 35799264
Hi, is it possible to modify the script just to type the server name only and then get all of the network shares recursively then pipe that output to the script above ?
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Are you one of those front-line IT Service Desk staff fielding calls, replying to emails, all-the-while working to resolve end-user technological nightmares? I am! That's why I have put together this brief overview of tools and techniques I use in o…
This script checks a path to see if a folder exists. If the folder does exist you will get output "The folder has previously been created. No action taken" If not it will create the folder. Then adds one user modify permission to the folder. It …
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now