Reputation: 6175
I have a NuGet package that sets up some PowerShell cmdlets in its Init.ps1 file, and one of the things I'd like them to be able to do is set environment variables that are passed to a build in Visual Studio.
In my Init.ps1 script I use the line:
[Environment]::SetEnvironmentVariable("MyVariable", $someValue, "User")
...to set a 'User' level environment variable, figuring that a regular 'Process' level variable won't work since Package Manager Console is in a different process than MSBuild. Also, manually setting $env:MyVariable = "foo"
in Package Manager Console does not pass its value to MSBuild.
$(MyVariable)
is not populated with 'foo' as desired.[Environment]::GetEnvironmentVariable('MyVariable')
, the overload that normally lets me target EnvironmentVariableTarget.User is not available.The goal is to be able to drop to Package Manager Console, run an arbitrary cmdlet and have the changes persisted in properties during build. Answers that require reboot, restart or reloading a solution aren't what I'm looking for.
Update - some further discoveries:
Seems like Visual Studio is caching the environment variable. Is there a way to 'refresh' a process' environment variables?
Upvotes: 1
Views: 1432
Reputation: 6175
At the end of the day, no, I couldn't find a way to get the Environment variables without a restart.
In the end I solved this by using a separate Properties.targets
(arbitrary name) to store my 'variables' like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Storage for global configuration properties -->
<PropertyGroup>
<MyVariable1></MyVariable1>
<MyVariable2></MyVariable2>
</PropertyGroup>
</Project>
and importing that into my build script with the following line:
<Import Project="Properties.targets" />
Then, to manipulate the variables I use two powershell functions, passing it $toolsPath from Init.ps1, and using this to set properties:
function SetPackageProperty($toolsPath, $name, $value) {
$propertiesFile = [System.IO.Path]::Combine($toolsPath, "Properties.targets")
$msbuild = New-Object -TypeName Microsoft.Build.Evaluation.Project -ArgumentList $propertiesFile
$var = $msbuild.Xml.AddProperty($name, $value)
$msbuild.Save()
[Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.UnloadProject($msbuild)
}
And to get properties:
function GetPackageProperty($toolsPath, $name) {
$msbuild = [Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.GetLoadedProjects($project.FullName) | Select-Object -First 1
$propertiesFile = [System.IO.Path]::Combine($toolsPath, "Properties.targets")
$msbuild = New-Object -TypeName Microsoft.Build.Evaluation.Project -ArgumentList $propertiesFile
$var = $msbuild.Xml.Properties | Where-Object {$_.Name -eq $name} | Select-Object -First 1
[Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.UnloadProject($msbuild)
return $var.Value
}
You can import Properties.targets
into any build script you want to use the properties.
Hope this helps somebody!
Upvotes: 3
Reputation: 10432
- If I use [Environment]::GetEnvironmentVariable('MyVariable'), the overload that normally lets me target EnvironmentVariableTarget.User is not available.
Are you sure?
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Foo">
<Exec Command="setx MyVariable Foo" />
<Exec Command="echo 1. %MyVariable%" />
<Exec Command="echo 2. $(MyVariable)" />
<PropertyGroup>
<MyVariable>$([System.Environment]::GetEnvironmentVariable('MyVariable', System.EnvironmentVariableTarget.User))</MyVariable>
</PropertyGroup>
<Message Text="3. $(MyVariable)" />
</Target>
</Project>
Upvotes: 3