What's the easiest way to extract part of this line? - powershell

I am using PowerShell to insert data into a database but before I get to that step I need to pull the information from a log file. How can I extract the title of the project from this line in the log file?
1>Project "E:\Builds\1\IS_WSD\Lab1\src\Lab1.sln" on node 1 (default targets).
The title would be "Lab1.sln"
I already have (Get-Content C:\Users\myusername\Documents\Lab1.log)[1] which pulls this whole line but I need to narrow down even more.

How about a regex way:
$x = '1>Project "E:\Builds\1\IS_WSD\Lab1\src\Lab1.sln" on node 1 (default targets).'
$x -match '".*\\(.*)"'
$Matches[1]
or a not regex way:
$x.SubString($x.LastIndexOf('\')+1, ($x.LastIndexOf('"')-$x.LastIndexOf('\'))-1)

Do this:
$logfile = 'C:\Users\myusername\Documents\Lab1.log'
(Get-Content $logfile)[1] -replace '^.*?".*?\\([^\\]+)".*', '$1'
or this:
$logfile = 'C:\Users\myusername\Documents\Lab1.log'
(Get-Content $logfile)[1] -replace '^.*?"' -replace '".*$' -replace '^.*\\'

Related

Powershell Search for specific string, then add text right after it

I'm pretty sure this is can be done easily but i couldn't find the answer.
Suppose i have a text file with a bunch of lines in it.
Contents of the text file below
dbuser=admin
dbpassword=
So in Powershell I want to find the string "dbpassword=" and add the text "password" right after the =.
Solutions I've searched for have -replace but i don't want to replace the line, just want to add "password" to it.
Can anyone share what the Powershell code may be?
This assumes that everything after the = character becomes 'password'.
Get-Content -Path '.\bunchoflines.txt' |
ForEach-Object { $_ -match '^dbpassword=' ? 'dbpassword=password' : $_ }
Not sure why you care if it's replaced, but you could just output that line followed by the password instead. Assuming you want to update the file I'd use Set-Content to write it and a switch statement to read the file.
$inputfile = '\path\to\inputfile.txt'
Set-Content -Path $inputfile -value $(
switch -Regex -File $inputfile {
'^dbpassword=' {"$($_)password"}
default {$_}
}
)
Thanks all for your contributions, I ended up finding this solution.
$config = Get-Content path\to\file\somefile.txt
$password = abcdef
$config -replace "dbpassword=.*",("dbpassword="+$password) |
Set-Content path\to\file\somefile.txt

Replace a non-unique line of text under a unique line of text in a text file using powershell

I have the following txt file.
[AppRemover]
Enable=0
[CleanWipe]
Enable=0
[RerunSetup]
Enable=0
How do I change the Enable=0 to Enable=1 under [CleanWipe] only?
Below is how I plan on using the code with my file.
$Path = C:\temp\file.txt
$File = Get-Content -Path $Path
# Code to update file
$File | Out-File $Path
You can use -replace to update the value if it is 0.
$Path = C:\temp\file.txt
(Get-Content $Path -Raw) -replace "(?<text>\[CleanWipe\]\r?\nEnable=)0",'${text}1' |
Set-Content $Path
Using a module that parses INI files will be the best solution though. I'd recommend trying PsIni.
Explanation:
The -Raw switch reads the file contents as a single string. This makes it easier to work with newline characters.
-replace performs a regex match and then replace. Below is the regex match breakdown.
(?<text>) is a named capture group. Anything matched within that capture group can be recalled in the replace string as '${text}'.
\[CleanWipe\] is a literal match of [CleanWipe] while escaping the [] characters with \.
\r? is optional carriage return
\n is the newline character
Enable= is a literal match
0 is a literal match
The replace string is the capture group contents and 1 when a match exists. Technically, a capture group is not needed if you want to use a positive lookbehind instead. The positive lookbehind assertion is (?<=). That solution would look like the following:
$Path = C:\temp\file.txt
(Get-Content $Path -Raw) -replace "(?<=\[CleanWipe\]\r?\nEnable=)0",'1' |
Set-Content $Path
The problem with the -replace solutions as they written is they will update the file regardless of a change actually being made to the contents. You would need to add an extra comparison to prevent that. Other issues could be extra white space on any of these lines. You can account for that by adding \s* where you think those possibilities may exist.
Alternative With More Steps:
$file = Get-Content $Path
$TargetIndex = $file.IndexOf('[CleanWipe]') + 1
if ($file[$TargetIndex] -match 'Enable=0') {
$file[$TargetIndex] = 'Enable=1'
$file | Set-Content $Path
}
This solution will only update the file if it meets the match condition. It uses the array method IndexOf() to determine where [CleanWipe] is. Then assumes the line you want to change is in the next index.
IndexOf() is not the only way to find an index. The method requires that your line match the string exactly. You can use Select-String (case-insensitive by default) to return a line number. Since it will be a line number and not an index (indexes start at 0 while line numbers start at 1), it will invariably be the index number you want.
$file = Get-Content $Path
$TargetIndex = ($file | Select-String -Pattern '[CleanWipe]' -SimpleMatch).LineNumber
if ($file[$TargetIndex] -match 'Enable=0') {
$file[$TargetIndex] = 'Enable=1'
$file | Set-Content $Path
}

Loop to replace c:\, d:\ ... z:\ with \\servername\c$\

I'm actually trying to build some code to identify rights on shared folders in every single server I've got in my enterprise.
For now, I've already listed every single server and exported it in a .txt file, did a loop on this .txt to export in an other .txt file all shared folders.
All this is working fine but the path is like : c:\...\...\folder$.
To be able to use this I need to do a loop to replace c:\ d:\ etc. with \\servername\c$\.
I've tried using [system.io.file]::ReadAllText and WriteAllText, it's working fine for one letter but didn't find a way to do a loop on it.
I've tried
get-content ... -replace "c:\","\\$ServerName\c$\" ` -replace "d:\" ...
but got an error about regular expression not valid, so trying with [regex]::Escape but didn't work as expected neither...
Powershell
$contenu = [System.IO.File]::ReadAllText("$path\$SharedFolders.txt").Replace("C:\","\\$SharedFolders\c$\")
[System.IO.File]::WriteAllText("$path\$SharedFolders.txt", $contenu)
Powershell
(Get-Content "$path\$SharedFolders.txt") | foreach {
$_ -replace "C:\","\\$SharedFolders\C$\" `
-replace "D:\","\\$SharedFolders\D$\" `
[...] | Set-Content "$path\$sharedfolders.txt"}
And i'd like to have something like that :
Powershell
('a'..'z').ForEach({ (Get-Content "$path\$SharedFolders.txt" -Raw).replace("$_`:\","\\$SharedFolders\$_$") })
But I'm too newbie in Powershell to make it work proprely
You need PSv6 to use 'a'..'z'
The -replace operator is RegEx based, you need to escape a literal backslash with another one in the pattern.
following #Lee_Daileys hint build a RegEx with valid Drive letters
$OFS = '|'
$RE = ('('+(Get-Psdrive -PSProvider filesystem).where({$_.Displayroot -notmatch '^\\'}).name)+'):\\'
$OFS = $Null
"`$RE = '{0}'" -f $RE
'Loop to replace c:\, d:\ … z:\ with \\servername\c$\' -replace $RE,"\\servername\`${1}$\"
Sample output on my PC
$RE = '(A|C|D):\\'
Loop to replace \\servername\c$\, \\servername\d$\ … z:\ with \\servername\c$\
Reading the file with the -raw parameter doesn't require a loop, but wil do all changes at once.
$OFS = '|'
$RE = ('('+(Get-Psdrive -PSProvider filesystem).where({$_.Displayroot -notmatch '^\\'}).name)+'):\\'
$OFS = $Null
$File = "$path\$SharedFolders.txt"
(Get-Content $File -raw) -replace $RE,"\\servername\`${1}$\" |
Set-Content $File
Well thanks for your help, I just manage to make it works like that :
$lecteur=[int][char]'A'
1..26 | % {
$LR=[char]$lecteur
$contenu =[System.IO.File]::ReadAllText("$path\$SharedFolders.txt").Replace("${LR}:\","\\$SharedFolders\$LR$\")
[System.IO.File]::WriteAllText("$path\$SharedFolders.txt", $contenu)
$lecteur++
}
Hope it'll help some people ;)

Powershell change file

I am very new in powershell, I hope someone will help me:
I have a file in C:\tmp\appFiles.appcache
Which contains:
CACHE MANIFEST
Version: 2019-01-04T00:48:08.3070330+01:00
Use from network if available
NETWORK:
I need to make a script to change date + time to actual time
For example:
CACHE MANIFEST
Version: 2019-01-19T13:55:08.3070330+01:00
Use from network if available
NETWORK:
Thank you for any help.
Or use Select-String and the 'Round-trip date/time pattern' 'o'
See Standard Date and Time Format Strings
$path = 'C:\tmp\appFiles.appcache\YOUR-FILENAME'
$content = Get-Content $path
$match = $content | Select-String -Pattern 'Version:' -SimpleMatch -List
if ($match) {
$content[$match.LineNumber - 1] = "Version: {0}" -f (Get-Date -Format 'o')
$content | Set-Content -Path $path
}
This really is not a script writing service. But if you promise me you will learn more about PowerShell and start trying to understand the following script, I will give you this to work with. Protip: when learning PowerShell you should use PowerShell ISE and press cntrl + R so you have a better way to write and understand PowerShell.
$path = "path to your file"
$content = Get-Content $path
$date = Get-Date -Format s
foreach($row in $content){
if($row -match "Version:"){
$newContent = $content.replace("$row","Version: $date+01:00")
}
}
$newContent | Set-Content $path
The above script gets the content of the file given, then takes the current date. It then searches each row of the content for a mathing text. When found it replaces that specific line with the custom line we created. Then we take the new content and set it to the file we specified. You basically overwrite the whole file this way!
To have a complete date string according to the given format with part seconds and UTC offset
replace the Version string with a positive lookbehind RegEx
save to same file name (requires reading to memory first)
## Q:\Test\2019\01\18\SO_54255102.ps1
$File = 'C:\tmp\appFiles.appcache'
$Date = Get-Date -f 'yyyy-MM-dd\THH:mm:ss.fffffffzzzzz' # or simply (Get-Date -f o)
(Get-Content $File) -Replace '(?<=^Version: ).*$',$Date | Set-Content $File

Replacing text only in lines that match a criteria, using the pipeline

My goal is to replace specific texts in specific lines in a text file, and I want to do that using the pipeline.
At first, I tried to write the code for the text replacement, without the condition that set the replacement to happen only in specific lines:
$fileName = Read-Host "Enter the full path of the file, without quotes"
(Get-Content -Path $fileName -Encoding UTF8) |
ForEach-Object { $_ -replace "01", "January " } |
Set-Content -Path $fileName -Encoding UTF8
It seems that it works. But then, I inserted an IF statement to the pipeline:
$fileName = Read-Host "Enter the full path of the file, without quotes"
(Get-Content -Path $fileName -Encoding UTF8) |
ForEach-Object { if ($_ -match "Month") {$_ -replace "03", "March"} } |
Set-Content -Path $fileName -Encoding UTF8
When I ran the last script, at the end of the process I got a file that includes only the lines that matched the if Statement. If I'm understanding correctly what happened, it seems that only the lines that match the if statement are passed to the next stage in the pipeline. So I understand why the output of the process, but I still can't figure how to solve this - How to pass all the lines in the files through all the stages of the pipeline, but to still make the text replacements to happen only in specific lines that match a specific criteria.
Could you please assist me with this issue?
Please notice that I would like not to use a temporary file for this and also remember that I prefer an elegant way of doing this, using the pipeline.
You have to add else statement like:
(Get-Content -Path $fileName -Encoding UTF8) |
Foreach-Object { If ($_ - match "Month") { $_ -replace "03", "March"} else { $_ } } |
Set-Content -Path $fileName - Encoding UTF8
Without else you didn't put line in pipeline. So your if was like filter
Depending on what your input data looks like you may not need a nested conditional (or a ForEach-Object) at all. If your input looks for instance like this:
Month: 03
you can do the replacement like this:
(Get-Content -Path $fileName -Encoding UTF8) -replace '^(.*Month.*)03','$1March' |
Set-Content -Path $fileName -Encoding UTF8
That will modify just the lines matching the pattern (^(.*Month.*)03) and leave everything else unchanged.