How to edit INI file value in Powershell? - powershell

I have an INI file:
[Name]
Female = 10
Male = 30
[Class]
Kids = 2
Adult = 10
I want to change the value of each section. Give me idea please.
I tried this code:
function Set-OrAddIniValue
{
Param(
[string]$FilePath,
[hashtable]$keyValueList
)
$content = Get-Content $FilePath
$keyValueList.GetEnumerator() | ForEach-Object {
if ($content -match "^$($_.Key)=")
{
$content= $content -replace "^$($_.Key)=(.*)", "$($_.Key)=$($_.Value)"
}
else
{
$content += "$($_.Key)=$($_.Value)"
}
}
$content | Set-Content $FilePath
}
this is the code

You would do so:
$ini = Get-IniContent "<pathToYourIniFile>"
$ini["<yourSection>"]["<yourKey>"] = "<yourValue>"
$ini | out-inifile -FilePath "<pathToYourIniFile>"

If you updated your code to the following, it will be more successful:
function Set-OrAddIniValue
{
Param(
[string]$FilePath,
[hashtable]$keyValueList
)
$content = Get-Content $FilePath
$keyValueList.GetEnumerator() | ForEach-Object {
if ($content -match "$($_.Key)\s*=")
{
$content= $content -replace "$($_.Key)\s*=(.*)", "$($_.Key)=$($_.Value)"
}
else
{
$content += "$($_.Key)=$($_.Value)"
}
}
$content | Set-Content $FilePath
}
One problem will be if you add extra key/value pairs, they will all be added to the last section. In other words, the code is not section-aware.

Related

How to modify Firefox config (pref.js) line using Powershell

Modifying the Mozilla Firefox Pref.js file using PowerShell.
Need to modify the pref.js file line to reflect a new value
(Hence, instead of any value under user_pref("network.automatic-ntlm-auth.trusted-uris", "*"); to show user_pref("network.automatic-ntlm-auth.trusted-uris", ".abc.com,.abcd.com,.abcde.com") or just add changes after the *
$TopDir = "$env:APPDATA\Mozilla\Firefox\Profiles"
$FileName = 'prefs.js'
$DefaultProfileDir = (Get-ChildItem -LiteralPath $TopDir -Directory).
Where({
$_.FullName -match '\.default'
}).FullName
$FullFileName = Join-Path -Path $DefaultProfileDir -ChildPath $FileName
$data = foreach($line in Get-Content $FullFileName)
{
if($line -contains 'user_pref("network.automatic-ntlm-auth.trusted-uris".*')
{
$line -replace '*' , 'user_pref("network.automatic-ntlm-auth.trusted-uris", ".abc.com,.abcd.com,.abcde.com");'
}
else
{
$line
}
}
$data | Set-Content C:\testfolder\test2.txt
Nelson,
I didn't have your line in my FF profile but I got the code to work on another line so you should be able to modify it to work with yours.
$TopDir = "G:\Test"
$FileName = 'prefs.js'
$FullFileName = "$TopDir\$FileName"
Clear-Host
$Data = foreach($line in Get-Content $FullFileName) {
if( ($line.IndexOf('browser.bookmarks.restore_default_bookmarks')) -ne -1)
{
If ($line.IndexOf('false') -ne -1) {
$line = $line.replace( 'false' , 'true')
}
}
$line
}
$data | Set-Content $("$TopDir" + "\prefs2.js")
I think your code would be:
$TopDir = "$env:APPDATA\Mozilla\Firefox\Profiles"
$FileName = 'prefs.js'
$DefaultProfileDir = (Get-ChildItem -LiteralPath $TopDir -Directory).
Where({
$_.FullName -match '\.default'
}).FullName
$FullFileName = Join-Path -Path $DefaultProfileDir -ChildPath $FileName
$Data = foreach($line in Get-Content $FullFileName) {
if( ($line.IndexOf('network.automatic-ntlm-auth.trusted-uris')) -ne -1)
{
If ($line.IndexOf('*') -ne -1) {
$line = $line.replace( '*' , 'abc.com,.abcd.com,.abcde.com')
}
}
$line
}
$data | Set-Content C:\testfolder\test2.txt
Note: -contains is designed for lists.
HTH
I extended it to be easier to use any property
Input
user_pref("foo", "bar")
user_pref("network.automatic-ntlm-auth.trusted-uris", "*")
Output
user_pref("foo", "bar")
user_pref("network.automatic-ntlm-auth.trusted-uris", ".abc.com,.abcd.com,.abcde.com")
$lines = 'user_pref("foo", "bar")', 'user_pref("network.automatic-ntlm-auth.trusted-uris", "*")'
# multi-line regex for readability
$regex = '(?x)
(?<prefix>user_pref\()
(?<name>
".*"
)
\s*,\s*
(?<value>
".*"
)
(?<suffix>.*)
'
"`ninput:"
$lines
"`noutput:"
$lines | ForEach-Object {
if($_ -match $regex) {
if($matches.name -eq '"network.automatic-ntlm-auth.trusted-uris"') {
$_ = '{0}{1}, {2}{3}' -f #(
$Matches.prefix,
$Matches.name,
'".abc.com,.abcd.com,.abcde.com"',
$Matches.suffix
)
}
}
$_
}

How to read a specific item of INI file using PowerShell?

I want to read a specific item of my INI file, I have 5 Items in the section of my INI file, and I want to read 4 items, except items number 3.
I already tried to read all the items, but I can not find a way how to specify the item that I want to read and the format of the file that I read is like this:
Name Value
AA 12
BB 13
CC 14
DD 15
EE 16
I used this command to execute it.
File1.ps1 Read-File -FilePath C:\Users\Data.ini -a_section Code -store C:\Users\
function Read-File {
Param(
[Parameter(Mandatory=$true)]$FilePath,
[Parameter(Mandatory=$true)]$a_section,
[Parameter(Mandatory=$true)]$store
)
$input_file = $FilePath
$ini_file = #{}
Get-Content $input_file | ForEach-Object {
$_.Trim()
} | Where-Object {
$_ -notmatch '^(;|$)'
} | ForEach-Object {
if ($_ -match '^\[.*\]$') {
$section = $_ -replace '\[|\]'
$ini_file[$section] = #{}
} else {
$key, $value = $_ -split '\s*=\s*', 2
$ini_file[$section][$key] = $value
}
}
$Path_Store = $store
$Get_Reg = $ini_file.($a_section)
$Output = $Get_Reg | Out-File $Path_Store\Out_Test
}
$cmd, $params = $args
& $cmd #params
My expectation result, I have an output file like this
AA=12
BB=13
DD=15
EE=16
My INI File look like this:
[Name]
1=Joe
2=Grace
[Code]
AA=12
BB=13
CC=14
DD=15
EE=16
Try this:
function Get-IniSection {
Param(
[Parameter(Mandatory=$true)]$Path,
[Parameter(Mandatory=$true)]$SectionName
)
$ini_file = #{}
Get-Content $Path | ForEach-Object {
$_.Trim()
} | Where-Object {
$_ -notmatch '^(;|$)'
} | ForEach-Object {
if ($_ -match '^\[.*\]$') {
$section = $_ -replace '\[|\]'
$ini_file += #{ $section = #{} }
} else {
$key, $value = $_ -split '\s*=\s*', 2
$ini_file[$section] += #{ $key = $value }
}
}
return $ini_file[$SectionName]
}
$section = Get-IniSection -Path "C:\temp\test.ini" -SectionName "code"
$section.GetEnumerator() | Where-Object { $_.Name -ne "EE" }
$section.GetEnumerator() | ForEach-Object { "$($_.Name)=$($_.Value)" }
$section.GetEnumerator() |
Where-Object { $_.Name -in #("A1","AE","AP","AS","E1","E2","JP","M1","M2","N1","N2","P1","P2","P3","P4","PR","RU","S1","S2","W1","W2","W3","W4","ZH") } |
Select-Object -ExpandProperty "Value"
$section.GetEnumerator() |
Where-Object { $_.Name -in #("A1","AE","AP","AS","E1","E2","JP","M1","M2","N1","N2","P1","P2","P3","P4","PR","RU","S1","S2","W1","W2","W3","W4","ZH") } |
Foreach-Object { ($_.Value -split ",")[0] }

How do I use Function in PowerShell to execute from Command Line?

I want to execute my script with command line. I use function inside my script.
I used this script:
Function Get-IniFile
{
Param(
[parameter(mandatory=$true)][string]$FilePath
)
$input_file = $FilePath
$ini_file = #{}
Get-Content $input_file | ForEach-Object {
$_.Trim()
} | Where-Object {
$_ -notmatch '^(;|$)'
} | ForEach-Object {
if ($_ -match '^\[.*\]$') {
$section = $_ -replace '\[|\]'
$ini_file[$section] = #{}
} else {
$key, $value = $_ -split '\s*=\s*', 2
$ini_file[$section][$key] = $value
}
}
$Get = $ini_file.Class.Amount
$Get
}
I execute this script from command line with this command:
PowerShell.ps1 Get-IniFile -FilePath
I dont get any result when I execute this code, but If I remove "Function Get-IniFile" I got the value of Amount.
This is my INI file
[Class]
Amount = 1000
Feature = 20
[Item]
Set = 100
Return = 5
You have to call your function inside your script. The script code is like your main function in C# or Java.
PowerShell.ps1 content :
# Global script parameters.
Param(
[parameter(mandatory=$true)][string]$FilePath
)
# Definition of the function
Function Get-IniFile
{
Param(
[parameter(mandatory=$true)][string]$Path
)
$input_file = $Path
$ini_file = #{}
Get-Content $input_file | ForEach-Object {
$_.Trim()
} | Where-Object {
$_ -notmatch '^(;|$)'
} | ForEach-Object {
if ($_ -match '^\[.*\]$') {
$section = $_ -replace '\[|\]'
$ini_file[$section] = #{}
} else {
$key, $value = $_ -split '\s*=\s*', 2
$ini_file[$section][$key] = $value
}
}
$Get = $ini_file.Class.Amount
$Get
}
# Calling the function with the global parameter $FilePath
Get-IniFile $FilePath

Perform function for all c:\users\*\AppData\Local

Got the following script that I thought would happily update the specified .ini file in each C:\users\*\AppData\Local\Greeentram folder individually.
function Set-OrAddIniValue {
Param(
[string]$FilePath,
[hashtable]$keyValueList
)
$content = Get-Content $FilePath
$keyValueList.GetEnumerator() | ForEach-Object {
if ($content -match "^$($_.Key)=") {
$content= $content -replace "^$($_.Key)=(.*)", "$($_.Key)=$($_.Value)"
} else {
$content += "$($_.Key)=$($_.Value)"
}
}
$content | Set-Content $FilePath
}
Set-OrAddIniValue -FilePath "C:\Users\*\AppData\Local\Greentram\SDA_Apps.ini" -keyValueList #{
UserName = "Dcebtcv7[[G"
UserEmail = "x}tpwpjmkxmvkYjmklzmx7zv7lr"
UserNo = "*++*(+"
UserKey = "^X(_0[*_/0L)\_0,U,-"
KEM = "H10"
}
What it seems to be doing is somehow combining all the .INI files together and creating a new .INI file for each user.
I have wrongly assumed that C:\Users\*\AppData\Local\Greentram\SDA_Apps.ini would work.
I only want to update or add these specific values to each .INI file.
Set-OrAddIniValue -FilePath "C:\Users\*\AppData\Local\Greentram\SDA_Apps.ini" -keyValueList #{
UserName = "Dcebtcv7[[G"
UserEmail = "x}tpwpjmkxmvkYjmklzmx7zv7lr"
UserNo = "*++*(+"
UserKey = "^X(_0[*_/0L)\_0,U,-"
KEM = "H10"
}
Your function Set-OrAddIniValue doesn't handle wildcards in paths.
$content = Get-Content $FilePath
...
$content | Set-Content $FilePath
The first statement reads the content of all matching files into a single array. The second statement then writes the entire modified content to all matching files. (How would it decide which content belongs to which file?)
You can either call your function for each file individually:
Get-ChildItem "C:\Users\*\AppData\Local\Greentram\SDA_Apps.ini" | ForEach-Object {
Set-OrAddIniValue -FilePath $_.FullName -keyValueList ...
}
or change your function so that it does the enumeration internally:
function Set-OrAddIniValue {
Param(
[string]$FilePath,
[hashtable]$keyValueList
)
Get-ChildItem $FilePath | Where-Object {
-not $_.PSIsContainer # process only files
} | ForEach-Object {
$file = $_.FullName
$content = Get-Content $file
...
$content | Set-Content $file
}
}
On PowerShell v3 and newer you can use Get-ChildItem -File instead of piping the object list through Where-Object {-not $_.PSIsContainer}.

Replace or add .INI file content

Need to update a .INI file across multiple computers and change the contents. I have the following script that works:
(Get-Content SDA_Apps.ini) | Foreach-Object {
$_ -replace "UserName=.+", "UserName=Test" `
-replace "UserEmail=.+", "UserEmail=test#test.com" `
-replace "UserNo=.+", "UserNo=1234" `
-replace "UserKey=.+", "UserKey=^%&$*$778-" `
-replace "KEM=.+", "KEM=H10"
} | Set-Content SDA_Apps.ini
Sometimes those lines of text do not exist and I need to add the text instead of replace it.
This is my attempt to do this - without success:
function setConfig( $file, $key1, $value1, $key2, $value2 ) {
$content = Get-Content $file
if ( $content -match "^$key\s*=" ) {
$content $_ -replace "^$key1\s*=.*", "$key1=$value1" -replace "^$key2\s*=.*", "$key2=$value2"|
Set-Content $file
} else {
Add-Content $file "$key1 = $value1"
Add-Content $file "$key2 = $value2"
}
}
setConfig "SDA_Apps.ini" "UserName" "Test" "UserEmail" "test#test.com"
I rewrote your function and renamed it to reflect what it actualy does Set-OrAddIniValue:
function Set-OrAddIniValue
{
Param(
[string]$FilePath,
[hashtable]$keyValueList
)
$content = Get-Content $FilePath
$keyValueList.GetEnumerator() | ForEach-Object {
if ($content -match "^$($_.Key)=")
{
$content= $content -replace "^$($_.Key)=(.*)", "$($_.Key)=$($_.Value)"
}
else
{
$content += "$($_.Key)=$($_.Value)"
}
}
$content | Set-Content $FilePath
}
The benefit of this function is that you can pass a key-value list as a hashtable to it. It reads the ini file only once, updates the content and saves it back. Here is an usage example:
Set-OrAddIniValue -FilePath "c:\yourinipath.ini" -keyValueList #{
UserName = "myName"
UserEmail = "myEmail"
UserNewField = "SeemsToWork"
}