I have have 2 files which I need to compare with PowerShell and generate the 3rd file with the merge output which contains all the lines from file1.txt and file2.txt.
This is an example of file1.txt and file2.txt:
file1.txt content
"Name","RcopyGroup","State","Type","Prov","UsrCPG","VSize_MB","Usr_Rsvd_MB","Usr_Used_Perc","Usr_Used_MB","Snp_Rsvd_MB","Snp_Used_Perc"
".srdata","-","normal","base","full","-","81920","81920","100.0","81920","0","0.0"
"admin","-","normal","base","full","-","12288","12288","100.0","12288","0","0.0"
"LUN1","-","normal","base","tpvv","SSD_CPG","1331200","1159552","85.6","1139240","17408","0.0"
"LUN2","-","normal","base","tpvv","FC_CPG","122880","82944","52.3","64304","17408","0.0"
"LUN3","-","normal","base","tpvv","SSD_CPG","71680","56320","73.7","52861","1024","0.0"
"LUN4","-","normal","base","tpvv","FC_CPG","40960","33792","77.9","31922","1024","0.0"
"LUN5","-","normal","base","tpvv","FC_CPG","10240","11264","99.7","10209","1024","0.0"
File2.txt Content
"Name","LunID","PresentTo","vvWWN"
"LUN1","10","Host1","60002AC0000000000000004400015537"
"LUN1","10","Host3","60002AC0000000000000004400015537"
"LUN1","110","Host2","60002AC0000000000000004400015537"
"LUN1","209","Host5","60002AC0000000000000004400015537"
"LUN1","110","Host4","60002AC0000000000000004400015537"
"LUN2","111","Host2","60002AC000000000080019FC000153AF"
"LUN3","110","Host2","60002AC000000000080019FD000153AF"
"LUN4","210","Host2","60002AC0000000000A004BC500015537"
"LUN5","211","Host2","60002AC0000000000A004BC700015537"
"LUN4","210","Host5","60002AC0000000000A004BC500015537"
"LUN5","211","Host5","60002AC0000000000A004BC700015537"
and i want the output on file3.txt to be like this
"Name","RcopyGroup","State","Type","Prov","UsrCPG","VSize_MB","Usr_Rsvd_MB","Usr_Used_Perc","Usr_Used_MB","Snp_Rsvd_MB","Snp_Used_Perc","PresentTo"
".srdata","-","normal","base","full","-","81920","81920","100.0","81920","0","0.0",""
"admin","-","normal","base","full","-","12288","12288","100.0","12288","0","0.0",""
"LUN1","-","normal","base","tpvv","SSD_CPG","1331200","1159552","85.6","1139240","17408","0.0","Host1;Host3;Host2;Host5;Host4"
"LUN2","-","normal","base","tpvv","FC_CPG","122880","82944","52.3","64304","17408","0.0","Host2"
"LUN3","-","normal","base","tpvv","SSD_CPG","71680","56320","73.7","52861","1024","0.0","Host2"
"LUN4","-","normal","base","tpvv","FC_CPG","40960","33792","77.9","31922","1024","0.0","Host2;Host5"
"LUN5","-","normal","base","tpvv","FC_CPG","10240","11264","99.7","10209","1024","0.0","Host2;Host5"
I have check the similar post in the forum Powershell compare two files and generate third file
but it is not producing the result which i required. Can someone help to think of a way to do this.
Thank you.
You can use Group-Object cmdlet to work out the hosts for each name and then add a new property to each of the new objects from file1 with the grouped data joined using -join ";".
$file1 = Import-Csv .\file1.csv
$file2 = Import-Csv .\file2.csv
# Group file2 by Name and output as a hashtable
$group2 = $file2 | Select-Object Name, PresentTo | Group-Object -Property Name -AsHashTable
$file1 | ForEach-Object {
# Add the new property (column) 'PresentTo' with the matching file2 Hosts joined by ';'
$_ | Add-Member -NotePropertyName PresentTo -NotePropertyValue ($group2.($_.Name).PresentTo -join ';') -PassThru
} | Export-Csv .\file3.csv
# have a look at our new file
Import-Csv .\file3.csv | Format-Table *
Output
Name RcopyGroup State Type Prov UsrCPG VSize_MB Usr_Rsvd_MB Usr_Used_Perc Usr_Used_MB Snp_Rsvd_MB Snp_Used_Perc PresentTo
---- ---------- ----- ---- ---- ------ -------- ----------- ------------- ----------- ----------- ------------- ---------
.srdata - normal base full - 81920 81920 100.0 81920 0 0.0
admin - normal base full - 12288 12288 100.0 12288 0 0.0
LUN1 - normal base tpvv SSD_CPG 1331200 1159552 85.6 1139240 17408 0.0 Host1;Host3;Host2;Host5;Host4
LUN2 - normal base tpvv FC_CPG 122880 82944 52.3 64304 17408 0.0 Host2
LUN3 - normal base tpvv SSD_CPG 71680 56320 73.7 52861 1024 0.0 Host2
LUN4 - normal base tpvv FC_CPG 40960 33792 77.9 31922 1024 0.0 Host2;Host5
LUN5 - normal base tpvv FC_CPG 10240 11264 99.7 10209 1024 0.0 Host2;Host5
Sorry guys..I am new to powershell. Would be great if someone help with the following scenario:
I have couple of files in a folder c:\test
sample.x.x.1
sample.x.x.2
sample.x.x.3
sample.x.x.4
sample.x.x.5
I want to find the name of the file which has the highest number in its name in the given folder. In the above example, 5 is the highest number and the script should return the output filename as sample.x.x.5
Thanks in advance!
Sorting file names with numbers is quite a problem, as there are two ways. The first one sets them to alphabetical order. That is, 0, 1, 11, 111, 2,... The second one uses natural order. That is, 0, 1, 2, 11, 111.... This is surprisingly tricky and about every third programmer is confused with this.
There's a good answer already, which I'll refer like so,
# Create files 1..5
for($i=1;$i -le 5; ++$i) { set-content sample.x.x.$i -Value $null }
# Tricksy! Create file .10 to confuse asciibetic/natural sorting
set-content sample.x.x.10 -Value $null
ls # Let's see the files
Directory: C:\temp\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2015-09-28 10:29 0 sample.x.x.1
-a---- 2015-09-28 10:29 0 sample.x.x.10
-a---- 2015-09-28 10:29 0 sample.x.x.2
-a---- 2015-09-28 10:29 0 sample.x.x.3
-a---- 2015-09-28 10:29 0 sample.x.x.4
-a---- 2015-09-28 10:29 0 sample.x.x.5
# Define helper as per linked answer
$ToNatural = { [regex]::Replace($_, '\d+$', { $args[0].Value.PadLeft(20,"0") }) }
# Sort with helper and check the output is natural result
gci | sort $ToNatural -Descending | select -First 1
Directory: C:\temp\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2015-09-28 10:29 0 sample.x.x.10
Alphabetical sorting.
PS C:\Users\Gebb> #("sample.x.x.1", "sample.x.x.5", "sample.x.x.11") | sort
sample.x.x.1
sample.x.x.11
sample.x.x.5
Numerical sorting.
PS C:\Users\Gebb> #("sample.x.x.1", "sample.x.x.5", "sample.x.x.11") |
sort -Property #{Expression={[Int32]($_ -split '\.' | select -Last 1)}}
sample.x.x.1
sample.x.x.5
sample.x.x.11
Largest number.
PS C:\Users\Gebb> #("sample.x.x.1", "sample.x.x.5", "sample.x.x.11") |
sort -Property #{Expression={[Int32]($_ -split '\.' | select -Last 1)}} |
select -Last 1
sample.x.x.11
I am writing a powershell script to calculate summary stats for a csv file with 100,000+ rows.
In my foreach loop, one of my lines is:
$count = $Not_10000.count
Where "$Not_10000" is the result after filtering a csv, which was read using the import-csv command and filtered using
where {$_.ifhighspeed -eq 10000}.
I found that the value of "$count" is correct whenever "$Not_10000" has more than one line. However, when "$Not_10000" only has one line, the result is that $count is empty. I tried going into the powershell prompt and doing
$count = $Not_10000 | Measure-Object -lines
But it shows 0 lines even though it has one line. The output of
$Not_10000[0]
is
DATE ENTITYNAME IFHIGHSPEED
---- ---------- -----------
8/25/2014 12:00:00 AM SF15-0326 1000
Why wouldn't this one line output be counted correctly? I manually changed the filters to make "$Not_10000" contain 15 lines, and this was counted correctly.
I seem to have trouble in general giving the full picture, so let me know if you need more info or clarification.
Matt gives a good answer, but is only kind of the answer to your question.
The .Count property is a member of the Array object type that is being referenced when the number of results is more than one. When you only have one result then what is returned is not an array, it is a String, or an Object, or an Integer or something, but not an array unless you specifically make it one. In order for this to always come back with a number:
$count = $Not_10000.count
You need to cast it as an array, which is most simply done by enclosing it in #()
$count = #($Not_10000).count
This is most easily seen by using the .PSObject member of any object, when used on an array. Let's create an array, and look at the Type to verify that it's an array, and then look at the PSObject members (filtering for just properties, since it has a lot of members we don't care about) for that array object.
PS C:\Users> $test = #("Red","Blue","Green")
PS C:\Users> $test.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS C:\Users> $test.PSObject.Members | Where{$_.MemberType -match "property"}|FT Name,MemberType,Value,ReferencedMemberName
Name MemberType Value ReferencedMemberName
---- ---------- ----- --------------------
Count AliasProperty 3 Length
Length Property 3
LongLength Property 3
Rank Property 1
SyncRoot Property {Red, Blue, Green}
IsReadOnly Property False
IsFixedSize Property True
IsSynchronized Property False
Item ParameterizedProperty ...int index) {get;set;}
What we see here is that it is an AliasProperty for the member Length, which on an array gives the number of records, just like it's alias Count does.
Use the Count property of Measure-Object. Lines, Words, Characters are things you use to measure text not objects
$count = $Not_10000 | Measure-Object | Select-Object -ExpandProperty Count
or
$count = ($Not_10000 | Measure-Object).Count
More Explanation
I have a csv with a header and 7 entries.
Path Data Files
---- ---- -----
\\someserver\somepath1 100 1
\\someserver\somepath2 150 4
\\someserver\somepath1 200 5
\\someserver\somepath3 450 8
\\someserver\somepath4 200 23
\\someserver\somepath1 350 2
\\someserver\somepath2 800 9
When i do the following (-lines is not a valid switch for Measure-Object )
Import-Csv E:\temp\stack.csv | Where-Object{$_.Data -gt 300} | Measure-Object -line
Since this is not text there are no lines to measure. I get this output regardless of how many entries in the file or filtered object. You would expect 3 but you actually get 0
Lines Words Characters Property
----- ----- ---------- --------
0
If i read the file as text i would get a result for lines
Get-Content E:\temp\stack.csv | Measure-Object -line
Lines
-----
8