How to dynamically create an environment variable? - powershell

I am using powershell script to set some environment variable--
$env:FACTER_Variable_Name = $Variable_Value
FACTER is for using these in the puppet scripts.
My problem is - the variable name and variable value both are dynamic and getting read from a text file.
I am trying to use
$env:FACTER_$Variable_Name = $Variable_Value
But $ is not acceptable syntax. When I enclose it in double quotes, the variable value is not getting passed. Any suggestion how to use it dynamically.
Thanks in Advance

[Environment]::SetEnvironmentVariable("TestVariable", "Test value.", "User")
This syntax allows expressions in the place of "TestVariable", and should be enough to create a profile-local environment variable. The third parameter can be "Process", this makes new vars visible in Get-ChildItem env: or "Machine" - this required administrative rights to set the variable. To retrieve a variable set like this, use [Environment]::GetEnvironmentVariable("TestVariable", "User") (or matching scope if you choose another).

On Powershell 5, to set dynamically an environment variable in the current shell I use Set-Item:
>$VarName="hello"
>Set-Item "env:$VarName" world
>$env:hello
world
>
and of course to persist the variable I use C# [Environment]::SetEnvironmentVariable("$VarName", "world", "User")

In pure PowerShell, something like this:
$Variable_Name = "foo"
$FullVariable_Name = "FACTER_$Variable_Name"
$Variable_Value = "Hello World"
New-Item -Name $FullVariable_Name -value $Variable_Value -ItemType Variable -Path Env:
I'm using the New-Item cmdlet to add a new variable, just have to specify the -itemtype and -path

Related

How two concatenate environment variables names in powershell

Say I have the following environment variables:
a = Poke
b = mon
Pokemon= Feraligatr
I want to be able to concatenate a and b environment variables to get the variable name Pokemon and the get Pokemon value like $($env:ab) or $($env:$($env:a)$($env:b)) (This examples does not work)
Building on the helpful comments:
You're looking for indirection, i.e. the ability to refer to an environment variable indirectly, via another (environment) variable(s) storing the target variable's name.
PowerShell-idiomatic solution:
Use the Env: drive in combination with the Get-Content cmdlet:
# The target environment variable.
$env:Pokemon='bingo!'
# The variables that, in combination, return the *name*
# of the target environment variable.
$env:a = 'Poke'
$env:b = 'mon'
# Use Get-Content and the env: drive to retrieve
# an environment variable by an *indirectly* specified name.
# Note:
# * env:$env:a$env:b is treated like "env:$env:a$env:b",
# i.e. an expandable (interpolating string).
# * For better visual delineation of the variables, use:
# env:${env:a}${env:b}
# * `-ErrorAction Ignore` ignores the case when the target var.
# doesn't exist (quietly returns $null`)
# -> 'bingo!'
Get-Content -ErrorAction Ignore env:$env:a$env:b
# Alternative, with explicit string concatenation.
Get-Content -ErrorAction Ignore ('env:' + $env:a + $env:b)
Note:
To set environment variables indirectly, use the Set-Content cmdlet; e.g.:
$varName = 'FOO'
Set-Content env:$varName BAR # $env:FOO now contains 'BAR'
Applying the same technique to regular shell variables (non-environment variables), requires either use of the variable: drive, or, for more flexibility, the Get-Variable and Set-Variable cmdlets - see this answer.
More more information about expandable (interpolating) string literals such as "env:$env:a$env:b", see the conceptual about_Quoting help topic.
.NET API alternative:
As Max points out, you can also use the static System.Environment.GetEnvironmentVariable .NET method:
[Environment]::GetEnvironmentVariable("${env:a}${env:b}")
For more information about calling .NET API methods from PowerShell, see the conceptual about_Methods help topic.

Setting up Git Server: Why is access denied while setting variables using Powershell

I'm trying to set up a local Git server on Windows the way it is described on this website: https://github.com/PowerShell/Win32-OpenSSH/wiki/Setting-up-a-Git-server-on-Windows-using-Git-for-Windows-and-Win32_OpenSSH. When I try to set the variable $machinePath ($machinePath = ${C:\Program Files\Git\mingw64\bin}::GetEnvironmentVariable('Path', 'MACHINE')) I get an error message telling me that accessing the path C:\Program Files\Git\mingw64\bin was denied. I do run PowerShell as Administrator. Can anyone tell me how to fix that?
The first step of your linked guide says to run these commands to add git to your PATH globally. There's no reason to change them unless you installed git somewhere else:
$gitPath = Join-Path -Path $env:ProgramFiles -ChildPath "git\mingw64\bin"
$machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE')
[Environment]::SetEnvironmentVariable('Path', "$gitPath;$machinePath", 'Machine')
Note that setting machine-level environment variables does require running-as-administrator.
As for powershell syntax:
# accessing a class's member method/property is done via
[ClassName]::Method('parameter1','p2')
# curly brackets are usually script blocks or hash tables
$sciptblock = { ping localhost }
$hashtable = #{ key1 = 'value1'; key2 = 'value2'}
# they can also be used to set a variable name with spaces:
${a b c} = 'abc'
# BUT if you have a file path, powershell will GET/SET the data of the file:
${c:\temp\test.txt} = 'test file'

Running a command with arguments assistance

I have a command which runs a program in silent mode, it uses an XML file for the data repository and a word template to create multiple word documents based on a filter xml file.
The command I use is:
"P:\ath to\executable" -Username:Admin -Password:Pa55w0rd -Datadefinition:"C:\Data.xml" -Datafilter:"C:\Filter.xml" -wordtemplate:"C:\Batch\Paul1.dotx" -Targetdocument:="C:\Batch\Paul1.pdf" -filetype:PDF -Log:"C:\Logs\error.log" -Usage:DOCGENSILENT
I need to run this as a PowerShell script which I have mostly managed:
set-executionpolicy unrestricted
$datadefinition = Get-Content "C:\Data file.xml"
$datafilter = Get-Content "C:\Filter for data file.xml"
$wordTemplate = Get-Content "C:\"C:\Template\Paul1.dotx"
$targetFolder = Get-Content "C:\"C:\Paul\Paul.pdf"
Stop-Job = "Executable path" -Username:Admin -Password:Pa55w0rd -Datadefinition:%dataDefinition% -Datafilter:%dataFilter% -wordtemplate:%wordTemplate% -Targetdocument:%targetFolder% -filetype:docx -Log:%logPath% -Usage:DOCGENSILENT
Stop-Job 1
set-executionpolicy restricted
Write-Host -NoNewLine "Press any key to continue..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
My issue is that the script starts the executable but then doesnt pass the Variables, can anyone guide me in the right direction to fix this?
Getting this working depends on the behavior of your executable. Some things I noticed:
Shouldn't this:
$wordTemplate = Get-Content "C:\"C:\Template\Paul1.dotx"
be this:
$wordTemplate = "C:\Template\Paul1.dotx"
Are you sure you need Get-Content? (Aside from that, the path and quoting in your sample are not correct.)
Shouldn't this:
$targetFolder = Get-Content "C:\"C:\Paul\Paul.pdf"
be this:
$targetDocument = "C:\Paul\Paul.pdf"
I doubt Get-Content is correct here, since presumably your output file doesn't exist yet? I also renamed the variable so it makes more sense in your command.
In fact, are you sure you need Get-Content for any of those? Aren't you specifying filenames, not the content of the files?
In PowerShell, variables are prefixed with $ rather than being surrounded by %.
Using Set-ExecutionPolicy within a script to enable scripts to run is pointless, because the script is already running. (That is, if execution policy prevented script execution, PowerShell wouldn't let you run the script in the first place.)
If my guesses regarding your variables are correct, I think your script should look something like this (note also that I specified a $logFile variable, which I didn't see in your script):
$datadefinition = "C:\Users\Administrator\data\Sample Model_146_object type(s).xml"
$datafilter = "C:\Users\Administrator\data\Sample Model_146_object type(s).xml"
$wordtemplate = "C:\Users\Administrator\Templates\Base object.docx"
$targetdocument = "C:\Users\Administrator\Result\sample test15"
$logfile = "C:\Users\Administrator\Logs\C4W Error.log"
& "C:\Program Files (x86)\Communicator4Word.exe" -Username:Admin -Password: -Datadefinition:$datadefinition -Datafilter:$datafilter -wordtemplate:$wordtemplate -Targetdocument:$targetdocument -filetype:docx -Log:$logfile -Usage:DOCGENSILENT
I don't know the behavior of Communicator4Word.exe when you use -Password: with no password after it. (Is that a syntax error, or should you just omit -Password: altogether?)

Why can't I retrieve custom environment variable?

I created a user environment variable testPurpose:
My script either doesn't display it if I call it like this:
$env:testPurpose
or if I try this way
$x = "testPurpose"
(get-item env:$x).Value
I get this error:
get-item : Cannot find path 'Env:\testPurpose' because it does not exist.
Using gci env:* | sort-object name, I can clearly see it has been created for sure
So why can't I retrieve it? If I try this:
$env:ProgramData
I get back program data location printed just fine!
So I am positive it's not a command issue
Try restarting the PowerShell session.
Environment variables are loaded only at the start of the session, or run within the context of the session.
You might have created them in the running process, which are only available to that session. They also go away after yo close that PS window. Try making it a machine-wide variable which should persist.
Note: I am not sure why you would want to create these rather than just creating the variable in the script, but to each their own.
[Environment]::SetEnvironmentVariable("testPurpose", "TESTING", "Machine")
(Get-Item "env:testPurpose").Value
$testPurpose = "testPurpose"
(Get-Item env:$testPurpose).Value

PowerShell: provide parameters in a file

Is there a way to provide powershell parameters with a file?
At the moment I have a script which is called My_Script.ps1. To start this script I have to provide the right parameters in the command:
.\My_Script.ps1 -param1="x" -param2="x" -param3="x" -param4="x" -param5="x" -param6="x" ...
This works but it isn't a very easy way to start the script. Is it possible in powershell to use a file in which you store your parameters and to use that file when you start the script?
Example
In My_Script.ps1 I add something like:
Param(
[string]$File="Path/to/file"
)
In my file I have something like
param1="x"
param2="x"
param3="x"
param4="x"
...
To execute the script you can edit the file and just start the script with .\My_Script.ps1
Another option:
Just use a ps1 file as config file and define your variables as you would do in your main script
$Param1 = "Value"
$Param2 = 42
Then you can use dot-sourcing or import-module to get the data from the config file
. .\configfile.ps1
or
Import-Module .\Configfile.ps1
afterwards you can just use the variables
In addition to splatting you can create variables from = separated values in a file.
param1=foo
param2=bar
param3=herp
param4=derp
Don't quote the values. The parameter names should be valid for a variable (no spaces etc.)
PowerShell 3 and newer:
(Get-Content c:\params.ini -raw | ConvertFrom-StringData).GetEnumerator() |
ForEach { Set-Variable $_.name $_.value }
PowerShell 2:
([IO.File]::ReadAllText('c:\params.ini') | ConvertFrom-StringData).GetEnumerator() |
ForEach { Set-Variable $_.name $_.value }
The code creates variables in current scope. It's possible to create in a global/script/parent scope.
You can use this blog posting
for a start and declare your parameters in an ini-like format.
For sure you could also use a csv-like format and work with import-csv cmdlet.