PowerShell: Drive Space Info from multiple systems

With PowerShell 2 came Powershell remoting and jobs, both of which are REALLY cool!  I’m going to show you two ways to get drive space info from multiple systems, first with a normal foreach loop, and then with remoting (which is basically a remote job).  Both methods use WMI class Win32_LogicalDisk to query the drives for information.

First, the old fashion foreach loop.  Notice the “Process” section – this in essence does a foreach of the $Identity – notice that in the parameter that the $Identity has  [object[]] in front of it.  Two things about this:  One, [] denotes an array, versus a single object.  Two, it’s object, instead of string, int or other data type.  Object allows the parameter to be just a string – a computer name (“SERVER01″), a string array (“SERVER01″, “SERVER02″), or even the identity from other objects (Get-ExchangeServer | GetDriveSpace).  I’ll be posting more in the future about parameters, and advanced functions (cmdletbinding).

Function GetDriveSpace
{
	[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Low")]
	param (
	[parameter(Mandatory=$true,HelpMessage="ComputerName(s)",ValueFromPipeline=$true)]
	[Object[]]$Identity
	)
	Process
	{
		$Name = (Get-WmiObject -ComputerName $Identity win32_computersystem  | Select Name).Name.ToString()
		$drives = Get-WmiObject -ComputerName $Identity Win32_LogicalDisk | Where-Object {$_.DriveType -eq 3}

		foreach($drive in $drives)
		{
			$NewObjectProperties = @{
				ComputerName=$Name;`
				DriveLetter=$drive.DeviceID;`
				Label=($drive.VolumeName);`
				DriveSize=($drive.Size/1gb).ToString("0.00");`
				FreeSpaceMB=($drive.freespace/1GB).tostring("0.00");`
				PercentFree=((($drive.freespace/1GB)/($drive.size/1GB))*100).tostring("0.00")`
			}
			New-Object psobject -Property $NewObjectProperties
		}
	}

	GetDriveSpace -Identity SERVER01

		Returns Drive Space Info for SERVER01

		.EXAMPLE
		PS] C:\>Get-MailboxServer | GetDriveSpace | FT

		Returns Drive Space Info for Exchange Mailbox Servers

		.EXAMPLE
		PS] C:\>GetDriveSpace -Identity SERVER01, SERVER02 | FT -AutoSize

		Returns Drive Space Info for SERVER01 & SERVER02

		.NOTES
		Function Name : GetDriveSpace
		Author : Dan Burgess
		Email: nerd@everydaynerd.com
		Script Requires:  Powershell 2.0 or higher
	#>
}

Now, lets do the same thing, but this time with PowerShell remoting.  As before, the function is utilizing  CmdletBinding, Parameter, with a single param [object[]]$Identity, and the Process block, but an End block as well.  In the Process block, each server passed in the parameter has a remote job started with the Invoke-Command cmdlet, passing the script block with the code to query WMI to return the disk space information.  Note the -AsJob switch – this allows the invoke-command to work in the background, instead of waiting on the job to finish.  The End block then checks all the jobs, and waits till none of the jobs have a status of “Running” before issuing a “Receive-Job”.  This gathers all the returned values from each job that ran.  The -Keep leaves a copy of the results in the job queue – if receive-job is run with out this, the results are removed from the job status.

Function GetDriveSpace-Remoting
{
	[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Low")]
	param (
	[parameter(Mandatory=$true,HelpMessage="ComputerName(s)",ValueFromPipeline=$true)]
	[Object[]]$Identity
	)
	Process
	{
		Invoke-Command -ComputerName $Identity -ScriptBlock {$drives = Get-WmiObject Win32_LogicalDisk | Where-Object {$_.DriveType -eq 3}
			foreach($drive in $drives)
			{
				$NewObjectProperties = @{
					DriveLetter=$drive.DeviceID;`
					Label=($drive.VolumeName);`
					DriveSizeMB=($drive.Size/1gb).ToString("0.00");`
					FreeSpaceMB=($drive.freespace/1GB).tostring("0.00");`
					PercentFree=((($drive.freespace/1GB)/($drive.size/1GB))*100).tostring("0.00")`
				}
				New-Object psobject -Property $NewObjectProperties
			}
		} -SessionOption (New-PSSessionOption -NoMachineProfile) -AsJob

	}
	End
	{
		While (Get-Job -State "Running")
		{
			$i = ((Get-Job).Count) - ((Get-Job -State "Running").count)
			$Progress = [int][Math]::Ceiling(($i / ((Get-Job).Count) * 100))
			Write-Progress -Activity "Waiting on $(((Get-Job -State "Running").count)) Jobs to finish" -PercentComplete $progress -Status "$($progress)% Complete" -Id 1;
		}
		$Results = Get-Job | % {Receive-Job $_ }
		$Results
	}

	GetDriveSpace-Remoting -Identity SERVER01

		Returns Drive Space Info for SERVER01

		.EXAMPLE
		PS] C:\>Get-MailboxServer | GetDriveSpace-Remoting | FT

		Returns Drive Space Info for Exchange Mailbox Servers

		.EXAMPLE
		PS] C:\>GetDriveSpace-Remoting -Identity SERVER01, SERVER02 | FT -AutoSize

		Returns Drive Space Info for SERVER01 & SERVER02

		.NOTES
		Function Name : GetDriveSpace-Remoting
		Author : Dan Burgess
		Email: nerd@everydaynerd.com
		Script Requires:  Powershell 2.0 or higher and WinRM enabled on remote hosts
	#>
}

Both methods work, but in my tests, the remote function was MUCH faster when pulling from multiple systems.  For a list of 48 systems, the normal foreach loop took 30 seconds, while the remote function only took 5 seconds!!!

Related posts:

  1. PowerShell: Get-Uptime for Computer(s)
  2. Easy hyperlink trick for Windows (Even if it has a space in the UNC path)
  3. Create multiple RDP files with Powershell
  4. Vista Drive Icons in 2000/XP
  5. 1GB Flash Drive – Only $2.49!!!
This entry was posted in Exchange, PowerShell. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>