Using .TXT file as input variables - PowerShell - powershell

I have the following script that I have to input manually.
However, I am looking to provide a text file along with the script to read the inputs from there.
For example, I have two variable below:
$RedirectURIs = $CustomerWebUIurl
$appURI = $CustomerSamlIssuerID
Where I need to pull the following values from text file
$CustomerWebUIurl
$CustomerSamlIssuerID
So when I add
$configFile = Get-Content -Path .\config.conf
What else I can use/add to define those two lines in the text file to the two variables I have in the script?
Thanks for the help!

Your config file is in a format that the ConvertFrom-StringData can process, which converts lines of =-separated key-value pairs into hashtables:
# Create a sample config.conf file
#'
$CustomerWebUIurl = http://example.org&1
$CustomerSamlIssuerID = http://example.org&2
'# > ./config.conf
# Load the key-value pairs from ./config.conf into a hashtable:
$config = ConvertFrom-StringData (Get-Content -Raw ./config.conf)
# Output the resulting hashtable
$config
The above yields:
Name Value
---- -----
$CustomerWebUIurl http://example.org&1
$CustomerSamlIssuerID http://example.org&2
That is, $config now contains a hashtable with entries whose key names are - verbatim - $CustomerWebUIurl and $CustomerSamlIssuerID, which you can access as follows: $config.'$CustomerWebUIurl' and $config.'$CustomerSamlIssuerID'
The need to quote the keys on access is somewhat cumbersome, and the fact that the key names start with $ can be confusing, so I suggest defining your config-file entries without a leading $.
If you have no control over the config file, you can work around the issue as follows:
# Trim the leading '$' from the key names before converting to a hashtable:
$config = ConvertFrom-StringData ((Get-Content -Raw .\config.conf) -replace '(?m)^\$')
Now you can access the entries more conveniently as $config.CustomerWebUIurl and $config.CustomerSamlIssuerID

I just figured out how, to use simply array:
Here is the answer script
$configFile = Get-Content -Path .\config.conf
$configFile.GetType()
$configFile.Count
$configFile
$CustomerWebUIurl = $configFile[0]
$CustomerWebUIurl
$CustomerSamlIssuerID = $configFile[1]
$CustomerSamlIssuerID

Related

how to parse this (inner)xml?

i’m very new to powershell, and i’m abit stuck.
I have this innerXML:
<sl-test.protocol>HTTP</sl-test.protocol>
<sl-test.responseTimeout>14000</sl-test.responseTimeout>
<env>${myenv}</env>
<http.port>8081</http.port>
And i want to convert it into a .properties file in this format:
sl-test.protocol=HTTP
sl-test.responseTimeout=14000
env=${myenv}
http.port=8081
i have the part to create the .properties file (hardcoded value right now) which works:
$test = New-Item -Name "mule-app.properties" -ItemType "file" -Value "test.prop=testprop`ntest2.prop=test2prop"
So basically i need to go from the innerXML to a big string of key/values separated by `n
But also i need to escape any $ with a backtick
desired string:
sl-test.protocol=HTTP`nsl-test.responseTimeout=14000`nenv`${myenv}`nhttp.port=8081
But right now i cant even seem to iterate through all the keys and values.
Note: the keys and values will be dynamic, it will not always be those 4
Any help will be greatly appreciated.
The .ChildNodes property of the nodes in an [xml] (System.Xml.XmlDocument instance allows you to loop over a given XML element's (System.Xml.XmlElement) child elements.
# Sample XML input.
[xml] $xml = #'
<el>
<sl-test.protocol>HTTP</sl-test.protocol>
<sl-test.responseTimeout>14000</sl-test.responseTimeout>
<env>${myenv}</env>
<http.port>8081</http.port>
</el>
'#
# Loop over all child elements of the document element.
$xml.el.ChildNodes |
ForEach-Object {
# Create and output a line for the output file, based on the
# element's name and inner text, with "$" escaped as "`$"
'{0}={1}' -f $_.Name, $_.InnerText.Replace('$', '`$')
} | # Set-Content out.properties -Encoding utf8
Uncomment and adapt the Set-Content call as needed.

Replace text at specific line number with file name

I have 400+ .vcf files that I would like to replace the "FN:" line (line 4) with the file name. I've looked at multiple solutions and I can't seem to find something that will achieve what I'm looking for even though I know there's a way to do this.
This is what I have currently
File Name: LastNamefirstName
BEGIN:VCARD
VERSION:3.0
N:lastName;firstName;;;
FN:firstName lastName
ADR:;;111 Main Rd;Columbia;MO;65202;
TEL;TYPE=mobile:(111) 222-3333
EMAIL;TYPE=work:email#gmail.com
BDAY:20000101
END:VCARD
This is what I would like to achieve
Keep "FN:" and replace the text after it with the file name text.
BEGIN:VCARD
VERSION:3.0
N:lastName;firstName;;;
FN:LastNamefirstName
ADR:;;111 Main Rd;Columbia;MO;65202;
TEL;TYPE=mobile:(111) 222-3333
EMAIL;TYPE=work:email#gmail.com
BDAY:20000101
END:VCARD
This Powershell script does do half what I want but I would really like to take the file name and input it in the replacementLineText.
# Set by user to their needs.
$filesToCheck = "C:\path\*.vcf"
$lineToChange = 4
$replacementLineText = "New Text"
# Gather list of files based on the path (and mask) provided by user.
$files = gci $filesToCheck
# Iterate over each file.
foreach ($file in $files) {
# Load the contents of the current file.
$contents = Get-Content $file
# Iterate over each line in the current file.
for ($i = 0; $i -le ($contents.Length - 1); $i++) {
# Are we on the line that the user wants to replace?
if ($i -eq ($lineToChange - 1)) {
# Replace the line with the Replacement Line Text.
$contents[$i] = $replacementLineText
# Save changed content back to file.
Set-Content $file $contents
}
}
}
Any input or guidance would be greatly appreciated!
I would really like to take the file name and input it in the replacementLineText.
To accept the paths of all target files, all you need to do is declare a parameter:
param(
[Parameter(Mandatory = $true)]
[string[]]$Path
)
$lineToChange = 4
# Gather list of files based on the path (and mask) provided by user.
$files = gci -Path $Path
# ... rest of original script
I made a slight modification to the variable names - Path is the idiomatic parameter name for strings describing expandable paths, and parameter names are generally expected to be upper case.
The Mandatory flag in the [Parameter()] attribute associated with $Path means that the caller MUST supply a value - otherwise PowerShell will prompt for it:
PS C:\> .\script.ps1
cmdlet script.ps1 at command pipeline position 1
Supply values for the following parameters:
Path:
PS C:\> .\script.ps1 -Path "C:\path\*.vcf" # now it won't prompt
For more information on parameters, see the about_Functions and about_Functions_Advanced_Parameters help topics - although the documentation is about functions, the rules for parameters and their declaration is the same for script files (you can think of a script file as a function that happens to sit on the filesystem instead of in memory)
The gci (or Get-ChildItem) cmdlet returns [FileInfo] objects, with all the files metadata, so to use the file name as the replacement value inside the loop, you simply do $file.Name:
$contents[$i] = "FN:$($file.Name)"
# or using the -f format operator:
$contents[$i] = "FN:{0}" -f $file.Name
Since you already know which index (line number minus 1) you want to modify, you can skip the inner loop and instead do:
param(
[Parameter(Mandatory = $true)]
[string[]]$Path
)
$lineToChange = 4
# Gather list of files based on the path (and mask) provided by user.
$files = Get-ChildItem -Path $Path
# Iterate over each file.
foreach ($file in $files) {
# Load the contents of the current file.
$contents = Get-Content $file
if($contents.Count -ge $lineToChange){
# Replace the line with the Replacement Line Text.
$contents[$lineToChange - 1] = "FN:$($file.Name)"
# Save changed content back to file.
Set-Content $file $contents
}
}

Select String From Text File and Create variable

I have a text file containing a string I need to make a variable. I need the value for "file" to be retained as a variable. How can I capture this and make it a variable: "\APPSRV\I\Run\OPTI\CLIENT\20171031\25490175\Data\brtctybv\". This data will change per file, but it will retain the same format, it will start with \ and end with \
Example Text File
order_id = 25490175-brtctybv
file = \\APPSRV\I\Run\OPTI\CLIENT\20171031\25490175\Data\brtctybv\
copies = 1
volume = 20171031-brtctybv
label = \\domain.com\prodmaster\jobs\OPTI\CLIENT\Cdlab\somefile.file
merge = \\APPSRV\I\Run\OPTI\CLIENT\20171031\25490175\mrg\25490175-brtctybv.MRG
FIXATE = NOAPPEND
$file = ((Get-Content -path file.txt) | Select-String -pattern "^file\s*=\s*(\\\\.*\\)").matches.groups[1].value
$file
See Regex Demo to see the regex in action. The .matches.groups[1].value is grabbing the value of capture group 1. The capture group is created by the () within the pattern. See Select-String for more information about the cmdlet.
Regexes are powerful, but complex; sometimes there are conceptually simpler alternatives:
PS> ((Get-Content -Raw file.txt).Replace('\', '\\') | ConvertFrom-StringData).file
\\APPSRV\I\Run\OPTI\CLIENT\20171031\25490175\Data\brtctybv\
The ConvertFrom-StringData cmdlet is built for parsing key-value pairs separated by =
\ in the values is interpreted as an escape character, however, hence the doubling of \ in the input file with .Replace('\', '\\').
The result is a hash table (type [hashtable]); Get-Content -Raw - the input file read as a single string - is used to ensure that a single hash table is output); accessing its file key retrieves the associated value.

How to append last field of a line in a file to a variable on powershell cli?

Here is my file hello.txt:
"ReceiptHandle" = "hellomyfriend==++"
I would like to append only the last field of a line to a variable:
$friend = hellomyfriend==++
Assuming that is all that's in your hello.txt file. The following would assign "" to your $friend variable...
$myhash = (gc 'hello.txt') -replace """","" | ConvertFrom-StringData
$friend = $myhash["ReceiptHandle"]
ConvertFrom-StringData makes this easy because your text is already in "something = value" format.
So what's going on here? First,
gc 'hello.txt'
is getting the contents of your file. I encapsulate it in () so that i can use..
-replace """",""
.. to get rid of the surrounding double-quotes. That's piped into ConvertFrom-StringData, which converts the string into a named key/value pair [hashtable]. From there, I can access the second part by interrogating the hashtable.
Alternatively, you could put this all on one line...
(gc 'hello.txt') -replace """","" | ConvertFrom-StringData | %{$friend = $_["ReceiptHandle"]}

How can I use PowerShell to expand placeholders in a template string using values read from an INI file?

values.ini looks like
[default]
A=1
B=2
C=3
foo.txt looks like
Now is the %A% for %a% %B% men to come to the %C% of their %c%
I want to use Powershell to search for all of the %x% values in values.ini and then replace every matching instance in foo.txt with the corresponding value, case insensitively; generating the following:
Now is the 1 for 1 2 men to come to the 3 of their 3
Assuming PowerShell version 3.0 or newer, you can use the ConvertFrom-StringData cmdlet to parse the key-value pair in your ini file, but you'll need to filter out the [default] directive:
# grab relevant lines from file
$KeyValPairs = Get-Content .\values.ini | Where {$_ -like "*=*" }
# join strings together as one big string
$KeyValPairString = $KeyValPairs -join [Environment]::NewLine
# create hashtable/dictionary from string with ConvertFrom-StringData
$Dictionary = $KeyValPairString |ConvertFrom-StringData
You can then use the [regex]::Replace() method to do a lookup against the dictionary for each match you want to replace:
Get-Content .\foo.txt |ForEach-Object {
[Regex]::Replace($_, '%(\p{L}+)%', {
param($Match)
# look term up in dictionary
return $Dictionary[$Match.Groups[1].Value]
})
}
To complement Mathias R. Jessen's excellent answer with alternative approaches that also take the later requirement change of limiting values to a specific INI-file section into account (PSv2+, except for Get-Content -Raw; in PSv2, use (Get-Content ...) -join "`n" instead.)
Using PsIni\Get-IniContent and [environment]::ExpandEnvironmentVariables():
# Translate key-value pairs from section the section of interest
# into environment variables.
# After this command, the following environment variables are defined:
# $env:A, with value 1 (cmd.exe equivalent: %A%)
# $env:B, with value 2 (cmd.exe equivalent: %B%)
# $env:C, with value 3 (cmd.exe equivalent: %C%)
$section = 'default' # Specify the INI-file section of interest.
(Get-IniContent values.ini)[$section].GetEnumerator() |
ForEach-Object { Set-Item "env:$($_.Name)" -Value $_.Value }
# Read the template string as a whole from file foo.txt, and expand the
# environment-variable references in it, using the .NET framework.
# With the sample input, this yields
# "Now is the 1 for 1 2 men to come to the 3 of their 3".
[environment]::ExpandEnvironmentVariables((Get-Content -Raw foo.txt))
The 3rd-party Get-IniContent cmdlet, which conveniently reads an INI file (*.ini) into a nested, ordered hashtable, can easily be installed with Install-Module PsIni from an elevated console (alternatively, add -Scope CurrentUser), if you have PS v5+ (or v3 or v4 with PackageManagement installed).
This solution takes advantage of the fact that the placeholders (e.g., %a%) look like cmd.exe-style environment-variable references.
Note the assumptions and caveats:
All ini-file keys / placeholder names are legal environment-variable names.
Preexisting variables may be overwritten, which can be problematic with names such as PATH.
Cross-platform caveat: on Unix-like platforms, environment-variable references are case-sensitive, so the solution won't work the same there.
Using custom INI-file parsing and [environment]::ExpandEnvironmentVariables():
If installing a module for INI-file parsing is not an option, the following solution uses a - rather complex - regular expression to extract the section of interest via the -replace operator.
$section = 'default' # Specify the INI-file section of interest.
# Get all non-empty, non-comment lines from the section using a regex.
$sectLines = (Get-Content -Raw values.ini) -replace ('(?smn)\A.*?(^|\r\n)\[' + [regex]::Escape($section) + '\]\r\n(?<sectLines>.*?)(\r\n\[.*|\Z)'), '${sectLines}' -split "`r`n" -notmatch '(^;|^\s*$)'
# Define the key-value pairs as environment variables.
$sectlines | ForEach-Object { $tokens = $_ -split '=', 2; Set-Item "env:$($tokens[0].Trim())" -Value $tokens[1].Trim() }
# Read the template string as a whole, and expand the environment-variable
# references in it, as before.
[environment]::ExpandEnvironmentVariables((Get-Content -Raw foo.txt))
I found a simpler solution using this INI script called Get-IniContent.
#read from Setup.ini
$INI = Get-IniContent .\Setup.ini
$sec="setup"
#REPLACE VARIABLES
foreach($c in Get-ChildItem -Path .\Application -Recurse -Filter *.config)
{
Write-Output $c.FullName
Write-Output $c.DirectoryName
$configFile = Get-Content $c.FullName -Raw
foreach($v in $INI[$sec].Keys)
{
$k = '%'+$v+'%'
$match = [regex]::IsMatch($configFile, $k)
if($match)
{
$configFile = $configFile -ireplace [regex]::Escape($k), $INI[$sec][$v]
}
}
Set-Content $c.FullName -Value $configFile
}