Powershell INI editing - powershell

I want to changing some values in an INI file. Unfortunately, I have keys in 2 different sections which share an identical name but need different values. My code uses the Get-IniContent function from PsIni.
Example INI file:
[PosScreen]
BitmapFile=C:\Temp\Random.bmp
Bitmap=1
[ControlScreen]
BitmapFile=C:\Temp\Random.bmp
Bitmap=1
I need to change the above to the following:
[PosScreen]
BitmapFile=C:\Temp\FileC.bmp
Bitmap=1
[ControlScreen]
BitmapFile=C:\Temp\FileD.bmp
Bitmap=1
The PowerShell code I am using seems to work, but it changes every value to "File D". It is obviously parsing everything twice, and the name is the same for each section.
$NewFileC = "C:\Temp\FileC.bmp"
$NewFileD = "C:\Temp\FileD.bmp"
$POSIniContent = Get-IniContent "C:\scripts\Update-EnablerImage\WINSUITE.INI"
$BOIniContent = Get-IniContent "C:\scripts\Update-EnablerImage\WINSUITE.INI"
If ($POSIniContent["PosScreen"]["BitmapFile"] -ne $NewFileC) {
Get-Content "C:\scripts\Update-EnablerImage\WINSUITE.INI" |
ForEach-Object {$_ -replace "BitmapFile=.+" , "BitmapFile=$NewFileC" } |
Set-Content "C:\scripts\Update-EnablerImage\WINSUITE.INI"
}
If ($BOIniContent["ControlScreen"]["BitmapFile"] -ne $NewFileD) {
Get-Content "C:\scripts\Update-EnablerImage\WINSUITE.INI" |
ForEach-Object {$_ -replace "BitmapFile=.+" , "BitmapFile=$NewFileD" } |
Set-Content "C:\scripts\Update-EnablerImage\WINSUITE.INI"
}
My struggle is how to change each one independently. I'm a bit of a scripting newbie, so calling out for some help. Tried using Conditional Logic (ForEach $line in $INIFile, for example), but no luck with that.

You are overcomplicating things. You can use Get-IniContent and Out-IniFile as follows:
$ini = Get-IniContent c:\temp\ini.ini
$ini["posscreen"]["BitmapFile"] = "C:\Temp\FileC.bmp"
$ini | Out-IniFile -FilePath c:\temp\ini2.ini
Note that if you want to overwrite the original file, you must add -Force to the Out-IniFile call.

Related

Create multiple files from one CSV, one files from each value in a column [Powershell]

I am new to PowerShell, and I have an issue figuring out how to create from one or multiple .csv files, one file for each value finding in a column, with all the rows that contains in that value.
Let me explain with a example:
I have this source CSV:
I need to create a file for each App in the file. the output of the script should be something like this.
App1.csv
App2.CSV
That for each app that appear in the Original CSV, a new file with all row that have such value, in this case App.
I want to do it in PowerShell so in can be automated, I try with Group-object, then foreach with the values, without luck. I wasn't even remotely close to found the solution.
Thanks in advance and happy coding!
I do not have the most elegant solution, but it works, I checked it on your files, but I ask you to upload the contents of the file as text next time to make it easier to copy. And don't forget choose delimiter in code (I usually use ';')
$some=Import-Csv "D:\testdir\file1.csv" -Delimiter ';'|
Sort-Object header2|
Group-Object -Property header2
foreach ($i in $some){
$i.Group|
Export-Csv -Delimiter ';' -Encoding UTF8 -NoTypeInformation -Force -Path ("D:\testdir\"+$i.Name+".csv")
}
Import the CSV.
Select all the unique values from the column that contains the App name.
Loop through the app names and get all rows where the app name matches.
Export to CSV.
$Path = "./MyFile.csv"
$DestinationDir = "./"
$CSV = Import-CSV -Path $Path
$AppNames = $CSV.H2 | Select -Unique
Foreach ($App in $AppNames)
{
$DestinationPath = Join-Path -ChildPath $App -Path $DestinationDir
$CSV | Where {$_.H2 -eq $APP} | Export-Csv -NoTypeInformation -Path $DestinationPath
}
Example CSV:
H1,H2,H3,H4
Data,App1,Data,Data
Data,App1,Data,Data
Data,App1,Data,Data
Data,App2,Data,Data
Data,App2,Data,Data
For performance reasons, you probably want to use the steppable pipeline here:
$Pipeline = #{}
Import-Csv .\Source.csv |
ForEach-Object -Process {
if (!$Pipeline.Contains($_.Header2)) {
$Pipeline[$_.Header2] = { Export-CSV -notype -Path .\$($_.Header2).csv }.GetSteppablePipeline()
$Pipeline[$_.Header2].Begin($True)
}
$Pipeline[$_.Header2].Process($_)
} -End {
foreach ($Key in $Pipeline.Keys) { $Pipeline[$Key].End() }
}
For a detailed explanation, see: Mastering the (steppable) pipeline

Powershell Adjusting Column Values across multiple text files

New to Powershell and looking for some help. I have multiple xyz files that are currently displaying a z value with positive up and I need to make all the values negative (or z-positive down). So far my best attempt has been to try to cobble together what I know from other lines of code, but I'm still far from a solution.
$data = Get-ChildItem "C:\Users\dwilson\Desktop\test" -Recurse |
foreach ($item in $data) {$item.'Col 3' = 0 - $item.'Col 3'}
Any help would be greatly appreciated!
Somewhat of an aside, but you're using mixed syntax here.
foreach ($i in $set) { ... }
This is the Foreach statement. It does not accept input from the pipeline, nor will it automatically send output down the pipeline. See also Get-Help about_Foreach.
Get-ChildItem | ForEach-Object { ... }
This is the ForEach-Object command. It accepts input from the pipeline and sends output down the pipeline. Critically, this command also has a default alias of foreach. See also Get-Help ForEach-Object.
The help for the Foreach statement explains how PowerShell decides what foreach means (emphasis mine):
When Foreach appears in a command pipeline, PowerShell uses the foreach alias, which calls the ForEach-Object command. When you use the foreach alias in a command pipeline, you do not include the ($<item> in $<collection>) syntax as you do with the Foreach statement. This is because the prior command in the pipeline provides this information.
Using the looping over the files returned by Get-ChildItem you can import each with Import-CSV using the -Header parameter to assign the property name for each column. Then we can update the information for that property then export it. Using the ConvertTo-CSV cmdlet and then using Select-Object -Skip 1 we can drop the header off the CSV before exporting it.
$Files = Get-ChildItem "C:\Users\dwilson\Desktop\test" -Recurse
foreach ($File in $Files) {
$Data = Import-CSV $File -Header 'Col1','Col2','Col3'
$newData = ForEach ($Row in $Data) {
$Row.'Col3' = 0 - $Row.'Col3'
$Row
}
$newData |
Convertto-CSV -NoTypeInformation |
Select-Object -Skip 1 |
Out-File "$($File.Fullname).new)"
}

Update multiple config files using PowerShell scripting

The task is to update the app Settings in web.config and app.config using the power-shell scripting. After some search I found some script to update single file but not for multiple files. Can anyone help?
$Config = C:\inetpub\wwwroot\TestService\Web.config
$doc = (Get-Content $Config) -as [Xml]
$obj = $doc.configuration.appSettings.add | where {$_.Key -eq 'SCVMMServerName'}
$obj.value = CPVMM02
$doc.Save($Config)
I can give you a logical set off. You can get that line which you want to update using the -match in select-string then similarly you can select the remaining things which is already there in file using -notmatch.
Put them in variables. Update the line, store it back in the variable.
Then set both(the modified line variable and the remaining values which you have not modified) back to the file using set-content
Hope you got a set off on how to approach
There are many ways to do this, for instance:
"C:\inetpub\wwwroot\TestService\Web.config",
"C:\inetpub\wwwroot\TestService\App.config" |
ForEach-Object {
$doc = (Get-Content $_) -as [Xml]
$obj = $doc.configuration.appSettings.add |
Where-Object { $_.Key -eq 'SCVMMServerName' }
$obj.value = CPVMM02
$doc.Save($_)
}

Storing output in CSV file

I have wriiten the following SQL script to execute using PowerShell.
cls
foreach ($svr in get-content "demo.txt")
{
$con = "server=MC1-PQ10X.RF.LILLY.COM\SQL01;database=mylilly_WSS_Content_INCTSK0014840;Integrated Security=sspi"
$cmd = "SELECT
Docs.DirName + '/' + Docs.LeafName AS 'Item Name',
DocVersions.UIVersion,
(DocVersions.UIVersion/512) as Version_Label, DocVersions.Level, DocVersions.TimeCreated
FROM DocVersions FULL OUTER JOIN Docs ON Docs.Id = DocVersions.Id
-- INNER JOIN Webs On Docs.WebId = Webs.Id
--INNER JOIN Sites ON Webs.SiteId = SItes.Id
WHERE (DirName LIKE '%globalcontentrepository%')
AND (IsCurrentVersion = '0')
AND (DocVersions.Id IN ('$svr'))"
$da = new-object System.Data.SqlClient.SqlDataAdapter ($cmd, $con)
$dt = new-object System.Data.DataTable
$da.fill($dt) |out-null
$dt | Export-Csv music.csv -Encoding ascii -NoTypeInformation
}
The problem I'm facing with the above code is regarding the output. For every $svr this code is creating a new CSV file. The input file is containing around 1000 inputs. My requirement is that all the output should get stored in the same file rather than creating new file.
There are several ways to achieve your goal. One is to append to the output file as #PeterMmm suggested in the comments to your question:
foreach ($svr in Get-Content "demo.txt") {
...
$dt | Export-Csv music.csv -Encoding ascii -NoTypeInformation -Append
}
Note, however, that Export-Csv doesn't support appending prior to PowerShell v3. Also, appending usually has a negative impact on performance, because you have to repeatedly open the output file. It's better to put the export cmdlet outside the loop and write the output file in one go. foreach loops don't play nicely with pipelines, though, so you'd have to assign the loop output to a variable first:
$music = foreach ($svr in Get-Content "demo.txt") {
...
$dt
}
$music | Export-Csv music.csv -Encoding ascii -NoTypeInformation
or run it in a subexpression:
(foreach ($svr in Get-Content "demo.txt") {
...
$dt
}) | Export-Csv music.csv -Encoding ascii -NoTypeInformation
Personally I'd prefer a ForEach-Object loop over a foreach loop, because the former does work well with pipelines:
Get-Content "demo.txt" | ForEach-Object {
...
$dt
} | Export-Csv music.csv -Encoding ascii -NoTypeInformation
Note that you must replace every occurrence of your loop variable $svr with the "current object" variable $_ for this to work, though.

Powershell. Writing out lines based on string within the file

I'm looking for a way to export all lines from within a text file where part of the line matches a certain string. The string is actually the first 4 bytes of the file and I'd like to keep the command to only checking those bytes; not the entire row. I want to write the entire row. How would I go about this?
I am using Windows only and don't have the option to use many other tools that might do this.
Thanks in advance for any help.
Do you want to perform a simple "grep"? Then try this
select-string .\test.txt -pattern "\Athat" | foreach {$_.Line}
or this (very similar regex), also writes to an outfile
select-string .\test.txt -pattern "^that" | foreach {$_.Line} | out-file -filepath out.txt
This assumes that you want to search for a 4-byte string "that" at the beginning of the string , or beginning of the line, respectively.
Something like the following Powershell function should work for you:
function Get-Lines {
[cmdletbinding()]
param(
[string]$filename,
[string]$prefix
)
if( Test-Path -Path $filename -PathType Leaf -ErrorAction SilentlyContinue ) {
# filename exists, and is a file
$lines = Get-Content $filename
foreach ( $line in $lines ) {
if ( $line -like "$prefix*" ) {
$line
}
}
}
}
To use it, assuming you save it as get-lines.ps1, you would load the function into memory with:
. .\get-lines.ps1
and then to use it, you could search for all lines starting with "DATA" with something like:
get-lines -filename C:\Files\Datafile\testfile.dat -prefix "DATA"
If you need to save it to another file for viewing later, you could do something like:
get-lines -filename C:\Files\Datafile\testfile.dat -prefix "DATA" | out-file -FilePath results.txt
Or, if I were more awake, you could ignore the script above, use a simpler solution such as the following one-liner:
get-content -path C:\Files\Datafile\testfile.dat | select-string -Pattern "^DATA"
Which just uses the ^ regex character to make sure it's only looking for "DATA" at the beginning of each line.
To get all the lines from c:\somedir\somefile.txt that begin with 'abcd' :
(get-content c:\somedir\somefile.txt) -like 'abcd*'
provided c:\somedir\somefile.txt is not an unusually large (hundreds of MB) file. For that situation:
get-content c:\somedir\somefile.txt -readcount 1000 |
foreach {$_ -like 'abcd*'}