How to Create a Windows Server Inventory Report for Free with PowerShell

Contents

Powershell logo

Many server administrators use PowerShell. Of course, one of the most used tasks is the ability to create scripts and functions to inventory your servers and understand what your environment has.

Even though there are many alternatives to achieve this, with different levels of complexity, we are going to create a fairly simple but effective Windows Server Inventory Report in this post.

Prerequisites

This post will be practical. If you intend to move on, first make sure you meet the following prerequisites:

  • Work on a Windows PC 10 joined to an Active Directory domain (AD)
  • Have the ActiveDirectory PowerShell module installed from the RSAT Toolkit.
  • Have permission to view AD computer accounts
  • Can run WMI queries / Remote CIMs on remote computers
  • I have PowerShell remoting available on remote computers

Recovering servers

Fundamental to the script we are building are the servers themselves. You can write them individually to a text file that is read, or in an array within the script itself, but with PowerShell we can do better. To make the script more dynamic and not require us to modify it every time a new server is added, we can use Active Directory (AD) to extract the list of computer objects in an organizational unit (WHERE) determined.

Next, we are using the ActiveDirectory module, available in the RSAT Toolkit, to consult the Servers OU and retrieve all computer objects there via Get-ADComputer.

Import-Module ActiveDirectory

$OU = 'OU=Servers,DC=domain,DC=local'

$Params = @{
    "SearchBase" = $OU
    "Filter"     = '*'
}

$Servers = Get-ADComputer @Params

In this point, we could have just filtered the name property to complete the $servers variable, but it is often very useful to have the entire object returned for later use.

Determination of the data to collect

Now that we have our servers, we need to figure out what exactly we should collect from each server. One reason it may be important to keep your AD object complete is to combine that data with the data directly from the server to get a larger picture of your environment..

In practice, How does something like this look? We are going to list some of the properties that it would be very useful to know.

Server settings

  • Server host name
  • Free disk space
  • Memory
  • Network connections

The values ​​of AD

  • Last password setting
  • Last login
  • DNS host name

Retrieving information from the server

How do we go about collecting this information on our list of returned servers?? Since we have a list of servers, we will have to iterate over it $Servers object and query. Starting with a simple Foreach-Object loop below, we can create a custom object to keep our values.

$Servers | Foreach-Object {
    [PSCustomObject]@{
        "ServerHostName"     = $_.Name
        "Description"        = $_.Description
        "FreeDiskSpace"      = $Null
        "TotalMemory"        = $Null
        "NetworkConnections" = $Null
        "PasswordLastSet"    = $_.pwdLastSet
        "LastLogon"          = $_.lastLogon
        "DNSHostName"        = $_.DNSHostName
        "CreationDate"       = $_.WhenCreated
    }
}

As you can see, when saving the entire Active Directory object when we first recovered computers, enables us to complete a wide range of information. Unfortunately, this is not all the information we need.

To get the information of each server, we will use an interface familiar to many server administrators, What is the Windows Administration Instrumentation interface? (WMI). You can see that the cmdlets used below are from the Common Information Model interface (CIM), of which WMI is Microsoft's implementation of this standard.

Get free disk space

Using the WMI class available from Win32_LogicalDisk, we can get all the available disks and their free space. When we run the command for the first time, Get-CimInstance -ClassName Win32_LogicalDisk, you may notice that it is not exactly readable in its default output.

The second problem here is that we have more than one unit returned. I'd like to know about each of those drives and how much free space is available in GB. Let's modify the code to do some transformations and improve it.

$Disks = Get-CimInstance -ClassName Win32_LogicalDisk

$DisksResult = $Disks | Foreach-Object {
    [PSCustomObject]@{
        "Drive"     = $_.DeviceID
        "FreeSpace" = [Math]::Round(($_.FreeSpace / 1GB),2)
    }
}

$DisksResult

After running the commands, our output is much cleaner and can now be used in our script.

But, What if we wanted to alert about a low disk space condition? It would be nice to expand this just a bit to determine a flag in each unit that meets that condition. Comparing the free space with the total available space, we can see if it is below the 10% O 10 GB. The reason for the -or The condition is that on very large discs, the 10% can still be very generous, so determining an absolute limit helps.

$Disks = Get-CimInstance -ClassName Win32_LogicalDisk

$DisksResult = $Disks | Foreach-Object {
  $FreeSpace  = [Math]::Round(($_.FreeSpace / 1GB),2)
  $TotalSpace = [Math]::Round(($_.Size / 1GB),2)

  If ( ($FreeSpace / $TotalSpace -LT 0.10) -Or $FreeSpace -LT 10 ) {
    $LowDiskSpace = $True
  } Else {
    $LowDiskSpace = $False
  }

    [PSCustomObject]@{
        "Drive"        = $_.DeviceID
    "FreeSpace"    = $FreeSpace
    "LowDiskSpace" = $LowDiskSpace
    }
}

$DisksResult

As you can see now, we have a large set of information to store on our servers.

How% 20to% 20Build% 20a% 20Windows% 20Server% 20Inventory% 20Report% 20for / Untitled% 202.png? Trim = 1,1 & bg-color = 000 & pad = 1,1

Get available memory

It is useful to know how much RAM is allocated to each server, especially in a virtual machine environment. If you find that some are over-provisioned, you can save valuable resources by adjusting the correct size of servers. Fortunately, this is much easier to recover.

Using the Win32_PhysicalMemory WMI class, we can add all the returned Capacity properties to get total memory.

(Get-CimInstance -ClassName Win32_PhysicalMemory | Measure-Object -Property Capacity -Sum).Sum / 1GB

Get all network connections

In conclusion, we want to recover all network connections together. This is useful to know if a certain server has multiple interfaces to worry about. Using a slightly different mechanism this time, we are using the Get-NetAdapter cmdlet, but since this one doesn't have a ComputerName , we will use PS Remoting to invoke it locally on the target server and return the results to our script.

$NetworkConnections = Invoke-Command -ComputerName $_.DnsHostName -ScriptBlock  Select-Object Name, Status, LinkSpeed

Our output will look similar to the one below and then we can save this in our script.

Please note that for Invoke-Command To make it work, it will be necessary to configure PS Remoting on the target servers.

Putting it all together

Now that we have all the pieces, let's put all this together. The final script is below and combines all the code to create a custom output object with what we want to report.

Import-Module ActiveDirectory

$OU = 'OU=Servers,DC=domain,DC=local'

$Params = @{
    "SearchBase" = $OU
    "Filter"     = '*'
}

$Servers = Get-ADComputer @Params

$Servers | Foreach-Object {
  $Disks = Get-CimInstance -ComputerName $_.DnsHostName -ClassName Win32_LogicalDisk

  $DisksResult = $Disks | Foreach-Object {
    [PSCustomObject]@{
      "Drive"     = $_.DeviceID
      "FreeSpace" = [Math]::Round(($_.FreeSpace / 1GB),2)
    }
  }
  
  $NetworkConnections = Invoke-Command -ComputerName $_.DnsHostName -ScriptBlock  Select-Object Name, Status, LinkSpeed
  

    [PSCustomObject]@ Measure-Object -Property Capacity -Sum).Sum / 1GB)
        "NetworkConnections" = $NetworkConnections
        "PasswordLastSet"    = $_.pwdLastSet
        "LastLogon"          = $_.lastLogon
        "DNSHostName"        = $_.DNSHostName
        "CreationDate"       = $_.WhenCreated
    
}

conclusion

What we have shown here is just the tip of the iceberg in terms of what can be built for an inventory report.. There are many more useful properties that you can add to this report. Taking this further, you can build it into an HTML page, schedule a task to run weekly or even incorporate it into other tools like Ansible.

PowerShell makes it trivially easy to get all the information you need to gather in one place. Once you analyze your environment and determine what you need to know, create the report in PowerShell to help you prepare your ability to audit your environment in the future.

Subscribe to our Newsletter

We will not send you SPAM mail. We hate it as much as you.