One of the most common scripts I see PowerShell newcomers tackle is the "server inventory" script. This will often involve several sections of output, and the scripts often turn out looking something like this:
param ( [string]$computername = $(Read-Host "Enter computer name") ) Write-Host "----------- COMPUTER SYSTEM ------------" $cs = Get-WmiObject -Class Win32_ComputerSystem -computername $computername $bios = Get-WmiObject -class Win32_BIOS Write-Host "Computer: $($cs.Name)" Write-Host "Manufacturer: $($cs.Manufacturer)" Write-Host "Model: $($cs.Model)" Write-Host "BIOS Serial: $($bios.SerialNumber)" Write-Host "" Write-Host "----------- OPERATING SYSTEM -------------" Get-WmiObject -Class Win32_OperatingSystem -computername $computername | Select-Object -Property Version,BuildNumber,ServicePackMajorVersion,OSArchitecture | Format-List Write-Host "" Write-Host "----------- PROCESSORS -------------" Get-WmiObject -class Win32_Processor -computername $computername | Select-Object -Property AddressWidth,MaxClockSpeed -First 1 | Format-List Write-Host "" Write-Host "----------- DISKS -------------" Get-WmiObject -class Win32_LogicalDisk -filter "drivetype=3" -computername $computername | Select-Object -Property DeviceID,Size,FreeSpace | Format-List
This just makes me die a little inside, unfortunately. The first clue that something's wrong is the profligate use of Write-Host. I know what folks are trying to accomplish, but they're just going about it the wrong way.
- The use of Read-Host to prompt for a computer name.
- That crazy $($cs.name) syntax, which is being used to insert property values into a string
- Write-Host. This is rarely the correct answer.
- Write-Host. Seriously, this is bad enough to warrant being called out twice!
- Putting multiple objects types into the pipeline. Not exactly bad, but cumbersome to work with.
To really see what's wrong with this approach, try copying it and pasting it into the PowerShell ISE on your computer. Save it as c:\test.ps1 or something. Then run it like this:
./test | Out-File results.txt
The text file will be awful, and not look at all like what was on the screen. A seemingly-easy fix would be to replace all the Write-Host calls with Write-Output instead. That'll get a more consistent-looking file. Sort of. But it'll still be awful.
I'm going to present two fixes for this situation, and present them in a way that you can use as a template to build on, if you want to.