Powershell to reformat the file content - powershell

I have a script which gets content from one file and checks for its ip. Then that is added to some other text file.
[System.Collections.ArrayList]$hlist1 = Get-Content -Path "C:\Timezone\Update\host.txt"
$hiplist = New-Object System.Collections.ArrayList
$hlist2 = New-Object System.Collections.ArrayList
ForEach ($h in $hlist1)
{
$hip = Resolve-DnsName $h
$hiplist.Add($hip)
}
$hiplist | Out-File "C:\Timezone\Update\hiplist.txt"
The file which is getting created is as shown below:
---- ---- --- ------- --------
WIN-JB2A2FS84MQ.domain.com A 1200 Answer 10.3.0.4
8
WIN-QP0BH4SD2H9.domain.com A 1200 Answer 10.3.1.1
9
I need to:
get rid of the first -------- lines.
get the entire ip in the same line (10.3.0.10)
Have tried Format-Table -Autosize, then Select -Skip 1 etc, but no luck.
How can this be achieved.? Please note that the code works fine as expected when it is ran manually, but throws this issue when executed using task scheduler.
Edit Based on Matt's answer
Now the text file contains:
"Address","IPAddress","QueryType","IP4Address","Name","Type","CharacterSet","Section","DataLength","TTL"
"10.3.0.48","10.3.0.48","A","10.3.0.48","WIN-JB2A2FS84MQ.domain.com","A","Unicode","Answer","4","1200"
"10.3.1.19","10.3.1.19","A","10.3.1.19","WIN-QP0BH4SD2H9.domain.com","A","Unicode","Answer","4","1200"
Peter-sal's reply output:
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
WIN-JB2A2FS84MQ.domain.com A 1200 Answer 10.3.0.48
WIN-QP0BH4SD2H9.domain.com A 1200 Answer 10.3.1.19
But again on top of Name there's one space. I need to delete everything present before WIN-JB2.....

I cannot test perfectly but I would like to come back to an earlier comment of mine. Resolve-DNSName returns objects so their output is better destined for something object aware. Export-CSV should be preferable here.
$hlist1 = Get-Content -Path "C:\Timezone\Update\host.txt"
$hlist1 | ForEach-Object{Resolve-DnsName $_} |
Export-Csv "C:\Timezone\Update\hiplist.txt" -NoTypeInformation
I normally don't like this but if you prefer you should be able to use the Format-table output now. This seems to be more inline with what you are looking for.
$hlist1 = Get-Content -Path "C:\Timezone\Update\host.txt"
$hlist1 | ForEach-Object{Resolve-DnsName $_} |
Format-Table -HideTableHeaders | Select-Object -Skip 1 |
Out-File "C:\Timezone\Update\hiplist.txt" -Width 200
Perhaps you prefer that output. The header should be removed now as well as a blank line in the beginning.
That creates some white-space before and after the output. Simple solution is to wrap that up in a Trim()
$hlist1 = Get-Content -Path "C:\Timezone\Update\host.txt"
$results = ($hlist1 | ForEach-Object{Resolve-DnsName $_} |
Format-Table -HideTableHeaders |
Out-string).Trim()`
$results | Out-File "C:\Timezone\Update\hiplist.txt" -Width 200`

Related

Powershell Array to export-csv shows System.Object[]

Having a simple issue that's only affecting export-csv output, out-gridview and results to the console are fine. Looking to capture the top 5 processes by "handles" on a set of servers.
Code is as follows:
$Servers = "Server1", "Server2", "Server3"
$OutArray = #()
ForEach ($Item in $Servers)
$Top5 = Get-Process -Computer $Item | Sort Handles -descending |Select -First 5
$OutArray += New-Object PSObject -property # {
Server = $Item
Top5 = $Top5
} #OutArray
} #ForEach
$OutArray | Export-csv Test.csv
The results of which come out looking fine via console as follows
Server Top5
------ ----
SERVER1 {#{ProcessName=svchost.exe; PercentCpuLoad=13.79}, #{ProcessName=services.exe; PercentCpuLoad=11.4}, #{ProcessName=WmiPrvSE.exe; PercentCpuLoad=10.03}, #{ProcessName=irfilcol.exe; PercentCpuLoad=9.79}...}
...However, in the csv they show as follows:
Server Top5
Server1 System.Object[]
Server2 System.Object[]
Server3 System.Object[]
I'm thinking it's because the $Top5 variable is an variable with multiple properties (5 each) for one server. How would do I correct the code so that export-csv shows the actual values?
any help appreciated!
I would like the csv results to look like the following that's shown in GRIDVIEW
Using the suggestion from BenH to review the post from Powershell legend Boe Prox, I now have the following working:
$Top5 = Get-Process -Computer $Item | Sort Handles -descending |Select -expand Handles | |Select -First 5
$new = [pscustomobject]#{ Top5 = (#($Top5) -join ',')
}
Just about got this working now:
i'd like to add more piece of formatting, where the Top5Processes have the actual CPU % used in (brackets) right now, I've got the following for output
Top2Proc Top2CPU
services.exe,BESClient.exe 32.76,16.6
However, it would be nicer output-wise, if i could combine the above two values into one, so it looks like this:
Top2Proc
Services(32.76), BesClient.exe(16.6)
Any idea how that would be done?
Use Select-Object to turn your process objects into strings before piping them to Export-Csv:
$OutArray |Select-Object Server,#{Expression={$_.Top5.Name -join ';'}} |Export-Csv test.csv
If you want that table to appear in your csv file then you would need to format the string Top5 property as such. Using Out-String will do just that
Sends objects to the host as a series of strings.
So a simple change should get you what you want.
$Top5 = Get-Process -Computer $Item |
Sort Handles -descending |
Select -First 5 |
Out-String
It will look a little ugly when not displayed with a mono-space font much like you see in Out-GridView. Also consider using .Trim() to remove the leading and trailing whitespace on your $top5.
There are other ways to tackle this. You could use the above in conjunction with Format-Table / Format-List depending what you want. In general if you want the output to be saved as it is displayed in host Out-String is something to test with.
I would have tried to add one row for each process with a the first column being the computer name. That way you would have better structured output that can be sorted or queried as needed.
ComputerName ProcessName Handles
------------ ----------- -------
Computer1 avp 54639
Computer1 OUTLOOK 7708
Computer1 RDTabs 6108
Computer1 svchost 3160
Computer1 chrome 2530
Keep in mind that you can use other methods to export this data while keeping the objects entact. Really depends the data recipeint but remeber there are other cmdlets like Export-CLIMXL and ConvertTo-JSON | Set-Content.

powershell find string in csv get associated cell

Alright I have a csv that i import into variable $csv
name description system redundant
---- ----------- ------ ---------
hi don't settle sight dumb
hello why not settle settle
this just fails why? settle
I want to find a specific string in either $csv.description or $csv.system. If that string is found, i want to return the associated cell value under $csv.name
I can't have the select-string look for anything in $csv.redundant
this is what i have so far:
$csv = import-csv -path c:\hi
$find = $csv | select-string "settle"
output: $find
#{name=hi; description=don't settle; system=sight; redundant=dumb }
#{name=hello; description=why not; system=settle; redundant=settle}
#{name=this; description=just fails; system=why?; redundant=settle}
however - nothing returns if i do a $find.name, even though the $find.gettype() shows that this is an array. Also i don't know how to get the select-string to avoid $csv.redundant
I need the output to only be the $find.name of only the first 2 objects from the array.
thanks
Don't use Select-String, use Where-Object instead:
$searchTerm = 'settle'
$csv |Where-Object {$_.description -match $searchTerm -or $_.system -match $searchTerm} |Select-Object -Expand Name
ipcsv C:\temp\test.csv | ? {$_.description, $_.system -like "*settle*"} | select Name

Powershell Searching within a text file and exporting horizontally to CSV

I have a big file which content somme blocks of text data like this.
[SERVER1]
LIBELLE=DATA, SOMME DATA
VARIABLES=A,B,C,D,E
PHYSICAL NAME=E:\SOMME\PATH\FILE.INI
ARTICLE SIZE=50
MACHINE=SOME SERVER
PARAMETER =
OPTION =
[SERVER2]
LIBELLE=DATA2, SOMME DATA2
VARIABLES=A,B,C,D,E
PHYSICAL NAME=Z:\SOMME\PATH\FILE2.INI
ARTICLE SIZE=150
MACHINE=SOME SERVER XY
PARAMETER =
OPTION 1 = VOID
OPTION 2 =
OPTION 3 =
OPTION 4 =
OPTION 5 =
What i would like to do is retrieving every block [SERVERX] and put it into a CSV file in this format (horizontally)
ColumnA__ | ColumnB (LIBELLE)___ | ColumnC (VARIABLES) | ColumnD ect...
[SERVER1] | DATA1, SOMME DATA1 | A,B,C,D,E___________ | Ect...
[SERVER2] | DATA2, SOMME DATA2 | A,B,C,D,E___________ | Ect...
I've tried this, the output work as i want but it need to be automated and exported to scv, which doesn't work for me.
$mydata = Get-Content my_file.txt
write-Host $mydata[0] $mydata[1] $mydata[2] $mydata[3] $mydata[4] $mydata[5] | Export-Csv -Path $rep\results.csv -Force -UseCulture -NoTypeInformation
Tried also somthing with select-string but i dont know if this is the right way to do my job..
select-String -path $my_file -Pattern '\[*\]', 'IDENTIFIANTS=','LIBELLE=','VARIABLES=' | Select-Object -Property LineNumber, Line | Export-Csv -Path $rep\results.csv -Force -UseCulture -NoTypeInformation
Thanks for your advices.
So, I would read the whole file in as a multi-line string using the -Raw switch for Get-Content. Then split the file up based on the [ character to denote records. The get the properties from the ConvertFrom-StringData cmdlet (have to prepend "SERVER=" to each record), and make an object from it. Then we find out what all properties any given record can have, make sure to add them all to the first record if it doesn't have it (this is done because when you export to CSV it bases the columns off of the first entries' property list). Then you can export a CSV.
$Data = (Get-Content my_file.txt -Raw) -split "(\[[^[]+)" | ?{![string]::IsNullOrWhiteSpace($_)}
$Records = $Data -replace '\\','\\'|%{$Record="SERVER="+$_.trim()|ConvertFrom-StringData;New-Object PSObject -Prop $Record}
$Props = $Records|%{$_.psobject.properties.name}|select -Unique
$Props | Where{$_ -notin $Records[0].PSObject.Properties.Name}|%{Add-Member -InputObject $Records[0] -NotepropertyName $_ -NotepropertyValue $Null}
$Records|Export-CSV .\my_file.csv -notype
Edit: For those of you out there running PowerShell 2.0 (3 versions out of date at this point in time), you can't use the -Raw parameter. Here's the alternative:
$Data = (Get-Content my_file.txt) -Join "`r`n" -split "(\[[^[]+)" | ?{![string]::IsNullOrWhiteSpace($_)}
Alternative: Thanks #Matt for the suggestion, it is always good to have a different point of view on these things. As Matt suggested, you can use Out-String to combine the array of strings that Get-Content generates, and end up with a single multi-line string. Here's the usage!
$Data = (GC my_file.txt | Out-String) -split "(\[[^[]+)" | ?{![string]::IsNullOrWhiteSpace($_)}

Powershell - Creating Wide Tables

Good afternoon!
I am a Powershell novice trying to understand how data output works. I am trying to find the differences between two users in Active Directory. I found a solution that worked (Compare-Object on two AD user accounts), but the data some of in the relevant fields was truncated with an ... which didn't help.
I found a solution which seems very elegant at the bottom of the page here: http://poshoholic.com/2010/11/11/powershell-quick-tip-creating-wide-tables-with-powershell/
I attempted to combine these two into a single script. This is what I have:
$user1 = get-aduser jdoe -Properties *
$user2 = get-aduser jsmith -Properties *
$Usercomparison = #()
$user1.GetEnumerator() | ForEach-Object {
If ($User2.($_.Key) -eq $_.Value)
{
$Comparison = 'Equal'
}
else
{
$Comparison = 'Different'
}
$UserObj = New-Object PSObject -Property ([ordered]#{
Property = $_.Key
User1 = $_.Value
User2 = $User2.($_.Key)
Comparison = $Comparison
})
$UserComparison += $UserObj
}
$UserComparison
| Format-Table -Property * -AutoSize `
| Out-String -Width 4096 `
| Out-File C:\Users\USER\Desktop\differences.txt
This produces an error that "an empty pipe element is not allowed". If I delete a line return to put the first pipe line after the $UserComparison variable...
$UserComparison | Format-Table -Property * -AutoSize `
| Out-String -Width 4096 `
| Out-File C:\aliases.txt
...then the text file is created, but it's badly formatted. Only the first two columns appear in the output and there is a ton of wasted whitespace to the right and several blank line returns after each line... nothing like the example on the website.
Is this because the script I found writes the data to a variable and then just prints the variable on screen instead of using a command that can be output properly? I feel like I have all the pieces that I need, just not in the right configuration to get the output I want.
Thanks!
So, #1 the line:
$UserComparison
| Format-Table -Property * -AutoSize `
| Out-String -Width 4096 `
| Out-File C:\Users\USER\Desktop\differences.txt
Doesn't work because you are first executing
$UserComparison
Which outputs the contents of $UserComparison. Next, you execute
| Format-Table -Property * -AutoSize `
Which errors out because nothing is being piped into Format-Table. The "ticks" ( ` ) at the end of the Format-Table statement is a continue line statement i.e. the second version:
$UserComparison | Format-Table -Property * -AutoSize `
| Out-String -Width 4096 `
| Out-File C:\aliases.txt
Is correct because it will be interpreted as one giant line.
Second question, the reason why you are having issues is because 4096 characters is not enough space to hold everything, and so is truncated. Remember, -AutoSize will calculate the width of the longest item, and make that the width of the column. There are some items that are too long. For ex. For me, the thumbnailPhoto (which happened to be item 140 in my array):
$UserComparison[140]
Gives something like this (truncated depending on width):
Property User1
-------- -----
thumbnailPhoto {255 216 255 224 0 16 74 70 73 70 0 1 1 1 0 96 0...
When I calculate the width of this, it gives me:
#Calculate width of User1
($UserComparison[140].User1 | Out-String).Length
7555
#Calculate width of full field
($UserComparison[140] | Out-String).Length
12297
Yes, User1 is 7,555 characters long. That means that Format-Table -Autosize will make the User1 column at least 7,555 characters wide, which obviously is truncated by the 4,096 width limit that you specified on the Out-String, and then won't display the User2 or Comparison columns. In this case, your Out-String needs to have a width of at least 12,297 wide in order to display the full field.
The workaround is to specify an even bigger width on the Out-String that is guaranteed to be wider, like, say, 50,000 so your code would be:
$UserComparison | Format-Table -Property * -AutoSize `
| Out-String -Width 50000 `
| Out-File C:\Users\USER\Desktop\differences.txt
Now, the downside to doing things this way is that every line in the text file will be the full width of the longest item, and so (in my case) every line will be 12,297 characters long. This makes things harder to read.
Other ways to output things would be to:
Limit things to just displaying the Property and Comparison columns:
$UserComparison | Select Property, Comparison `
| Format-Table -Property * -AutoSize `
| Out-String -Width 4096 `
| Out-File SimpleCompare.txt
Or if you need to see what the full values are, chop each property up into a separate table with a ForEach-Object, and then pass that through so that would be easier to read, and each property is limited to it's specific width:
$UserComparison | Select Property, Comparison, User1, User2 `
| ForEach-Object { $_ | Format-Table -Property * -AutoSize `
| Out-String -Width 50000 `
| Out-File EasyToRead.txt -Append }

Powershell System.Array to CSV file

I am having some difficulty getting an Export-Csv to work. I am creating an array like this...
[pscustomobject] #{
Servername = $_.Servername
Name = $_.Servername
Blk = ""
Blk2 = ""
Method = "RDP"
Port = "3389"
}
The issue I have is when I try to export that to a CSV I get garbage that looks like this...
"9e210fe47d09416682b841769c78b8a3",,,,,
I have read a ton of articles addressing this issue, but I just don't understand how to get the data right.
For testing, I built a CSV file w/ the servernames, and read it in, and the following works in PS4:
$serverList = import-csv "datafile.csv"
$AllObjects = #()
$serverList | ForEach-Object {
$AllObjects += [pscustomobject]#{
Servername = $_.Servername
Name = $_.Servername
Blk = ""
Blk2 = ""
Method = "RDP"
Port = "3389"
}
}
$AllObjects | Export-Csv -Path "outfile.csv" -NoTypeInformation
This happens when you try to pipe out from any of the Format-* commands.
The Format-List, Format-Table and Format-Wide cmdlets are special in PowerShell, in that they're meant to consume the pipeline, and transform it for display in the console. So, you can't pipe from FL, FT or FW into Export-csv. As Don Jones says "Format On the Right".
Don't believe me? Observe, as I run Get-Process, send it through Format-Table and then convert to Csv.
gps | ft | ConvertTo-Csv
#TYPE Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
"ClassId2e4f51ef21dd47e99d3c952918aff9cd","pageHeaderEntry","pageFooterEntry","autosizeInfo","shapeInfo","groupingEntry"
"033ecb2bc07a4d43b5ef94ed5a35d280",,,,"Microsoft.PowerShell.Commands.Internal.Format.TableHeaderInfo",
"9e210fe47d09416682b841769c78b8a3",,,,,
"27c87ef9bbda4f709f6b4002fa4af63c",,,,,
"27c87ef9bbda4f709f6b4002fa4af63c",,,,,
"27c87ef9bbda4f709f6b4002fa4af63c",,,,,
It's even the same string! Why do we get this string? I really wish I knew, but I think it has something to do with the way the Format-* commands convert objects into text instructions for display in the console.
If you REALLY love the way your Format-Table looks, send it to Out-File, which is the only way to redirect the output of a Format-* command.
Another message is to use Tee-Object to dump a copy of your pipe to a variable, and then send that out to Export.
Get-Process | Tee-Object -Variable ExportMe | Format-Table
$exportMe | export-Csv .\Export.csv
I call this the 'have your cake and eat it too approach'.
Use Select-Object to prevent the bad CSV export.
Example:
Get-Services | Select-Object * | export-csv -Path C:\log.csv