System Object Error when exporting results to CSV - csv

I am trying to export my results from a compare-object into a csv but I get an error When I export it. It looks ok when I just call it in excel. My guess is whenever there is a output of more than one value the error is placed instead of the value.
Here are my csvs
past.csv
VKEY
V-12345
V-23456
V-1111
current.csv
VKEY
V-12345
V-6789
V-23456
V-256
My new csv should say
Past, Current
V-6789,V-1111
V-256
What I am getting now is
Past, Current
System.Object[],#{vkey=V-1111}
.
$Past = Import-CSV "past.csv"
$Current = Import-CSV "Current.csv"
$pastchange = Compare-Object $Past $Current -Property vkey | Where-Object {$_.SideIndicator -eq '=>'} | Select-Object VKEY
$currentchange = Compare-Object $Past $Current -Property vkey | Where-Object {$_.SideIndicator -eq '<='} | Select-Object VKEY
$obj = New-Object PSObject
$obj | Add-Member NoteProperty Past $pastchange
$obj | Add-Member NoteProperty Current $currentchange
$obj | Export-Csv "ChangeResults.csv" -NoTypeInformation

That System.Object[] displayed in $obj.Past column is simply an array of custom objects similar to #{vkey=V-1111} in $obj.Past column. Proof:
PS D:\PShell> $obj
$obj.Past.Gettype() | Format-Table
$obj.Current.Gettype()
"---"
$obj.Past | ForEach-Object { $_.Gettype() }
Past Current
---- -------
{#{vkey=V-6789}, #{vkey=V-256}} #{vkey=V-1111}
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
---
True False PSCustomObject System.Object
True False PSCustomObject System.Object
My solution makes use of ArrayList Class (.NET Framework):
$csvOutFile = "d:\test\ChangeResults.csv" # change to fit your circumstances
$PastInFile = "d:\test\past.csv"
$CurrInFile = "d:\test\curr.csv"
$Past = Import-CSV $PastInFile
$Curr = Import-CSV $CurrInFile
# compare CSV files and convert results to arrays
$PastCh=#(, <# always return an array #>
$( Compare-Object $Past $Curr -Property vkey |
Where-Object { $_.SideIndicator -eq '=>' } ) |
ForEach-Object { $_ | Select-Object -ExpandProperty vkey }
)
$CurrCh=#(, <# even if no SideIndicator matches #>
$( Compare-Object $Past $Curr -Property vkey |
Where-Object { $_.SideIndicator -eq '<=' } ) |
ForEach-Object { $_ | Select-Object -ExpandProperty vkey }
)
[System.Collections.ArrayList]$csvout = New-Object System.Collections.ArrayList($null)
$auxHash = #{} # an auxiliary hash object
$max = ($CurrCh.Count, $PastCh.Count | Measure-Object -Maximum).Maximum
for ($i=0; $i -lt $max; $i++) {
Try { $auxHash.Past = $PastCh.GetValue($i) } Catch { $auxHash.Past = '' }
Try { $auxHash.Curr = $CurrCh.GetValue($i) } Catch { $auxHash.Curr = '' }
$csvout.Add((New-Object PSObject -Property $auxHash)) > $null
}
$csvout | Format-Table -AutoSize # show content: 'variable $csvout'
$csvout | Export-Csv $csvOutFile -NoTypeInformation
Get-Content $csvOutFile # show content: "output file $csvOutFile"
Output:
PS D:\PShell> D:\PShell\SO\37753277.ps1
Past Curr
---- ----
V-6789 V-1111
V-256
"Past","Curr"
"V-6789","V-1111"
"V-256",""
PS D:\PShell>
Here is an alternative for Try … Catch blocks:
<# another approach instead of `Try..Catch`:
if ($i -lt $PastCh.Count) { $auxHash.Past = $PastCh.GetValue($i)
} else { $auxHash.Past = '' }
if ($i -lt $CurrCh.Count) { $auxHash.Curr = $CurrCh.GetValue($i)
} else { $auxHash.Curr = '' }
#>

Related

How to handle an expression when input is taken from a csv

Beginner with powershell and looking for some help with the #{Label='ID'; expression={??} section please:-
$ID = #()
Import-Csv C:\computers2.csv | ForEach-Object {$ID += $_.ID}
Get-WmiObject -Class Win32_LogicalDisk -ComputerName $ID |
Select-Object -Property DeviceID, #{Label='ID'; expression=
{$ID}},
#{Label='Total (Gb)'; expression={($_.Size/1GB).ToString('F2')}},
#{Label='Free (Gb)'; expression=
{($_.FreeSpace/1GB).ToString('F2')}},
#{label='Percent'; expression={[Math]::Round(($_.freespace /
$_.size) * 100, 2)}} | Format-Table
The output I get is this:-
output
What I'm trying to achieve would be this:-
desired output
Managed to work it out after following some guides and getting the correct variables
$CSV = Import-Csv C:\computers.csv
$SPACE = ForEach ($ID in $CSV) {
Get-WmiObject -Class Win32_LogicalDisk -ComputerName ($ID.ID) |
Select-Object -Property DeviceID,
#{Label='ID'; expression={$_.SystemName}},
#{Label='Total (Gb)'; expression={($_.Size/1GB).ToString('F2')}},
#{Label='Free (Gb)'; expression={($_.FreeSpace/1GB).ToString('F2')}},
#{Label='PercentFree'; expression={[Math]::Round(($_.freespace / $_.size) *
100, 2)}}
} | FormatTable

Powershell: convert ForEach loop results into an HTML table

I wrote a code for Azure subscription cost calculation based on two Tags (In this case Application tag and Owner tag), that are used in our environment.
$ApplicationTags = ((Get-AzResource).Tags).Application | select -Unique
$ApplicationTagLoop = #(Foreach ($ApplicationTag in $ApplicationTags) {
$ConsumptionUsageDetail = (Get-AzConsumptionUsageDetail -StartDate (Get-Date).addmonths(-1) -EndDate
(Get-Date)) | Where-Object {$_.Tags -ne $null} | Where-Object {$_.Tags['Application'] -eq
$ApplicationTag}
$SumForApplicationTag = 0
$TotalCostPerApplicationTag = $ConsumptionUsageDetail.PretaxCost
$TotalCostPerApplicationTag | ForEach {$SumForApplicationTag += $_}
Write-Host "Application tag is"$ApplicationTag". Sum for the tag is:" $([int]$SumForApplicationTag) "Eur"
$OwnerTags = ((Get-AzResource -TagValue $ApplicationTag).Tags).Owner | select -Unique
ForEach ($OwnerTag in $OwnerTags) {
$ConsumptionUsageDetail = (Get-AzConsumptionUsageDetail -StartDate (Get-Date).addmonths(-1) -
EndDate (Get-Date)) | Where-Object {$_.Tags -ne $null} | Where-Object {$_.Tags['Application'] -eq
$ApplicationTag} | Where-Object {$_.Tags['Owner'] -eq $OwnerTag}
$SumForOwner = 0
$TotalCostPerOwnerTag = $ConsumptionUsageDetail.PretaxCost
$TotalCostPerOwnerTag | Foreach {$sumforowner += $_}
ConvertTo-HTML -Body "Application tag: $ApplicationTag 'Owner: $OwnerTag Cost:
$([int]$SumForOwner) Eu." -Title "Cost of subscriptions" | Out-File c:\example.html
Write-Host Owner is - $OwnerTag" Sum for the owner is:" $([int]$SumForOwner) "Eur"
}
})
Output of this PS code is:
Application tag is Testing. Sum for the tag is: 25 Eur
Owner is - john.johnson#contoso.com Sum for the owner is: 15 Eur
Owner is - tom.thompson#contoso.com Sum for the owner is: 10 Eur
Application tag is Testing 2. Sum for the tag is: 100 Eur
Owner is - jim.jameson#contoso.com Sum for the owner is: 40 Eur
Owner is - eve.evens#contoso.com Sum for the owner is: 40 Eur
Owner is - charles.mcgill#contoso.com Sum for the owner is: 20Eur
...and so on...
Now I need to stream this output to an HTML table somehow, I tried doing that with ConvertTo-HTML command but it keeps rewriting itself with the last output and does not populate the table in any way.
I also tried to make ForEach loops into arrays like so:
$ApplicationTagLoop = #(foreach ($i in $ApplicationTag)
And using that with Convert-To-HTML, but doing it this way $ApplicationTagLoop does not provide any results at all, so nothing is converted to HTML.
How could I rewrite the ConvertTo-HTML part so that every output of the loop would be saved into a new line of the HTML file?
Desired output format should be:
https://i.stack.imgur.com/z13SM.png
Viewing the code, i guess the expected oputput.
Use object collection build to get proper HTML :
$ApplicationTags = ((Get-AzResource).Tags).Application | select -Unique
$html = [System.Collections.ArrayList]#()
Foreach ($ApplicationTag in $ApplicationTags) {
$ConsumptionUsageDetail = (Get-AzConsumptionUsageDetail -StartDate (Get-Date).addmonths(-1) -EndDate
(Get-Date)) | Where-Object {$_.Tags -ne $null} | Where-Object {$_.Tags['Application'] -eq
$ApplicationTag}
$SumForApplicationTag = 0
$TotalCostPerApplicationTag = $ConsumptionUsageDetail.PretaxCost
$TotalCostPerApplicationTag | ForEach {$SumForApplicationTag += $_}
Write-Host "Application tag is"$ApplicationTag". Sum for the tag is:" $([int]$SumForApplicationTag) "Eur"
$OwnerTags = ((Get-AzResource -TagValue $ApplicationTag).Tags).Owner | select -Unique
ForEach ($OwnerTag in $OwnerTags) {
$ConsumptionUsageDetail = (Get-AzConsumptionUsageDetail -StartDate (Get-Date).addmonths(-1) -
EndDate (Get-Date)) | Where-Object {$_.Tags -ne $null} | Where-Object {$_.Tags['Application'] -eq
$ApplicationTag} | Where-Object {$_.Tags['Owner'] -eq $OwnerTag}
$SumForOwner = 0
$TotalCostPerOwnerTag = $ConsumptionUsageDetail.PretaxCost
$TotalCostPerOwnerTag | Foreach {$sumforowner += $_}
#ConvertTo-HTML -Body "Application tag: $ApplicationTag 'Owner: $OwnerTag Cost:
#$([int]$SumForOwner) Eu." -Title "Cost of subscriptions" | Out-File c:\example.html
$html.Add((Select-Object #{n='Application tag';e={$ApplicationTag}},#{n='Owner';e={$OwnerTag}},#{n='Cost';e={[string]$([int]$SumForOwner)+" Eu."}} -InputObject ''))
Write-Host Owner is - $OwnerTag" Sum for the owner is:" $([int]$SumForOwner) "Eur"
}
}; $html | ConvertTo-Html -As Table -Title "Cost of subscriptions" | Out-File c:\example.html
Which should render the following HTML :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Cost of subscriptions</title>
</head><body>
<table>
<colgroup><col/><col/><col/></colgroup>
<tr><th>Application tag</th><th>Owner</th><th>Cost</th></tr>
<tr><td>Testing</td><td>john.johnson#contoso.com</td><td>15 Eu</td></tr>
<tr><td>Testing</td><td>tom.thompson#contoso.com</td><td>10 Eu</td></tr>
<tr><td>Testing 2</td><td>jim.jameson#contoso.com</td><td>40 Eu</td></tr>
<tr><td>Testing 2</td><td>eve.evens#contoso.com</td><td>40 Eu</td></tr>
<tr><td>Testing 2</td><td>charles.mcgill#contoso.com</td><td>20 Eu</td></tr>
</table>
</body></html>
Second edit as OP required a new formatted output, we're using a hash to break by application tag and format the output accordingly.
$ApplicationTags = ((Get-AzResource).Tags).Application | select -Unique
$html = [System.Collections.ArrayList]#()
$hash = #{}
Foreach ($ApplicationTag in $ApplicationTags) {
$ConsumptionUsageDetail = (Get-AzConsumptionUsageDetail -StartDate (Get-Date).addmonths(-1) -EndDate
(Get-Date)) | Where-Object {$_.Tags -ne $null} | Where-Object {$_.Tags['Application'] -eq
$ApplicationTag}
$SumForApplicationTag = 0
$TotalCostPerApplicationTag = $ConsumptionUsageDetail.PretaxCost
$TotalCostPerApplicationTag | ForEach {$SumForApplicationTag += $_}
Write-Host "Application tag is"$ApplicationTag". Sum for the tag is:" $([int]$SumForApplicationTag) "Eur"
$OwnerTags = ((Get-AzResource -TagValue $ApplicationTag).Tags).Owner | select -Unique
ForEach ($OwnerTag in $OwnerTags) {
$ConsumptionUsageDetail = (Get-AzConsumptionUsageDetail -StartDate (Get-Date).addmonths(-1) -
EndDate (Get-Date)) | Where-Object {$_.Tags -ne $null} | Where-Object {$_.Tags['Application'] -eq
$ApplicationTag} | Where-Object {$_.Tags['Owner'] -eq $OwnerTag}
$SumForOwner = 0
$TotalCostPerOwnerTag = $ConsumptionUsageDetail.PretaxCost
$TotalCostPerOwnerTag | Foreach {$sumforowner += $_}
# We use the hash to check for break by ApplicationTag
if (!$hash[ApplicationTag]) {
$hash[$ApplicationTag]=$True
$html.Add((Select-Object #{n="Application tag";e={$ApplicationTag}},#{n="Owner";e={""}},#{n="Cost";e={[string]$([int]$SumForApplicationTag)+" Eu."}} -InputObject ''))
}
# Adding the owners
$html.Add((Select-Object #{n="Application tag";e={""}},#{n='Owner';e={$OwnerTag}},#{n='Cost';e={[string]$([int]$SumForOwner)+" Eu."}} -InputObject ''))
Write-Host Owner is - $OwnerTag" Sum for the owner is:" $([int]$SumForOwner) "Eur"
}
}; $html | ConvertTo-Html -As Table -Title "Cost of subscriptions" | Out-File c:\example.html
Which should render the following HTML :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Cost of subscriptions</title>
</head><body>
<table>
<colgroup><col/><col/><col/></colgroup>
<tr><th>ApplicationTag</th><th>Owner</th><th>Cost</th></tr>
<tr><td>Testing</td><td></td><td>25 Eu</td></tr>
<tr><td></td><td>john.johnson#contoso.com</td><td>15 Eu</td></tr>
<tr><td></td><td>tom.thompson#contoso.com</td><td>10 Eu</td></tr>
<tr><td>Testing 2</td><td></td><td>100 Eu</td></tr>
<tr><td></td><td>jim.jameson#contoso.com</td><td>40 Eu</td></tr>
<tr><td></td><td>eve.evens#contoso.com</td><td>40 Eu</td></tr>
<tr><td></td><td>charles.mcgill#contoso.com</td><td>20 Eu</td></tr>
</table>
</body></html>
Wich should render as :

Getting blanks while reading a CSV

I am trying to read a csv file and store in a hasmap. Below is the code I am using.
$data | ForEach-Object {
$ht = #{}
$_.psobject.Properties |
#Get only the grouped properties (that have a number at the end)
Where-Object { $_.Name -match '\d+$' } |
#Group properties by param/group number
Group-Object {$_.Name -replace '\w+(\d+)$', '$1' } | ForEach-Object {
$param = $_.Group | Where-Object { $_.Name -match 'param' }
$value = $_.Group | Where-Object { $_.Name -match 'value' }
#If property has value
if($value.value -ne ""){
#Add to hashtable
$ht.add($param.Value,$value.Value)
}
}
$ht
}
Below is the output for $ht. I am getting 1 $null value for one of the field OrgId.
Name Value
---- -----
{orgId, } {1000002, $null}
type CSVFile
codepage MS1252
agentId 00000208000000000002
name infa_param_file_Pravakar
dateFormat MM/dd/yyyy HH:mm:ss
database C:\\Program Files\\Informatica Cloud Secure A
Sample CSV:
"param1","value1","param2","value2","param3","value3","param4","value4","param5","value5","param6","value6","param7","value7","param8","value8","param9","value9","param10","value10","param11","value11"
"orgId","000002","name","infa_param_file_Pravakar","agentId","00000208000000000002","dateFormat","MM/dd/yyyy HH:mm:ss","database","C:\\Program Files\\Informatica Cloud Secure Agent\\main\\rdtmDir\\userparameters","codepage","MS1252","type","CSVFile","","","","","","","",""

Transpose rows into columns using PowerShell

I having a hard time,again, trying to transpose row into columns.
The original code comes from #Mathias R. Jessen, Powershell transpose rows into columns but now I need to add some additionals columns in the csv file. I would like to have (I don't mind about the order)
EndTime,ActualStartTime,"MachineName1", "MachineName2", MachineNameX",ElapsedTime,FinalJobStatus
#1.csv
#MachineName, TotalDataSizeBytes, ActualStartTime,EndTime,ElapsedTime,FinalJobStatus
#SERVER1, 322349304901, 28/02/2016 23:00:03, 29/03/2016 23:33:23, 222,OK
#SERVER1, 322349304902, 26/02/2016 23:00:03, 27/03/2016 23:33:24, 222,OK
#SERVER2, 322349304903, 28/02/2016 23:00:01, 29/03/2016 23:33:25, 11, OK
#SERVER2, 322349304904, 26/02/2016 23:00:01, 27/03/2016 23:33:26, 122,OK
#
#2.csv (Desired output)
#EndTime","ActualStartTime","SERVER1","SERVER2",ElapsedTime,FinalJobStatus
#"29/03/2016 23:33:23","28/02/2016 23:00:03","322349304901",222,OK
#"27/03/2016 23:33:24","26/02/2016 23:00:03","322349304902",222,OK
#"29/03/2016 23:33:25","28/02/2016 23:00:01",,"322349304903",11,OK
#"27/03/2016 23:33:26","26/02/2016 23:00:01",,"322349304904",122,OK
$Rows = Import-Csv c:\_Scripts\1.csv
$MachineNames = $Rows |Select-Object -ExpandProperty MachineName |Sort -Unique
$ConsolidatedRows = $Rows |Group-Object EndTime |ForEach-Object {
$NewRowProperties = #{ EndTime = [DateTime]::Parse($_.Name) }
foreach($Row in $_.Group)
{
$NewRowProperties.Add($Row.MachineName,$Row.TotalDataSizeBytes)
}
New-Object psobject -Property $NewRowProperties
}
$ConsolidatedRows |Select-Object #("EndTime";$MachineNames) |
Sort-Object EndTime |Export-Csv c:\_Scripts\2.csv -NoTypeInformation
Edit1. I have succeeded:
$Rows = Import-Csv c:\_Scripts\1.csv
$MachineNames = $Rows |Select-Object -ExpandProperty MachineName |Sort -Unique
$ConsolidatedRows =""
$NewRowProperties =""
$ConsolidatedRows = $Rows |Group-Object EndTime |ForEach-Object {
$NewRowProperties = #{ EndTime = [DateTime]::Parse($_.Name) }
foreach($Row in $_.Group)
{
$NewRowProperties.Add("ActualStartTime",$Row.ActualStartTime)
$NewRowProperties.Add("ElapsedTime",$Row.ElapsedTime)
$NewRowProperties.Add($Row.MachineName,$Row.TotalDataSizeBytes)
$NewRowProperties.Add("FinalJobStatus",$Row.FinalJobStatus)
}
New-Object psobject -Property $NewRowProperties
}
$ConsolidatedRows |Ft
$ConsolidatedRows |Select-Object #("EndTime";$MachineNames;"ActualStartTime";"ElapsedTime";"FinalJobStatus")
|Sort-Object EndTime |Export-Csv c:\_Scripts\2.csv -NoTypeInformation

Replace empty fields in CSV with 0

I am trying to replace null values in a certain column to 0 using PowerShell.
I have the CSV in this format:
test test2 test3 test4
---- ----- ----- -----
blah fsds 4 45645
bla1 fsds1 45645
blah2 fsds2 4 34322
blah3 fsds3 4 67544
blah4 fsds4 3432432
so I want to go through the null values in "test3" and replace to 0.
I have this, but it doesn't work:
$inFilePath = "G:\powershell\excel\test.csv"
$csvColumnNames = (Get-Content $inFilePath | Select-Object -First 1).Split(",")
foreach ($row in $inFilePath) {
if ($row.test3 -eq $null) {
$row.test3 = 0
Write-Host "updating value in excel"
}
}
$csvColumnNames | Export-Csv "G:\powershell\excel\replaced2.csv" -NoTypeInformation
you are on the right track with foreach and if.Try this:
foreach($row in $inFilePath)
{
if (-not $row.test3)
{
$row.test3= 0
}
}
to get the column headers:
$inFilePath | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name
Use Import-Csv for reading and Export-Csv for writing CSV files.
$inFilePath = "G:\powershell\excel\test.csv"
$outFilePath = "G:\powershell\excel\replaced2.csv"
Import-Csv $inFilePath | % {
if (-not $_.test3) { $_.test3 = 0 }
$_ # echo all records, so they can be exported back to a file
} | Export-Csv $outFilePath -NoType