Powershell - Change format of output - powershell

How can I change the presenation of the output my code produces:
$apps = Import-CSV apps.csv
$computers = Import-CSV compobj.csv
foreach($computer in $computers) {
$computerLob = $computer.lob
$lobApps = $apps | ? {$_.lob -eq $computerLob }
foreach($app in $lobApps){
$computerHostname = $computer.hostname
$appLocation = $app.location
$installed=Test-Path "\\$computerHostname\$appLocation"
New-Object PSObject #{Computer=$computer.hostname;App=$app.appname;Installed=$installed}
}
}
I would like for the presentation of the code to be changed. This is how it looks like:
Name Value
---- -----
Installed True
App App1
Computer 171.159.192.10
Installed True
App App2
Computer 171.159.192.10
I'd like for it to look like this:
Computer App1 App2
----------- ------ -----
171.159.192.10 True True

You're passing the hashtable to New-Object as its ctor argument instead of a property set. Change it to:
New-Object PSObject -Property #{
Computer=$computer.hostname
App=$app.appname
Installed=$installed
}

If you are on PowerShell V3, rather than use new-object you can do this:
[pscustomobject]#{Computer=$computer.hostname;App=$app.appname;Installed=$installed}
On V2, don't forget to use the -Property parameter e.g.:
new-object psobject -property #{Computer=$computer.hostname;App=$app.appname;Installed=$installed}
And to force the output order you can use Format-Table:
$obj = new-object psobject -property #{Computer=$computer.hostname;App=$app.appname;Installed=$installed}
$obj | Format-Table Computer,App,Installed

Here is what I mean (a follow-up to OP's question asked in comments, too big to fit there):
function MyFunction(){
$apps = Import-CSV apps.csv
$computers = Import-CSV compobj.csv
foreach($computer in $computers) {
$computerLob = $computer.lob
$lobApps = $apps | ? {$_.lob -eq $computerLob }
foreach($app in $lobApps){
$computerHostname = $computer.hostname
$appLocation = $app.location
$installed=Test-Path "\\$computerHostname\$appLocation"
New-Object PSObject #{Computer=$computer.hostname;App=$app.appname;Installed=$installed}
}
}
}
MyFunction | select Computer,App,Installed
A reduced test case to prove the above should work:
function MyFunction(){
New-Object PSObject -Property #{
Computer="computer"
App="app"
Installed="installed"
}
}
MyFunction | select Computer,App,Installed

Related

Export a custom object to a CSV file only gives me one computer

If I run this it works fine:
$Computers = get-content C:\POSH\test.txt
foreach ($comp in $Computers) {
$CS = Get-WmiObject -Class Win32_computersystem -ComputerName $comp
$Encl = Get-WmiObject -Class Win32_Systemenclosure -ComputerName $comp
$props = #{CompName=$cs.name
Manufacturer=$cs.manufacturer
Model=$cs.model
Serial=$encl.serialnumber}
$obj = New-Object -TypeName PSObject -property $props
Write-Output $obj
}
But if I change write-output $obj to $obj | export-csv c:\posh\test.csv
I only get one computer in the CSV file.
At a quick glance:
It seems you keep overwriting the object you make, by making a new object in each iteration.
You see all $computers on the screen because you use write-output before you repeat the task and overwrite the object. This becomes an issue once you want to combine them.
Otherwise more information might be helpful.
Hello. You can try this:
$obj | export-csv c:\posh\test.csv -Append
Or you can do try:
$Computers = get-content C:\POSH\test.txt
$Computers | % {
$CS = Get-WmiObject -Class Win32_computersystem -ComputerName $_
$Encl = Get-WmiObject -Class Win32_Systemenclosure -ComputerName $_
$obj = New-Object -TypeName psobject -Property #{
CompName=$cs.name
Manufacturer=$cs.manufacturer
Model=$cs.model
Serial=$encl.serialnumber
}
$obj1 = $obj | select -ExpandProperty CompName
$obj2 = $obj | select -ExpandProperty Manufacturer
$obj3 = $obj | select -ExpandProperty Model
$obj4 = $obj | select -ExpandProperty Serial
$out = $obj1 + ";" + $obj2 + ";" + $obj3 + ";" + $obj4
$out >> c:\posh\test.csv
}
$Computers = get-content C:\POSH\test.txt
$obj = foreach ($comp in $Computers) {
$CS = Get-WmiObject -Class Win32_computersystem -ComputerName $comp
$Encl = Get-WmiObject -Class Win32_Systemenclosure -ComputerName $comp
$props = #{CompName=$cs.name
Manufacturer=$cs.manufacturer
Model=$cs.model
Serial=$encl.serialnumber}
New-Object -TypeName PSObject -property $props
}
Write-Output $obj
You are overwriting the $obj variable on each iteration of the loop. So when you export it, it will always only contain the last computer in your list. You can create an array and add each object to it and then output the array to csv.
For example,
$Computers = get-content C:\POSH\test.txt
# Create array to hold all objects
$data = #()
foreach ($comp in $Computers) {
$CS = Get-WmiObject -Class Win32_computersystem -ComputerName $comp
$Encl = Get-WmiObject -Class Win32_Systemenclosure -ComputerName $comp
$props = #{CompName=$cs.name
Manufacturer=$cs.manufacturer
Model=$cs.model
Serial=$encl.serialnumber}
$obj = New-Object -TypeName PSObject -property $props
#Append the object to the array using +=
$data += $obj
}
#Export the objects which were stored in the data array
$data | Export-Csv C:\Test\output.csv -NoTypeInformation

Trouble with foreach logic

I'm trying to get a list of all virtual machines in all of my Veeam backup jobs. I wrote this
#Add Veeam snapin
Add-PSSnapin VeeamPSSnapin
#variables
$Masterlist = #()
$jobs = Get-VBRJob
foreach($job in $jobs) {
$backupJobObjects = Get-VBRJobObject -Job $job
foreach($backupJobObject in $backupJobObjects) {
$MyObject = New-Object PSObject -Property #{ Name = $backupJobObject.Name }
}
$Masterlist += $MyObject
}
$Masterlist | sort-object -Property Name
but it only spits out data from one job (there are 5). I assume this is because of some logic error in the foreach loop but I'm not seeing it. Can anyone help?
As per the per the comment from 4c74356b41
foreach($backupJobObject in $backupJobObjects) {
$MyObject = New-Object PSObject -Property #{ Name = $backupJobObject.Name }
$Masterlist += $MyObject
}
Is how the last foreach loop should look

Resolve-DnsName inside Test-Connection

I was wondering how I could return the Resolve-DnsName output from my Test-Connection script and add it to the CSV I created.
I like to capture the Name, Type, TTL, Section from that please.
Only invoke the Resolve-DnsName when the ping is not successful.
$servers = Get-Content "servers.txt"
$collection = $()
foreach ($server in $servers)
{
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s) }
$result = Test-Connection $server -Count 1 -ErrorAction SilentlyContinue
if ($result)
{
$status.Results = "Up"
$status.IP = ($result.IPV4Address).IPAddressToString
}
else
{
$status.Results = "Down"
$status.IP = "N/A"
$status.DNS = if (-not(Resolve-DnsName -Name $server -ErrorAction SilentlyContinue))
{
Write-Output -Verbose "$server -- Not Resolving"
}
else
{
"$server resolving"
}
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
$collection += $serverStatus
}
$collection | Export-Csv -LiteralPath .\ServerStatus3.csv -NoTypeInformation
but nothing new is added to the CSV.
You ran into a PowerShell gotcha. PowerShell determines the columns displayed in tabular/CSV output from the first object processed. If that object doesn't have a property DNS that column won't be shown in the output, even if other objects in the list do have it. If other objects don't have properties that were present in the first object they will be displayed as empty values.
Demonstration:
PS C:\> $a = (New-Object -Type PSObject -Property #{'a'=1; 'b'=2}),
>> (New-Object -Type PSObject -Property #{'a'=3; 'b'=4; 'c'=5}),
>> (New-Object -Type PSObject -Property #{'b'=6; 'c'=7})
>>
PS C:\> $a | Format-Table -AutoSize
a b
- -
1 2
3 4
6
PS C:\> $a[1..2] | Format-Table -AutoSize
c b a
- - -
5 4 3
7 6
If you want to generate tabular output always create your objects uniformly with the same set of properties. Choosing sensible defaults even allows you to reduce your total codebase.
$collection = foreach ($server in $servers) {
$status = New-Object -Type PSObject -Property #{
'ServerName' = $server
'TimeStamp' = Get-Date -f s
'Results' = 'Down'
'IP' = 'N/A'
'HasDNS' = [bool](Resolve-DnsName -Name $server -EA SilentlyContinue)
}
$result = Test-Connection $server -Count 1 -EA SilentlyContinue
if ($result) {
$status.Results = 'Up'
$status.IP = ($result.IPV4Address).IPAddressToString
}
$status
}

Powershell how to convert System.Collections.Generic.Dictionary to PSCustomObject?

I have a System.Collections.Generic.Dictionary that I have obtained by running the code snippet below. How do I convert $Obj to a PSCustomObject?
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
$jsonserial= New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer
$jsonserial.MaxJsonLength = 67108864
$Obj = $jsonserial.DeserializeObject($JsonString)
New-Object should work from PS 2.0 onwards:
$custom = new-object PSCustomObject -Property $obj
I ended up using the following after the last line in the question
$Obj | ForEach-Object {
$props = #{}
$_.GetEnumerator() | ForEach-Object {
$props[$_.Key] = $_.Value
}
[PSCustomObject]$props
}
If there is a faster, shorter or better way, please feel free to answer
This seems to work:
$ht = #{}
$ht += $obj
[PSCustomObject]$ht
Edit:
V3 solution:
$ht = [collections.hashtable]$obj
[PSCustomObject]$ht

Script works fine until I use variable for the server name

This script works perfectly until I put in $Server as the computer name instead of the actual computer name. Please advise. The error I get is ERROR: Exception calling "DownloadFile" with "2" argument(s): "URI formats are not supported."
$Servers = Get-Content -Path C:\temp\servers.txt
foreach ($Server in $Servers)
{
$web = New-Object System.Net.WebClient
$web.DownloadFile("http://$server:1055/sinfo?gr=1","c:\temp\Test.xml")
[xml] $xdoc = Get-Content c:\Temp\test.xml
$properties = #{
Serialnumber = $xdoc.sinfo.systeminfo.bios.SerialNumber;
Model = $xdoc.sinfo.systeminfo.sys.Model;
Manufacturer = $xdoc.sinfo.systeminfo.sys.Manufacturer;
ComputerName = $xdoc.sinfo.systeminfo.sys.Name;
Domain = $xdoc.sinfo.systeminfo.sys.Domain;
}
}
$obj = new-object psobject -property $properties
$obj | Select-Object model, manufacturer, ComputerName, domain, SerialNumber | export-csv c:\temp\results.csv -NoTypeInformation -Append
The colon is the scope operator in PowerShell. Your script is looking for a variable $server:1055, meaning it's looking for $1055 in the scope or namespace of server.
Try:
"http://$server`:1055/sinfo?gr=1"
Or:
"http://$($server):1055/sinfo?gr=1"
Or:
"http://${server}:1055/sinfo?gr=1"