Passing string included : signs to -Replace Variable in powershell script - string

$FilePath = 'Z:\next\ResourcesConfiguration.config'
$oldString = 'Z:\next\Core\Resources\'
$NewString = 'G:\PublishDir\next\Core\Resources\'
Any Idea how can you replace a string having : sign in it. I want to change the path in a config file. Simple code is not working for this. tried following
(Get-Content $original_file) | Foreach-Object {
$_ -replace $oldString, $NewString
} | Set-Content $destination_file

The Replace operator takes a regular expression pattern and '\' is has a special meaning in regex, it's the escape character. You need to double each backslash, or better , use the escape method:
$_ -replace [regex]::escape($oldString), $NewString
Alterntively, you can use the string.replace method which takes a string and doesn't need a special care:
$_.Replace($oldString,$NewString)

Try this,
$oldString = [REGEX]::ESCAPE('Z:\next\Core\Resources\')
You need escape the pattern to search for.

This works:
$Source = 'Z:\Next\ResourceConfiguration.config'
$Dest = 'G:\PublishDir\next\ResourceConfiguration.config'
$RegEx = "Z:\\next\\Core\\Resources"
$Replace = 'G:\PublishDir\next\Core\Resources'
(Get-Content $FilePath) | Foreach-Object { $_ -replace $RegEx,$Replace } | Set-Content $Dest
The reason that your attempt wasn't working is that -replace expects it's first parameter to be a Regular Expression. Simply put, you needed to escape the backslashes in the directory path, which is done by adding an additional backspace (\\). It expects the second parameter to be a string, so no changes need to be done there.

Related

Manipulate strings in a txt file with Powershell - Search for words in each line containing "." and save them in new txt file

I have a text file with different entries. I want to manipulate it to filter out always the word, containing a dot (using Powershell)
$file = "C:\Users\test_folder\test.txt"
Get-Content $file
Output:
Compass Zype.Compass 1.1.0 thisisaword
Pomodoro Logger zxch3n.PomodoroLogger 0.6.3 thisisaword
......
......
......
Bla Word Program.Name 1.1.1 this is another entry
As you can see, in all lines, the "second" "word" contains a dot, like "Program.Name".
I want to create a new file, which contains just those words, each line one word.
So my file should look something like:
Zype.Compass
zxch3n.PomodoroLogger
Program.Name
What I have tried so far:
Clear-Host
$folder = "C:\Users\test_folder"
$file = "C:\Users\test_folder\test.txt"
$content_txtfile = Get-Content $file
foreach ($line in $content_textfile)
{
if ($line -like "*.*"){
$line | Out-File "$folder\test_filtered.txt"
}
}
But my output is not what I want.
I hope you get what my problem is.
Thanks in advance! :)
Here is a solution using Select-String to find sub strings by RegEx pattern:
(Select-String -Path $file -Pattern '\w+\.\w+').Matches.Value |
Set-Content "$folder\test_filtered.txt"
You can find an explanation and the ability to experiment with the RegEx pattern at RegEx101.
Note that while the RegEx101 demo also shows matches for the version numbers, Select-String gives you only the first match per line (unless argument -AllMatches is passed).
This looks like fixed-width fields, and if so you can reduce it to this:
Get-Content $file | # Read the file
%{ $_.Substring(29,36).Trim()} | # Extract the column
?{ $_.Contains(".") } | # Filter for values with "."
Set-Content "$folder\test_filtered.txt" # Write result
Get-content is slow and -like is sometimes slower than -match. I prefer -match but some prefer -like.
$filename = "c:\path\to\file.txt"
$output = "c:\path\to\output.txt"
foreach ($line in [System.IO.File]::ReadLines($filename)) {
if ($line -match "\.") {
$line | out-file $output -append
}
}
Otherwise for a shorter option, maybe
$filename = "c:\path\to\file.txt"
$output = "c:\path\to\output.txt"
Get-content "c:\path\to\file.txt" | where {$_ -match "\.") | Out-file $output
For other match options that are for the first column, either name the column (not what you do here) or use a different search criteria
\. Means a period anywhere seein the whole line
If it's all periods and at the beginning you can use begining of line so..
"^\." Which means first character is a period.
If it's always a period before the tab maybe do an anything except tab period anything except tab or...
"^[^\t]*\.[^\t]*" this means at the start of the line anything except tab any quantity then a period then anything except a tab any number of times.

How do I insert chars at multiple places in a string?

I want to insert ":" after every second character - the end result should look like this 51:40:2e:c0:11:0b:3e:3c.
My solution
$s = "51402ec0110b3e3c"
for ($i = 2; $i -lt $s.Length; $i+=3)
{
$s.Insert($i,':')
}
Write-Host $s
returns
51:402ec0110b3e3c
51402:ec0110b3e3c
51402ec0:110b3e3c
51402ec0110:b3e3c
51402ec0110b3e:3c
51402ec0110b3e3c
Why is $s being returned multiple times when I only put Write-Host at the very end? Also, it looks like $s keeps returning to its original value after every loop, overwriting the previous loops...
I would've thought that the loop accomplishes the same as this:
$s = $sInsert(2,':').Insert(5,':').Insert(8,':').Insert(11,':').Insert(14,':').Insert(17,':').Insert(20,':')
You can also do this without looping via the -replace operator:
$s = "51402ec0110b3e3c"
$s = $s -replace '..(?!$)','$0:'
A combination of -split and -join works too:
$s = "51402ec0110b3e3c"
$s = $s -split '(..)' -ne '' -join ':'
This is because insert returns a new string. It does not modify inplace. So you have to change
$s.Insert($i,':')
to
$s = $s.Insert($i,':')
an alternate method for converting a hex string to a colon-delimited string is to use the -split operator with a pattern that specifies two consecutive characters. this ...
$s = "51402ec0110b3e3c"
($s -split '(..)').Where({$_}) -join ':'
... will give this = 51:40:2e:c0:11:0b:3e:3c.
the .Where() filters out the blank entries the split leaves behind. [grin]
take care,
lee

Replacing a set of strings containing any character

Is there a way to replace a set of string no matter what the string contains?
I am trying to replace one string containing: quotes(""), brackets([]), #, e.
gci C:\test *.txt -recurse | ForEach {(Get-Content $_ | ForEach {$_ -replace '"my"', "money"}) | Set-Content $_ }
but what if a string I want to replace has EVERYTHING in <>:
PowerPlayReport Product_version="10.2.6100.36" xmlns="http://www.cognos.com/powerplay/report[1234#1]" Author="PPWIN" Version="4.0"
So you want to replace everything in [] in the sample text you included in your question. If you were not aware ( although I think you are now ) -replace supports regular expressions. A simple regex can find the text you are looking for. I am also going remove some of the redundancy in your code.
Get-ChildItem C:\test -Filter *.txt -Recurse | ForEach-Object{
$file = $_.FullName
(Get-Content $file) -replace "\[.*?]","[bagel]" | Set-Content $file
}
Explanation borrowed from regex101.com
\[ matches the character [ literally
.*? matches any character (except newline). Quantifier: *? Between zero and unlimited times, as few times as possible, expanding as needed [lazy]
] matches the character ] literally
So that line would then appear as the following inside the source file.
PowerPlayReport Product_version="10.2.6100.36" xmlns="http://www.cognos.com/powerplay/report[bagel]" Author="PPWIN" Version="4.0"

Specifying certain characters for powershell script to run on

This may be a complete shot in the dark, I have done some research and can't seem to find anything on this. But anythings possible with powershell I guess!
I asked a question earlier here! on how to change certain characters in a script.
$infopath = Get-ChilItem "C:\Users\X\Desktop\Info\*.txt" -Recurse
$infopath | %{
(gc $_) -replace "bs", "\" -replace "fs", "/" -replace "co", ":" -replace ".name", "" | Set-Content $_.fullname
However there are some parts of the text file, that may contain bs, fs or co, that I don't want changing. Therefore what I would like to do, is add some sort of parameter into this existing script that only changes the text in the last 70 characters, or after the 4th # or after the 78th character.
Like I said, this could well be a ridiculous idea, but I would like to see other peoples views.
Any help greatly appreciated!
Using your suggestion of getting the substring after the 78th character, I've created the following using 78 as the starting point. This leaves the first 78 characters unedited, and replaces the given strings after the 78th character. The whole file is replaced with the output.
$infopath = Get-ChilItem "C:\Users\X\Desktop\Info\*.txt" -Recurse
$startpos = 78
$infopath | %{
$content = (gc $_);
$content.Substring(0,$startpos)+($content.Substring($startpos,$content.Length-$startpos) -replace "bs", "\" -replace "fs", "/" -replace "co", ":" -replace ".name", "")|Set-Content $_.fullname
}
I hope this helps.
Thanks, Chris.

Powershell Replace Characters in a String

Using powershell, but open to other potential solutions....
I have a long string. I need to replace several sequences of characters by position in that string with a mask character (period or space). I don't know what those characters are going to be, but I know they need to be something else. I have written code using mid and iterating through the string using mid and position numbers, but that is a bit cumbersome and wondering if there is a faster/more elegant method.
Example:
Given the 2 strings:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
12345678901234567890123456
I want to replace characters 2-4, 8-9, 16-22, & 23 with ., yielding:
A...EFGH..KLMNOP.....VWX.Z
1...5678..123456.....234.6
I can do that with a series of MID's, but I was just wanting to know if there were some sort of faster masking function to make this happen. I have to do this through millions of rows and second count.
Try this:
$regex = [regex]'(.).{3}(.{4}).{2}(.{6}).{5}(.{3}).(.+)'
$replace = '$1...$2..$3.....$4.$5'
('ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'12345678901234567890123456') -Replace $regex,$replace
A...EFGH..KLMNOP.....VWX.Z
1...5678..123456.....234.6
The -replace operator is slower than string.replace() for a single operation, but has the advantage of being able to operate on an array of strings, which is faster than the string method plus a foreach loop.
Here's a sample implementation (requires V4):
$regex = [regex]'(.).{3}(.{4}).{2}(.{6}).{5}(.{3}).(.+)'
$replace = '$1...$2..$3.....$4.$5'
filter fix-file {
$_ -replace $regex,$replace |
add-content "c:\mynewfiles\$($file.name)"
}
get-childitem c:\myfiles\*.txt -PipelineVariable file |
get-content -ReadCount 1000 | fix-file
If you want to use the mask method, you can generate $regex and $replace from that:
$mask = '-...----..------.....---.-'
$regex = [regex]($mask -replace '(-+)','($1)').replace('-','.')
$replace =
([char[]]($mask -replace '-+','-') |
foreach {$i=1}{if ($_ -eq '.'){$_} else {'$'+$i++}} {}) -join ''
$regex.ToString()
$replace
(.)...(....)..(......).....(...).(.)
$1...$2..$3.....$4.$5
Here another approach:
C:\PS> $mask ="-...----..------.....---.-"
C:\PS> ([char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ' | % {$i=0}{if ($mask[$i++] -eq '-') {$_} else {'.'}}) -join ''
A...EFGH..KLMNOP.....VWX.Z
And if we are going to take advantage of V4 features :-), try this:
C:\PS> $i=0;([char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ').Foreach({if ($mask[$i++] -eq '-') {$_} else {'.'}}) -join ''
Here yet another approach:
C:\PS> $mask = "{0}...{4}{5}{6}{7}..{10}{11}{12}{13}{14}{15}.....{21}{22}{23}.{25}"
C:\PS> $singlecharstrings = [string[]][char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
C:\PS> $mask -f $singlecharstrings
A...EFGH..KLMNOP.....VWX.Z

Resources