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:
Microsoft DPM
MicrosoftExchange
Nerd with a .45
PowerShell