Edit and save changes in file with powershell script - powershell

please tel me how to edit variable content in xml file with powershell script.
<application>
<name>My Application</name>
<platforms>
<platform>android</platform>
<icon gap:density="ld" src="/icon-1.png" />
<icon gap:density="md" src="/icon-2.png" />
</platforms>
</application>
i tried this but, it's not what i want, i want to edit based on the name of the variable: name, platform... but i dont know how in powershell
$editfiles=get-childitem . *.xml -rec
foreach ($file in $editfiles)
{
(get-content $file.pspath) |
foreach-object {$_ -replace "My Application", "My New App"} | set-content $file.pspath }
Tks
Many tks for your help

It is better to edit XML documents using an XML Api rather than text search/replace. Try this:
[xml]$xml = Get-Content foo.xml
$xml.application.name = "new name"
$xml.Save("$pwd\foo.xml")

$newitem = $xml.CreateElement("Value")
$newitem.set_InnerXML("111")
$xml.Items.ReplaceChild($newitem, $_)
something like this i think.. i didn't try it so i could be off track

Please use Keith Hill's answer, I'm only leaving mine here for reference. He's right, it's better to modify it through an XML API. I never use XML, I'm not familiar with it, so I didn't even think of it.
I gotta ask, did you try anything to do this? Did you look for an answer? This is pretty basic stuff that just a minute or two on Google probably would have gotten you an answer for.
(Get-Content "C:\Source\SomeFile.XML") -replace "My Application","Shiny New App"|Set-Content "C:\Source\SomeFile.XML"
Or if you wanted to change something less specific, such as the word "android" for the platform tag you could just include the tags to make sure it gets the right thing. (some shorthand used in this example)
(GC "C:\Source\SomeFile.XML") -replace "<platform>android</platform>","<platform>tacos</platform>"|SC "C:\Source\SomeFile.XML"
Seriously though, at least try and help yourself before coming and asking to be spoon-fed answers. I just hit up Google and searched for "powershell replace text in file" and the very first link would have given you the answer.
Edit:
Without knowing what you are looking for and going based solely off tags you will need to perform a RegEx (Regular Expression) search.
(GC "C:\Source\SomeFile.XML") -replace "(?<=`<platform`>).*?(?=`</platform`>)", 'New Platform'
That will pull the content of the file, look for any length of text that is preceded with and followed by and replace that text with 'New Platform'. Note that the Greater Than and Less Than symbols are escaped with a grave character (to the left of the 1, and above the Tab on your keyboard). Here's a breakdown of the RegEx:
(?<=<platform>) Checks that immediately preceding the string that we're looking for is the string <platform>. This will not be replaced, it just makes sure we have the right starting point.
.*? searches for any number of characters except a new line, and accepts the possibility that it may be blank. This is our match that will be replaced.
(?=</platform>) Checks that immediately following the string it just found should be the string </platform>. This will not be replaced, it just makes sure our match ends at the correct place.

Related

Parsing "" - Unrecognized escape sequence \T

I am trying to modify .config file. this line of code is only meant to be repleced in this file and few others with a new one from xml file but that goes later in code, currently I have issue with this line as I am not able to pass it to variable in a way that it will be treated as a regular string, will not be changed it in any way and will not throw "Parsing "" - Unrecognized escape sequence \T" exeption
I have always been doing it in this way if I don't need to use variables inside:
$oldValueSU = '<add key="splunk_username" value="${(splunk_username=D:\Tools\localtokens.xml)}"/>'
I also tried in this way
$oldValueSU = "<add key=""splunk_username"" value='`${(splunk_username=D:\Tools\localtokens.xml)}'/>"
None of these options work I am still receiving error "parsing "[Path I provided above]" - Unrecognized escape sequence \T."
How Script works:
The script works in a way that it takes that variable and looks through the whole file in order to find a mathing one of it does then it takes a path to that file and adds it to other variable and then changes it's value to a diffrent string.
If more information is needed I will be happy to provide it
Alright I found the issue and solution in my code
The issue was while trying to check if content of a file matches given string
if (($file -match $oldValueSU) -and ($file -match $oldValueSP))
It was using -match which uses Regex which was cousing the exeption I changed it to:
if (($file -like "*$oldValueSU*") -and ($file -like "*$oldValueSP*"))
After that in a part where in my code I was using -replace (which also uses Regex):
$fileContentPathTemp -replace "*$oldValueSU*", $newValueSU
I changed it to .Replace which works directly on String and it solved the issue:
$fileContentPathTemp.Replace($oldValueSU,$newValueSU)
So the whole issue was based on using Regex this solution is more like a workaround which just does not use it at all
I hope this solution will help somebody in the future, I am sorry for not providing all of the nececary information at the beggining. Thanks everyone for spending time on my issue

Bulk Move Sequential Numbers (Suffix) - Images, JPEG, RAW etc

I need to move a sequential number or sometimes a random ID with letters.
As an example:
Australia_Brisbane_NP_©_Hello_World_1163
Australia_Brisbane_NP_©_Hello_World_1164
Australia_Brisbane_NP_©_Hello_World_1165
Australia_Brisbane_NP_©_Hello_World_AHDFGF
Australia_Brisbane_NP_©_Hello_World_GHRADQ
Australia_Brisbane_NP_©_Hello_World_QGASFS
What I need to do is have ©_Hello_World at the end and move the ID behind the ©, Example below:
Australia_Brisbane_NP_1165_©_Hello_World
Australia_Brisbane_NP_AHDFGF_©_Hello_World
The ideal script would allow me to specify between 1-15 characters at the end of the word without effecting the extension and move the 1-15 characters behind _©.
I have tried searching for a lot of different scripts however either they do not work or they are too complicated for me to adapt them to what is required.
I am unable to use any external software and as such I have to stick to PowerShell.
The basic "change filename" script is:
Get filenames Get-ChildItem -LiteralPath 'C:\Path\To\Files'
Pipe the results into Rename-Item
Use the property -NewName with a scriptblock {}
In the scriptblock, code to calculate the new name from the old name
Extract the filename out from the path and the extension
Change it
Put the path and the extension back on
I have tried searching for a lot of different scripts however either they do not work or they are too complicated for me to adapt them to what is required.
Text processing is all about details, details make code more complicated, and small details can invalidate whole approaches.
It's not at all clear to my why you say:
The ideal script would allow me to specify between 1-15 characters at the end of the word without effecting the extension and move the 1-15 characters behind _©.
Why would you benefit from specifying the character count, instead of having the ideal script move "all of them"?
This script should do it:
$count = Read-Host -Prompt 'How many characters to move?'
Get-ChildItem -LiteralPath 'C:\Path\To\Files' |
Rename-Item -NewName {
$newName = $_.BaseName -replace "(©_Hello_World)_(.{$($count)})", '$2_$1'
"$($_.DirectoryName)/$($newName + $_.Extension)"
}
Nb. it will move the count you asked for, even if there are more characters there.
If you don't need to specify the count, and just take all to the extension, then replace (.{$($count)}) with (.*), and remove the Read-Host line.

Pipes in replace causing line to be duplicated

I have a script that I need to replace a couple of lines in. The first replace is going fine but the second is wiping out my file and duplicating the line multiple times.
My code
(get-content $($sr)) -replace 'remoteapplicationname:s:SHAREDAPP',"remoteapplicationcmdline:s:$($sa)" | Out-File $($sr)
(get-content $($sr)) -replace 'remoteapplicationprogram:s:||SHAREDAPP',"remoteapplicationprogram:s:||$($sa)" | Out-File $($sr)
The first replace works perfectly. The second one is causing this:
remoteapplicationprogram:s:||stagaredrremoteapplicationprogram:s:||stagarederemoteapplicationprogram:s:||stagareddremoteapplicationprogram:s:||stagarediremoteapplicationprogram:s:||stagaredrremoteapplicationprogram:s:||stagarederemoteapplicationprogram:s:||stagaredcremoteapplicationprogram:s:||stagaredtremoteapplicationprogram:s:||stagaredcremoteapplicationprogram:s:||stagaredlremoteapplicationprogram:s:||stagarediremoteapplicationprogram:s:||stagaredpremoteapplicationprogram:s:||stagaredbremoteapplicationprogram:s:||stagaredoremoteapplicationprogram:s:||stagaredaremoteapplicationprogram:s:||stagaredrremoteapplicationprogram:s:||stagareddremoteapplicationprogram:s:||stagared:remoteapplicationprogram:s:||stagarediremoteapplicationprogram:s:||stagared:remoteapplicationprogram:s:||stagared1remoteapplicationprogram:s:||stagared
etc...
Is this because of the ||? If so, how do I get around it?
Thanks!
To begin with, you should be using slightly more meaningful names for your variables. Especially if you want someone else to be reviewing your code.
The gist of your issue is that -replace supports regexes (regular expressions), and you have regex control characters in your pattern string. Consider the following simple example, and notice everywhere the replacement string is found:
PS C:\Users\Matt> "ABCD" -replace "||", "bagel"
bagelAbagelBbagelCbagelDbagel
-replace is also an array operator, so it works on every line of the input file, which is nice. For simplicity's sake, if you are not using a regex, you should just consider using the string method .Replace(), but it is case-sensitive, so that might not be ideal. So let's escape those control characters in the easiest way possible:
$patternOne = [regex]::Escape('remoteapplicationname:s:SHAREDAPP')
$patternTwo = [regex]::Escape('remoteapplicationprogram:s:||SHAREDAPP')
(get-content $sr) -replace $patternOne, "remoteapplicationcmdline:s:$sa" | Out-File $($sr)
(get-content $sr) -replace $patternTwo, "remoteapplicationprogram:s:||$sa" | Out-File $($sr)
Now we get both patterns matched as you have them written. Run $patternTwo on the console to see what has changed to it! $patternOne, as written, has no regex control characters in it, but it does not hurt to use the escape method if you are just expecting simple matching.
Aside from the main issue pointed out, there is also some redundancy and misconception that can be addressed here. I presume you are updating a source file to replace all occurrences of those strings, yes? Well, you don't need to read the file in twice, given that you can chain -replace:
$patternOne = [regex]::Escape('remoteapplicationname:s:SHAREDAPP')
$patternTwo = [regex]::Escape('remoteapplicationprogram:s:||SHAREDAPP')
(get-content $sr) -replace $patternOne, "remoteapplicationcmdline:s:$sa" -replace $patternTwo, "remoteapplicationprogram:s:||$sa" |
Set-Content $sr
Perhaps that will do what you intended.
You might notice that I've removed the subexpressions operators ($(...)) around your variables. While they have their place, they don't need to be used here. They are only needed inside more complicated strings, like when you need to expand object properties or something.

Copy block of text from webpage using PowerShell

I've extracted a whole web page as text and that text is assigned to a variable. Now I need to select a portion of that text and assign it to another variable. Let's say, the text I have is:
Note: Your feedback is very important to us, however, we do not
respond to individual submissions through this channel. If you require
support, please visit the Safety & Security Center. Follow: Change log
for version 1.211.2457.0 This page shows you what's changed in the
most recent definitions update for Microsoft antimalware and
antispyware software.
You can also see changes in the last 20 updates from the Change
definition version menu on the right.
The latest update is:
1.211.2457.0
Download the latest update.
 New definitions (?)
Antimalware (Antivirus + Antispyware)
I would like the following text to be assigned to a variable
1.211.2457.0
The code I have for now is
$URI = "http://www.example.com/mynewpage"
$HTML = Invoke-WebRequest -Uri $URI
$WebPageText = ($HTML.ParsedHtml.getElementsByTagName("div") | Where-Object{$_.className -eq "span bp0-col-1-1 bp1-col-1-1 bp2-col-1-1 bp3-col-1-1"}).innerText
I tried Select-String -SimpleMatch "The latest update is:*Download the latest update." -InputObject $WebPageText, but I'm pretty sure that's wrong.
I'm new to PowerShell scripting. So please pardon me if I'm missing something obvious.
Thank you in advance!
SimpleMatch would ignore any regex metacharaters. It would not allow any wildcards either. From TechNet:
Uses a simple match rather than a regular expression match. In a simple match, Select-String searches the input for the text in the Pattern parameter. It does not interpret the value of the Pattern parameter as a regular expression statement
What you could do is use regex to find a string where the line only contains digits and periods: "^[\d\.]+$".
$version = ($WebPageText | Select-String "^[\d\.]+$").Matches.Value
It is possible more that one could be returned so you might need to account for that.
If you wanted a more targeted (but no guaranteed unique result) you could just use the -match operator.
If(($WebPageText | out-string) -match "(?sm)The latest update is:\s+(.*?)\s+Download the latest update"){
$version = $Matches[1]
}

How to get a list of contents in a directory, then wrap text around the list?

My aim is really simple: I want to list hundreds of ebooks on my site. Just words that you click on and it opens the pdf in a new tab. My issue lays in that doing this manually would take days for a single folder. In powershell, I've managed to find a way to list all contents in a directory and save them to a file.
cd "directory\to\file"
ls $search_dir > text.txt
This prints the contents and saves them in a text file. What I want to do is wrap text around it. In HTML it's obvious you need to make your tags like
<p>file</p>
This is how I want my printed list to look. So how do I get the list of contents to get wrapped around like this (and also printed again between the tags without the ".pdf" extention)?
Here's half the puzzle, solving the other half is more rewarding than being simply told the answer.
This will read the text file in ( ) and add the string Added to the end of every line item.
Thanks goes out to https://stackoverflow.com/a/4952679/4317867 #mjolinor
(gc C:\Temp\z.txt) | ForEach-Object { $_ + " Added" } | Set-Content C:\Temp\z.txt
In powershell, type in
cd "directory/to/file"
Then type in
ls $search_dir
ALT+left click to select a block of the 'name' section. Copy it to a text file and name it something like filename.txt. Then use the following line to apply the wrapping:
(gc C:\location\to\filename.txt) | ForEach-Object { "<p><a href=$([char]34)ebooks/Books/path/to/file/$_$([char]34) target=$([char]34)_blank$([char]34) class=$([char]34)downloadlink2$([char]34)>$_</a></p>" } | Set-Content C:\location\to\filename.txt
gc grabs the file in the directory next to it. ForEach-Object tells powershell to run what's in the curly brackets for each line in the document. $([char]34) is quotation marks inside the string and $_ is a line in the filename.txt file. Set-Content tells powershell to apply the changes made to the .txt file. When it's done the thing will look something like:
<p>file.pdf</p>
Hope this helps someone in the future.