0

I am really new to powershell. I need to replace a value (that is always changing) in a file. The value looks like this:

"version": "2.4.5",

And I wish to replace the number. I have this bit of code:

(Get-Content .\bower.json).replace('2.4.5', $version) | Set-Content .\bower.json

But that requires that the version number is always 2.4.5 before setting it to the new version. As you can figure out, the next time around that number won't be the same.

Does anyone know of a way I can replace the version number regardless of what it is? Maybe with regex?


After a bit of playing, I have tried this:

$pattern = '\"version\": \"(.*)\"'
$replace = """version"": ""$version""";
(Get-Content .\bower.json).replace($pattern, $replace) | Set-Content .\bower.json

But it doesn't replace anything :( If I run:

$replace -match $pattern

it returns "True", so I would expect it to replace correctly? This is my bower.json file:

{
  "name": "sapphire",
  "version": "2.4.5",
  "dependencies": {
    "angular": "~1.7.4",
    "angular-animate": "~1.7.4",
    "angular-barcode": "0.0.4",
    "angular-bootstrap": "2.5.0",
    "angular-cookies": "~1.7.4",
    "angular-google-maps": "2.4.1",
    "angular-loading-bar": "0.9.0",
    "angular-mocks": "~1.7.4",
    "angular-resource": "~1.7.4",
    "angular-sanitize": "~1.7.4",
    "angular-simple-cache": "1.0.6",
    "angular-touch": "~1.7.4",
    "angular-ui-mask": "1.8.7",
    "angular-ui-select": "0.19.8",
    "bootstrap-sass-official": "3.3.7",
    "ng-idle": "1.3.2",
    "ng-notify": "0.8.0",
    "vkbeautify": "*",
    "ngclipboard": "~2.0.0",
    "angular-confirm": "angular1-confirm#1.1.0",
    "angular-ui-router": "~1.0.20",
    "font-awesome": "^5.6.1",
    "ng-confirm": "angular-confirm#^1.1.0"
  },
  "devDependencies": {},
  "appPath": "src",
  "moduleName": "sapphire",
  "overrides": {
    "bootstrap": {
      "main": [
        "less/bootstrap.less",
        "dist/css/bootstrap.css",
        "dist/js/bootstrap.js"
      ]
    }
  },
  "resolutions": {
    "angular": "~1.7.4",
    "angular-animate": "~1.7.4",
    "angular-cookies": "~1.7.4",
    "angular-mocks": "~1.7.4",
    "angular-resource": "~1.7.4",
    "angular-sanitize": "~1.7.4",
    "angular-touch": "~1.7.4",
    "components-font-awesome": "~5.0.6",
    "ngclipboard": "~2.0.0",
    "clipboard": "^2.0.0",
    "angular-ui-router": "~1.0.20"
  }
}
r3plica
  • 13,017
  • 23
  • 128
  • 290
  • have you tried to use the JSON file as JSON? `$InStuff = Get-Content -LiteralPath 'FIle.json | ConvertFrom-JSON` should give you a structured object in `$InStuff` that you can address as you do other objects. that otta allow doing a replacement on the object directly. then you can convert from json and send it to a file. – Lee_Dailey Feb 15 '19 at 10:39
  • Can you show me an example of how to do that. As I said, I am new to powershell, so I don't even know how to do a replacement on the variable and how to then save it over my existing file – r3plica Feb 15 '19 at 10:43
  • i'll post this as an answer since code here is too hard to read. [*grin*] – Lee_Dailey Feb 15 '19 at 10:56
  • $versionString -replace '^(.*)(\d\.\d\.\d)(.*)$', ('${1}' + $newversion + '${3}') – f6a4 Feb 15 '19 at 11:14

2 Answers2

2

since you have a valid JSON file, the better approach seems to be to use it as such. [grin] this code does the following ...

  • fakes reading in the JSON file
    i didn't feel like creating a test file for this.
  • converts that to a PSCustomObject with ConvertFrom-JSON
  • shows the imported .Version property value
  • changes that value
  • shows the now-current value of the .Version prop
  • converts the object back to JSON and writes it to a file

here's the code ...

# fake reading in a text file
#    in real life, use Get-Content
$InStuff = @'
{
  "name": "sapphire",
  "version": "2.4.5",
  "dependencies": {
    "angular": "~1.7.4",
    "angular-animate": "~1.7.4",
    "angular-barcode": "0.0.4",
    "angular-bootstrap": "2.5.0",
    "angular-cookies": "~1.7.4",
    "angular-google-maps": "2.4.1",
    "angular-loading-bar": "0.9.0",
    "angular-mocks": "~1.7.4",
    "angular-resource": "~1.7.4",
    "angular-sanitize": "~1.7.4",
    "angular-simple-cache": "1.0.6",
    "angular-touch": "~1.7.4",
    "angular-ui-mask": "1.8.7",
    "angular-ui-select": "0.19.8",
    "bootstrap-sass-official": "3.3.7",
    "ng-idle": "1.3.2",
    "ng-notify": "0.8.0",
    "vkbeautify": "*",
    "ngclipboard": "~2.0.0",
    "angular-confirm": "angular1-confirm#1.1.0",
    "angular-ui-router": "~1.0.20",
    "font-awesome": "^5.6.1",
    "ng-confirm": "angular-confirm#^1.1.0"
  },
  "devDependencies": {},
  "appPath": "src",
  "moduleName": "sapphire",
  "overrides": {
    "bootstrap": {
      "main": [
        "less/bootstrap.less",
        "dist/css/bootstrap.css",
        "dist/js/bootstrap.js"
      ]
    }
  },
  "resolutions": {
    "angular": "~1.7.4",
    "angular-animate": "~1.7.4",
    "angular-cookies": "~1.7.4",
    "angular-mocks": "~1.7.4",
    "angular-resource": "~1.7.4",
    "angular-sanitize": "~1.7.4",
    "angular-touch": "~1.7.4",
    "components-font-awesome": "~5.0.6",
    "ngclipboard": "~2.0.0",
    "clipboard": "^2.0.0",
    "angular-ui-router": "~1.0.20"
  }
}
'@

$NewVersion = '6.6.6'

$FromJSON = $InStuff |
    ConvertFrom-Json

# show the current imported value
$FromJSON.Version

$FromJSON.Version = $NewVersion

# show the new value
$FromJSON.Version

# send it to a file    
$FromJSON |
    ConvertTo-Json |
    Set-Content -LiteralPath "$env:TEMP\r3plica_-_NewVersion.json"

on screen output ...

2.4.5
6.6.6

content of the new file ...

{
    "name":  "sapphire",
    "version":  "6.6.6",
    "dependencies":  {
                         "angular":  "~1.7.4",
                         "angular-animate":  "~1.7.4",
                         "angular-barcode":  "0.0.4",
                         "angular-bootstrap":  "2.5.0",
                         "angular-cookies":  "~1.7.4",
                         "angular-google-maps":  "2.4.1",
                         "angular-loading-bar":  "0.9.0",
                         "angular-mocks":  "~1.7.4",
                         "angular-resource":  "~1.7.4",
                         "angular-sanitize":  "~1.7.4",
                         "angular-simple-cache":  "1.0.6",
                         "angular-touch":  "~1.7.4",
                         "angular-ui-mask":  "1.8.7",
                         "angular-ui-select":  "0.19.8",
                         "bootstrap-sass-official":  "3.3.7",
                         "ng-idle":  "1.3.2",
                         "ng-notify":  "0.8.0",
                         "vkbeautify":  "*",
                         "ngclipboard":  "~2.0.0",
                         "angular-confirm":  "angular1-confirm#1.1.0",
                         "angular-ui-router":  "~1.0.20",
                         "font-awesome":  "^5.6.1",
                         "ng-confirm":  "angular-confirm#^1.1.0"
                     },
    "devDependencies":  {

                        },
    "appPath":  "src",
    "moduleName":  "sapphire",
    "overrides":  {
                      "bootstrap":  {
                                        "main":  "less/bootstrap.less dist/css/bootstrap.css dist/js/bootstrap.js"
                                    }
                  },
    "resolutions":  {
                        "angular":  "~1.7.4",
                        "angular-animate":  "~1.7.4",
                        "angular-cookies":  "~1.7.4",
                        "angular-mocks":  "~1.7.4",
                        "angular-resource":  "~1.7.4",
                        "angular-sanitize":  "~1.7.4",
                        "angular-touch":  "~1.7.4",
                        "components-font-awesome":  "~5.0.6",
                        "ngclipboard":  "~2.0.0",
                        "clipboard":  "^2.0.0",
                        "angular-ui-router":  "~1.0.20"
                    }
}

note the new value of version ... [grin]

Lee_Dailey
  • 7,292
  • 2
  • 22
  • 26
  • looks good. How come the formatting is all messed up when you set-content? – r3plica Feb 15 '19 at 11:14
  • @r3plica - that is actually fairly normal JSON formatting. [*grin*] it came from the `ConvertTo-JSON, not the `Set-Content`. – Lee_Dailey Feb 15 '19 at 11:16
  • Can it not retain the same formatting as the original file? – r3plica Feb 15 '19 at 11:17
  • 1
    @r3plica In [PowerShell v6 the formatting is fixed](https://github.com/PowerShell/PowerShell/issues/2736) but don't expect this to be backported to earlier versions. You could help yourself with [this link](https://stackoverflow.com/questions/33145377/how-to-change-tab-width-when-converting-to-json-in-powershell) –  Feb 15 '19 at 12:14
  • @r3plica - by the time that conversion happens ... the format of the original file is long, long gone. if it is not tolerable in your situation, you will need to fix it yourself, unfortunately. i see that LotPings has pointed out a way to do that. [*grin*] – Lee_Dailey Feb 16 '19 at 00:07
0

To answer on your regex approach:

The Replace() method on the string itself is used for simple replacements. PowerShell cannot use regex there.

One way to be done is to use the -replace operator which can make advanced replacements using regex.

Here is an example:

$data = @'
{
  "name": "sapphire",
  "version": "2.4.5",
  "dependencies": {
    "angular": "~1.7.4",
    "angular-animate": "~1.7.4",
    "angular-barcode": "0.0.4",
    "angular-bootstrap": "2.5.0",
    "angular-cookies": "~1.7.4",
    "angular-google-maps": "2.4.1",
    "angular-loading-bar": "0.9.0",
    "angular-mocks": "~1.7.4",
    "angular-resource": "~1.7.4",
    "angular-sanitize": "~1.7.4",
    "angular-simple-cache": "1.0.6",
    "angular-touch": "~1.7.4",
    "angular-ui-mask": "1.8.7",
    "angular-ui-select": "0.19.8",
    "bootstrap-sass-official": "3.3.7",
    "ng-idle": "1.3.2",
    "ng-notify": "0.8.0",
    "vkbeautify": "*",
    "ngclipboard": "~2.0.0",
    "angular-confirm": "angular1-confirm#1.1.0",
    "angular-ui-router": "~1.0.20",
    "font-awesome": "^5.6.1",
    "ng-confirm": "angular-confirm#^1.1.0"
  },
  "devDependencies": {},
  "appPath": "src",
  "moduleName": "sapphire",
  "overrides": {
    "bootstrap": {
      "main": [
        "less/bootstrap.less",
        "dist/css/bootstrap.css",
        "dist/js/bootstrap.js"
      ]
    }
  },
  "resolutions": {
    "angular": "~1.7.4",
    "angular-animate": "~1.7.4",
    "angular-cookies": "~1.7.4",
    "angular-mocks": "~1.7.4",
    "angular-resource": "~1.7.4",
    "angular-sanitize": "~1.7.4",
    "angular-touch": "~1.7.4",
    "components-font-awesome": "~5.0.6",
    "ngclipboard": "~2.0.0",
    "clipboard": "^2.0.0",
    "angular-ui-router": "~1.0.20"
  }
}
'@

$rex = '(?<="version": ")(.*)(?=",)'

$data -replace $rex, "5.1" 

The regular expression is getting anything between "version": " and ",. Thus the replace operator will change all values matched by this pattern with 5.1. You should get this as a result:

"version": "5.1",
pesh
  • 45
  • 5