I wrote this one without the variable while figuring out how to go about doing what I needed:
#Variables
$replace='2.55'
$filepath= 'C:\folder\path\bond.out'
#go straight to the line I want to change something in
$data = Get-Content $filepath | select -skip 38 -first 1
#split it all, find the other variable and overwrite it
$split=$data.split("{|}")
$split[3]=$replace
#put it all back again
$join = $split -join "|"
write-output $join
This works perfectly.
I then changed the "$data" line to select the variable instead:
#Variables
$replace='2.55'
$filepath= 'C:\folder\path\bond.out'
#find the variable
$data = Get-Content $filepath | select-string $bond
#split it all, find the other variable and overwrite it
$split=$data.split("{|}")
$split[3]=$replace
#put it all back again
$join = $split -join "|"
write-output $join
Now I get the below error:
I understand the second error block is because the first error block occurred, but don't understand why it now doesn't work at all?
As others have said, Select-String outputs a MatchInfo, not a String. Also, you don't need Get-Content with Select-String. It does that for you already.
Try this:
$data = Select-String -Path $filepath -Pattern $bond | Select-Object -ExpandProperty Line
Related
I have a PowerShell script that creates a csv file and neatly separates all user input. I need the remaining output to be split across the two headers and I'm struggling to find out how. Tried lots of different code but had no luck.
$Devices = read-host -Prompt "Enter Full Device Name" | out-file 'C:\Users\Public\Desktop\Devices.csv' -Force
$Find = ", "
$Replace = "`n"
$Arrange = (Get-Content 'C:\Users\Public\Desktop\Devices.csv') -replace "$Find","$Replace" | Set-Content 'C:\Users\Public\Desktop\Devices.csv' -Force
$CSV = import-csv 'C:\Users\Public\Desktop\Devices.csv' -Header "Firstname","Lastname"
$CSV | Export-Csv -NoTypeInformation 'C:\Users\Public\Desktop\Devices.csv'
$import = Import-Csv 'C:\Users\Public\Desktop\Devices.csv'
This is the output I currently have in the CSV:
This is the output I am after:
Could almost do with a foreach loop as the first and last names are likely to change as these are inputted using a variable
any help is appreciated.
Export-Csv exports 1 column per distinct property of the input - so to get 2 columns, you need to pipe an object with 2 properties to Export-Csv.
# read device names, split into individual strings
$devices = Read-Host -Prompt "Enter Full Device Name(s)"
$devices = $devices -split ',\s*' |ForEach-Object Trim
# now create one object per device name
$records = $devices |ForEach-Object {
# start by splitting the string into 2 on the first `-`
$FirstName,$LastName = $_ -split '-',2
# now create the object
[pscustomobject]#{
FirstName = $FirstName
LastName = $LastName
}
}
# ... and finally, export to CSV
$records |Export-Csv 'C:\Users\Public\Desktop\Devices.csv' -NoTypeInformation
If you want to retain the - as part of the FirstName value, change this line:
$FirstName,$LastName = $_ -split '-',2
to:
$FirstName,$LastName = $_ -split '(?<=-)',2
Try this out. Since I don't know what your input file looks like there might be some redundant steps in there. Feel free to modify the code to remove any redundant lines if you feel like.
$Devices = read-host -Prompt "Enter Full Device Name" | out-file 'C:\Users\Public\Desktop\Devices.csv' -Force
$Find = ", "
$Replace = "`n"
$Arrange = (Get-Content 'C:\Users\Public\Desktop\Devices.csv') -replace "$Find","$Replace" | Set-Content 'C:\Users\Public\Desktop\Devices.csv' -Force
$CSV = import-csv 'C:\Users\Public\Desktop\Devices.csv' -Header "Firstname","Lastname"
$X = $CSV | select -Skip 1
$y = $x -replace '-','-,' # this adds a comma so that the values are in different columns
$y | Export-Csv -NoTypeInformation 'C:\Users\Public\Desktop\Devices.csv'
$import = Import-Csv 'C:\Users\Public\Desktop\Devices.csv' -Header "Firstname","Lastname"
I am using the following script that iterates through hundreds of text files looking for specific instances of the regex expression within. I need to add a second data point to the array, which tells me the object the pattern matched in.
In the below script the [Regex]::Matches($str, $Pattern) | % { $_.Value } piece returns multiple rows per file, which cannot be easily output to a file.
What I would like to know is, how would I output a 2 column CSV file, one column with the file name (which should be $_.FullName), and one column with the regex results? The code of where I am at now is below.
$FolderPath = "C:\Test"
$Pattern = "(?i)(?<=\b^test\b)\s+(\w+)\S+"
$Lines = #()
Get-ChildItem -Recurse $FolderPath -File | ForEach-Object {
$_.FullName
$str = Get-Content $_.FullName
$Lines += [Regex]::Matches($str, $Pattern) |
% { $_.Value } |
Sort-Object |
Get-Unique
}
$Lines = $Lines.Trim().ToUpper() -replace '[\r\n]+', ' ' -replace ";", '' |
Sort-Object |
Get-Unique # Cleaning up data in array
I can think of two ways but the simplest way is to use a hashtable (dict). Another way is create psobjects to fill your Lines variable. I am going to go with the simple way so you can only use one variable, the hashtable.
$FolderPath = "C:\Test"
$Pattern = "(?i)(?<=\b^test\b)\s+(\w+)\S+"
$Results =#{}
Get-ChildItem -Recurse $FolderPath -File |
ForEach-Object {
$str = Get-Content $_.FullName
$Line = [regex]::matches($str,$Pattern) | % { $_.Value } | Sort-Object | Get-Unique
$Line = $Line.Trim().ToUpper() -Replace '[\r\n]+', ' ' -Replace ";",'' | Sort-Object | Get-Unique # Cleaning up data in array
$Results[$_.FullName] = $Line
}
$Results.GetEnumerator() | Select #{L="Folder";E={$_.Key}}, #{L="Matches";E={$_.Value}} | Export-Csv -NoType -Path <Path to save CSV>
Your results will be in $Results. $Result.keys contain the folder names. $Results.Values has the results from expression. You can reference the results of a particular folder by its key $Results["Folder path"]. of course it will error if the key does not exist.
I need to concatenate multiple text files (skipping the headers) into one big file using PowerShell. Currently I'm using this command:
Get-Content *.txt |
Select-String -Pattern "^[1-9]" |
Select-Object line |
Export-Csv mybigfile.txt
I now have two issues:
How to define the end of line? It will automatically use CRLF and I need only LF like in the source files.
How to remove double quotes? It will automatically add double quotes around each line and around columns that are already double quoted in the source files.
Example:
Source input:
h1,h2,h3,h4
3145,"blabla",4568,""LF
Current output:
"3145,""blabla"",4568,""""CRLF
Desired output:
3145,"blabla",4568,""LF
PowerShell cmdlets use the system's default line terminator (CR-LF), so they can't do what you want. Use a StreamWriter instead:
$reader = New-Object IO.StreamReader 'C:\path\to\input.txt'
$writer = New-Object IO.StreamWriter ('C:\path\to\output.txt', $true)
# override default line terminator
$writer.NewLine = "`n"
# skip first line of input file
if ($reader.Peek() -ge 0) {
$reader.ReadLine() | Out-Null
}
while ($reader.Peek() -ge 0) {
$writer.WriteLine($reader.ReadLine())
}
$reader.Close(); $reader.Dispose()
$writer.Close(); $writer.Dispose()
Use the Get-ChildItem cmdlet with the -Filter parameter to retrieve all text files, load the content using Get-Content and skip the first line using the Select-Object cmdlet and the -skip parameter.
You then have a string array which you can join together by LF and finally write the file using the Out-File cmdlet:
$output = Get-ChildItem 'your_path_here' -Filter '*.txt' | Foreach { $_ | Get-Content | Select -Skip 1 }
$output -join "`n" | out-file 'mybigfile.txt'
I have a text file containing some data as follows:
test|wdthe$muce
check|muce6um#%
How can I check for a particular string like test and retrieve the text after the | symbol to a variable in a PowerShell script?
And also,
If Suppose there is variable $from=test#abc.com and how to search the file by splitting the text before "#" ?
this may be one possible solution
$filecontents = #'
test|wdthe$muce
check|muce6um#%
'#.split("`n")
# instead of the above, you would use this with the path of the file
# $filecontents = get-content 'c:\temp\file.txt'
$hash = #{}
$filecontents | ? {$_ -notmatch '^(?:\s+)?$'} | % {
$split = $_.Split('|')
$hash.Add($split[0], $split[1])
}
$result = [pscustomobject]$hash
$result
# and to get just what is inside 'test'
$result.test
*note: this may only work if there is only one of each line in the file. if you get an error, try this other method
$search = 'test'
$filecontents | ? {$_ -match "^$search\|"} | % {
$_.split('|')[1]
}
First you need to read the text from the file.
$content = Get-Content "c:\temp\myfile.txt"
Then you want to grab the post-pipe portion of each matching line.
$postPipePortion = $content | Foreach-Object {$_.Substring($_.IndexOf("|") + 1)}
And because it's PowerShell you could also daisy-chain it together instead of using variables:
Get-Content "C:\temp\myfile.txt" | Foreach-Object {$_.Substring($_.IndexOf("|") + 1)}
The above assumes that you happen to know every line will include a | character. If this is not the case, you need to select out only the lines that do have the character, like this:
Get-Content "C:\temp\myfile.txt" | Select-String "|" | Foreach-Object {$_.Line.Substring($_.Line.IndexOf("|") + 1)}
(You need to use the $_.Line instead of just $_ now because Select-String returns MatchInfo objects rather than strings.)
Hope that helps. Good luck.
gc input.txt |? {$_ -match '^test'} |% { $_.split('|') | select -Index 1 }
or
sls '^test' -Path input.txt |% { $_.Line.Split('|') | select -Index 1 }
or
sls '^test' input.txt |% { $_ -split '\|' | select -Ind 1 }
or
(gc input.txt).Where{$_ -match '^test'} -replace '.*\|'
or
# Borrowing #Anthony Stringer's answer shape, but different
# code, and guessing names for what you're doing:
$users = #{}
Get-Content .\input.txt | ForEach {
if ($_ -match "(?<user>.*)\|(?<pwd>.*)") {
$users[$matches.user]=$matches.pwd
}
}
$users = [pscustomobject]$users
I have a tab delimited file that has 10k+ rows. I need to change a specific field of the first(header) record to a specific value..
I am using the following script, but it messes up the format.
$contents = Get-Content $PATH -Delimiter "`t"
$contents[1] = 'Replaced Text'
$contents | Out-File $PATH
I can see that the format will mess up, but i am not sure how to keep the file exactly as it is and just change what I need to.
Also, I would like to know if there is an efficient way.. Because i am just concerned with the first line of the file.
I tried a different approach, it works "ok" but introduces extra blank lines after each line:
$content = Get-Content $PATH -Delimiter "`n"
$content |
ForEach-Object {
if ($_.ReadCount -le 1) {
$_ -replace 'A','B'
} else {
$_
}
} |
Set-Content $PATH
One option:
$content = {Get-Content $PATH}.Invoke()
$content[0].Replace('A','B') | Set-Content $PATH
$content.RemoveAt(0)
$content | Add-Content $PATH
Using .invoke() on the script block causes Get-Content to return a collection rather than an array, which simplifies removing the first element.