Context
I have a multi line file named DEV.properties. It contains references to ENV variables
ACTIVEMQ_DB_USERNAME=${ACTIVEMQ_DB_USERNAME}
I am writing a ps script to replace this file with one populated with the relevant variables
Problem
Here is how I proceed
#first load variables from a file
Get-Content C:\somewhere\over\the\rainbow\.credentials | Foreach-Object{$var = $_.Split('=');New-Variable -Name $var[0] -Value $var[1]}
$template = Get-Content DEV.properties
$expanded = $ExecutionContext.InvokeCommand.ExpandString($template)
Substitution is successful but while $template is a multi line string, all CRLF seems to have disappeared from $expanded. How can I fix it? Is there a more direct approach than looping though all lines?
$expanded = $template | %{ $ExecutionContext.InvokeCommand.ExpandString($_) }
Related
I want to add text into specific line of txt file. I can't find any solution on internet.
This code adds text in further line (I want for example second line):
$test_out = "test"
$test_out | Add-Content "C:\tmp\test.txt"
If you want to add text to the end of a specific line, you can do it like this
$fileContent = Get-Content $filePath
$fileContent[$lineNumber-1] += $textToAdd
$fileContent | Set-Content $filePath
If you want to replace the text instead of adding, just remove the '+' sign.
You do of course have to set the variables
$filePath, $textToAdd and $lineNumber first.
Here a solution which reads the content of the file and access the line using the array index (-1). This example adds the line test and a line break to the second line.
$filePath = 'C:\tmp\test.txt'
$test_out = "test"
$fileContent = Get-Content -Path $filePath
$fileContent[1] = "{0}`r`n{1}" -f $test_out, $fileContent[1]
$fileContent | Set-Content $filePath
I have a file 'abc.txt' that contains below lines.
c:myfilepath\filepath\filepath1\file1.csv
c:myfilepath\filepath\filepath1\file2.csv
c:myfilepath\filepath\filepath1\file2.csv
How to loop through the above file 'abc.txt' and read line by line and create another file called 'xyz.txt' that should contains like below. The file name in the path in 'xyz.txt' should be different, see below (ex. newfile_file1.txt)
c:mynewfile\newfilepath\newfilepath1\newfile_file1.txt (<-This is
corresponding to file1.csv)
c:mynewfile\newfilepath\newfilepath1\newfile_file2.txt
c:mynewfile\newfilepath\newfilepath1\newfile_file2.txt
I've tried using Get-Content to loop through the file but I just get nothing returned. I'm unclear as to where to put the syntax and how to completely construct it.
This should do it (edited to get file names and paths as requested, and dynamic so the paths in the abc-file are used).
$f = Get-Content C:\temp\abc.txt # this is the contents-file
foreach ($r in $f)
{
$r2 = (Split-Path $r).Replace("\", "\new") + '\newfile_' + [io.path]::GetFileNameWithoutExtension($r) + '.txt'
$r2 = $r2.replace(":\", ":\mynewfile\")
Get-Content $r | Out-File -filepath $r2
}
Assuming all of your file paths start with c:myfilepath\filepath\filepath1, then you can just replace the string then Out-File it.
$File1 = get-content E:\abc.txt
$File1 -replace ('c:myfilepath\\filepath\\filepath1\\', 'c:mynewfile\newfilepath\newfilepath1\newfile_') |
Out-File E:\xyz.txt
Note the double backslashes \\ which escape the regex.
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.
When running the following code:
$txt = Get-Content file1.txt
$a = #"
-- file start --
$txt
-- file end --
"#
$a
All new lines are removed from the file's contents, but just running
$txt
prints out the file without stripping the new lines.
Any idea how to get it to work as desired using the here-string?
Thanks!
If you put an array in a string it will be expanded with $OFS (or a space if $OFS is $null) between the items. You can see the same effect with either
"$txt"
''+$txt
and a few others. You can set $OFS="`r`n" which would change the space with which they are joined to a line break.
You could also change the Get-Content at the start to either
$txt = Get-Content file1.txt | Out-String
$txt = [IO.File]::ReadAllText((Join-Path $pwd file1.txt))
Pipe $txt to Out-String inside a sub-expression.
$a = #"
-- file start --
$($txt | Out-String)
-- file end --
"#
I've got a file containing some data in PowerShell Object Notation:
#{ X = 'x'; Y = 'y' }
I'd like to load this into a variable from the file.
(I figured it out while putting together a repro)
PS> $content = ( Get-Content .\foo.pson | Out-String )
PS> $data = ( Invoke-Expression $content )
Get-Content returns an array with the lines in the file; the Out-String is used to join them together.
Invoke-Expression then runs the script, and the result is captured. This is open to injection attacks, but that's OK in my specific case.
Or, if you prefer your PowerShell terse:
PS> $data = gc .\foo.pson | Out-String | iex
(I can't find a shorter form of Out-String)
I've used ConvertFrom-StringData. If you want to use this approach you'll need to change the way you store key/value pairs with each on its own line and no quotes:
#Contents of test.txt
X = x
Y = y
get-content .\test.txt | ConvertFrom-StringData
Name Value
---- -----
X x
Y y
ConvertFrom-StringData is a built-in cmdlet. I created corresponding ConvertTo-StringData function available here http://poshcode.org/1986
I ran into trouble using ConvertFrom-StringData as #Chad suggested. If you do:
$hash = get-content .\test.txt | ConvertFrom-StringData
I found I had an object array rather than a hash table. In fact, it appears that I had an array of hash tables, each with one entry. I confirmed with a:
$hash.GetType()
It looks like you need to join each line of the slurped input file to ensure that it forms a single string for ConvertFrom..'s use:
$hash = ((get-content .\test.txt) -join '`n') | ConvertFrom-StringData
If you can give this file the extension .ps1, say, data.ps1 then it cannot be simpler than this code:
$data = <path>\data.ps1
Starting from PowerShell 5.0 you have
Import-PowerShellDataFile
Which imports values from a .psd1-file. So the only thing you have to do is rename your file to *.psd1
Official help is here.
This is an older post but, this is sort of a twist on your accepted solution and perhaps slightly more "safe", keep in mind un-trusted files.
From your notes, you have a file that contains a hashtable using Powershell syntax. Given that constraint, you can import it directly:
$HashPath = ".\foo.pson"
# input file contents
$filecontent = Get-Content -Path $HashPath -Raw -ErrorAction Stop
# put the file in a script block
$scriptBlock = [scriptblock]::Create( $filecontent )
#check that the file contains no other Powershell commands
$scriptBlock.CheckRestrictedLanguage( $allowedCommands, $allowedVariables, $true )
#execute it to create the hashtable
$hashtable = ( & $scriptBlock )
Note on the $scriptBlock.CheckRestrictedLanguage you could replace that with
$scriptBlock.CheckRestrictedLanguage([string[]]#(), [string[]]#(), $false)
Use an empty list of strings so we do not allow any Powershell commands. When importing a hashtable, this is exactly what we want. That last one is allowEnvironmentVariables so we restrict that in this example with $false.
Side note, a Powershell module (psd1 file) is just a hashtable so this concept may help you to also pull in script blocks or other things.
Reference: https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.scriptblock.checkrestrictedlanguage?view=powershellsdk-1.1.0