Use PowerShell Environmental Variables to Store Temporary Information

Use PowerShell Environmental Variables to Store Temporary Information

  • Comments 2
  • Likes

Summary: Use the Windows PowerShell environmental drive to store temporary information, and still use the Set-StrictMode cmdlet.

Microsoft Scripting Guy, Ed Wilson, is here. It is exactly 11 days until the 2012 Scripting Games commence. Here is how I found out that salient piece of information.

New-TimeSpan -Start (get-date) -End "april 2, 2012"

Note   Thanks to Windows PowerShell MVP, Richard Siddaway, for recently pointing out that typing a date in the fashion, 4/2/12 can lead to problems in international locations. (I knew that, but I tend to forget at times.)

The excitement of the 2012 Scripting Games is really growing. In fact, this year I am proud to announce that the Scripting Manager has caught the excitement from all my weekly status reports, and he has volunteered to be a judge for the games this year! Check out Dave Bishop’s biography on the Announcing the PowerShell Judges for the 2012 Scripting Games page.

Speaking of excitement…

Tomorrow, the long awaited Charlotte IT Pro Appreciation Day commences at 9:00 Eastern Time. So if you are in the Charlotte, North Carolina area, hopefully you will be able to attend this event. Luckily, you do not have to preregister for this event, so if your day looks slack tomorrow, come on out and join the nearly 1000 other people who are expected to turn out. The Scripting Wife will be helping with registration, so you will have a chance to meet her, and I will be making two presentations about Windows PowerShell. It will be a great occasion, and I hope to see you there.

The past several days I have talked about using the Set-StrictMode cmdlet to avoid certain types of Windows PowerShell errors. On Tuesday, I wrote Use Strict Mode for PowerShell to Help You Write Good Code, and yesterday I posted Avoid PowerShell Errors by Initializing Variables. Last night I received an email on scripter@microsoft.com that asked the following question.

What if I want my script to continue to increment?

In yesterday blog, I talked about initializing a variable to avoid continuously incrementing a variable each time the script runs. In the script that follows, each time the script runs, the value of the $a variable increases by five.

UninitializedVariable.ps1

1..5 | foreach{

 $a++}

$a

The output is shown in the image that follows.

Image of command output

Normally, the output from the previous script is an error, and the way to correct it is to initialize the value of the $a variable prior to incrementing it. In this way, the script produces the same output each time it runs. The best way to ensure that you initialize variables prior to use is to use the Set-StrictMode cmdlet as discussed yesterday. Here is the code that sets -Version 1 checking so that directly accessing a noninitialized variable causes an error, but using a noninitialized variable in a string does not generate an error.

InitializedVariable.ps1

Set-StrictMode -Version 1

$a = 0

1..5 | foreach{

 $a++}

$a

Using the environmental drive to persist information

The question that came into Scripter was how to use the Set-StrictMode cmdlet and yet be able to increment the value of the $a variable each time the script runs. The solution is to persist the final value of the $a variable, and to read it the next time the script runs. One way to do this is to write the value to the registry, but that would also presume some sort of clean up between Windows PowerShell sessions to avoid completely polluting the values. Another way to do this is to store the value in a temporary text file, but clean up once again becomes a problem (I hate leaving temporary files laying around on the file system).

A better approach is to write the value to an environmental variable. By using Windows PowerShell and the environmental drive, this is a piece of cake—and better yet, when the Windows PowerShell session ends, the environmental variable goes away. This is exactly what I need. The InitializeVariableFromEnv.ps1 script that follows illustrates one way to persist the value of the $a variable to permit incrementing it with each run of the script.

InitializeVariableFromEnv.ps1

Set-StrictMode -Version 1

if(test-path -path env:\a)

  { [int]$a = $env:a }

else

  { New-Item -Name a -Path env: -Value 0 | out-null

    [int]$a = $env:a }

1..5 | foreach{

 $a++}

$env:a = $a

$a

In the InitializeVariableFromEnv.ps1, script the first thing I do is use the Set-StrictMode cmdlet to set the strict mode to -Version 1. Next, I use the Test-Path cmdlet to see if an environmental variable named a exists. If it does exist, I read the value and populate the value of $a. One thing that is really important is to cast the value from env:\a to an integer, or else it is interpreted as a string and the ++ operator fails. This is shown here.

Set-StrictMode -Version 1

if(test-path -path env:\a)

  { [int]$a = $env:a }

If the env:\a variable does not exist, I use the New-Item cmdlet to create a new instance of it. I set the value to 0, and pipe the returned object to the Out-Null cmdlet to avoid cluttering the output with distracting information. I then set the value of $a to the value of $env:a. This code is shown here.

else

  { New-Item -Name a -Path env: -Value 0 | out-null

    [int]$a = $env:a }

The last things I do are increment the value of $a five times, and assign the present value of the $a variable to the $env:a variable. Lastly, I display the value of $a. This code is shown here.

1..5 | foreach{

 $a++}

$env:a = $a

$a

The code and the output associated with running the script three times is shown in the image that follows.

Image of command output

Well, that is about it. Join me tomorrow for more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Ed,

    a good idea! Just save the value of my persistent vars to the registry!

    btw: There's one thing, I would change in the InitializeVariableFromEnv.ps1 script.

    I would eliminate the else part of the condition and just write:

    ...

    if(-not (test-path -path env:\a))

     { New-Item -Name a -Path env: -Value 0 | out-null }

    [int]$a = $env:a

    ...

    It's good to remember that the environment variables are strings and need to be casted to the appropriate types! But we have to be aware of the fact, that this solution is not generally applicable because we stick to storing integers here. Simple types can quite easily be stored in environment strings like that.

    If you try to store an array like "$env:a=1,2,3,4,5" you'll get "1 2 3 4 5" back, which can be restored to an array by [int[]]$a=$env:a -split " " e.g.

    Things will quickly become complicated if you have to store anything else than simple types in environment variables and we are better off using the Export-CliXml (and Import-CliXml) Cmdlet to persist our information in files.

    Klaus

  • @K_Schulte You are right, I could eliminate the Else clause in the script. You are also right that this is a simple solution to the problem of storing simple data. It should be a good tool to use for that. For more complex data, I certainly agree with you about exporting the XML.