├── Collect-ServerInfo.ps1 ├── LICENSE └── README.md /Collect-ServerInfo.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Collect-ServerInfo.ps1 - PowerShell script to collect information about Windows servers 4 | 5 | .DESCRIPTION 6 | This PowerShell script runs a series of WMI and other queries to collect information 7 | about Windows servers. 8 | 9 | .OUTPUTS 10 | Each server's results are output to HTML. 11 | 12 | .PARAMETER -Verbose 13 | See more detailed progress as the script is running. 14 | 15 | .EXAMPLE 16 | .\Collect-ServerInfo.ps1 SERVER1 17 | Collect information about a single server. 18 | 19 | .EXAMPLE 20 | "SERVER1","SERVER2","SERVER3" | .\Collect-ServerInfo.ps1 21 | Collect information about multiple servers. 22 | 23 | .EXAMPLE 24 | Get-ADComputer -Filter {OperatingSystem -Like "Windows Server*"} | %{.\Collect-ServerInfo.ps1 $_.DNSHostName} 25 | Collects information about all servers in Active Directory. 26 | 27 | 28 | .NOTES 29 | Written by: Paul Cunningham 30 | 31 | Find me on: 32 | 33 | * My Blog: https://paulcunningham.me 34 | * Twitter: https://twitter.com/paulcunningham 35 | * LinkedIn: https://au.linkedin.com/in/cunninghamp/ 36 | * Github: https://github.com/cunninghamp 37 | 38 | License: 39 | 40 | The MIT License (MIT) 41 | 42 | Copyright (c) 2016 Paul Cunningham 43 | 44 | Permission is hereby granted, free of charge, to any person obtaining a copy 45 | of this software and associated documentation files (the "Software"), to deal 46 | in the Software without restriction, including without limitation the rights 47 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 48 | copies of the Software, and to permit persons to whom the Software is 49 | furnished to do so, subject to the following conditions: 50 | 51 | The above copyright notice and this permission notice shall be included in all 52 | copies or substantial portions of the Software. 53 | 54 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 55 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 56 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 57 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 58 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 59 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 60 | SOFTWARE. 61 | 62 | Change Log: 63 | V1.00, 20/04/2015 - First release 64 | V1.01, 01/05/2015 - Updated with better error handling 65 | #> 66 | 67 | 68 | [CmdletBinding()] 69 | 70 | Param ( 71 | 72 | [parameter(ValueFromPipeline=$True)] 73 | [string[]]$ComputerName 74 | 75 | ) 76 | 77 | Begin 78 | { 79 | #Initialize 80 | Write-Verbose "Initializing" 81 | 82 | } 83 | 84 | Process 85 | { 86 | 87 | #--------------------------------------------------------------------- 88 | # Process each ComputerName 89 | #--------------------------------------------------------------------- 90 | 91 | if (!($PSCmdlet.MyInvocation.BoundParameters[“Verbose”].IsPresent)) 92 | { 93 | Write-Host "Processing $ComputerName" 94 | } 95 | 96 | Write-Verbose "=====> Processing $ComputerName <=====" 97 | 98 | $htmlreport = @() 99 | $htmlbody = @() 100 | $htmlfile = "$($ComputerName).html" 101 | $spacer = "
" 102 | 103 | #--------------------------------------------------------------------- 104 | # Do 10 pings and calculate the fastest response time 105 | # Not using the response time in the report yet so it might be 106 | # removed later. 107 | #--------------------------------------------------------------------- 108 | 109 | try 110 | { 111 | $bestping = (Test-Connection -ComputerName $ComputerName -Count 10 -ErrorAction STOP | Sort ResponseTime)[0].ResponseTime 112 | } 113 | catch 114 | { 115 | Write-Warning $_.Exception.Message 116 | $bestping = "Unable to connect" 117 | } 118 | 119 | if ($bestping -eq "Unable to connect") 120 | { 121 | if (!($PSCmdlet.MyInvocation.BoundParameters[“Verbose”].IsPresent)) 122 | { 123 | Write-Host "Unable to connect to $ComputerName" 124 | } 125 | 126 | "Unable to connect to $ComputerName" 127 | } 128 | else 129 | { 130 | 131 | #--------------------------------------------------------------------- 132 | # Collect computer system information and convert to HTML fragment 133 | #--------------------------------------------------------------------- 134 | 135 | Write-Verbose "Collecting computer system information" 136 | 137 | $subhead = "

Computer System Information

" 138 | $htmlbody += $subhead 139 | 140 | try 141 | { 142 | $csinfo = Get-WmiObject Win32_ComputerSystem -ComputerName $ComputerName -ErrorAction STOP | 143 | Select-Object Name,Manufacturer,Model, 144 | @{Name='Physical Processors';Expression={$_.NumberOfProcessors}}, 145 | @{Name='Logical Processors';Expression={$_.NumberOfLogicalProcessors}}, 146 | @{Name='Total Physical Memory (Gb)';Expression={ 147 | $tpm = $_.TotalPhysicalMemory/1GB; 148 | "{0:F0}" -f $tpm 149 | }}, 150 | DnsHostName,Domain 151 | 152 | $htmlbody += $csinfo | ConvertTo-Html -Fragment 153 | $htmlbody += $spacer 154 | 155 | } 156 | catch 157 | { 158 | Write-Warning $_.Exception.Message 159 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 160 | $htmlbody += $spacer 161 | } 162 | 163 | 164 | 165 | #--------------------------------------------------------------------- 166 | # Collect operating system information and convert to HTML fragment 167 | #--------------------------------------------------------------------- 168 | 169 | Write-Verbose "Collecting operating system information" 170 | 171 | $subhead = "

Operating System Information

" 172 | $htmlbody += $subhead 173 | 174 | try 175 | { 176 | $osinfo = Get-WmiObject Win32_OperatingSystem -ComputerName $ComputerName -ErrorAction STOP | 177 | Select-Object @{Name='Operating System';Expression={$_.Caption}}, 178 | @{Name='Architecture';Expression={$_.OSArchitecture}}, 179 | Version,Organization, 180 | @{Name='Install Date';Expression={ 181 | $installdate = [datetime]::ParseExact($_.InstallDate.SubString(0,8),"yyyyMMdd",$null); 182 | $installdate.ToShortDateString() 183 | }}, 184 | WindowsDirectory 185 | 186 | $htmlbody += $osinfo | ConvertTo-Html -Fragment 187 | $htmlbody += $spacer 188 | } 189 | catch 190 | { 191 | Write-Warning $_.Exception.Message 192 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 193 | $htmlbody += $spacer 194 | } 195 | 196 | 197 | #--------------------------------------------------------------------- 198 | # Collect physical memory information and convert to HTML fragment 199 | #--------------------------------------------------------------------- 200 | 201 | Write-Verbose "Collecting physical memory information" 202 | 203 | $subhead = "

Physical Memory Information

" 204 | $htmlbody += $subhead 205 | 206 | try 207 | { 208 | $memorybanks = @() 209 | $physicalmemoryinfo = @(Get-WmiObject Win32_PhysicalMemory -ComputerName $ComputerName -ErrorAction STOP | 210 | Select-Object DeviceLocator,Manufacturer,Speed,Capacity) 211 | 212 | foreach ($bank in $physicalmemoryinfo) 213 | { 214 | $memObject = New-Object PSObject 215 | $memObject | Add-Member NoteProperty -Name "Device Locator" -Value $bank.DeviceLocator 216 | $memObject | Add-Member NoteProperty -Name "Manufacturer" -Value $bank.Manufacturer 217 | $memObject | Add-Member NoteProperty -Name "Speed" -Value $bank.Speed 218 | $memObject | Add-Member NoteProperty -Name "Capacity (GB)" -Value ("{0:F0}" -f $bank.Capacity/1GB) 219 | 220 | $memorybanks += $memObject 221 | } 222 | 223 | $htmlbody += $memorybanks | ConvertTo-Html -Fragment 224 | $htmlbody += $spacer 225 | } 226 | catch 227 | { 228 | Write-Warning $_.Exception.Message 229 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 230 | $htmlbody += $spacer 231 | } 232 | 233 | 234 | #--------------------------------------------------------------------- 235 | # Collect pagefile information and convert to HTML fragment 236 | #--------------------------------------------------------------------- 237 | 238 | $subhead = "

PageFile Information

" 239 | $htmlbody += $subhead 240 | 241 | Write-Verbose "Collecting pagefile information" 242 | 243 | try 244 | { 245 | $pagefileinfo = Get-WmiObject Win32_PageFileUsage -ComputerName $ComputerName -ErrorAction STOP | 246 | Select-Object @{Name='Pagefile Name';Expression={$_.Name}}, 247 | @{Name='Allocated Size (Mb)';Expression={$_.AllocatedBaseSize}} 248 | 249 | $htmlbody += $pagefileinfo | ConvertTo-Html -Fragment 250 | $htmlbody += $spacer 251 | } 252 | catch 253 | { 254 | Write-Warning $_.Exception.Message 255 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 256 | $htmlbody += $spacer 257 | } 258 | 259 | 260 | #--------------------------------------------------------------------- 261 | # Collect BIOS information and convert to HTML fragment 262 | #--------------------------------------------------------------------- 263 | 264 | $subhead = "

BIOS Information

" 265 | $htmlbody += $subhead 266 | 267 | Write-Verbose "Collecting BIOS information" 268 | 269 | try 270 | { 271 | $biosinfo = Get-WmiObject Win32_Bios -ComputerName $ComputerName -ErrorAction STOP | 272 | Select-Object Status,Version,Manufacturer, 273 | @{Name='Release Date';Expression={ 274 | $releasedate = [datetime]::ParseExact($_.ReleaseDate.SubString(0,8),"yyyyMMdd",$null); 275 | $releasedate.ToShortDateString() 276 | }}, 277 | @{Name='Serial Number';Expression={$_.SerialNumber}} 278 | 279 | $htmlbody += $biosinfo | ConvertTo-Html -Fragment 280 | $htmlbody += $spacer 281 | } 282 | catch 283 | { 284 | Write-Warning $_.Exception.Message 285 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 286 | $htmlbody += $spacer 287 | } 288 | 289 | 290 | #--------------------------------------------------------------------- 291 | # Collect logical disk information and convert to HTML fragment 292 | #--------------------------------------------------------------------- 293 | 294 | $subhead = "

Logical Disk Information

" 295 | $htmlbody += $subhead 296 | 297 | Write-Verbose "Collecting logical disk information" 298 | 299 | try 300 | { 301 | $diskinfo = Get-WmiObject Win32_LogicalDisk -ComputerName $ComputerName -ErrorAction STOP | 302 | Select-Object DeviceID,FileSystem,VolumeName, 303 | @{Expression={$_.Size /1Gb -as [int]};Label="Total Size (GB)"}, 304 | @{Expression={$_.Freespace / 1Gb -as [int]};Label="Free Space (GB)"} 305 | 306 | $htmlbody += $diskinfo | ConvertTo-Html -Fragment 307 | $htmlbody += $spacer 308 | } 309 | catch 310 | { 311 | Write-Warning $_.Exception.Message 312 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 313 | $htmlbody += $spacer 314 | } 315 | 316 | 317 | #--------------------------------------------------------------------- 318 | # Collect volume information and convert to HTML fragment 319 | #--------------------------------------------------------------------- 320 | 321 | $subhead = "

Volume Information

" 322 | $htmlbody += $subhead 323 | 324 | Write-Verbose "Collecting volume information" 325 | 326 | try 327 | { 328 | $volinfo = Get-WmiObject Win32_Volume -ComputerName $ComputerName -ErrorAction STOP | 329 | Select-Object Label,Name,DeviceID,SystemVolume, 330 | @{Expression={$_.Capacity /1Gb -as [int]};Label="Total Size (GB)"}, 331 | @{Expression={$_.Freespace / 1Gb -as [int]};Label="Free Space (GB)"} 332 | 333 | $htmlbody += $volinfo | ConvertTo-Html -Fragment 334 | $htmlbody += $spacer 335 | } 336 | catch 337 | { 338 | Write-Warning $_.Exception.Message 339 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 340 | $htmlbody += $spacer 341 | } 342 | 343 | 344 | #--------------------------------------------------------------------- 345 | # Collect network interface information and convert to HTML fragment 346 | #--------------------------------------------------------------------- 347 | 348 | $subhead = "

Network Interface Information

" 349 | $htmlbody += $subhead 350 | 351 | Write-Verbose "Collecting network interface information" 352 | 353 | try 354 | { 355 | $nics = @() 356 | $nicinfo = @(Get-WmiObject Win32_NetworkAdapter -ComputerName $ComputerName -ErrorAction STOP | Where {$_.PhysicalAdapter} | 357 | Select-Object Name,AdapterType,MACAddress, 358 | @{Name='ConnectionName';Expression={$_.NetConnectionID}}, 359 | @{Name='Enabled';Expression={$_.NetEnabled}}, 360 | @{Name='Speed';Expression={$_.Speed/1000000}}) 361 | 362 | $nwinfo = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -ErrorAction STOP | 363 | Select-Object Description, DHCPServer, 364 | @{Name='IpAddress';Expression={$_.IpAddress -join '; '}}, 365 | @{Name='IpSubnet';Expression={$_.IpSubnet -join '; '}}, 366 | @{Name='DefaultIPgateway';Expression={$_.DefaultIPgateway -join '; '}}, 367 | @{Name='DNSServerSearchOrder';Expression={$_.DNSServerSearchOrder -join '; '}} 368 | 369 | foreach ($nic in $nicinfo) 370 | { 371 | $nicObject = New-Object PSObject 372 | $nicObject | Add-Member NoteProperty -Name "Connection Name" -Value $nic.connectionname 373 | $nicObject | Add-Member NoteProperty -Name "Adapter Name" -Value $nic.Name 374 | $nicObject | Add-Member NoteProperty -Name "Type" -Value $nic.AdapterType 375 | $nicObject | Add-Member NoteProperty -Name "MAC" -Value $nic.MACAddress 376 | $nicObject | Add-Member NoteProperty -Name "Enabled" -Value $nic.Enabled 377 | $nicObject | Add-Member NoteProperty -Name "Speed (Mbps)" -Value $nic.Speed 378 | 379 | $ipaddress = ($nwinfo | Where {$_.Description -eq $nic.Name}).IpAddress 380 | $nicObject | Add-Member NoteProperty -Name "IPAddress" -Value $ipaddress 381 | 382 | $nics += $nicObject 383 | } 384 | 385 | $htmlbody += $nics | ConvertTo-Html -Fragment 386 | $htmlbody += $spacer 387 | } 388 | catch 389 | { 390 | Write-Warning $_.Exception.Message 391 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 392 | $htmlbody += $spacer 393 | } 394 | 395 | 396 | #--------------------------------------------------------------------- 397 | # Collect software information and convert to HTML fragment 398 | #--------------------------------------------------------------------- 399 | 400 | $subhead = "

Software Information

" 401 | $htmlbody += $subhead 402 | 403 | Write-Verbose "Collecting software information" 404 | 405 | try 406 | { 407 | $software = Get-WmiObject Win32_Product -ComputerName $ComputerName -ErrorAction STOP | Select-Object Vendor,Name,Version | Sort-Object Vendor,Name 408 | 409 | $htmlbody += $software | ConvertTo-Html -Fragment 410 | $htmlbody += $spacer 411 | 412 | } 413 | catch 414 | { 415 | Write-Warning $_.Exception.Message 416 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 417 | $htmlbody += $spacer 418 | } 419 | 420 | #--------------------------------------------------------------------- 421 | # Collect services information and covert to HTML fragment 422 | # Added by Nicolas Nowinski (nicknow@nicknow.net): Mar 28 2019 423 | #--------------------------------------------------------------------- 424 | 425 | $subhead = "

Computer Services Information

" 426 | $htmlbody += $subhead 427 | 428 | Write-Verbose "Collecting services information" 429 | 430 | try 431 | { 432 | $services = Get-WmiObject Win32_Service -ComputerName $ComputerName -ErrorAction STOP | Select-Object Name,StartName,State,StartMode | Sort-Object Name 433 | 434 | $htmlbody += $services | ConvertTo-Html -Fragment 435 | $htmlbody += $spacer 436 | 437 | } 438 | catch 439 | { 440 | Write-Warning $_.Exception.Message 441 | $htmlbody += "

An error was encountered. $($_.Exception.Message)

" 442 | $htmlbody += $spacer 443 | } 444 | 445 | #--------------------------------------------------------------------- 446 | # Generate the HTML report and output to file 447 | #--------------------------------------------------------------------- 448 | 449 | Write-Verbose "Producing HTML report" 450 | 451 | $reportime = Get-Date 452 | 453 | #Common HTML head and styles 454 | $htmlhead=" 455 | 468 | 469 |

Server Info: $ComputerName

470 |

Generated: $reportime

" 471 | 472 | $htmltail = " 473 | " 474 | 475 | $htmlreport = $htmlhead + $htmlbody + $htmltail 476 | 477 | $htmlreport | Out-File $htmlfile -Encoding Utf8 478 | } 479 | 480 | } 481 | 482 | End 483 | { 484 | #Wrap it up 485 | Write-Verbose "=====> Finished <=====" 486 | } 487 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Paul Cunningham 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Collect-ServerInfo 2 | This PowerShell script runs a series of WMI and other queries to collect information about Windows servers. 3 | 4 | Each server's results are output to a HTML file. 5 | 6 | ## Parameters 7 | - **-Verbose**, See more detailed progress as the script is running. 8 | 9 | ## Examples 10 | 11 | Collect information about a single server named SERVER1. 12 | ``` 13 | .\Collect-ServerInfo.ps1 SERVER1 14 | ``` 15 | 16 | Collect information about multiple servers. 17 | ``` 18 | "SERVER1","SERVER2","SERVER3" | .\Collect-ServerInfo.ps1 19 | ``` 20 | 21 | Collect information about all servers in Active Directory. 22 | ``` 23 | Get-ADComputer -Filter {OperatingSystem -Like "Windows Server*"} | %{.\Collect-ServerInfo.ps1 $_.DNSHostName} 24 | ``` 25 | 26 | ## Download 27 | 28 | Download the latest release from [Github](https://github.com/cunninghamp/Collect-ServerInfo/releases/latest) or from the [TechNet Script Gallery](https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Collect-Server-089f1da3). 29 | 30 | ## Credits 31 | Written by: Paul Cunningham 32 | 33 | Find me on: 34 | 35 | * My Blog: https://paulcunningham.me 36 | * Twitter: https://twitter.com/paulcunningham 37 | * LinkedIn: https://au.linkedin.com/in/cunninghamp/ 38 | * Github: https://github.com/cunninghamp 39 | 40 | Additional contributions by: 41 | * [Nicolas Nowinski](https://github.com/nicknow) 42 | --------------------------------------------------------------------------------