Ibrahim just posted something to the PowerShell blog about how to create tied variables in PowerShell. If you extend this approach with script blocks, you have a very powerful dynamic scripting technique.
PS C:\temp> cd \temp
PS C:\temp> New-ScriptVariable.ps1 GLOBAL:lee { $myTestVariable } { $GLOBAL:myTestVariable = 2 * $args[0] }
PS C:\temp> $lee
PS C:\temp> $lee = 10
PS C:\temp> $lee
20
PS C:\temp> New-ScriptVariable.ps1 GLOBAL:today { (Get-Date).DayOfWeek }
PS C:\temp> $today
Wednesday
PS C:\temp> New-ScriptVariable.ps1 GLOBAL:random -Get { Get-Random } -Set { Get-Random -SetSeed $args[0] }
PS C:\temp> $random
1740776676
PS C:\temp> $random
1507521897
PS C:\temp> $random = 10
PS C:\temp> $random
1613858733
PS C:\temp> $random = 10
PS C:\temp> $random
1613858733
He alluded to it in the post – here is the full text of the script:
(Edit 05/17: Updated to make the getters more like PowerShell pipelines: return a single object, or collection of PSObject)
|
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057
|
## New-ScriptVariable.ps1 param($name, [ScriptBlock] $getter, [ScriptBlock] $setter)
Add-Type @" using System; using System.Collections.ObjectModel; using System.Management.Automation;
namespace Lee.Holmes { public class PSScriptVariable : PSVariable { public PSScriptVariable(string name, ScriptBlock scriptGetter, ScriptBlock scriptSetter) : base(name, null, ScopedItemOptions.AllScope) { getter = scriptGetter; setter = scriptSetter; } private ScriptBlock getter; private ScriptBlock setter;
public override object Value { get { if(getter != null) { Collection<PSObject> results = getter.Invoke(); if(results.Count == 1) { return results[0]; } else { PSObject[] returnResults = new PSObject[results.Count]; results.CopyTo(returnResults, 0); return returnResults; } } else { return null; } } set { if(setter != null) { setter.Invoke(value); } } } } } "@
if(Test-Path variable:\$name) { Remove-Item variable:\$name -Force } $executioncontext.SessionState.PSVariable.Set( (New-Object Lee.Holmes.PSScriptVariable $name,$getter,$setter)) |