Comment-Based Help

Guest Post — Get-myFreeSpace Revisited

Today's post comes by way of a co-worker, Robert Carlson, who took my previous post on getting the free disk space of remote computers and offered a very useful suggestion -- instead of outputting strings, which is only useful for a display or report, he suggests creating a PSCustomObject and outputting that. Slick! I like it.

 

So, why a PSCustomObject? Because now he can use it to drive automation, rather than simply reporting. A very handy change, and a good reminder for all of us that we should put off formatting until the last possible moment, because once you pipe something to Format-*, you're done. All your precious objects and their properties are gone, and you're left with a simple string.

 

The other thing Robert has done is change this from a script to a function. This makes it easier to call from other scripts and allows it to be added to your "toolbox" module. (More on Toolbox Modules soon. )  A worthy change. So, without further ado, here's Robert's revised Get-myFreeSpace function.

function Get-myFreeSpace {
<#
.Synopsis
Gets the disk utilization of one or more computers
 
.Description
Get-myFreeSpace queries an array of remote computers and returns a nicely formatted display of 
their current disk utilization and free space. The output can be redirected to a file or other 
output option using standard redirection, or can be piped to further commands.

.Parameter ComputerName
An array of computer names from which you want the disk utilization

.Example
(Get-VM -Name “*server*” | Where-Object {$_.State -eq ‘Running’).Name } | Get-myFreeSpace
Gets the free disk space of the running virtual machines whose name includes 'server'

.Inputs
[string[]]

.Notes
 Original Author: Charlie Russel
Secondary Author: Robert Carlson
Copyright: 2017 by Charlie Russel
         : Permission to use is granted but attribution is appreciated
  Initial: 26 Nov, 2014 (cpr)
  ModHist: 29 Sep, 2016 — Changed default to array of localhost (cpr)
         : 18 Apr, 2017 — Changed to use Write-Output,accept Pipeline,added man page, (cpr)
         : 20 Apr, 2017 — Changed output to pscustomobject rather than string, etc.(RC)
#>

[CmdletBinding()]
Param(
[Parameter(Mandatory=$False,Position=0,`
           ValueFromPipeline=$True,`
           ValueFromPipelineByPropertyName=$True,`
           ValueFromRemainingArguments=$True)]
           [alias(“Name”,”Computer”)]
           [string[]]
           $ComputerName = @(“localhost”)
           )

Begin {
   if ($Input) {
      $ComputerName = @($Input) 
   }
}

Process {
   ForEach ( $Computer in $ComputerName ) {
      $volumes = Get-WmiObject -ComputerName $Computer -Class Win32_Volume -ErrorAction SilentlyContinue 
      foreach ($volume in $volumes) {
         $volumeData = [pscustomobject]@{
            ComputerName=$Computer 
            Drive=$volume.DriveLetter
            VolumeLabel=$volume.Label
            VolumeSize=”{0:N0}” -f ($volume.Capacity / 1GB)
            FreeSpace=”{0:N0}” -f ($volume.FreeSpace/1GB)
            }
         if ($volume.Capacity) {
            $percentage = “{0:P0}” -f ($volume.FreeSpace / $volume.Capacity)
            $volumeData | Add-Member -NotePropertyName “PercentageFree” -NotePropertyValue $percentage
         } else {
            $volumeData | Add-Member -NotePropertyName “PercentageFree” -NotePropertyValue “n/a”
         }
         Write-Output $volumeData
      }
   }
 }
}

I really appreciate Robert's contribution, and I thank him profoundly for his suggestion. I learned something, and I hope you have too.  I hope you found this useful, and I'd love to hear comments, suggestions for improvements, or bug reports as appropriate. As always, if you use this script as the basis for your own work, please respect my copyright and provide appropriate attribution.

Getting the Free Disk Space of Remote Computers Revisited

Several years ago, I wrote a fairly simplistic script to get the free disk space of remote computers. It wasn't all that sophisticated, but it got the job that I needed done, so I shared it here on my blog, since I thought others might find it useful. Which, based on the number of hits here, and the comments, they did. However, based on some of those comments, it had a problem for some users.

 

The problem was that I used Write-Host in it. That was fine for me, because I only used it to write to my screen. But it's a bad practice to be using Write-Host unless you really need to manipulate screen colours. The reason it's a bad practice is that it prevents any sort of redirection! This meant that those users who wanted to capture the result of the script in a file were horked, because Write-Host will ALWAYS write to ( ... wait for it...  )

 

The Host. You can't redirect it. The fix, of course, is easy -- use Write-Object instead, which is what I should have done in the first place.

 

While I was in the process of making that change, I thought it would be nice to add in a basic Get-Help page for it, which was trivial. But then it occurred to me that I really should let it handle pipeline input, allowing me to use other PowerShell commands to select the group of machines I wanted the free disk space on, and then pipe that result directly to Get-myFreeSpace.

 

Seemed like a good idea, but it turned out I had to almost completely rewrite the script to use the Begin{}/Process{}/End{} syntax. Accepting pipeline input is not as simple as just saying you do in the Parameter statement, you need to actually process that input. The result is the new, improved version of Get-myFreeSpace.ps1 shown below. (If you care about how I got to this script in the first place, do check out the original post, here. There's some useful information there about the whole process. )

 

<#
.Synopsis
Gets the disk utilization of one or more computers

.Description
Get-myFreeSpace queries an array of remote computers and returns a nicely formatted display of 
their current disk utilization and free space. The output can be redirected to a file or other 
output option using standard redirection. 

.Example
Get-myFreeSpace 
Gets the disk utilization and free space of all drives on the local host. 

.Example
Get-myFreeSpace -ComputerName Server1,Server2
Gets the disk utilization and free space of all drives on the Server1 and Server2

.Example
(Get-VM -Name "*server*" | Where State -eq 'Running' ).Name | Get-myFreeSpace
PS C:\>(Get-VM -Name "*server*" | Where-Object {$_.State -eq 'Running').Name | Get-myFreeSpace

Gets a list of running VMs with Server in their name, and passes it to Get-myFreeSpace to process for 
their current disk utilization. The first version of this example uses PowerShell v5 syntax, while 
the second version uses the older syntax that works on earlier versions. 
.Parameter ComputerName
An array of computer names from which you want the disk utilization

.Inputs
[string[]]

.Notes
    Author: Charlie Russel
 Copyright: 2017 by Charlie Russel
          : Permission to use is granted but attribution is appreciated
   Initial: 26 Nov, 2014 (cpr)
   ModHist: 29 Sep, 2016 -- Changed default to array of localhost (cpr)
          : 18 Apr, 2017 -- Changed to use Write-Output,accept Pipeline,added man page,  (cpr)
          :
#>
[CmdletBinding()]
Param(
     [Parameter(Mandatory=$False,Position=0,`
                ValueFromPipeline=$True,`
                ValueFromPipelineByPropertyName=$True,`
                ValueFromRemainingArguments=$True)]
     [alias("Name","Computer")]
     [string[]]
     $ComputerName = @("localhost")
     )

Begin {
   if ($Input) {
      $ComputerName = @($Input)
   } 
   Write-Output ""
   # Save ErrorActionPreference so we can reset it when we're done
   $eap = $ErrorActionPreference
}

Process {
   $ErrorActionPreference = 'SilentlyContinue'
   ForEach ( $Computer in $ComputerName ) {
      Write-Output "Disk Utilization for Computer $Computer is: " 
      Get-WmiObject  -ComputerName $Computer -Class Win32_Volume `
         | Format-Table  -auto `
            @{Label="Drive";`
               Expression={$_.DriveLetter};`
               Align="Right"},`
            @{Label="Free(GB)";`
               Expression={"{0:N0}" -f ($_.FreeSpace/1GB)};`
               Align="Right"},`
            @{Label="% Free";`
               Expression={"{0:P0}" -f ($_.FreeSpace / $_.Capacity)};`
               Align="Right"},`
            @{Label="Size(GB)";`
               Expression={"{0:N0}" -f ($_.Capacity / 1GB)};`
               Align="Right"},`
            @{Label="Volume Label";`
               Expression={$_.Label};`
               Width=25}
      } #EndForEach
} #EndProcessBlock

End {
   # Reset ErrorActionPreference to original value
   $ErrorActionPreference = $eap
}

And there you have it. A new and improved version of one of the most popular scripts I've ever posted here. You can use it to get the disk utilization on your current machine, or any list of remote computers to which you have the rights to run WMI against.

 

I hope you find this script useful, and I'd love to hear comments, suggestions for improvements, or bug reports as appropriate. As always, if you use this script as the basis for your own work, please respect my copyright and provide appropriate attribution.