Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <#
- .SYNOPSIS
- Creates a namespace for your testing variables.
- .DESCRIPTION
- PowerShell has the Variable PSProvider, which contains a bunch of stuff by default. While it prevents you from deleting anything crucial, it often becomes difficult to look through it to find your test variables so you can remove them or work with them.
- My first thought was, "well, since we have the Variable PSProvider, and the Variable: PSDrive is just an instance of that, why don't we just make a second one and use that?". However, that doesn't work like we want. As it turns out, all PSDrives using the Variable PSProvider share the same set of variables. There's no way to make an empty one that doesn't pollute the others. Also, that wouldn't store functions very easily. I know, I know, script blocks can be stored in variables and run with their .invoke() method, but that's kind of ugly.
- Thus, this function. It creates an object that serves as a namespace. It has Add, Remove, Clear, and List methods that create, remove, and work with the members you create within the namespace. So, instead of adding a ton of variables to your Variable PSProvider, you can add only one, and just expand that one variable as much as you want.
- You can even add functions, which will show up as methods on the object. Yeah, this is the real deal.
- .INPUTS
- This function does not take input from the pipeline.
- .OUTPUTS
- This function returns an object, that you should probably store in a variable so it will be useful.
- .NOTES
- Have fun!
- .LINK
- Twitter: @XT8147
- Blog: http://xt-8147.blogspot.com/
- .EXAMPLE
- $ns = New-Namespace
- Creates a new namespace, and stores it in the variable $ns. But you knew that, right?
- .EXAMPLE
- $ns.add( 'test', 5 )
- True
- C:\PS>$ns.test
- 5
- Adds a variable named 'test' to your namespace. It gets the value 5. True is returned to indicate success adding the value. If something goes horribly wrong, False will be returned instead. I vastly prefer exit status to exceptions out the wazoo, I guess I'm not really cut out for .NET.
- .EXAMPLE
- $ns.add( 'helloworld', { write-output 'Hello, World!' } );
- True
- C:\PS>$ns.helloworld()
- Hello, World!
- Adding functions works as expected. Just write code in a script block. That script block can also be parameterized as you might normally parameterize a script block.
- .EXAMPLE
- $ns.list()
- Name Type Value
- ---- ---- -----
- test Variable 5
- helloworld Function { write-output 'Hello, World!' }
- As you can see, the list() method will tell you what everything in the namespace is, including all the values. Function code will be shown as well.
- .EXAMPLE
- $ns.list( 'Function' )
- Name Type Value
- ---- ---- -----
- helloworld Function { write-output 'Hello, World!' }
- But wait, there's more! You can send a type to list(), and it will return anything in the namespace that matches that wildcard.
- In fact, anything in the set @( 'All', 'Variable', 'Function', 'A', 'V', 'F', 'var', 'func' ) is accepted for this parameter.
- .EXAMPLE
- $ns.list( 'All', 'hello*' )
- Name Type Value
- ---- ---- -----
- helloworld Function { write-output 'Hello, World!' }
- We're still not done with list()! In addition to the type parameter, you can also pass a wildcard to only grab anything in the namespace whose name matches that wildcard. Yes sir.
- Note that if you want to pass a wildcard, you must pass the type parameter. If you only want to wildcard match, that's what passing 'All' is for.
- .EXAMPLE
- $ns.remove( 'test' )
- True
- Should you no longer require one of your namespace variables, you can just remove it. Just like with add(), a boolean is returned. True indicates that the variable was removed successfully, False indicates something went horribly wrong.
- Also, you can't use remove() to remove any of the namespace's built-in stuff, or any of the built-in members provided by PowerShell.
- You also can't pass a wildcard to this. You'll need to know the exact name of what you want to delete. You can still wildcard it, though, using other bits of PowerShell and just ForEach-Object'ing the result into this. I won't hold it against you.
- .EXAMPLE
- $ns.clear()
- Finally, if you don't want any of your variables or functions anymore, you can just clear the entire thing. It's that easy.
- .EXAMPLE
- $ns._protected | Get-Member
- I won't go into this too much since it's the internals of the namespace, but this exists. Of particular interest might be $ns._protected.describe(), which returns the labelled object that $ns.list() filters for its output. You can use this to write other code that uses the contents of the namespace in an easier manner, since the Type property contains more contextual strings instead of .NET types. Remember that all PSCustomObjects have the PSObject property that allows for management of the object.
- #>
- [CmdletBinding()]
- param()
- new-variable -scope script -name ret -value ( new-object psobject )
- # give ourselves a space to store a few relevant things
- $script:ret | add-member -type noteproperty -name _protected -value ( new-object psobject )
- # these two properties hold the names of members that the user shouldn't be allowed to remove
- $script:ret._protected | add-member -type noteproperty -name methods -value @( 'Add', 'Remove', 'Clear', 'List' )
- $script:ret._protected | add-member -type noteproperty -name properties -value @( '_protected' )
- # let's also give ourselves a nice way to group the above two properties together
- $script:ret._protected | add-member -type scriptproperty -name members -value { $this.methods + $this.properties }
- # store a reference to $ret within $ret._protected, so methods on $ret._protected can access $ret
- # since getting a reference actually makes an object whose 'value' property is the object being referenced, we name the
- # reference itself something completely different, so we can use a scriptproperty to grab the 'value' property
- # and have our code look nicer
- $script:ret._protected | add-member -type noteproperty -name __dotnetisweirdsometimes -value ([ref]$script:ret)
- $script:ret._protected | add-member -type scriptproperty -name parentobject -value { $this.__dotnetisweirdsometimes.value }
- # this is kinda ugly, but we need it
- # and it needs to be separate
- # returns an object that labels the object's members
- $script:ret._protected | add-member -type scriptmethod -name describe -value {
- param()
- new-variable members
- # use select-object -property so we can easily iterate through all members and tag them appropriately
- $members = $this.parentobject.psobject.members | select-object -property @( 'Name',
- @{ name = 'Type';
- expression = {
- if( $_.membertype -eq 'NoteProperty' ) {
- if( $this.properties -contains $_.name ) { 'ManagementProperty' }
- else { 'Variable' }
- }
- elseif( $_.membertype -eq 'ScriptMethod' ) {
- if( $this.methods -contains $_.name ) { 'ManagementMethod' }
- else { 'Function' }
- }
- else { 'PSObjectBuiltin' }
- }
- },
- @{ name = 'Value';
- expression = {
- if( $_.membertype -eq 'ScriptMethod' ) { '{ ' + ( '{0}' -f $_.script ) + ' }' }
- else { $_.value }
- }
- }
- )
- return $members
- }
- # we need a way to add variables to this namespace
- # I prefer exit status, even though EXCEPTIONS EVERYWHERE is the .NET way...
- $script:ret | add-member -type scriptmethod -name Add -value {
- param( [string]$name, $value )
- # PowerShell transparently prevents adding a member with the name 'psobject'
- # It reports success but silently fails, so let's explicitly return false
- if( $name -eq 'psobject' ) {
- return $false
- }
- # test to see if we already have a member with this name
- if( $this.psobject.members | where-object { $_.name -eq $name } ) {
- # we do
- return $false
- }
- else {
- # no member with this name exists, create and assign
- new-variable type
- # delicious runtime type identification go
- switch( $value.gettype().name ) {
- 'ScriptBlock' {
- $type = 'ScriptMethod'
- }
- default {
- $type = 'NoteProperty'
- }
- }
- $this | add-member -type $type -name $name -value $value
- return $true
- }
- }
- # we also need a way to remove variables from this namespace
- $script:ret | add-member -type scriptmethod -name Remove -value {
- param( [string]$name )
- new-variable member ( $this.psobject.members | where-object { $_.name -eq $name } )
- # make sure the member we're trying to remove exists
- if( $member ) {
- # see if we're trying to remove any of the methods for managing the namespace
- if( ( $this._protected.members -notcontains $name ) ){
- # nope, go ahead and remove the member so long as it's a NoteProperty or ScriptMethod
- if( @( 'NoteProperty', 'ScriptMethod' ) -contains $member.membertype ) {
- $this.psobject.members.remove( $name )
- return $true
- }
- else {
- # member was not a NoteProperty or ScriptMethod
- # this does the job of explicitly preventing the removal of the default methods
- # even though actually trying to do so silently fails
- return $false
- }
- }
- else {
- # don't let any of the protected members be removed
- return $false
- }
- }
- else {
- # trying to remove that which does not exist?
- # note that trying to remove 'psobject' returns this particular false
- return $false
- }
- }
- # I know, I know, mass-deletion only leads to mass-sadness, but this is a namespace for test variables we're talking about here.
- $script:ret | add-member -type scriptmethod -name Clear -value {
- param()
- # delete everything from the namespace
- $this.psobject.members |
- where-object { ( @( 'NoteProperty', 'ScriptMethod' ) -contains $_.membertype ) -and ( $this._protected.members -notcontains $_.name ) } |
- foreach-object {
- $this.psobject.members.remove( $_.name )
- }
- }
- # What the heck, a way to list what's in the namespace. Filters out default methods on the psobject object, and the protected members.
- # note that if you want to pass a type, you have to pass a wildcard. If you don't need a wildcard, pass '*' to it.
- $script:ret | add-member -type scriptmethod -name List -value {
- param(
- [Parameter( Mandatory = $false )]
- [ValidateSet( 'All', 'Variable', 'Function', 'A', 'V', 'F', 'var', 'func' )]
- [string]$type = 'All', # defaults to all, but can be restricted (various forms of shorthand available as seen in the ValidateSet)
- [Parameter( Mandatory = $false )]
- [string]$wildcard = '*' # defaults to all, but can be restricted
- )
- new-variable members $this._protected.describe()
- # Grab what was requested from our the object we just got
- switch -regex ( $type ) {
- 'All|A' {
- $members | where-object { ( @( 'Variable', 'Function' ) -contains $_.type ) -and ( $_.name -like $wildcard ) }
- }
- 'Variable|V|var' {
- $members | where-object { ( $_.type -eq 'Variable' ) -and ( $_.name -like $wildcard ) }
- }
- 'Function|F|func' {
- $members | where-object { ( $_.type -eq 'Function' ) -and ( $_.name -like $wildcard ) }
- }
- }
- }
- $script:ret
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement