I am trying to parse a string using [regex]::matches. I am able to split the words but i am having trouble with the open and close paren. Could someone help me and explain what I am doing wrong? Thank you in advanced.
$results = "All domain controllers have migrated successfully to the Global state ('Start')."
[regex]::Matches($results , "\w+['a-z']") | foreach-object {$_.value}
Tweaking #TheMadTechnician's regex just a bit, "\('([^\)']*)'\)" will get the word between (' and '), without the quotes. I use the -match operator below. The result you want will be in the $matches[1] variable.
PS> $results = "All domain controllers have migrated successfully to the Global state ('Start')."
PS> $results -match "\('([^\)']*)'\)"
True
PS> $matches[1]
Start
So, this was the only way I could figure out how to get this. If others are able to give a simpler solution I am all ears. But for now, this is the way I got it to work
([regex]::Matches($results , '\w+[('')^]' ) | foreach-object {$_.value }).replace("'", "")
Related
I have a PowerShell script that imports a CSV file, filters out rows from two columns and then concatenates a string and exports to a new CSV file.
Import-Csv "redirect_and_canonical_chains.csv" |
Where { $_."Number of Redirects" -gt 1} |
Select {"Redirect 301 ",$_.Address, $_."Final Address"} |
Export-Csv "testing-export.csv" –NoTypeInformation
This all works fine however for the $_.Address value I want to strip the domain, sub-domain and protocol etc using the following regex
^(?:https?:\/\/)?(?:[^#\/\n]+#)?(?:www\.)?([^:\/\n]+)
This individually works and matches as I want but I am not sure of the best way to implement when selecting the data (should I use $match, -replace etc) or whether I should do it after importing?
Any advice greatly appreciated!
Many thanks
Mike
The best place to do it would be in the select clause, as in:
select Property1,Property2,#{name='NewProperty';expression={$_.Property3 -replace '<regex>',''}}
That's what a calculated property is: you give the name, and the way to create it.Your regex might need revision to work with PowerShell, though.
I've realized now that I can just use .Replace in the following way :)
Select {"Redirect 301 ",$_.Address.Replace('http://', 'testing'), $_."Final Address"}
Based on follow-up comments, the intent behind your Select[-Object] call was to create a single string with space-separated entries from each input object.
Note that use of Export-Csv then makes no sense, because it will create a single Length column with the input strings' length rather than output the strings themselves.
In a follow-up comment you posted a solution that used Write-Host to produce the output string, but Write-Host is generally the wrong tool to use, unless the intent is explicitly to write to the display only, thereby bypassing PowerShell's output streams and thus the ability to send the output to other commands, capture it in a variable or redirect it to a file.
Here's a fixed version of your command, which uses the -join operator to join the elements of a string array to output a single, space-separated string:
$sampleCsvInput = [pscustomobject] #{
Address = 'http://www.example.org/more/stuff';
'Final Address' = 'more/stuff2'
}
$sampleCsvInput | ForEach-Object {
"Redirect 301 ",
($_.Address -replace '^(?:https?://)?(?:[^#/\n]+#)?(?:www\.)?([^:/\n]+)', ''),
$_.'Final Address' -join ' '
}
Note that , - PowerShell's array-construction operator - has higher precedence than the -join operator, so the -join operation indeed joins all 3 preceding array elements.
The above yields the following string:
Redirect 301 /more/stuff more/stuff2
I have a text file that contains elements separated by an '=' sign (i.e. color1=red, color2=blue, etc.
I used the import-csv command and provide headers (i.e.
$Import_Cfg = Import-Csv .\Env.cfg -Header Title,Setting -Delimiter =
)
Now this works fine if I want to assign a particular item to another variable if I know the index number and I have used that approach but it won't always work for me because I don't always know what other data will be there.
I thought that by using something like:
$MyColor1 = $Import_Cfg.Setting |where {$_.Title -match "Blue"}
$MyColor2 = $Import_Cfg.Setting |where {$_.Title -match "Red"}
it should work, but I get no returns for either item. When I type in $Import_cfg I can see the entire array (without the "=" signs). If I tell use the command
$MyColor1 = $import_cfg[0].setting
I get the right answer.
Obviously I'm not using colors but a bunch of different items that I need to assign to variables for use elsewhere. Any thoughts on what I'm doing wrong? Everything I've read says that what I have above should work.
Please no flames on why I'm using import-csv vs get-content. I'm sure either will work. This is an approach that I've used and computationally it doesn't matter. If programatically it makes a difference I'm all ears!!!
Thanks for all your help.
The value of the Setting property itself has no Title property.
You need to apply Where before you extract the property value you need (as mentioned in the comments):
$BlueSettings = $Import_Cfg |where {$_.Title -match "Blue"} |Select-Object -ExpandProperty Setting
or, using property enumeration:
$BlueSettings = ($Import_Cfg |where {$_.Title -match "Blue"}).Setting
I'm trying to get a script running that maps network drives at login. Generally, I use get-content with | convertfrom-stringdata to put my parameters (drive letter and path) in a hash.
My problem is the following:
net use /persistent:no $driveletter $networkpath
results with an error. When I replace $networkpath with the actual path (\\server\share\folder), it works.
Does anyone know what to do there? Help is greatly appreciated.
If any information is missing, I'll add it as soon as I can!
Greetings,
Blaargh
EDIT: more code for better understanding of problem
$hash = get-content C:\temp\file.txt | convertfrom-stringdata
foreach ($keys in $hash.keys) {
$hashtwo = $hash.$keys -split ("=")
net use /persistent:no $hashtwo[1] $hashtwo[0]
}
My textfile looks like this:
key = \\\\server\\share\\folder =G:
PetSerAl found the solution:
#blaargh Add Write-Host "'$($hashtwo[1])' '$($hashtwo[0])'" to be sure, that variables does not have extra space somewhere.
I've looked all around this site and can't quite seem to find anything that fits my situation. Basically, I am trying to write an addition to the NETLOGON file that will replace text in a text file on all of our users' desktops. The current text is static across the board.
The text I want it changed to will be unique to each user. I want to change the current text (user1) to the users AD username (i.e. johnd, janed, etc.). I am using Windows Server 2008 R2 and all the workstations are Windows 7 Professional SP1 64 bit.
Here's what I have tried so far (with a few variables, which none have worked for one reason or the other):
gc c:\Users\%USERNAME%\desktop\VPN.txt' -replace "user1",$env:username | out-file c:\Users\%USERNAME%\desktop\VPN.txt
I didn't get an error, but it also did not go back to the normal "PS C:>" prompt, just ">>>" and the file did not change as anticipated.
If that is how you have the code exactly then I suppose it is because you have an opening single quote without a closing one. You are still going to have two other problems and you have one answer in your code. The >>> is the line continuation characters because the parser knows that the code is not complete and giving you the option to continue with the code. If you were purposely coding a single line on multiple lines you would consider this a feature.
$path = "c:\Users\$($env:username)\desktop\VPN.txt"
(Get-Content $path) -replace "user1",$env:username | out-file $path
Closed the path in quotes and used a variable since you called the path twice.
%name% is used in command prompt. Environment variables in PowerShell use the $env: provider which you did you once in your snippet.
-replace is a regex replaced tool that can work against Get-Content but you need to capture the result in a sub expression first.
Secondly with -replace is for regex and your string is not regex based you could just use .Replace() as well.
Set-Content is generally preferred over Out-File for performance reasons.
All that being said...
you could also try something like this.
$path = "c:\Users\$($env:username)\desktop\VPN.txt"
(Get-Content $path).Replace("user1",$env:username) | Set-Content $path
Do you want to only replace the first occurrence?
You could use a little regex here with a tweak in how you get the use Get-Content
$path = "c:\Users\$($env:username)\desktop\VPN.txt"
(Get-Content $path | Out-String) -replace "(.*?)user1(.*)",('$1{0}$2' -f $env:username) | out-file $path
Regex will match the entire file. There are two groups which it captures.
(.*?) - Up until the first "user1"
(.*) - Everything after that
Then we use the format operator to sandwich the new username in between those capture groups.
Use:
(Get-Content $fileName) | % {
if ($_.ReadCount -eq 1) {
$_ -replace "$original", "$content"
}
else {
$_
}
} | Set-Content $fileName
I do a lot of regex matching using Select-String in Powershell.
For example, the simplest and maybe the most common match, an IPv4 address:
$regex = \b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
Now, if I was to match this in a line that said:
$output = `
"Blah blah blah, 202.100.100.9, you're going to match the IP in the middle of this line,
but not on this line, because '2.a.3.one' is not a valid IPv4 address"
and then I do:
$output | Select-String $regex
It will give me the entire line.
I can't really use that in it's raw form.
However if I use this:
$output | Select-String $regex | %{$_.Matches} | %{$_.Value}
It will give me JUST the IP address, which is great.
My question is:
Is there a simpler way to do this?
I'd rather not type out | %{$.Matches} | %{$.Value} every time I want to grab just one particular string.
If you prefer Select-String over the -replace operator (which is just syntactic sugar for calling [Regex]::Replace), PowerShell V3 has a few shortcuts that can save some typing.
First, there is an alias for Select-String => sls.
Second, with simple foreach-object script blocks, you can replace the script block with just the property.
Combining these, you can use
$output | sls $regex | % Matches | % Value
To save even more typing, PowerShell can tab complete Matches but not Value.
Another option that is even less typing is to use property syntax:
($output | sls $regex).Matches.Value
As a bonus, tab completion can complete both Matches and Value in this example. Note that this second example works in V2 but only if there is a single matching line. If there are multiple matching lines, only in V3 will you see all the results, V2 would show nothing or an error if strict mode is enabled.
Try this:
$output -replace ".*($regex).*",'$1'
First I want to thank everyone for their help and their efforts in trying to figure this out for me. All of your suggestions have been good, and useful.
I had a think, and I realized that I am looking for a command that doesn't really exist, so I just wrote a function for it instead:
function Regex-Match {
[cmdletbinding()]
param (
[parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]$RegexString,
[parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true)]$SearchString
)
$Results = #($SearchString | Select-String -Pattern $RegexString | % {$_.Matches} | % {$_.Value})
Return $Results
}
To further shorten this, I can use
New-Alias -Name regx -Value Regex-match
Example command:
"test string" | regx "\w\s\w"
or
Regex-Match -SearchString (gc .\Stuff.txt) -RegexString "\w+"