Replacing only the first occurrence of a word in a string - powershell

I am having some issues with regular expression mainly because I think the information I can find is not specifically for powershell and all the samples I have tried either error or don't work as intended. I am trying to replace the first occurrence of a word in a string with another word but not replace any other occurrences of that word. for an example take the string:
My name is Bob, her name is Sara.
I would like to replace the first occurrence of name with baby so the resulting string would be
My baby is Bob, her name is Sara.
I have been working in https://regex101.com/ to try to build and see what is selected as I go but as I said none of these have a powershell flavor of regex. In that I can just turn off the global flag and it seems to select the first occurrence but not in powershell. So I am really at a loss of where to begin all really have at this point is selecting all occurrences of the word namewith:
$test = "My name is Bob, her name is Sara."
$test -replace 'name', 'baby'

One way to replace n times:
$test = "My name is Bob, her name is Sara."
[regex]$pattern = "name"
$pattern.replace($test, "baby", 1)
> My baby is Bob, her name is Sara

You could capture everything before and behind and replace it:
'My name is Bob, her name is Sara.' -replace '(.*?)name(.*)', '$1baby$2'

Related

How to rename files with only 1 occurrence? [duplicate]

I am having some issues with regular expression mainly because I think the information I can find is not specifically for powershell and all the samples I have tried either error or don't work as intended. I am trying to replace the first occurrence of a word in a string with another word but not replace any other occurrences of that word. for an example take the string:
My name is Bob, her name is Sara.
I would like to replace the first occurrence of name with baby so the resulting string would be
My baby is Bob, her name is Sara.
I have been working in https://regex101.com/ to try to build and see what is selected as I go but as I said none of these have a powershell flavor of regex. In that I can just turn off the global flag and it seems to select the first occurrence but not in powershell. So I am really at a loss of where to begin all really have at this point is selecting all occurrences of the word namewith:
$test = "My name is Bob, her name is Sara."
$test -replace 'name', 'baby'
One way to replace n times:
$test = "My name is Bob, her name is Sara."
[regex]$pattern = "name"
$pattern.replace($test, "baby", 1)
> My baby is Bob, her name is Sara
You could capture everything before and behind and replace it:
'My name is Bob, her name is Sara.' -replace '(.*?)name(.*)', '$1baby$2'

PowerShell split method on string value

I'm trying to grab a value from a string within my PowerShell script.
The string can come like this:
$TargetOU = "OU=Company Users,OU=Company,OU=Organisation Users,DC=domain,DC=local"
or like this:
$TargetOU = "OU=Company,OU=Organisation Users,DC=domain,DC=local"
Using the following will return "Company" in the first example but "Company,OU" in the second. How Can I modify this to provide just "Company" in both instances?
$TargetOU.Split('= ')[1]
You can achieve this by adding a , to the characters in your split method.
This is because you split your string at every char given to the split method.
Your first string splits to:
OU
Company
Users,OU
Company,OU
Organisation
Users,DC
domain,DC
local
while your second string splits to:
OU
Company,OU
Organisation
Users,DC
domain,DC
local
When using $TargetOU.Split('= ,') instead your second string will split to:
OU
Company
OU
Organisation
Users
DC
domain
DC
local
where the element with index 1 is only "Company", not "Company,OU"
Try this. Given your examples of input this returns "Company" every time.
What it does: saves your split in a variable and checks if that variable contains a comma, as it would if "OU=Company,OU=Organisation Users,DC=domain,DC=local" was your input. If true, split that again at the comma and save the first part in a variable. I used the same variable name as with the first split, since I assume you want to do the same thing with the result later in your script, regardless of how the input looks.
$SplitTargetOU = $TargetOU.Split('= ')[1]
if ($SplitTargetOU -like '*,*')
{
$SplitTargetOU = $SplitTargetOU.Split(',')[0]
}
EDIT: J. Bergmann's answer was a little simpler. Nice one. :)
This answer doesn't work for me. The split method is not treating the characters as a character array. To fix it, I have to explicitly cast it:
"OU=Company Users,OU=Company,OU=Organisation Users,
DC=domain,DC=local".Split('= ,')
returns
OU=Company Users,OU=Company,OU=Organisation Users,DC=domain,DC=local
but
"OU=Company Users,OU=Company,OU=Organisation Users,
DC=domain,DC=local".Split([char[]]'= ,')
returns
OU
Company
Users
OU
Company
OU
Organisation
Users
DC
domain
DC
local

How to grab a portion of an LDAP string into a variable (Powershell)

I am able to get the full LDAP path into a variable $strPath and it will return a result such as:
LDAP://CN=computername,OU=City,OU=Servers,OU=###,DC=dom,DC=ain,DC=com
or in other locations it could look like:
LDAP://CN=computername,OU=Servers,OU=##,DC=dom,DC=ain,DC=com
I want to return only the ##, ### or #### value (it can be either two, three or four characters) which is our district code.
So some computer objects have a city name in their LDAP string while others do not (depending on the size of the district), and the district code can be two, three or four characters long.
I'm guessing I want to do something like find text "Servers,OU=" and remove everything including and before that and also remove text ",DC=dom,DC=ain,DC=com" to get my final variable.
Thanks in advance!
You may be interested in the ADName module I wrote:
https://github.com/Bill-Stewart/PowerShell-ADName
For your first example, the OU code is the 4th element from the right:
LDAP://CN=computername,OU=City,OU=Servers,OU=###,DC=dom,DC=ain,DC=com
So for example, you can write this:
(Get-ADName "LDAP://CN=computername,OU=City,OU=Servers,OU=###,DC=dom,DC=ain,DC=com" -Split -ValuesOnly)[-4]
The -Split parameter splits the LDAP path into an array, and -ValuesOnly omits the CN=, OU=, DC=, etc. The [-4] means "return the 4th element from the end of the array."
How about something like this:
$ldapString = "LDAP://CN=computername,OU=Servers,OU=##,DC=dom,DC=ain,DC=com"
$temp = $ldapString.Split(",=")
$districtCode = $temp[[array]::IndexOf($temp,"DC") - 1]
It works with both and no extra imports. As long as you do not have a district code that is "DC".

Splunk csv to match country code

I'm using splunk but having trouble trying to match first 2 or 3 digits in this:
sample:
messageId=9492947, to=61410428007
My csv looks like this:
to, Country
93, Afghanistan
355, Albania
213, Algeria
61, Australia
I'm trying to push the fields into a CSV and tell me what Country they matched.
I think I need to be doing a regex or something, but i have interesting fields marked in splunk which is "to"
This is one of those messy ones, but it does not require regular expressions. Let's say you have a CSV file with a header - something like:
code,country
92,Afghanistan
355,Albania
214,Algeria
61,Australia
44,United Kingdom
1,United States
You need the header for this. I created an example file, but the source can come from anywhere just as long as you have the to field extracted properly.
source="/opt/testfiles/test-country-code.log"
| eval lOne=substr(to,1,1)
| eval lTwo=substr(to,1,2)
| eval lThree=substr(to,1,3)
| lookup countries.csv code as lOne OUTPUT country as cOne
| lookup countries.csv code as lTwo OUTPUT country as cTwo
| lookup countries.csv code as lThree OUTPUT country as cThree
| eval country=coalesce(cOne,cTwo,cThree)
| table to,country
The substr calls extract one, two or three characters from the start of the string. The lookups convert each of those variables to the country name using the lookup table. The coalesce will take the first one of those with a value.

Determine if string exists in file

I have a list of strings such as:
John
John Doe
Peter Pan
in a .txt file.
I want to make a loop that checks if a certain name exists. However, I do not want it to be true if I search for "Peter" and only "Peter Pan" exists. Each line has to be a full match.
Ha ha, ep0's answer is very sophisticated!
However, you want to use a parsing loop something like this (this example expects that your names are separated by carriage returns). Consider that you have a text file with contents arranged like this:
John
Harry
Bob
Joe
Here is your script:
fileread, thistext, %whatfile% ;get the text from the file into a variable
;Now, loop through each line and see if it matches your results:
loop, parse, thistext, `r`n, `r`n
{
if(a_loopfield = "John")
msgbox, Hey! It's John!
else
msgbox, No, it's %a_loopfield%
}
If your names are arranged in a different order, you might have to either change the delimiter for the parsing loop, or use regex instead of just a simple comparison.
If you want to check for multiple names use a trie. If you have just one name, you can use KMP.
I'll explain this for multiple names you want to check that exist, since for only one, the example provided on Wikipedia is more than sufficient and you can apply the same idea.
Construct the said trie from your names you want to find, and for each line in file, traverse the trie character by character until you hit a final node.
BONUS: trie is used by Aho-Corasick algorithm, which is an extension of KMP to multiple patters. Read about it. It's very worthwhile.
UPDATE:
For checking if a single name exists, hash the name you want to find, then read the text file line by line. For each line, hash it with the same function and compare it to the one you want to find. If they are equal, compare the strings character by character. You need to do this to avoid false positives (see hash collisions)