Friday, April 26, 2013

Embedding Csharp in PowerShell Script

I wanted to use a "using block" found in C# to dispose of objects in PowerShell such as Streams or other object types that require the calling of Dispose. After seeing different examples here is where I stopped. I made some minor tweaks.
  1. Begin by creating a class in C#. You can also save the code in a separate file such as Code.cs. See help Add-Type -Examples for additional examples. The class must also inherit from System.IDisposable, otherwise the using-block function will complain with something like 'using-block : Cannot process argument transformation on parameter 'InputObject'. Cannot convert the "Code" value of type "Code" to type "System.IDisposable".'
  2. Create your using block with the instantiation of a new object in parentheses.
  3. Finally, in the script block place your needed logic.

Add-Type @"
using System;

public class Code : IDisposable
{
    public Code()
    {
        Name = "Michael";
    }
    
    public string Name { get; set; }

    public bool IsDisposed { get; set; }
    public void Dispose() 
    {
        Dispose(true);
        GC.SuppressFinalize(this);      
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!IsDisposed)
        {
            IsDisposed = true;   
        }
    }
}
"@

function using-block {
    param (
        [System.IDisposable]$InputObject = $(throw "The parameter -inputObject is required."),
        [ScriptBlock]$ScriptBlock = $(throw "The parameter -scriptBlock is required.")
    )
    try { & $ScriptBlock }
    finally {
        if ($InputObject) {
            if ($InputObject.PSBase) {
                $InputObject.PSBase.Dispose()
            } else {
                $InputObject.Dispose()
            }
        }
    }
}

using-block($c = New-Object Code) {
    $name = $c.Name
    $name # Michael
    $c.IsDisposed # False
}
$name # Not in this scope so no value
$c.IsDisposed # True
This may not be the most elegant approach but it served it's purpose.

Sunday, April 7, 2013

PowerShell Module In Session

I found it a little difficult to bring in functions into a session so I thought this would help others with what helps me get the job done.
The video goes from creating a script module to importing that module into a session.

Tuesday, April 2, 2013

Run with PowerShell Context Menu

Today I was working on our automated build process at work, and found myself running a batch file in a console window that I wanted to remain open. I setup a context menu item associated with .bat files which launches with PowerShell.
Here are the steps:
# We need to create our keys under HKEY_CLASSES_ROOT, which by default has not associated PSDrive.
New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT

# Set the current location to the new drive.
cd HKCR:

# Set the current location to the shell key for .bat files.
cd '.\batfile\shell'

# Create a new key called "Run with PowerShell"
New-Item -Path 'Run with PowerShell'

# Set the current location to the new key.
cd '.\Run with PowerShell'

# Create a new key called "command", which will contain the reference to PowerShell.
New-Item -Path 'command'
cd '.\command'

# Create a new "(default)" string with the command to execute PowerShell. The "%1" contains the path to the .bat file. 
New-ItemProperty -Path '.' -Name '(default)' -Value 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe "-nologo" "-noexit" "-command" "& {%1}"'

Here is an example of the output:
PS C:\> New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT

Name           Used (GB)     Free (GB) Provider      Root                  CurrentLocation
----           ---------     --------- --------      ----                  ---------------
HKCR                                   Registry      HKEY_CLASSES_ROOT

PS C:\> cd HKCR:\batfile\shell
PS HKCR:\batfile\shell> New-Item -Path 'Run with PowerShell'

    Hive: HKEY_CLASSES_ROOT\batfile\shell

Name                           Property
----                           --------
Run with PowerShell

PS HKCR:\batfile\shell> cd '.\Run with PowerShell'
PS HKCR:\batfile\shell\Run with PowerShell> New-Item -Path 'command'

    Hive: HKEY_CLASSES_ROOT\batfile\shell\Run with PowerShell

Name                           Property
----                           --------
command

PS HKCR:\batfile\shell\Run with PowerShell> cd '.\command'
PS HKCR:\batfile\shell\Run with PowerShell\command> New-ItemProperty -Path '.' -Name '(default)' -Value 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe "-nologo" "-noexit" "-command" "& {%1}"'

(default)    : C:\WINDOWS\SysWow64\WindowsPowerShell\v1.0\powershell.exe "-nologo" "-noexit" "-command" "& {%1}"
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_CLASSES_ROOT\batfile\shell\Run with PowerShell\command
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CLASSES_ROOT\batfile\shell\Run with PowerShell
PSChildName  : command
PSDrive      : HKCR
PSProvider   : Microsoft.PowerShell.Core\Registry