Question

When storing text temporarily in powershell variables at runtime, what is the most efficient way of removing a variables contents from memory when no longer needed?

I've used both Clear-Item variable: and Remove-Variable but how quickly does something get removed from memory with the latter vs nulling the memory contents with the former?

EDIT: I should have made it a little clearer why I am asking.

I am automating RDP login for a bunch of application VMs (application doesn't run as a service, outsourced developers, long story).

So, I am developing (largely finished) a script to group launch sessions to each of the VMs.

Idea is that the script function that stores credentials uses read-host to prompt for hostname then get-credentials to pick up domain/user/password.

The pass is then converted from secure-string using 256-bit key (runtime key unique to machine/user that stored the creds and runs the group launch).

The VMs name, domain, user and encrypted pass are stored in a file. When launching a session, the details are read in, password decrypted, details passed to cmdkey.exe to store \generic:TERMSRV credential for that VM, clear plaintext pass variable, launch mstsc to that host, a few seconds later remove the credential from windows credential store. (If I passed password to cmdkey.exe as anything other than plaintext, the RDP session would either receive incorrect or no credentials).

So, hence the question, I need the password In plaintext to exist in memory for as short a time as possible.

To keep security guys happy, the script itself is aes256 encrypted and a c# wrapper with its own ps host reads, decrypts and runs the script, so there is no plaintext source on the machine that runs this. (Encrypted source on a file share so effectively I have a kill switch, can simply replace encrypted script with another displaying a message that this app has been disabled)

Was it helpful?

Solution 3

You can use a stopwatch to get the execution time for the commandlets. I think there is not really a time difference between these two cmdlets. I´m using normally "Remove-Item" because in my eyes it´s better to remove a variable complete.

$a = "TestA"
$b = "TestB"
$c = "TestC"
$d = "TestD"

$time = New-Object system.Diagnostics.Stopwatch  

Start-Sleep 1
$time.Start() 
$time.Stop()
$system = $time.Elapsed.TotalMilliseconds
Write-Host "Stopwatch StartStop" $system
$time.Reset()

Start-Sleep 1
$time.Start() 
Clear-Item Variable:a
$time.Stop()
$aTime = $time.Elapsed.TotalMilliseconds - $system
Write-Host "Clear-Item in " $aTime
$time.Reset()

Start-Sleep 1
$time.Start() 
Remove-Variable b
$time.Stop()
$bTime  = $time.Elapsed.TotalMilliseconds - $system
Write-Host "Remove-Variable in " $bTime
$time.Reset()

Start-Sleep 1
$time.Start() 
Clear-Item Variable:c
$time.Stop()
$cTime = $time.Elapsed.TotalMilliseconds - $system
Write-Host "Clear-Item in " $cTime
$time.Reset()

Start-Sleep 1
$time.Start() 
Remove-Variable d
$time.Stop()
$dTime  = $time.Elapsed.TotalMilliseconds - $system
Write-Host "Remove-Variable in " $dTime
$time.Reset()

OTHER TIPS

The only way I have been able to, with certainty, to clear variable data/content is to remove all variables running in the current session using:

Remove-Variable -Name * -ErrorAction SilentlyContinue

This removes all variables immediately. In fact, I add this to the end of some of my scripts, so that I can be sure that running another script with potentially the same name, will not have new data added and cause undesired results.

DRAWBACK: If you only need one variable cleared, which was in my case a few minutes ago, then you need to re-instantiate input variables required by your script.

The most efficient way is to let garbage collection do its job. Remember, Powershell is all .NET, with its famous memory management. Always control your scope and make sure variables get out of scope as soon as they are not needed. For example, if temporary variables are needed inside loops, they will invalidate at loop's end automatically, so no need to worry about that, etc.

EDIT: Regarding your update, why not just do $yourPasswordVariable = $null? I think it would be much easier to understand. And it should be the fastest way to do it. Because Remove-Item and Clear-Item are kind of all-in-one handlers, they need to process some stuff first, before determining you really wanted to erase a variable.

Both efficiently remove "a" reference to a .NET object. Now if that reference is the last reference to the object then the GC will determine when the memory for said object is collected. However, if you no longer need the variable then use Remove-Variable to also allow the memory associated with the System.Management.Automation.PSVariable object to be eventually collected as well.

To measure the time it takes to run script blocks and cmdlets, use Measure-Command

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top