String split with PowerShell - powershell

I have a log file what contains S.M.A.R.T. data of my hard drive.
I would like to handle this file with PowerShell.
Here is the part of my log file.
3 Spin_Up_Time 0x0020 100 100 000 Old_age Offline - 0
4 Start_Stop_Count 0x0030 100 100 000 Old_age Offline - 0
5 Reallocated_Sector_Ct 0x0032 100 100 000 Old_age Always - 0
And here is my code
$i = 1
$a = Get-Content log.txt
do {
$trimmed = $a[$i].trim()
$splitted = $trimmed.split(" ")
$i++
}while ($i -le 3)
If I use the .split(" ") it is working only with the thrid row.
How can I split my all rows correctly?
Thank you

A bit more code, but it gives you something that's a little easier to work with in the end:
$SMART = gc c:\temp\test.txt | %{
$temp = $_ -split " "|?{!([string]::IsNullOrWhiteSpace($_))}
new-object psobject -Property #{
"Entry"=$temp[0]
"TestName"=$temp[1]
"HexCode"=$temp[2]
"Number1"=$temp[3]
"Number2"=$temp[4]
"Number3"=$temp[5]
"Age"=$temp[6]
"Status"=$temp[7]
"Filler"=$temp[8]
"Zero?"=$temp[9]
}
}
$SMART|FT Entry,TestName,HexCode,Number1,Number2,Number3,Age,Status,Filler,Zero?

what does this do for you?
$a = Get-Content log.txt
-split $a
I get this
H:\> -split $a
3
Spin_Up_Time
0x0020
100
100
000
Old_age
Offline
-
0
4
Start_Stop_Count
0x0030
100
100
000
Old_age
Offline
-
0
5
Reallocated_Sector_Ct
0x0032
100
100
000
Old_age
Always
-
0

I like working with regex' here's a sample that allows you to name your columns.
$a = Get-Content log.txt
$pattern = [regex]'(?<rowid>\d+)\s(?<desc>[a-zA-Z_]+)\s+(?<hexdata>0x\d{4})\s+(?<col4>\d{3})\s+(?<col5>\d{3})\s+(?<col6>\d{3})\s+(?<text1>.+?)\s+(?<state>.+?)-\s+0'
foreach ($line in $a) {
if ($line -match $pattern) {
$dataobj = New-Object PSObject
$dataobj | Add-Member -type NoteProperty -name "Description" -value $matches['desc']
$dataobj | Add-Member -type NoteProperty -name "Hex Data" -value $matches['hexdata']
$dataobj | Add-Member -type NoteProperty -name "State" -value $matches['state']
$dataobj
}
}
Results:
Description Hex Data State
----------- -------- -----
Spin_Up_Time 0x0020 Offline
Start_Stop_Count 0x0030 Offline
Reallocated_Sector_Ct 0x0032 Always

Related

CSV misalignment when reading in powershell

I have a CSV with a lot of headers. It ranges from Column A to AZ. I need to read only the first column of the CSV.
My issue is the last column (comments) bleeds into the first column when opened in notepad++ and it appears to show that it is apart of Column one (host name). When I run my code it reads it as notepad++ does.
I originally convert this from an .xls to a CSV file, is there a way to ensure the last column does not wrap around?
#region - Convert to CVS
$strFileName = "C:\working\Server Count & Status Check ARC 0219183.xlsx"
$strSheetName = 'SCI$'
$strProvider = "Provider=Microsoft.ACE.OLEDB.12.0"
$strDataSource = "Data Source = $strFileName"
$strExtend = "Extended Properties='Excel 8.0;HDR=Yes;IMEX=1';"
$strQuery = "Select * from [$strSheetName]"
$objConn = New-Object
System.Data.OleDb.OleDbConnection("$strProvider;$strDataSource;$strExtend")
$sqlCommand = New-Object System.Data.OleDb.OleDbCommand($strQuery)
$sqlCommand.Connection = $objConn
$objConn.open()
$da = New-Object system.Data.OleDb.OleDbDataAdapter($sqlCommand)
$dt = New-Object system.Data.datatable
$da.fill($dt)
$dt | Export-Csv "C:\working\Server Count & Status Check ARC 0219183.csv" -
NoTypeInformation
$objConn.close()
#endregion
Original Spreadsheet
After trying to gather first column(hostname)
$array=#{}
$ServerStatus = Get-Content "C:\Users\user\Desktop\Scripts\Linux Server
Compare\Server Count & Status Check ARC 0219183.csv" | select -skip 1 |
ConvertFrom-Csv -Header "HostName","Business Application","Technical
Function","Location","Environment","Day Number","Slot
Number","SlotTime","Description","DNS Name","Key Server","Host Name","Public
IP","Server Type","Build Date","Builder","Product Name","Serial
No","Enclosure","Bay","CPU Model","CPU Socket","CPU Cores","Logical
CPU","Memory","Up Time","Kernel Version","OS Type","Version","Patch
level","Multipath Disks?","Multipath Checker?","Customized Fsck?","Splx
Installed?","Splx Running?","Suse Manager Status","RHN Running ?","RHN
Autostart?","Installed Kernel","Available Kernel in
/boot","Hardened","Syslog
Config correct ?","Syslog Running ?","Patrol Running?","Splunk
Installed?","Splunk Running?","Puppet Installed?","Puppet
Running?","Centrify
Version","VM Tools Installed?","VM Tools Running?","Comments"
$ServerStatusObj = new-object Object
$ServerStatusObj | add-member -membertype NoteProperty "Name" -value ""
$ServerStatusObj | add-member -membertype NoteProperty "Origin" -value ""
$array=#{name = $ServerStatus.HostName}
foreach ($name in $array.name){
if($name -ne $null){
$Value = $name
if($name -ne $null){
$ServerStatusObj.name =$Value
$ServerStatusObj.Origin = " Linux Servers"
} #End of IF
else {Write-Output "null"}
Write-Output $ServerStatusObj | export-csv
"C:\Users\user\Desktop\Scripts\Linux Server Compare\ServerStatusParse.csv" -notypeinformation -Append
}

Need to convert txt file to CSV (with headers) using PowerShell

Can we convert below txt file to CSV format added at the end?
Text file:
IP Address: 192.168.1.1
Hostname: 01-any1TEST
Event Message: Ping
Alert Status: Down at least 3 min
Event Time: 17:25:14
Alert Type: :Windows 2012 Server
-------------------------------------------------------------------------------------
IP Address: 192.168.1.2
Hostname: 02-any2TEST
Event Message: Ping
Alert Status: Down at least 4 min
Event Time: 17:25:40
Alert Type: :Unix Server
-------------------------------------------------------------------------------------
IP Address: 192.168.1.3
Hostname: 03-any3TEST
Event Message: Ping
Alert Status: Down at least 3 min
Event Time: 17:26:21
Alert Type: :windows host
-------------------------------------------------------------------------------------
CSV file output required as below:
'IP Address','Hostname','Event Message','Alert Status','Event Time','Alert Type'
'192.168.1.1','01-any1TEST','Ping','Down at least 3 min','17:26:21','Windows 2012 Server '
'192.168.1.2','02-any2TEST','Ping','Down at least 3 min','17:26:21','unix host '
'192.168.1.3','03-any3TEST','Ping','Down at least 3 min','17:26:21','windows host '
Here's one way you could do it:
$logFile = "logfile.txt"
$delimeterPattern = '^####'
$recordPattern = '^([^:]+): (.+)'
# how many lines in a record?
$recordLines = Select-String $delimeterPattern $logFile -List |
Select-Object -ExpandProperty LineNumber
$logContent = Get-Content $logFile
for ( $i = 0; $i -lt $logContent.Count; $i += $recordLines ) {
$output = New-Object PSObject
for ( $j = $i; $j -lt $i + $recordLines; $j++ ) {
$logContent[$j] | Select-String $recordPattern | ForEach-Object {
$output | Add-Member NoteProperty $_.Matches[0].Groups[1].Value $_.Matches[0].Groups[2].Value
}
}
$output
}
To write to a CSV file, put the above in a script and pipe to Export-Csv.
I hope this will solve your problem:
Function Convert2CSV()
{
param($logFile, $csvFile)
"'IP Address','Hostname','Event Message','Alert Status','Event Time','Alert Type'" | Out-File $csvFile
get-content $logFile -Delimiter "-------------------------------------------------------------------------------------" | &{ process{
$IsValidMatch=$_ -match "IP Address: (.*)\r\nHostname: (.*)\r\nEvent Message: (.*)\r\nAlert Status: (.*)\r\nEvent Time: (.*)\r\nAlert Type: (.*)\r\n"
if($IsValidMatch)
{
$nextLine="'$($matches[1])','$($matches[2])','$($matches[3])','$($matches[4])','$($matches[5])','$($matches[6])'" | Out-File $csvFile -Append
}
}}
}
Finally call the Convert2CSV function, and define your log file and output file as parameter:
Convert2CSV -logFile .\1.txt -csvFile 3.txt
$delimeterPattern = '^--'
$recordPattern = '^([^:]+): (.+)'
$logContent = Get-Content "logfile.txt"
# how many lines in a record?
$recordLines = ($logContent | Select-String $delimeterPattern |
Select-Object -First 1).LineNumber
for ( $i = 0; $i -lt $logContent.Count; $i += $recordLines ) {
$output = New-Object PSObject
for ( $j = $i; $j -lt $i + $recordLines; $j++ ) {
$logContent[$j] | Select-String $recordPattern | ForEach-Object {
$output | Add-Member NoteProperty $_.Matches[0].Groups[1].Value
$_.Matches[0].Groups[2].Value
}
}
$output
}
Updated seprator $delimeterPattern = '^--' to $delimeterPattern = '^####' .

Powershell split csv column value into two seperate column values

Lets say I have a csv file with 5 records (in reality it's about 80,000).
Csv File:
column1,columnICareAbout,column2
someRandomValue,John Doe - Generic,someRandomValue
someRandomValue,Captain Teemo - pocketPet,someRandomValue
someRandomValue,Pinky Brain - Fictional,someRandomValue
someRandomValue,Miyamoto Musashi - swordsman,someRandomValue
someRandomValue,Kato yasunori - troubleMaker - Extreme,someRandomValue
Given the following code:
Note: I know the array values are correct, I just need to know how to loop through the array in the expression.
$firstNames = #()
$firstNameCounter = 0
$lastNames = #()
$lastNameCounter = 0
Import-Csv $file1 |
foreach {
$firstNames += $_.Description.split(" ")[0]
$lastNames += $_.Description.split(" ")[1]
}
Import-Csv $file1 |
Select-Object *, #{n='First Name'; e={$firstNames[$firstNameCounter];$script:firstNameCounter++}}, #{n='Last Name'; e={$lastNames[$lastNameCounter];$script:lastNameCounter++}} |
Export-Csv "testresults.csv" -NoTypeInformation -Force
I only get the first element in the array every time. So the end result file looks like this
column1,columnICareAbout,column2,First Name,Last Name
someRandomValue,John Doe - Generic,someRandomValue,John,Doe
someRandomValue,Captain Teemo - pocketPet,someRandomValue,John,Doe
someRandomValue,Pinky Brain - Fictional,someRandomValue,John,Doe
someRandomValue,Miyamoto Musashi - swordsman,someRandomValue,John,Doe
someRandomValue,Kato yasunori - troubleMaker - Extreme,someRandomValue,John,Doe
I want the file to look like this
column1,columnICareAbout,column2,First Name,Last Name
someRandomValue,John Doe - Generic,someRandomValue,John,Doe
someRandomValue,Captain Teemo - pocketPet,someRandomValue,Captain,Teemo
someRandomValue,Pinky Brain - Fictional,someRandomValue,Pinky,Brain
someRandomValue,Miyamoto Musashi - swordsman,someRandomValue,Miyamoto,Musashi
someRandomValue,Kato yasunori - troubleMaker - Extreme,someRandomValue,Kato,yasunori
Can Anyone tell me what I'm doing wrong?
Import-Csv $file1 |
foreach {
$firstName = $_.Description.split(" ")[0]
$lastName = $_.Description.split(" ")[1]
$_ | Add-Member -MemberType NoteProperty -Name FirstName -Value $firstName
$_ | Add-Member -MemberType NoteProperty -Name LastName -Value $lastName
} | Export-Csv 'results.csv'
Add-Member commands will append the 2 columns FirstName and LastName

Powershell - Insert column in between specific columns in csv file

I have 2 csv files
First file:
firstName,secondName
1234,Value1
2345,Value1
3456,Value1
4567,Value3
7645,Value3
Second file:
firstName,fileSplitter,Csv2ColumnOne,Csv2ColumnTwo,Csv2ColumnThree
1234,,1234,abc,Value1
1234,,1234,asd,Value1
3456,,3456,qwe,Value1
4567,,4567,mnb,Value1
I want to insert column secondName in the second file in between columns firstName and fileSplitter.
The result should look like this:
firstName,secondName,fileSplitter,Csv2ColumnOne,Csv2ColumnTwo,Csv2ColumnThree
1234,Value1,,1234,abc,Value1
1234,Value1,,1234,asd,Value1
3456,Value1,,3456,qwe,Value1
4567,Value3,,4567,mnb,Value1
I'm trying the following code:
Function InsertColumnInBetweenColumns
{
Param ($FirstFileFirstColumnTitle, $firstFile, [string]$1stColumnName, [string]$2ndColumnName, [string]$columnMergedFileBeforeInput)
Write-Host "Creating hash table with columns values `"$1stColumnName`" `"$2ndColumnName`" From $OimFileWithMatches"
$hashFirstFileTwoColumns = #{}
Import-Csv $firstFile | ForEach-Object {$hashFirstFileTwoColumns[$_.$1stColumnName] = $_.$2ndColumnName}
Write-Host "Complete."
Write-Host "Appending Merge file with column `"$2ndColumnName`" from file $secondCsvFileWithLocalPath"
Import-Csv $outputCsvFileWithLocalPath | Select-Object $columnMergedFileBeforeInput, #{n=$2ndColumnName; e={
if ($hashFirstFileTwoColumns.ContainsKey($_.$FirstFileFirstColumnTitle)) {
$hashFirstFileTwoColumns[$_.$FirstFileFirstColumnTitle]
} Else {
'Not Found'
}}}, * | Export-Csv "$outputCsvFileWithLocalPath-temp" -NoType -Force
Move-Item "$outputCsvFileWithLocalPath-temp" $outputCsvFileWithLocalPath -Force
Write-Host "Complete."
Write-Host ""
}
This function will be called in a for loop for each column found in the first file (can contain an indefinite number). For testing, I am only using 2 columns from the first file.
I'm getting an error output resulting the following:
Select : Property cannot be processed because property "firstName" already exists.
At C:\Scripts\Tests\Compare2CsvFilesOutput1WithMatchesOnly.ps1:490 char:43
+ Import-Csv $outputCsvFileWithLocalPath | Select $columnMergedFileBeforeInput, # ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (#{firstName=L...ntName=asdfas}:PSObject) [Select-Object], PSArgume
ntException
+ FullyQualifiedErrorId : AlreadyExistingUserSpecifiedPropertyNoExpand,Microsoft.PowerShell.Commands.SelectObjectC
ommand
I know the issue is where it says Select-Object $columnMergedFileBeforeInput,.
How can I get the loop statement to insert the column in between the before column (name is specified), and append the rest using *?
Update
Just an fyi, changing this line Select-Object $columnMergedFileBeforeInput, #{n=$2ndColumnName..... to this line Select-Object #{n=$2ndColumnName..... works, it just attaches the columns out of order. That is why I'm trying to insert the column in between. Maybe if i do it this way but insert the columns in backwards using the for loop, this would work...
Not sure if this is the most efficient way to do it, but it should do the trick. It just adds the property to the record from file2, then reorders the output so secondName is the second column. You can output results to csv where required too (ConvertTo-Csv).
$file1 = Import-Csv -Path file1.csv
$file2 = Import-Csv -Path file2.csv
$results = #()
ForEach ($record In $file2) {
Add-Member -InputObject $record -MemberType NoteProperty -Name secondName -Value $($file1 | ? { $_.firstName -eq $record.firstName } | Select -ExpandProperty secondName)
$results += $record
}
$results | Select-Object -Property firstName,secondName,fileSplitter,Csv2ColumnOne,Csv2ColumnTwo,Csv2ColumnThree
I've created the following function. What it does is find the match (in this case "firstname") and adds the matching columnname to the new array afther the columnname on which the match is made (little difficult to explain in my poor English).
function Add-ColumnAfterMatchingColumn{
[CmdletBinding()]
param(
[string]$MainFile,
[string]$MatchingFile,
[string]$MatchColumnName,
[string]$MatchingColumnName
)
# Import data from two files
$file1 = Import-Csv -Path $MainFile
$file2 = Import-Csv -Path $MatchingFile
# Find column names and order them
$columnnames = $file2 | gm | where {$_.MemberType -like "NoteProperty"} | Select Name | %{$_.Name}
[array]::Reverse($columnnames)
# Find $MatchColumnName index and put the $MatchingColumnName after it
$MatchColumnNameIndex = [array]::IndexOf($columnnames, $MatchColumnName)
if($MatchColumnNameIndex -eq -1){
$MatchColumnNameIndex = 0
}
$columnnames = $columnnames[0..$MatchColumnNameIndex] + $MatchingColumnName + $columnnames[($MatchColumnNameIndex+1)..($columnnames.Length -1)]
$returnObject = #()
foreach ($item in $file2){
# Find corresponding value MatchingColumnName in $file1 and add it to the current item
$item | Add-Member -Name "$MatchingColumnName" -Value ($file1 | ?{$_."$($MatchColumnName)" -eq $item."$($MatchColumnName)"})."$MatchingColumnName" -MemberType NoteProperty
# Add current item to the returnObject array, in the correct order
$newItem = New-Object psobject
foreach ($columnname in [string[]]$columnnames){
$newItem | Add-Member -Name $columnname -Value $item."$columnname" -MemberType NoteProperty
}
$returnObject += $newItem
}
return $returnObject
}
When you run this function you will have the following output:
Add-ColumnAfterMatchingColumn -MainFile C:\Temp\file1.csv -MatchingFile C:\Temp\file2.csv -MatchColumnName "firstname" -MatchingColumnName "secondname" | ft
firstName secondname fileSplitter Csv2ColumnTwo Csv2ColumnThree Csv2ColumnOne
--------- ---------- ------------ ------------- --------------- -------------
1234 Value1 abc Value1 1234
1234 Value1 asd Value1 1234
3456 Value1 qwe Value1 3456
4567 Value3 mnb Value1 4567

Format display in powershell

I have a csv file with the following information:
OS Name: Microsoft© Windows Server© 2008 Standard
OS Version: 6.0.6002 Service Pack 2 Build 6002
System Manufacturer: IBM
System Model: IBM 3850 M2 / x3950 M2 -[7233Z1H]-
I need to use powrshell to read and format the display.. My existing code is this:
$Array = #()
Get-Content <txtfilename> | foreach {
$Test = $_
$Title = $Test.split(":")[0]
$Content = $Test.split(":")[1]
$Obj = New-Object System.Object
$Obj | Add-Member -MemberType NoteProperty -value $Title -Name Title
$Obj | Add-Member -MemberType NoteProperty -value $Content -Name Value
$Array += $Obj
}
$Array | Select Title,Value | Export-Csv <csvfilename> -NoTypeInformation
It displays the information as follows listed:
Title Content
OS Name Microsoft? Windows Server? 2008 Standard
OS Version 6.0.6002 Service Pack 2 Build 6002
System Manufacturer IBM
System Model IBM 3850 M2 / x3950 M2 -[7233Z1H]-
I need the information displayed in a single line like this:
ServerName, OS Name , OS Version, System Manufacture, Sytem model,
TestServer1, Microsoft Windows, 6.0.6002 Service Pack 2, IBM, IBM 3850
Thanks
Here's a second answer for the more advanced case, where you don't know how many unique headers you have or what they're called. As long as they're consistently the same and in the same order, the following will work:
$filePath = "C:\users\chris\desktop\info.txt"
$headers = #()
[int]$headerCount = 0
$endUnique = $false
Get-Content $filePath | % {
$header = ($_.split(':')[0] -replace '\s+', ' ').Trim()
if (($headers -notcontains $header) -and (!$endUnique)){
$headers += $header
$headerCount += 1
}
else{
$endUnique = $true
}
}
$headerRow = ""
$headers | % {$headerRow += $_ + ","}
$headerRow = $headerRow.Substring(0,$headerRow.Length-1)
[int]$i = 1
$outString = ""
Get-Content $filePath | % {
$lineContent = ($_.split(':')[1] -replace '\s+', ' ').Trim()
if ($i -lt $headerCount){
$outstring += $linecontent + ','
$i += 1
}
else{
$outstring += $linecontent + "`r`n"
$i = 1
}
}
$outstring = $headerRow+ "`r`n"+$outstring
I'd like to see the other answers from more advanced PowerShell users.
First, just a quick correction. You say you have a CSV. It looks like you have a formatted text file and you want to make a CSV out of it.
Following that assumption, something like this should get you started. It assumes that the text document has either only those 4 items in it, or those 4 items are repeated multiple times - always in the same order, and without a space in between them. Reformatting text files is never fun without a bunch of examples of how they could look.
That being said, the following should get you started.
[int]$i = 1
$outString = ""
Get-Content C:\users\chris\desktop\info.txt | % {
#Take the line, remove the title, remove whitespaces from inside of the line and trim whitespaces from the outside.
$lineContent = ($_.split(':')[1] -replace '\s+', ' ').Trim()
#Chunk them together...
if ($i -lt 4){
$outstring += $linecontent + ','
$i += 1
}
#or insert a return, new line
else{
$outstring += $linecontent + "`r`n"
$i = 1
}
}
#Add a header row. Now $outstring is your CSV formatted text.
$outstring = "OSName,OSVersion,SystemMfg,SystemModel`r`n"+$outstring
$object = New-Object System.Object
Get-Content TestServer1-OSInfo.txt | % {
If($_.Contains(":")){
$Left = $_.split(":")[0].TrimStart().TrimEnd()
$Right = $_.split(":")[1].TrimStart().TrimEnd()
$object | Add-Member -type NoteProperty -name $Left -value $Right
}
}
$object | Export-Csv TestServer1-OSInfo.csv -NoTypeInformation