Typically, you’ll pipe a whole object to Format-List and tell it which properties to display, rather than trying to construct each line yourself. Something like this, for the Win32_ComputerSystem parts. (The properties array doesn’t have to be defined before passing it to Format-List; I just do that for readability in the pipeline.)
Thanks Dave, that looks more like what I want to achieve. I’ll work on the rest of my script and see how things turn out.
I know when I’m working with PowerShell that more often than not there’s a better way than how I’m doing it. Sadly I don’t have the skills (yet!) to achieve exactly what I want. The good thing is, because I know what I want I will persevere until I get there.
Sorry, my point was not a code-complete example, but to show how to get to the data easier. You really should, as much as possible, collect all the data and then concentrate on outputting.
I’ve been through my script and made some adjustments as suggested by Dave. I’m now getting the output to my text file in the format I require. The problem is the about amount of blank lines between each output. For example one part of my script gives CPU details, followed by quite a few blank lines, then the next output. Is there a way to reduce these blank lines?
My second problem is that I planned on running this script on multiple remote servers using ‘invoke-command’. I thought I could run the script-block, creating a text file on the remote server and then copy the file over to my laptop using ‘copy-item’. When testing this the text file creation is fine but the copy fails with ‘access denied’ due to permission problems. If I run the script on the ‘remote’ server (not from my laptop) the file is created and the copy completes successfully. I only chose this method because I was having trouble getting information out of my script-block and into a text file on my laptop. This something I’ve had trouble with for some time.
Yeah, Format-List does put a lot of padding around its output for some reason. You can fiddle with that by piping to Out-String first, manipulating the string and then sending it on to Out-File or Add-Content. Here’s a very basic example that just uses the String.Trim() method:
Using this method worked perfectly and I’m able to produce the txt file I want. However I’m unable to copy the file from the server to my desktop/share (using copy-item) due to ‘access denied’. If I run the script on the server it produces the txt file and copies it over fine. I’m a but confused as to why?
Perhaps this is a question for another thread but is it possible to output the data from a scriptblock? Not from within the scriptblock itself but similar to piping it out.
You haven’t come right out and said this, but I gather that you’re executing this code on a remote server via Invoke-Command; is that right? If so, you’re running into the “second hop” scenario when you try to copy the file from your remote computer up to a network share via Invoke-Command. There are ways of getting around this. You could use CredSSP as mentioned in the Secrets of PowerShell Remoting ebook (https://powershell.org/ebooks/), but in this case, I’d probably send the results back to the calling computer and then put it into a text file from there. For example, here’s one way you could use the existing code to build a string for each server, send the string back to the caller, and let the file creation happen locally on your computer (which conveniently avoids the second-hop scenario as well):
$scriptBlock = {
$stringBuilder = New-Object System.Text.StringBuilder
$props = @(
@{Label = 'Server Name'; Expression = { $_.Name } }
'Domain'
@{Label = 'Total Memory'; Expression = { '{0}GB' -f ([Math]::Round($_.TotalPhysicalMemory / 1GB)) } }
)
$string = Get-WmiObject Win32_ComputerSystem |
Format-List -Property $props |
Out-String
$null = $stringBuilder.Append($string.Trim())
# Add other information to the StringBuilder with other WMI classes.
# Send the complete string back to the caller
$stringBuilder.ToString()
}
Invoke-Command -ComputerName $computerList -ScriptBlock $scriptBlock |
ForEach-Object {
$computerName = $_.PSComputerName
$date = Get-Date -Format 'MM-dd-yyyy'
$_ | Out-File -FilePath "$computerName-Server_Spec-$date.txt"
}
Notice that Invoke-Command automatically adds a PSComputerName property to the objects that are returned by the remote script blocks. Making the remote script blocks only return a single object is my own personal preference; it keeps network chatter to a minimum (and in this case, disk activity as well.)
you’re correct about what I’m trying to achieve. Believe it or not I was originally trying to pull the data over to my laptop but having problems getting it across (due to lack of skills). I’ll work on what you’ve provide above and see how I get on.