In my line of work we often evaluate new ways to do things, specifically new platforms for server hosting, disaster recovery, backups, etc.

One of the requests that often comes from vendors is “How big is your environment?”

Microsoft has the rather excellent “MAP” tool however I find it to be a bit slow, somewhat complex, and often returns a lot more information than I want… and not always everything I need.

To that end, I wrote the following powershell function and it has been a major help in automating these inventory requests:

FUNCTION GetSystemInventory ($ServerNamesStartWith) {
    FUNCTION GetSystemNames ($convention) {
        $convention = "$convention" + "*"
        Get-ADComputer -Filter {(Name -like $convention)}| select -ExpandProperty Name
    FUNCTION GetSize($Servername) {
        Invoke-Command -ScriptBlock {
        $size = get-volume | Foreach { $_.Size }
        $sumA = 0
        $size | Foreach { $sumA += $_}
        $size = [math]::Round($sumA/1GB,0)
        $remaining = get-volume | ForEach {$_.SizeRemaining }
        $sumB = 0
        $remaining | Foreach { $sumB += $_}
        $remaining = [math]::Round($sumB/1GB,0)
        $usedspace = $size - $remaining
        $usedspace = [math]::Round($usedspace,0)

        $ram = gwmi Win32_OperatingSystem | Measure-Object -Property TotalVisibleMemorySize -Sum | % {[Math]::Round($_.sum/1024/1024)}
        $CPUcores = Get-WmiObject Win32_Processor |Select-Object -ExpandProperty NumberOfCores
        $CPUthreads = Get-WmiObject Win32_Processor |Select-Object -ExpandProperty NumberOfLogicalProcessors
        $CPUname = Get-WmiObject Win32_Processor |Select-Object -ExpandProperty Name
        $SystemType = get-wmiobject win32_computersystem | Select-Object -ExpandProperty model
        $OSname = Get-WmiObject win32_operatingsystem | Select-Object -ExpandProperty caption
        $out = "$size" + "`t" + "$usedspace" + "`t" + "$ram" + "`t" + "$CPUname" + "`t" + "$CPUcores" + "`t" + "$CPUthreads" + "`t" + "$SystemType" + "`t" + "$OSname"
        } -ComputerName $servername -ErrorAction SilentlyContinue
    $output = @(GetSystemNames $ServerNamesStartWith)
    #Can uncomment and modify below (change XYZ,ABC) to specify additional system naming conventions for the same run.
    #$output += @(GetSystemNames XYZ)
    #$output += @(GetSystemNames ABC)
    $head = "SERVER" + "`t" + "STORAGE ALLOCATED" + "`t" + "STORAGE USED" + "`t" + "RAM" + "`t" + "CPU" + "`t" + "CORES" + "`t" + "THREADS" + "`t" + "SYSTEM" + "`t" + "OS"
    ForEach($name in $output) {
        $size = GetSize $name
        $info = "$name" + "`t" + "$size"

After declaring the above function, I then run it and pipe the output like this:

GetSystemInventory SVR | Out-File C:\output\test.csv

Which then outputs a CSV file that looks something like this:
(NOTE: I have stripped/faked/anonymized data so I could post this publicly)

What the Script is Doing

  • Takes a single parameter which is the “server name ‘starts with'”. In my example above, I used “SVR.”
  • Runs a sub-function that scans active directory and finds computer objects that start with the pattern specified in the parameter (ex. SVR). It outputs these to an array.
  • It then loops through that array of names and runs another sub-function which pulls all of the information items and outputs them in tab-delimited format. It also creates a “header row” to make things pretty and easy to understand.

  • Explanation of What Data is Pulled
    Now the real beauty is in what gets pulled… Most of this is self-explanatory from the screenshot but I did want to explain a few items regardless..

  • Storage Allocated – It scans how big all of the partitions on the server are and reports the total size of all partitions added together.
  • Storage Used – It grabs free space from all partitions, adds them together and then subtracts the freespace from the allocated storage to get the real-world “storage used” value. Which for me historically was always one of the biggest pains to pull.
  • RAM – I had to try about 10 different things to find what actually pulls a ram value I can use… A lot of tools pull odd crap like page file size and whatnot. This gets “assigned” memory on the system.
  • CPU – We use a mix of hypervisors in our environment. For the KVM based system, I get a virtualized proc name which may not be helpful if that is your entire environment. For out platforms it pulls the actual processor model and speed.
  • CORES and THREADS – Obvious enough, you will note for servers that have multiple sockets the presentation of this data is a bit odd but it is still readable/understandable.
  • SYSTEM – I.E. reported “chassis” – This is great because it quickly delineates between “virtual machines” and physical systems – for the latter it often also tells you what model chassis the box is.

  • Conclusion
    For me, I pump this into excel and can quickly split out the physical and virtual systems, from there I can add up the “Storage Used” column and quite effortlessly know how big the data footprint is for my entire environment. That’s a key metric for lots of things… particularly platform hosting decisions, backups, disaster recovery, etc. I can also sort by processor type and pull down how many assigned vCORES I have of a given processor model… etc. etc. I find the barrier to entry and use SO much lower with this method vs. using the more expansive MAP tool and it has saved me a LOT of time. I hope it does the same for you!


  • You need to run this script in a Powershell session that is running under a decently privileged account and from a system in your environment that has remote access to each system you want to pull data from.
  • Any server that makes it onto the initial list that can then NOT be contacted will show up in the resultant CSV file but will display BLANKS. I have found this to also be useful for working on the network and cleaning up AD.
  • This still takes a while to run, and the more dead servers on the list, the longer it takes.
  • 1 of 1

    This post has no comments. Be the first to leave one!

    Join the discussion

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