Remove a substring from a filename with Powershell - regex

In a deployment szenario, I need to rename config files. There are config files for every environment (Dev.Test, Dev.Prod, Integration, Prod). For example a web.config would be called web.Dev.Test.config if it was for the Dev.Test environment. On the target machine, I need to rename the files back to their original name (i.e. from web.Dev.Test.config to web.config) with Powershell.
$test = "web.Dev.Prod.config"
$environment = $test | Select-String -Pattern ".*\.(?<environment>(Dev.Test|Dev.Prod|Prod|Integration))\.config" | select -expand Matches | foreach {$_.groups["environment"].value}
if ($test -match "Dev.Prod")
{
$environment = "Dev.Prod"
}
$environment
$newFileName = $test.Remove($test.IndexOf($environment),$environment.Length + 1)
$newFileName
The problem I have with this is, that the Regex does not find the Dev.Prod evironment, but returns Prod instead. This is why I introduced the if statement. I was wondering if there was a more elegant way of renaming the files with Powershell.

Watch out for greedy matching. Modify your regex that starts ".*\.(?" to ".*?\.(?".

Related

Need to search a line from a long config file with powershell

In short,
I need to find a specific line in a long file that starts with "set ip " and continues with some parameter that I need to replace. this line appears multiple times in the file so I need to find it between 2 specific lines.
The longer story:
We will soon get to configure many FortiGate Firewalls for our offices, most of the settings, policies etc. will be the same but the external IP changes, some other addresses change etc.
So I'm trying to make a powershell script that will take an existing config (which might change) and find the specific lines I need and replace them.
I tried with regex but couldn't make it work for me on multiple lines.
basically for a reference I need to find the "set ip " in the following part:
config system interface
edit "wan1"
set vdom "root"
set ip 7.7.7.7 255.255.255.252
set allowaccess ping https ssh
set ident-accept enable
set type physical
set scan-botnet-connections block
set alias "WAN1"
set role wan
set snmp-index 1
next
(IP was changed for security) and so on.
what I've got so far is:
get-content .\Fortigate.conf | select-string -pattern "^#","set uuid " -notmatch
sadly nothing I tried to cut that part of text to search only there worked.
for example with regex I tried:
get-content .\Fortigate.conf | select-string -pattern "^#","set uuid " -notmatch | select-string -Pattern '(?m)edit "wan1".*?end'
For this issue, I would not try to regex multiple line but approach it the PowerShell way "Implement for the Middle of a Pipeline" and remember information as which section your in, e.g.:
Read each specific line (if you writing a cmdlet, use the processmethod section):
get-content .\Fortigate.conf | ForEach {...
Remember the current edit section:
$Wan = ($_ | Select-String 'edit[\s]+"(.*)"').Matches.Groups[1].Value
Catch the specific set within the (edit) section:
$SetIP = ($_ | Select-String 'set[\s]+ip[\s]+(.*)').Matches.Groups[1].Value
Make your decisions based on the values and section, e.g.:
If ($Wan -eq $MyWan) {
if (($SetIP -Split "[\s]+") -Contains $MyIP) {...
Drop your new string entry (intermediately) on the pipeline:
Write-Output " set ip $MyNewIP"
Or keep the original string entry:
Else {Write-Output $_}

How to parse the folder path from a WMI process?

I need to be able to parse the folder path (which could vary) from an installed Windows service.
In PowerShell using
$serviceToRemove = Get-WmiObject -Class Win32_Service -Filter "name='Labelary'"
I can get the object, and if I do
$serviceToRemove.PathName
it gives
c:\program files\myapplicationname\mybinary.exe //rs/labelry
I need to get
c:\program files\myapplicationname
I've tried various combinations of splitting, but the path could vary or have spaces in it.
Is there a regex way of getting this portion of the path. The only guaranteed pattern is that I want the portion of the string which is before the wildcard *.exe . But I don't know how to express this in PowerShell. I tried \w*\.exe in a regex tester but this just returns the mybinary.exe.
Also various combinations of PowerShell or System.IO path tools seem to consider the //rs/labelry to be part of the path and thus not return the root correctly.
I would probably write it this way:
$pathName = Get-WmiObject Win32_Service -Filter "Name='Labelary'" |
Select-Object -ExpandProperty PathName |
Select-String '^"?(.+)\.exe' | ForEach-Object {
Split-Path $_.Matches[0].Groups[1].Value -Parent
}
Something like this should work:
$path = if ($serviceToRemove.PathName -match '[a-z]:\\.*?(?=\\[^\\]+\.exe)') {
$matches[0]
}
The regular expression matches a drive letter ([a-z]:\\) plus the shortest sequence of characters before a backslash followed by an executable name (\\[^\\]+\.exe). The positive lookahead assertion ((?=...)) ensures that the backslash and executable name are not included in the returned string.

How to robocopy using regex matched folder from one server to another

I've a build system which uses robocopy to copy files from one system to our server, and to a specific path. The following has worked well till a new requirement was introduced:
robocopy local\dist \\server01\somepath\dist XF *.* /E
Now, we want to have a changing 'dist' name to include build information. For example, 'dist1', 'dist2', 'distabcd'. Anyhow, the point is, that the folder name is changing. How do I tell robocopy to match on any name beginning with 'dist', but copy to the correct full named dist folder on the remote server
robocopy local\dist* \\server01\somepath\[????] XF *.* /E
I have the option to use PowerShell commands to do this, assuming it may be able to copy to the server location. I know almost nothing about PowerShell, but welcome any tips.
Powershell provides RegEx functionality with the '-match' and '-contains' operators. Here would be an example of what capturing changing directories would look like:
$localDirectory = "local\dist"
$directory = "\\server01\somepath\dist"
$keyword = "dist"
$fileDirectory = Get-ChildItem -Path $directory -Recurse
foreach ($container in $fileDirectory)
{
# -match is one of the RegEx functions we may utilize for this operation
# e.g dist1.. dist2.. distabc.. adist.. mynewdistrubition
if ($container -match $keyword)
{
try
{
Copy-Item -Path "$($directory)\$($container)" -Destination $localDirectory -Force -Recurse
}
catch [System.Exception]
{
Write-Output $_.Exception
}
}
}

Batch rename files with regex

I have a number of files with the following format:
name_name<number><number>[TIF<11 numbers>].jpg
e.g. john_sam01 [TIF 15355474840].jpg
And I would like to remove the [TIF 15355474840] from all of these files
This includes a leading space before the '[TIF...' and a different combination of 11 numbers each time.
So the previous example would become:
josh_sam01.jpg
In short, using powershell (or cmd.exe) with regex I would like to turn this filename:
josh_sam01 [TIF 15355474840].jpg
Into this:
josh_sam01.jpg
With variables being: 'john' 'sam' two numbers and the numbers after TIF.
Something like, with added newlines for clarity:
dir ‹parameters to select the set of files› |
% {
$newName = $_.Name -replace '\s\[TIF \d+\]',''
rename-item -newname $newName -literalPath $_.Fullname
}
Almost certainly adding -whatif to the rename until I was sure I had the file selection and rename correct.

Changing directory to a folder matching a regex in powershell

I want to CD into a folder that begins with the word "Patch", followed by several other digits. All I care about is that it begins with the word "Patch"
How can I change my directory using a regex in powershell?
This is what I have at the moment and it doesn't work. Am I on the right track though?
$FolderPath = "^Patch[0-9]+$"
cd "C:\Test\" + $FolderPath
To put you in the right direction:
Use Get-ChildItem and only get the directories matching your regex, something like:
$matchingItem = Get-ChildItem "C:\Test" -Directory | ?{ $_.Name -match $FolderPath } | select -First 1
Now you can cd to the matching directory.
You don't really need the regex. Wildcard blobbing will handle that:
cd c:\test\patch[0-9]*