Quantcast
Channel: reflection – Learn Powershell | Achieve More
Viewing all 16 articles
Browse latest View live

Revisiting Get-FileTimestamp with Reflection

$
0
0

Ever since I wrote my function to locate a file’s MFT (ChangeTime) timestamp, I wanted to take on an extra challenge by taking all of the C# code that included using pinvoke and rewrite it using reflection in PowerShell after seeing fellow PowerShell MVP Matt Graeber’s article on using reflection. While there may not have been a need to keep this particular code resident in memory, it will server as a fun exercise in rewriting all of the C# code and avoid the use of Add-Type to compile the code (which does write to disk).

The plan is to piece through each part of code and show the translation from C# to using reflection to create the Structs, Enums and pinvoke methods in memory by showing the C# code followed by the PowerShell code. If you want to check out the code in its entirety, you can find the majority of it on the link that I referenced at the beginning of this article.

The following code is the initial part of the C# code that defines my environment and new class.  Nothing here will be translated over to PowerShell using reflection.

using System;
using System.Runtime.InteropServices; // for DllImport and friends
using Microsoft.Win32.SafeHandles; // for SafeHandle
using System.Collections.Generic; // for ParseFileAttributes helper function (List<FileAttributes> only
using System.IO; // for test main (FileStream) only
using System.Text; // for test main (Encoding) only
using System.Threading; // for test main (Thread.Sleep) only
using System.Diagnostics; // for test main (Trace.Write[Line]) only
public class Nt
{

First off, I am going to build my dynamic assembly and module which will be used the rest of the time to help define other types that will be required at different points.

#region Module Builder
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('TestAssembly')
# Only run in memory by specifying [System.Reflection.Emit.AssemblyBuilderAccess]::Run
$AssemblyBuilder = $Domain.DefineDynamicAssembly(
    $DynAssembly, 
    [System.Reflection.Emit.AssemblyBuilderAccess]::Run
) 
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('TimeStampModule', $False)
#endregion Module Builder

What I’ve done here is creating a new assembly called TestAssembly that is used later to build a dynamic module that is used to build out our required components (structs, enums, pinvoke, etc…).

I then hook into the current AppDomain and use a method called DefineAssembly() to configure the custom assembly (stored in memory by specifying [System.Reflection.Emit.AssemblyBuilderAccess]::Run). Once that is done, I build my dynamic module using DefineDynamicModule() and specify a module name and and whether the symbol information should be emitted.

Up next is where I define a Struct for IO_STATUS_BLOCK which is used to determine the status of using the win32 function,  NTQueryInformationFile.

struct IO_STATUS_BLOCK
{
    internal uint status;
    internal ulong information;
}

And now for the PowerShell reflection approach:

#region STRUCTs

#region IOStatusBlock
#Define STRUCT
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$TypeBuilder = $ModuleBuilder.DefineType('IOStatusBlock', $Attributes, [System.ValueType], 1, 0x40)
[void]$TypeBuilder.DefineField('status', [UInt64], 'Public')
[void]$TypeBuilder.DefineField('information', [UInt64], 'Public')

#Create STRUCT Type
[void]$TypeBuilder.CreateType()
#endregion IOStatusBlock

 

I use my $ModuleBuilder that I defined earlier to build a new Struct using the DefineType() method in which I specify a name for the Struct as well as specifying some attributes to make it more like a Struct (I found out what these attributes were by looking at my previously compiled C# code and using Get-Member against the Struct). From there I take the Type I have created and use the DefineField() method to build out the fields to match what is required of the IO_STATUS_BLOCK. The Define() method requires that I supply a name, a type and the FieldAttribute of the field. Once completed, I simply call CreateType() to complete the build of the type so it is available to me.

image

The next Struct is for FILE_BASIC_INFORMATION and is a little different to build out due to some unique requirements:

[StructLayout(LayoutKind.Explicit)]
struct FILE_BASIC_INFORMATION
{
    [FieldOffset(0)]
    internal long CreationTime;
    [FieldOffset(8)]
    internal long LastAccessTime;
    [FieldOffset(16)]
    internal long LastWriteTime;
    [FieldOffset(24)]
    internal long ChangeTime;
    [FieldOffset(32)]
    internal ulong FileAttributes;
}

Here I have a StructLayout attribute as well as FieldOffsets which define the physical position of the field in the struct. Have on fear though, we can easily put this one together!

#region FileBasicInformation
#Define STRUCT
$Attributes = 'AutoLayout, AnsiClass, Class, ExplicitLayout, Sealed, BeforeFieldInit,public'
$TypeBuilder = $ModuleBuilder.DefineType('FileBasicInformation', $Attributes, [System.ValueType], 8, 0x40)
$CreateTimeField = $TypeBuilder.DefineField('CreationTime', [UInt64], 'Public')
$CreateTimeField.SetOffset(0)
$LastAccessTimeField = $TypeBuilder.DefineField('LastAccessTime', [UInt64], 'Public')
$LastAccessTimeField.SetOffset(8)
$LastWriteTimeField = $TypeBuilder.DefineField('LastWriteTime', [UInt64], 'Public')
$LastWriteTimeField.SetOffset(16)
$ChangeTimeField = $TypeBuilder.DefineField('ChangeTime', [UInt64], 'Public')
$ChangeTimeField.SetOffset(24)
$FileAttributesField = $TypeBuilder.DefineField('FileAttributes', [UInt64], 'Public')
$FileAttributesField.SetOffset(32)

#Create STRUCT Type
[void]$TypeBuilder.CreateType()
#endregion FileBasicInformation

 

Same as before, I use my ModuleBuilder to define the type with specific attributes (I have added ExplicitLayout to match the [StructLayout(LayoutKind.Explicit)] attribute defined in C#) and then start adding the fields. The thing you might notice is that I save each field from DefineField() to a variable. This is because I must then call the SetOffset() method and supply an integer which will define the physical position of the field. This is how I do my FieldOffset!

image

That does it for the Structs! Time to do an Enum.

I only have one Enum to do for FILE_INFORMATION_CLASS. I didn’t need everything, just the following items that are listed below in the C# code.

enum FILE_INFORMATION_CLASS
{
    FileDirectoryInformation = 1,        // 1
    FileBasicInformation = 4,            // 4
    FileHardLinkInformation = 46        // 46   
}

The refactored code for PowerShell is below:

#region ENUMs
$EnumBuilder = $ModuleBuilder.DefineEnum('FileInformationClass', 'Public', [UInt32])
# Define values of the enum
[void]$EnumBuilder.DefineLiteral('FileDirectoryInformation', [UInt32] 1)
[void]$EnumBuilder.DefineLiteral('FileBasicInformation', [UInt32] 4)
[void]$EnumBuilder.DefineLiteral('FileModeInformation', [UInt32] 16)
[void]$EnumBuilder.DefineLiteral('FileHardLinkInformation', [UInt32] 46)

#Create ENUM Type
[void]$EnumBuilder.CreateType()
#endregion ENUMs

Unlike the previous items, I will be calling DefineEnum() vs. DefineType() and supplying the name of the enum, the type attributes and underlying type for the enum. From there I start adding the enum values using DefineLiteral() and giving values for the name of the value name, the underlying type (must be UInt32 because UInt16 will work on PowerShell V3, but V4+ will fail when using the pinvoke method) and the numeric value of the name. Once that has completed, I call the familiar CreateType() method and away we go!

image

Now to hook into the Win32 API using pinvoke and grabbing the NTQueryInformationFile() function.

[DllImport("ntdll.dll", SetLastError = true)]
    static extern IntPtr NtQueryInformationFile(SafeFileHandle fileHandle, 
    ref IO_STATUS_BLOCK IoStatusBlock, 
    IntPtr pInfoBlock, 
    uint length, 
    FILE_INFORMATION_CLASS fileInformation);

 

The PowerShell code is somewhat larger as we have to build everything out, but it is by no means impossible. I will step through by splitting up some parts of the code to better explain what is happening here.

#region DllImport
$TypeBuilder = $ModuleBuilder.DefineType('ntdll', 'Public, Class')

#region NtQueryInformationFile Method
$PInvokeMethod = $TypeBuilder.DefineMethod(
    'NtQueryInformationFile', #Method Name
    [Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes
    [IntPtr], #Method Return Type
    [Type[]] @([Microsoft.Win32.SafeHandles.SafeFileHandle], 
    [IOStatusBlock], [IntPtr] ,[UInt64], [FileInformationClass]) #Method Parameters
)

Once again, I use my ModuleBuilder object to define my type. This time I am specifying a name of the dll that the function resides on (I don’t have to do this, but it makes sense to make it something that relates to what I am using) as well as specifying the type attributes.

From there I can begin to define my NTQueryInformationFile method (the win32 function). To do this I use the DefineMethod() method and supply the name of the function, the method attributes (I found this by reviewing the method attributes on the compiled C# code), the return type that the function provides when used (in this case an IntPtr) and lastly I supply the required parameter types that are required for this to actually work. Fortunately, I can get all of this information from the MSDN page. This is a array of Types that consist of a SafeFileHandle, the IOStatusBlock type, an IntPtr, an UInt64 and lastly the FileInformationClass type.

$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
$FieldArray = [Reflection.FieldInfo[]] @(
    [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
    [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
)

$FieldValueArray = [Object[]] @(
    'NtQueryInformationFile', #CASE SENSITIVE!!
    $True
)

$SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
    $DllImportConstructor,
    @('ntdll.dll'),
    $FieldArray,
    $FieldValueArray
)

 

This piece is where I build out and define the attributes of the DLLImport attribute. In this case, I only need to worry about setting the EntryPoint (which is the actual Win32 function that this will use – AND IT IS CASE SENSITIVE) and the SetLastError field that I can use to get any error messages if this happens to fail.

$PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
#endregion NtQueryInformationFile Method

[void]$TypeBuilder.CreateType()
#endregion DllImport

 

I add that custom attribute to my method and then create the type.

image

Now I have a working method that will call a Win32 function! But that is not all! I had some extra stuff coded in C# (that really wasn’t needed, but I did it in C# just to learn more about it) that needs to be moved to PowerShell.

public static bool GetFourFileTimes(string path2file,
        out DateTime creationTime, out DateTime lastAccessTime, 
        out DateTime lastWriteTime, out DateTime changeTime, out string errMsg)
{
    bool brc = false;
    creationTime = default(DateTime);
    lastAccessTime = default(DateTime);
    lastWriteTime = default(DateTime);
    changeTime = default(DateTime);
    errMsg = string.Empty;
    IntPtr p_fbi = IntPtr.Zero;
    try
    {
        FILE_BASIC_INFORMATION fbi = new FILE_BASIC_INFORMATION();
        IO_STATUS_BLOCK iosb = new IO_STATUS_BLOCK();
        using (FileStream fs = new FileStream(path2file, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            p_fbi = Marshal.AllocHGlobal(Marshal.SizeOf(fbi));               
            IntPtr iprc = NtQueryInformationFile(fs.SafeFileHandle, ref iosb, p_fbi, 
            (uint)Marshal.SizeOf(fbi), FILE_INFORMATION_CLASS.FileBasicInformation);
            brc = iprc == IntPtr.Zero && iosb.status == 0;
            if (brc)
            {
                brc = false;
                fbi = (FILE_BASIC_INFORMATION)Marshal.PtrToStructure(p_fbi, typeof(FILE_BASIC_INFORMATION));
                creationTime = DateTime.FromFileTime(fbi.CreationTime);
                lastAccessTime = DateTime.FromFileTime(fbi.LastAccessTime);
                lastWriteTime = DateTime.FromFileTime(fbi.LastWriteTime);
                changeTime = DateTime.FromFileTime(fbi.ChangeTime);
                brc = true;
            }
        }
    }
    catch (Exception ex)
    {
        brc = false;
        errMsg = ex.Message;
    }
    finally
    {
        if (p_fbi != IntPtr.Zero) { Marshal.FreeHGlobal(p_fbi); }
    }
    return brc;
}

 

Pay no attention to the GetFourFileTimes() method as it will not be brought over into my PowerShell code. As you can see, there are a few things happening here that I need to migrate but nothing that is incredibly complex.

$fbi = New-Object "FileBasicInformation"
$iosb = New-Object "IOStatusBlock"

$FileStream = [System.IO.File]::Open("C:\Users\proxb\desktop\desktop.ini",'Open','Read','ReadWrite')

$p_fbi = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf($fbi))

First I create new objects using my newly created Structs. I then open up a file stream to a file of my choosing and making sure that others could access it if needed by supply values for the parameters of the Open() method of the System.Io.File type that ensure the file is not being locked.

I then get the physical location in memory ($p_fbi using AllocHGlobal()) of the FileBasicInformation struct type by first getting its size in bytes using the SizeOf() method (in this case, the size is 64 bytes).

$iprc = [ntdll]::NtQueryInformationFile($FileStream.SafeFileHandle, $iosb, $p_fbi, 
    [System.Runtime.InteropServices.Marshal]::SizeOf($fbi), [FileInformationClass]::FileBasicInformation
)

Here is where I call my NtQueryInformationFile() method with the required parameter values. I supply my SafeFileHandle from the file stream, my IO_STATUS_BLOCK struct that will be updated for review to see if something went wrong, the physical location of the FILE_BASIC_INFORMATION struct type that will also be updated by the method so I can view the timestamps, the size in bytes of the FILE_BASIC_INFORMATION type and finally the FILE_INFORMATION_CLASS type with FileBasicInformation. The returned IntPtr value will be used later on to determine if this was successful.

 

If ($IsOK) {
    # Pull data from unmanaged memory block into a usable object
    $fbi = [System.Runtime.InteropServices.Marshal]::PtrToStructure($p_fbi, [FileBasicInformation])
    [pscustomobject]@{
        FullName = $FileStream.Name
        CreationTime = [datetime]::FromFileTime($fbi.CreationTime)
        LastAccessTime = [datetime]::FromFileTime($fbi.LastAccessTime)
        LastWriteTime = [datetime]::FromFileTime($fbi.LastWriteTime)
        ChangeTime = [datetime]::FromFileTime($fbi.ChangeTime)
    }
} Else {
    Write-Warning "$($Item): $(New-Object ComponentModel.Win32Exception)"
}

 

After running the method, I now determine if everything went according to plan. If not an error will be thrown, otherwise I will continue on my path by marshaling the data ($p_fbi using PtrToStructure()) from the unmanaged memory over to a managed object that I can then look at (my $fbi type I created earlier). Now it is just a matter of converting the timestamps to a more human readable value using the FromFileTime() method and then displaying the results.

image

So there you go! I have tossed out my C# here string that was compiled using Add-Type and instead took the dive into Reflection to accomplish the same thing. While this is something that a very small percentage of people might ever use, it was absolutely a fun time learning more about this!

By the way, I did update my Get-FileTimeStamp function to use Reflection instead of compiled C#. You can download the updated function from the link below.

http://gallery.technet.microsoft.com/scriptcenter/Get-MFT-Timestamp-of-a-file-9227f399


Filed under: powershell Tagged: c#, changetime, mft, pinvoke, Powershell, reflection, timestamp

Guest Spot on Hey, Scripting Guy! On Making The Console Glassy

$
0
0

image

I did a spot on Hey, Scripting Guy! today talking about using reflection to hook into the Win32 API and give your PowerShell console a more glassy look. Click on the link below to check it out!

http://blogs.technet.com/b/heyscriptingguy/archive/2014/10/05/weekend-scripter-give-your-powershell-console-a-glassy-theme.aspx

I also had a PowerTip as well that is worth checking out as well.

http://blogs.technet.com/b/heyscriptingguy/archive/2014/10/05/powertip-view-all-values-of-an-enum.aspx


Filed under: News, powershell Tagged: console, guest blog, Powershell, reflection, scripting guy

Retrieving a Registry Key LastWriteTime Using PowerShell

$
0
0

While navigating through the registry, you may have noticed that there is something missing from there that you normally see in other places such as the file system. That little thing is a timestamp that might tell you when a particular key has been modified. In this case, you can’t see it because it is not openly visible to be seen. In fact, the timestamp is only available on the registry key itself, not on the values within the key. If a value gets updated, removed or added under the key, the timestamp on the key gets updated.

In order to actually view this information you would have to export the registry key in question and make sure to save it as a txt file so that when you open it up, it would list the lastwritetime of the key for you to see.

image

Now wouldn’t be great if we could somehow use some sort of command line approach to retrieving the same timestamp? Well, with a little bit of work, we can accomplish this using PowerShell with some help from our friends with p/invoke and some reflection!

First let’s start off with getting the proper signature which happens to be RegQueryInfoKey from pinvoke.net

image

More information about this actual function can be found at the following link:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms724902%28v=vs.85%29.aspx

I will be making a small change to this with the last parameter: lpftLastWriteTime. Instead of an IntPtr I will be using long as the Ref so it will be easier to convert the value to a DateTime object.

With that, I am going to build out the signature using reflection. Unlike some of my other scripts that use this approach, I only have to build the RegQueryInfoKey signature and have no need to worry about any Enums or Structs.

 
#region Create Win32 API Object
Try {
    [void][advapi32]
} Catch {
    #region Module Builder
    $Domain = [AppDomain]::CurrentDomain
    $DynAssembly = New-Object System.Reflection.AssemblyName('RegAssembly')
    $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) # Only run in memory
    $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('RegistryTimeStampModule', $False)
    #endregion Module Builder
 
    #region DllImport
    $TypeBuilder = $ModuleBuilder.DefineType('advapi32', 'Public, Class')
 
    #region RegQueryInfoKey Method
    $PInvokeMethod = $TypeBuilder.DefineMethod(
        'RegQueryInfoKey', #Method Name
        [Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes
        [IntPtr], #Method Return Type
        [Type[]] @(
            [Microsoft.Win32.SafeHandles.SafeRegistryHandle], #Registry Handle
            [System.Text.StringBuilder], #Class Name
            [UInt32 ].MakeByRefType(),  #Class Length
            [UInt32], #Reserved
            [UInt32 ].MakeByRefType(), #Subkey Count
            [UInt32 ].MakeByRefType(), #Max Subkey Name Length
            [UInt32 ].MakeByRefType(), #Max Class Length
            [UInt32 ].MakeByRefType(), #Value Count
            [UInt32 ].MakeByRefType(), #Max Value Name Length
            [UInt32 ].MakeByRefType(), #Max Value Name Length
            [UInt32 ].MakeByRefType(), #Security Descriptor Size           
            [long].MakeByRefType() #LastWriteTime
        ) #Method Parameters
    )
 
    $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
    $FieldArray = [Reflection.FieldInfo[]] @(       
        [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
        [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
    )
 
    $FieldValueArray = [Object[]] @(
        'RegQueryInfoKey', #CASE SENSITIVE!!
        $True
    )
 
    $SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
        $DllImportConstructor,
        @('advapi32.dll'),
        $FieldArray,
        $FieldValueArray
    )
 
    $PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
    #endregion RegQueryInfoKey Method
 
    [void]$TypeBuilder.CreateType()
    #endregion DllImport
}
#endregion Create Win32 API object

If you are interested in a more detailed explanation of this process, just check out one of my other articles with the reflection tag to learn more.

I can verify that I at least have everything compiled correctly by looking at the method.

 
[advapi32]::RegQueryInfoKey

image

At least this looks good. We now need to grab a registry key and then figure out what the timestamp is.

 
$RegistryKey = Get-Item 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\Autorun.inf'
$RegistryKey

image

What better key to use than the one that I showed in my previous example. Now I will create some common variables that will be used with the method.

 
#region Constant Variables
$ClassLength = 255
[long]$TimeStamp = $null
#endregion Constant Variables

With my registry key, I need the registry handle and the name that will be supplied to the method.

 
$ClassName = New-Object System.Text.StringBuilder $RegistryKey.Name
$RegistryHandle = $RegistryKey.Handle

I had to use a StringBuilder because it is required by one of the method parameters. Now that we have enough information, we can proceed with gathering the timestamp.

 
[advapi32]::RegQueryInfoKey(
    $RegistryHandle,
    $ClassName,
    [ref]$ClassLength,
    $Null,
    [ref]$Null,
    [ref]$Null,
    [ref]$Null,
    [ref]$Null,
    [ref]$Null,
    [ref]$Null,
    [ref]$Null,
    [ref]$TimeStamp
)

SNAGHTML5719a54

Most of the parameters here can be $Null, which is why they are that way. We know that this was successful by the return of the IntPtr 0. Any other value would mean that something happened and that would need to be investigated.

We are not quite done yet! We have the timestamp, but it is in a non-usable format and should be converted into a DateTime object using [datetime]::FromFileTime().

 
#Convert to DateTime Object
$LastWriteTime = [datetime]::FromFileTime($TimeStamp)
 
#Return object
$Object = [pscustomobject]@{
    FullName = $RegistryKey.Name
    Name = $RegistryKey.Name -replace '.*\\(.*)','$1'
    LastWriteTime = $LastWriteTime
}
$Object.pstypenames.insert(0,'Microsoft.Registry.Timestamp')
$Object

image

If you compare this to what I showed earlier with the manual exporting of the registry key to a text file, you will see that these times are exactly the same. Well, this also includes the seconds, which the exported file does not.

Now wouldn’t it be nice to have a function that does all of this work for you? Of course you would! I wrote a function called Get-RegistryKeyLastWriteTime that will allow you to get the registry key timestamp from either a remote or local system.

Let’s give it a couple of runs to see how it works. The first example shows how you can pipe an existing registry key object into the function to get the timestamp.

 
$RegistryKey = Get-Item "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\Autorun.inf"
$RegistryKey | Get-RegistryKeyTimestamp | Format-List

image

The next example runs against a remote system and allows you to specify the hive and subkey that you wish to query.

 
Get-RegistryKeyTimestamp -Computername boe-pc -RegistryHive LocalMachine –SubKey  'SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\Autorun.inf' |
Format-List

image

Works like a champ! Be sure to download this and give it a run and let me know what you think!

Download Get-RegistryKeyLastWriteTime

https://gallery.technet.microsoft.com/scriptcenter/Get-RegistryKeyLastWriteTim-63f4dd96


Filed under: powershell Tagged: lastwritetime, pinvoke, Powershell, reflection, registry, timestamp

A Look at Implementing $Using: Support in PowerShell for PoshRSJob

$
0
0

After I made my initial release of PoshRSJob, one of the things left that I wanted to accomplish was implementing the $Using: scope that is found when using Invoke-Command or Start-Job which allows you to use an existing variable in the current console session and send that over to the scriptblock for the PSJob. This is pretty cool and allows for easier flow of sending data to a scriptblock in a PSJob. Naturally, if my module was going to be an alternative to the current infrastructure, it needed this capability as well. The problem is that determining how this works isn’t quite as easy as it seems. A couple of options would include looking at using RegEx or the PSParser to maybe make this happen. I will say that to provide support for PowerShell V2, I had to resort to these approaches, but more on that later.

After some digging  around in the language using DotPeek, I found where call was being made to take an existing scriptblock (with parameters) that have $Using and then does some conversion behind the scenes that will add the variable automatically to the Param() block and adjusts the $Using: variable within the scriptblock as well.

Of course, converting this C# code to PowerShell isn’t always straight forward, especially when we cannot just use some of the methods that they use without bringing some reflection skills into play.

V3+ Attempt

So, lets get going with taking the following scriptblock and converting it so we can take advantage of $Using: and see how it works.

## Scriptblock
$Data = 42
$Computername = $env:COMPUTERNAME
$ScriptBlock = {
    [pscustomobject]@{
        Computername = $Using:Computername
        Output = ($Using:Data * 2)
    }
}

Here we have our data and then our script block which contains our $Using: variables. Note that in this example I do not have anything in a Param() block (I will show another example after this with a Param() block) so we will have an extra step at the end to build this out.

Next up is using some AST magic (System.Management.Automation.Language.UsingExpressionAst) to parse out the Using variables by looking at the AST on the script block:

$UsingVariables = $ScriptBlock.ast.FindAll({
    $args[0] -is [System.Management.Automation.Language.UsingExpressionAst]
},$True)

What that gives us is the following output:

image

With this information, I now need to go and grab the actual values for each variable and then put that into an object that includes what the converted $Using variable will look like in the new script block.

$UsingVariableData = ForEach ($Var in $UsingVariables) {
    Try {
        $Value = Get-Variable -Name $Var.SubExpression.VariablePath.UserPath -ErrorAction Stop
        [pscustomobject]@{
            Name = $Var.SubExpression.Extent.Text
            Value = $Value.Value
            NewName = ('$__using_{0}' -f $Var.SubExpression.VariablePath.UserPath)
            NewVarName = ('__using_{0}' -f $Var.SubExpression.VariablePath.UserPath)
        }
    } Catch {
        Throw "$($Var.SubExpression.Extent.Text) is not a valid Using: variable!"
    }
}

image

Notice how these are now renamed with the $__using_ now instead of their original name. This is important with how we convert the script block later on. Keep in mind that the original script block still has the original values.

Now we start setting up for the script block conversion by creating a couple of collections to hold some data. One of those required is a Tuple type that will hold a particular AST type of VariableExpressionAST.

$List = New-Object 'System.Collections.Generic.List`1[System.Management.Automation.Language.VariableExpressionAst]'
$Params = New-Object System.Collections.ArrayList

Assuming that we have Using variables, we can begin adding each item into our list collection.

If ($UsingVariables) {        
    ForEach ($Ast in $UsingVariables) {
        [void]$list.Add($Ast.SubExpression)
    }

With that done, next up is to work with our soon to be new parameters and adding the current values with the new values into our created Tuple.

[void]$Params.AddRange(($UsingVariableData.NewName | Select -Unique))
$NewParams = $Params -join ', '
$Tuple=[Tuple]::Create($list,$NewParams)

image

Now for some fun stuff! We need to use Reflection to hook into a nonpublic method that basically does all of the magic of converting the script block data into something that will be usable.

$bindingFlags = [Reflection.BindingFlags]"Default,NonPublic,Instance"
$GetWithInputHandlingForInvokeCommandImpl = ($ScriptBlock.ast.gettype().GetMethod('GetWithInputHandlingForInvokeCommandImpl',$bindingFlags))
$StringScriptBlock = $GetWithInputHandlingForInvokeCommandImpl.Invoke($ScriptBlock.ast,@($Tuple

))

image

Pretty cool, right? As I mentioned earlier, we need to build out a param() block still. This is due to one not already existing. Had I added a Param() block in the script block:

$ScriptBlock = {
    Param($Param1)
    [pscustomobject]@{
        Computername = $Using:Computername
        Output = ($Using:Data * 2)
    }
}

The output would look more like this:

image

Note how the $Param1 has been pushed to the very end while all of the new $__using variables are near the beginning.

Ok, with that out of the way, we will go back to dealing with our first example and adding our new Param() block.

If (-NOT $ScriptBlock.Ast.ParamBlock) {
    Write-Verbose "Creating Param() block" -Verbose
    $StringScriptBlock = "Param($($NewParams))`n$($StringScriptBlock)"
    [scriptblock]::Create($StringScriptBlock)
} Else {
    Write-Verbose "Param() will be magically updated!" -Verbose
    [scriptblock]::Create($StringScriptBlock)
}
}

And with that, we now have a script block that has been completely converted to support the $Using: variables! Of course, since I am using a nonpublic method to accomplish this, it does mean that this could be changed in a future release and could potentially break what I am doing.

What about V2 you ask? Well, since we do not have access to AST or the nonpublic method of ‘GetWithInputHandlingForInvokeCommandImpl’ to use for the conversion, we must resort to doing some of our own magic using the PSParser and RegEx.

V2 Using Attempt

We are going to use the same script block with just a minor change to full support V2:

$Data = 42
$Computername = $env:COMPUTERNAME
$ScriptBlock = {
    Param($TestParam)
    New-Object PSObject -Property @{
        Computername = $Using:Computername
        Output = ($Using:Data * 2)
    }
}

I am also going to use a function as well to make working with PSParser easier to convert a script block.

Function IsExistingParamBlock {
    Param([scriptblock]$ScriptBlock)
    $errors = [System.Management.Automation.PSParseError[]] @()
    $Tokens = [Management.Automation.PsParser]::Tokenize($ScriptBlock.tostring(), [ref] $errors)       
    $Finding=$True
    For ($i=0;$i -lt $Tokens.count; $i++) {       
        If ($Tokens[$i].Content -eq 'Param' -AND $Tokens[$i].Type -eq 'Keyword') {
            $HasParam = $True
            BREAK
        }
    }
    If ($HasParam) {
        $True
    } Else {
        $False
    }
}

Now we start pulling the $Using: variables by using the PSParser and looking at the tokens. I will also go ahead and pull the actual values of each variable and do the naming conversion just like I did with the previous example.

$errors = [System.Management.Automation.PSParseError[]] @()
$Tokens = [Management.Automation.PsParser]::Tokenize($ScriptBlock.tostring(), [ref] $errors)
$UsingVariables = $Tokens | Where {
    $_.Content -match '^Using:' -AND $_.Type -eq 'Variable'
}
$UsingVariable = $UsingVariables | ForEach {
    $Name = $_.Content -replace 'Using:'
    New-Object PSObject -Property @{
        Name = $Name
        NewName = '$__using_{0}' -f $Name
        Value = (Get-Variable -Name $Name).Value
        NewVarName = ('__using_{0}') -f $Name
    }
}

image

Now we get to the meaty part of this article by using quite a bit of code to work through the script block conversion.

$StringBuilder = New-Object System.Text.StringBuilder
$UsingHash = @{}
$UsingVariable | ForEach {
    $UsingHash["Using:$($_.Name)"] = $_.NewVarName
}
$HasParam = IsExistingParamBlock -ScriptBlock $ScriptBlock
$Params = New-Object System.Collections.ArrayList
If ($Script:Add_) {
    [void]$Params.Add('$_')
}
If ($UsingVariable) {        
    [void]$Params.AddRange(($UsingVariable | Select -expand NewName))
} 
$NewParams = $Params -join ', '  
If (-Not $HasParam) {
    [void]$StringBuilder.Append("Param($($NewParams))")
}
For ($i=0;$i -lt $Tokens.count; $i++){
    #Write-Verbose "Type: $($Tokens[$i].Type)"
    #Write-Verbose "Previous Line: $($Previous.StartLine) -- Current Line: $($Tokens[$i].StartLine)"
    If ($Previous.StartLine -eq $Tokens[$i].StartLine) {
        $Space = " " * [int]($Tokens[$i].StartColumn - $Previous.EndColumn)
        [void]$StringBuilder.Append($Space)
    }
    Switch ($Tokens[$i].Type) {
        'NewLine' {[void]$StringBuilder.Append("`n")}
        'Variable' {
            If ($UsingHash[$Tokens[$i].Content]) {
                [void]$StringBuilder.Append(("`${0}" -f $UsingHash[$Tokens[$i].Content]))
            } Else {
                [void]$StringBuilder.Append(("`${0}" -f $Tokens[$i].Content))
            }
        }
        'String' {
            [void]$StringBuilder.Append(("`"{0}`"" -f $Tokens[$i].Content))
        }
        'GroupStart' {
            $Script:GroupStart++
            If ($Script:AddUsing -AND $Script:GroupStart -eq 1) {
                $Script:AddUsing = $False
                [void]$StringBuilder.Append($Tokens[$i].Content)                    
                If ($HasParam) {
                    [void]$StringBuilder.Append("$($NewParams),")
                }
            } Else {
                [void]$StringBuilder.Append($Tokens[$i].Content)
            }
        }
        'GroupEnd' {
            $Script:GroupStart--
            If ($Script:GroupStart -eq 0) {
                $Script:Param = $False
                [void]$StringBuilder.Append($Tokens[$i].Content)
            } Else {
                [void]$StringBuilder.Append($Tokens[$i].Content)
            }
        }
        'KeyWord' {
            If ($Tokens[$i].Content -eq 'Param') {
                $Script:Param = $True
                $Script:AddUsing = $True
                $Script:GroupStart=0
                [void]$StringBuilder.Append($Tokens[$i].Content)
            } Else {
                [void]$StringBuilder.Append($Tokens[$i].Content)
            }                
        }
        Default {
            [void]$StringBuilder.Append($Tokens[$i].Content)         
        }
    } 
    $Previous = $Tokens[$i]   
}

Now we take that string and make it into a script block.

[scriptblock]::Create($StringBuilder.ToString())

image

Of course, using the PSParser does mean that it is possible for things to get missed if the variables are nested deep in something such as this:

Write-Verbose $($Using:Computername) –Verbose

Our $Using:Computername variable will be completely skipped, thus making it harder to go through with the conversion. Just something to keep in mind if you are using V2 and trying to get PoshRSJob to work properly.

This is definitely a one-off thing that I am doing, but wanted to share some of how I was able to provide some $Using support in my module. Hopefully this provides a little more insight into that and maybe gets you looking to explore more about the internals of PowerShell!


Filed under: powershell Tagged: PoshRSJob, Powershell, reflection, using

Managing Privileges using PoshPrivilege

$
0
0

A recent project of mine has been to write a module to manage privileges on a local system. What I came up is a module called PoshPrivilege that allows you to not only look at what user rights are available on a local or remote system, but also provide the ability to Add, Remove, Enable and Disable the privileges as well.

If you are running PowerShell V5, you can download this module from the PowerShell Gallery:

Install-Module –Name PoshPrivilege

Otherwise, check out my GitHub page where I am maintaining this project:

https://github.com/proxb/PoshPrivilege

I won’t spend time talking about how I wrote this module and my reasons behind it. What I will say is that instead of writing out C# code and then using Add-Type to compile it, I went with the Reflection approach of building out everything from the pinvoke signatures for methods to the Structs and even the Enums.

Let’s get started by looking at what is available in this module. The first function that is available is Get-Privilege and it comes with a few parameters. This function’s purpose is to let you view what privileges are currently available on the system (local or remote) as well as what is currently applied to your current process token.

image

A quick run through of using this function with various parameters:

Get-Privilege

image

Get-Privilege –Privilege SeAuditPrivilege, SeServiceLogonRight | Format-List

image

Get-Privilege –CurrentUser

image

If this one looks familiar, then it is probably likely that you have used the following command:

whoami /priv /fo csv | ConvertFrom-CSV

image

I opted for boolean values instead to determine the state for easier filtering if needed.

Up next are the Enable/Disable-Privilege functions. These work to Enable or Disable the privileges that are currently available on your local system to your process token. This means that if something like SeDebugPrivilege isn’t available on your system (such as being removed via Group Policy), then you cannot use Enable-Privilege to add your process token to this privilege. As in the previous image where we can see what is enabled and disabled, these are the only privileges that are available for me to work with.

To show this point, I am going to enable both SeSecurityPrivilege and SeDebugPrivilege so you can see that while the first privilege will show as Enabled, the other will not appear as it has not been made available.

Enable-Privilege -Privilege SeSecurityPrivilege,SeDebugPrivilege

SNAGHTMLd2422

As you can see from the picture, SeSecurityPrivilege has been enabled as expected, but SeDebugPrivilege is nowhere to be found. If we want SeDebugPrivilege, we will need to go about this another way which will be shown shortly.

Disabling a privilege can be done using Disable-Privilege as shown in the example below.

Disable-Privilege –Privilege SeSecurityPrivilege

SNAGHTMLfdf1c

Now that I have covered Enabling and Disabling of the privileges and their limitations, I will move onto the Add/Remove-Privilege functions which allow you to add a privilege for a user or group or remove them on a local system. Note that this only works up until it gets reverted if set by group policy. This will also note show up if you look at the privileges available on your current process token (you will log off and log back in to see it).

Remember that I do not have SeDebugPrivilege available to use? Well, now we can add it to my own account using Add-Privilege.

Add-Privilege –Privilege SeDebugPrivilege –Accountname boe-pc\proxb

image

We can see it is now available, but as I mentioned before, it doesn’t show up in my current process. A logoff and login now shows that it is not only available, but already enabled.

image

With this now enabled, we could disable it as well if needed using Disable-Privilege. I added my account for show, but we can also add groups this was as well.

As with Adding a privilege, we can remove privileges as well using Remove-Privilege.

Remove-Privilege –Privilege SeDebugPrivilege –AccountName boe-pc\proxb

image

As with Add-Privilege, you will need to log off and log back in to see the change take effect on your account.

Again, you can install this module using Install-Module if running PowerShell V5 and this project is out on GitHub to download (and contribute to as well). Enjoy!


Filed under: powershell Tagged: pinvoke, PoshPrivilege, Powershell, privileges, reflection, user rights

Invoking Private Static Methods Using PowerShell

$
0
0

Usually if I want to accomplish a task in PowerShell, I can count on either a cmdlet or a publicly available .Net method to come to my rescue. Sometimes though, a method that I would like to use is just seemingly not available. Fortunately on occasion I can find a method that does what I need (or at least sets me up to accomplish my goal a little easier) using a private (or hidden) static method.

An example of needing such a method was when I decided to incorporate the $Using: variable scope in my PoshRSJob module. I had to open up and dive into PowerShell using DotPeek to see the internal workings of Start-Job to see that there were some calls to a method which I could not see just by piping the object into Get-Member and viewing the methods. Instead, we have to take the object and dive into the guts of it to view some methods and also enlist the help of some reflection binding flags to actually uncover the method that we need.

I won’t actually go into this approach as it won’t really provide a good ‘real world’ use. Instead I will take a look at the [Array] type and we will uncover some private methods and use one to see what happens.

Lets take a look at the static methods on [Array] and see what we have:

[Array] | Get-Member –Type Method –Static

image

You might be wondering why I used the –Static switch instead of looking at just the Methods. This is because I only wanted to display the methods that would actually be associated with working with the Array in this case. Had I not done that, then we would be seeing methods associated with the System.RuntimeType object.

What isn’t shown here is a method within Array called GetMedian, which as you can tell, should help to tell you the middle item in an array. Also note that it isn’t even mentioned on the MSDN site for Array. Why would you need this? Well, there is always someone somewhere that might need this type of thing.

With that, we need to figure out how we can find this method. Looking at the methods for the System.RunTimeType object of Array, we can find two methods that stick out: GetMethod() and GetMethods(). Calling GetMethods() will spit out all of the methods of Array while GetMethod() is geared towards a particular method.

image

Taking a deeper look at the method overloads, we can see that there are more than a few overloads that we could use for each of these methods.

image

In this example, I just want to see all methods (just the names) for Array.

[Array].GetMethods().Name | Group | Select Count, Name

image

You can see the same static methods that we observed earlier, plus multiple methods with the same name. Let’s say that we wanted to look at a single method. We would just list the name of the method in GetMethod and then we can view more information about it.

[Array].GetMethod(‘Clear’)

image

Calling GetParameters() from this method will show us all of the parameters required for this method, if applicable. In the case of Clear, there are no parameters so we do not have to worry about adding a parameter to the private method if we were to call it. Don’t worry, we will see some parameters for GetMedian Winking smile.

Before we hit up on GetMedian, let’s examine what happens when we try to view a method that has multiple overloads.

[array].GetMethod('Reverse')

image

This error is talking about results for ‘Reverse’ were found which means that we need to find a way to only use a single instance. What we need to do is figure out the parameter types that exist for each method overload and we can then use those with our GetMethod() call.

[array].GetMethods() | Where {$_.Name -eq 'reverse'} | ForEach {
    Write-Verbose $($_.Name) -Verbose
    $_.GetParameters() | Select Name, ParameterType, Position
}

image

I’ll got for the second method which is looking for an Array and two Int32 types and plug those into the method and see what happens.

[array].getmethod('Reverse',[type[]]@('array','int32','int32')).GetParameters()

image

And now we have our method. Definitely something to keep in mind if you happen to run into this error message.

The problem here is that the GetMedian method is not here! This is now where we have to make use of the Reflection.BindingFlags to locate our private method.

Let’s take a look at all of the possible values here for System.Reflection.BindingFlags

[System.Reflection.BindingFlags].GetEnumNames()

image

Each of these provides specific filters for when you do a search for the methods using GetMethod() or GetMethods(). Rather than regurgitate all of the possible meanings for these, I will instead direct you to this link that does a fine job of explaining everything.

The binding flags that I need to locate the private methods are: Static, Nonpublic and Instance. The three of these will open up a whole new world of methods that were previously hidden from us.

$BindingFlags = 'static','nonpublic','instance'
[array].GetMethods($BindingFlags).Name

SNAGHTML2be7092d

Definitely a lot of private methods here! But in this case, I am only concerned with GetMedian. Let’s now view the method itself.

$BindingFlags = 'static','nonpublic','instance'
[array].GetMethod(‘GetMedian’,$BindingFlags)

image

Now we can view the parameters of this method and see what is required.

$Method = [array].getmethod('GetMedian',@('nonpublic','instance','static'))
$Method.GetParameters() | 
Select Name, ParameterType, Position | Format-Table –AutoSize

image

Here we can see that both of the parameters require an Int32. The low is the starting index of the array (usually 0) and the hi parameter requires the highest index of the array. Also note the positions of each parameter. Just like in PowerShell, if we don’t specify the correct value for the right parameter in the proper position, bad things can happen.

We have the method and we have the parameters, but how in the world do we actually use this method? It’s not publically available so what is the magical process to use it? Well, we have to call the Invoke() method on the method and supply the object that owns the method followed by the collection of values required by the parameters (in the proper order) for it to work properly.

I want to first create an array of letters:

$list = 'a','b','c','d','e'

image

We obviously know that ‘c’ is the middle item in the array, but imagine if this was a huge array. Might not be that obvious.

Next up is to set ourselves up to use the private method.

$GetMedian = [array].getmethod('GetMedian',@('nonpublic','instance','static'))

And now we get to call the method by supplying the array itself and the low and hi parameters.

$Index = $GetMedian.Invoke($list,@(0,$list.Count))
$Index

image

What we actually get back is the index of the array (remember the return type of the method) so we can use that to slice into the array and verify that the median is indeed ‘c’.

$list[$Index]

image

Sure enough, it is the letter ‘c’ that is the median of this array.

Given, this was a rather simple demonstration of how you can use private methods in PowerShell, but this was the same approach that I took when working with my module to implement $Using: support.

Just for the sake of having a reference, if I ran into a issue with multiple method overloads, I would use the following in order to get the one that I needed (after knowing the parameter types).

[array].getmethod('GetMedian',@('nonpublic','instance','static'),$Null,[type[]]@([int32],[int32]),$null)

It just took a little work to locate the method and then to supply the proper parameter types to the method and it worked like a champ!


Filed under: powershell Tagged: array, methods, Powershell, private, reflection

Finding the PowerShellAsyncResult on PowerShell Object After Using BeginInvoke

$
0
0

I’ve been here many of times when working with the console and creating a PowerShell instance and runspace to kick off a runspace in the background. I have everything situated and then call BeginInvoke() against my PowerShell object and realize my mistake when I see the PowerShellAsyncResult being displayed proudly in my console.

$Runspace = [runspacefactory]::CreateRunspace()
$PowerShell = [powershell]::Create()
$Runspace.Open()
$PowerShell.Runspace = $Runspace
[void]$PowerShell.AddScript({
    #Imagine that this was some crazy long operation
    [pscustomobject]@{
        Name = 'Boe Prox'
        PowerShell = $True
    }
})
$PowerShell.BeginInvoke()

SNAGHTML4ec3557

If you’ve worked with this before of done something where you had to use BeginInvoke() and not captured the resulting System.Management.Automation.PowerShellAsyncResult output, you know the pain in having to close out the console and re-running this and making sure to capture the output.

I had mentioned this in my talk on PowerShell runspaces that if you don’t capture this output, then it is the end of the line for your command running in the background.

It is painful. It is frustrating. And it is not the end of the world! There is actually hope for you if this happens and you do not want to kill whatever you are doing to restart the command in the runspace.

The trick lies in using Reflection to look into the PowerShell object for the invokeAsyncResult field and pulling the object out so you can use it later on with EndInvoke().

First we need to get the proper binding flags so we can look for our field. In this case, I only need the nonpublic and instance flags. I already know the name of the field: invokeAsyncResult from performing a all out look at the fields on my object.

Armed with this, I can now pull the field from the object.

$BindingFlags = [Reflection.BindingFlags]'nonpublic','instance'
$Field = $PowerShell.GetType().GetField('invokeAsyncResult',$BindingFlags)

image

Now all I have to do is get the value of this field. In order to do that, I use the GetValue() method on the field and give it the PowerShell object as the required object in the parameter.

$Handle = $Field.GetValue($PowerShell)

SNAGHTML4f785f2

We now have our PowerShellAsyncResult  object back and can now use it to properly end the command using EndInvoke().

image

Perfect! Now we have a way to save ourselves if we happen to call BeginInvoke() on our PowerShell object and happen to forget to save the output object to use later on!


Filed under: powershell Tagged: asynchandle, Powershell, reflection, runspace

Managing Privileges using PoshPrivilege

$
0
0

A recent project of mine has been to write a module to manage privileges on a local system. What I came up is a module called PoshPrivilege that allows you to not only look at what user rights are available on a local or remote system, but also provide the ability to Add, Remove, Enable and Disable the privileges as well.

If you are running PowerShell V5, you can download this module from the PowerShell Gallery:

Install-Module –Name PoshPrivilege

Otherwise, check out my GitHub page where I am maintaining this project:

https://github.com/proxb/PoshPrivilege

I won’t spend time talking about how I wrote this module and my reasons behind it. What I will say is that instead of writing out C# code and then using Add-Type to compile it, I went with the Reflection approach of building out everything from the pinvoke signatures for methods to the Structs and even the Enums.

Let’s get started by looking at what is available in this module. The first function that is available is Get-Privilege and it comes with a few parameters. This function’s purpose is to let you view what privileges are currently available on the system (local or remote) as well as what is currently applied to your current process token.

image

A quick run through of using this function with various parameters:

Get-Privilege

image

Get-Privilege –Privilege SeAuditPrivilege, SeServiceLogonRight | Format-List

image

Get-Privilege –CurrentUser

image

If this one looks familiar, then it is probably likely that you have used the following command:

whoami /priv /fo csv | ConvertFrom-CSV

image

I opted for boolean values instead to determine the state for easier filtering if needed.

Up next are the Enable/Disable-Privilege functions. These work to Enable or Disable the privileges that are currently available on your local system to your process token. This means that if something like SeDebugPrivilege isn’t available on your system (such as being removed via Group Policy), then you cannot use Enable-Privilege to add your process token to this privilege. As in the previous image where we can see what is enabled and disabled, these are the only privileges that are available for me to work with.

To show this point, I am going to enable both SeSecurityPrivilege and SeDebugPrivilege so you can see that while the first privilege will show as Enabled, the other will not appear as it has not been made available.

Enable-Privilege -Privilege SeSecurityPrivilege,SeDebugPrivilege

SNAGHTMLd2422

As you can see from the picture, SeSecurityPrivilege has been enabled as expected, but SeDebugPrivilege is nowhere to be found. If we want SeDebugPrivilege, we will need to go about this another way which will be shown shortly.

Disabling a privilege can be done using Disable-Privilege as shown in the example below.

Disable-Privilege –Privilege SeSecurityPrivilege

SNAGHTMLfdf1c

Now that I have covered Enabling and Disabling of the privileges and their limitations, I will move onto the Add/Remove-Privilege functions which allow you to add a privilege for a user or group or remove them on a local system. Note that this only works up until it gets reverted if set by group policy. This will also note show up if you look at the privileges available on your current process token (you will log off and log back in to see it).

Remember that I do not have SeDebugPrivilege available to use? Well, now we can add it to my own account using Add-Privilege.

Add-Privilege –Privilege SeDebugPrivilege –Accountname boe-pc\proxb

image

We can see it is now available, but as I mentioned before, it doesn’t show up in my current process. A logoff and login now shows that it is not only available, but already enabled.

image

With this now enabled, we could disable it as well if needed using Disable-Privilege. I added my account for show, but we can also add groups this was as well.

As with Adding a privilege, we can remove privileges as well using Remove-Privilege.

Remove-Privilege –Privilege SeDebugPrivilege –AccountName boe-pc\proxb

image

As with Add-Privilege, you will need to log off and log back in to see the change take effect on your account.

Again, you can install this module using Install-Module if running PowerShell V5 and this project is out on GitHub to download (and contribute to as well). Enjoy!


Filed under: powershell Tagged: pinvoke, PoshPrivilege, Powershell, privileges, reflection, user rights

Invoking Private Static Methods Using PowerShell

$
0
0

Usually if I want to accomplish a task in PowerShell, I can count on either a cmdlet or a publicly available .Net method to come to my rescue. Sometimes though, a method that I would like to use is just seemingly not available. Fortunately on occasion I can find a method that does what I need (or at least sets me up to accomplish my goal a little easier) using a private (or hidden) static method.

An example of needing such a method was when I decided to incorporate the $Using: variable scope in my PoshRSJob module. I had to open up and dive into PowerShell using DotPeek to see the internal workings of Start-Job to see that there were some calls to a method which I could not see just by piping the object into Get-Member and viewing the methods. Instead, we have to take the object and dive into the guts of it to view some methods and also enlist the help of some reflection binding flags to actually uncover the method that we need.

I won’t actually go into this approach as it won’t really provide a good ‘real world’ use. Instead I will take a look at the [Array] type and we will uncover some private methods and use one to see what happens.

Lets take a look at the static methods on [Array] and see what we have:

[Array] | Get-Member –Type Method –Static

image

You might be wondering why I used the –Static switch instead of looking at just the Methods. This is because I only wanted to display the methods that would actually be associated with working with the Array in this case. Had I not done that, then we would be seeing methods associated with the System.RuntimeType object.

What isn’t shown here is a method within Array called GetMedian, which as you can tell, should help to tell you the middle item in an array. Also note that it isn’t even mentioned on the MSDN site for Array. Why would you need this? Well, there is always someone somewhere that might need this type of thing.

With that, we need to figure out how we can find this method. Looking at the methods for the System.RunTimeType object of Array, we can find two methods that stick out: GetMethod() and GetMethods(). Calling GetMethods() will spit out all of the methods of Array while GetMethod() is geared towards a particular method.

image

Taking a deeper look at the method overloads, we can see that there are more than a few overloads that we could use for each of these methods.

image

In this example, I just want to see all methods (just the names) for Array.

[Array].GetMethods().Name | Group | Select Count, Name

image

You can see the same static methods that we observed earlier, plus multiple methods with the same name. Let’s say that we wanted to look at a single method. We would just list the name of the method in GetMethod and then we can view more information about it.

[Array].GetMethod(‘Clear’)

image

Calling GetParameters() from this method will show us all of the parameters required for this method, if applicable. In the case of Clear, there are no parameters so we do not have to worry about adding a parameter to the private method if we were to call it. Don’t worry, we will see some parameters for GetMedian Winking smile.

Before we hit up on GetMedian, let’s examine what happens when we try to view a method that has multiple overloads.

[array].GetMethod('Reverse')

image

This error is talking about results for ‘Reverse’ were found which means that we need to find a way to only use a single instance. What we need to do is figure out the parameter types that exist for each method overload and we can then use those with our GetMethod() call.

[array].GetMethods() | Where {$_.Name -eq 'reverse'} | ForEach {
    Write-Verbose $($_.Name) -Verbose
    $_.GetParameters() | Select Name, ParameterType, Position
}

image

I’ll got for the second method which is looking for an Array and two Int32 types and plug those into the method and see what happens.

[array].getmethod('Reverse',[type[]]@('array','int32','int32')).GetParameters()

image

And now we have our method. Definitely something to keep in mind if you happen to run into this error message.

The problem here is that the GetMedian method is not here! This is now where we have to make use of the Reflection.BindingFlags to locate our private method.

Let’s take a look at all of the possible values here for System.Reflection.BindingFlags

[System.Reflection.BindingFlags].GetEnumNames()

image

Each of these provides specific filters for when you do a search for the methods using GetMethod() or GetMethods(). Rather than regurgitate all of the possible meanings for these, I will instead direct you to this link that does a fine job of explaining everything.

The binding flags that I need to locate the private methods are: Static, Nonpublic and Instance. The three of these will open up a whole new world of methods that were previously hidden from us.

$BindingFlags = 'static','nonpublic','instance'
[array].GetMethods($BindingFlags).Name

SNAGHTML2be7092d

Definitely a lot of private methods here! But in this case, I am only concerned with GetMedian. Let’s now view the method itself.

$BindingFlags = 'static','nonpublic','instance'
[array].GetMethod(‘GetMedian’,$BindingFlags)

image

Now we can view the parameters of this method and see what is required.

$Method = [array].getmethod('GetMedian',@('nonpublic','instance','static'))
$Method.GetParameters() |
Select Name, ParameterType, Position | Format-Table –AutoSize

image

Here we can see that both of the parameters require an Int32. The low is the starting index of the array (usually 0) and the hi parameter requires the highest index of the array. Also note the positions of each parameter. Just like in PowerShell, if we don’t specify the correct value for the right parameter in the proper position, bad things can happen.

We have the method and we have the parameters, but how in the world do we actually use this method? It’s not publically available so what is the magical process to use it? Well, we have to call the Invoke() method on the method and supply the object that owns the method followed by the collection of values required by the parameters (in the proper order) for it to work properly.

I want to first create an array of letters:

$list = 'a','b','c','d','e'

image

We obviously know that ‘c’ is the middle item in the array, but imagine if this was a huge array. Might not be that obvious.

Next up is to set ourselves up to use the private method.

$GetMedian = [array].getmethod('GetMedian',@('nonpublic','instance','static'))

And now we get to call the method by supplying the array itself and the low and hi parameters.

$Index = $GetMedian.Invoke($list,@(0,$list.Count))
$Index

image

What we actually get back is the index of the array (remember the return type of the method) so we can use that to slice into the array and verify that the median is indeed ‘c’.

$list[$Index]

image

Sure enough, it is the letter ‘c’ that is the median of this array.

Given, this was a rather simple demonstration of how you can use private methods in PowerShell, but this was the same approach that I took when working with my module to implement $Using: support.

Just for the sake of having a reference, if I ran into a issue with multiple method overloads, I would use the following in order to get the one that I needed (after knowing the parameter types).

[array].getmethod('GetMedian',@('nonpublic','instance','static'),$Null,[type[]]@([int32],[int32]),$null)

It just took a little work to locate the method and then to supply the proper parameter types to the method and it worked like a champ!


Filed under: powershell Tagged: array, methods, Powershell, private, reflection

Finding the PowerShellAsyncResult on PowerShell Object After Using BeginInvoke

$
0
0

I’ve been here many of times when working with the console and creating a PowerShell instance and runspace to kick off a runspace in the background. I have everything situated and then call BeginInvoke() against my PowerShell object and realize my mistake when I see the PowerShellAsyncResult being displayed proudly in my console.

$Runspace = [runspacefactory]::CreateRunspace()
$PowerShell = [powershell]::Create()
$Runspace.Open()
$PowerShell.Runspace = $Runspace
[void]$PowerShell.AddScript({
    #Imagine that this was some crazy long operation
    [pscustomobject]@{
        Name = 'Boe Prox'
        PowerShell = $True
    }
})
$PowerShell.BeginInvoke()

SNAGHTML4ec3557

If you’ve worked with this before of done something where you had to use BeginInvoke() and not captured the resulting System.Management.Automation.PowerShellAsyncResult output, you know the pain in having to close out the console and re-running this and making sure to capture the output.

I had mentioned this in my talk on PowerShell runspaces that if you don’t capture this output, then it is the end of the line for your command running in the background.

It is painful. It is frustrating. And it is not the end of the world! There is actually hope for you if this happens and you do not want to kill whatever you are doing to restart the command in the runspace.

The trick lies in using Reflection to look into the PowerShell object for the invokeAsyncResult field and pulling the object out so you can use it later on with EndInvoke().

First we need to get the proper binding flags so we can look for our field. In this case, I only need the nonpublic and instance flags. I already know the name of the field: invokeAsyncResult from performing a all out look at the fields on my object.

Armed with this, I can now pull the field from the object.

$BindingFlags = [Reflection.BindingFlags]'nonpublic','instance'
$Field = $PowerShell.GetType().GetField('invokeAsyncResult',$BindingFlags)

image

Now all I have to do is get the value of this field. In order to do that, I use the GetValue() method on the field and give it the PowerShell object as the required object in the parameter.

$Handle = $Field.GetValue($PowerShell)

SNAGHTML4f785f2

We now have our PowerShellAsyncResult  object back and can now use it to properly end the command using EndInvoke().

image

Perfect! Now we have a way to save ourselves if we happen to call BeginInvoke() on our PowerShell object and happen to forget to save the output object to use later on!


Filed under: powershell Tagged: asynchandle, Powershell, reflection, runspace

Building a Enum that Supports Bit Fields in PowerShell

$
0
0

I was working on a project recently that required me to have an Enum that allowed bit fields as opposed to the normal fields that we might deal with in our day to day endeavors with PowerShell.

If you aren’t quite sure what I mean by this, here is a quick example that shows the difference between the two.

First, the regular Enum that we are used to:

([DayOfWeek]0..6).ForEach({[pscustomobject]@{Number=$_;Data=[DayOfWeek]$_}})

image

Notice that each number matches up to a single value: 0 = Sunday, 3 = Wednesday and so on.

Now for an Enum with bit fields:

([System.IO.FileAttributes]1..7).ForEach({
[pscustomobject]@{Number=$_;Data=[System.IO.FileAttributes]$_}
})

image

You can see here that depending on the value, you may end up for more than 1 item. This typically will follow a 1,2,4,8,16…etc… approach for the single items and then they perform a bitwise XOR to combine values for more items.

Now that we have covered this topic in a very basic form, we still need to understand how to build one so we can use it in PowerShell. In PowerShell V2..4 we would have to settle on creating the enum by creating a C# here string and loading it up into the session like so:

Add-Type -TypeDefinition @"
[System.Flags]
public enum Animals
{
Dog = 1,
Cat = 2,
Bird = 4,
Lizard = 8
}
"@

All we have to do is ensure that the [System.Flags] attribute is used within our code.

Now we can verify that this actually worked like we wanted:

(1..15).ForEach{[pscustomobject]@{Number=$_;Animal=[Animals]$_}}

image

I’d say it passes the test!

Next up is building one dynamically using reflection. A little more complex but not something that we can’t do..right?

#region Module Builder
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('Random')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) # Only run in memory
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('Random', $False)
#endregion Module Builder

#region Animals
$EnumBuilder = $ModuleBuilder.DefineEnum('Animals', 'Public', [int32])
[void]$EnumBuilder.DefineLiteral('Dog', [int32] 0x00000001)
[void]$EnumBuilder.DefineLiteral('Cat', [int32] 0x00000002)
[void]$EnumBuilder.DefineLiteral('Bird', [int32] 0x00000004)
[void]$EnumBuilder.DefineLiteral('Lizard', [int32] 0x00000008)
$EnumBuilder.SetCustomAttribute(
[FlagsAttribute].GetConstructor([Type]::EmptyTypes),
@()
)
[void]$EnumBuilder.CreateType()
#endregion Animals

The trick here is to create a custom attribute where we supply the default constructor for the Flags.Attribute type add that attribute to the enum.

We can test using the same code to see if everything matches up:

image

Success! Ok, so I have covered the old ways of doing it and even the reflection approach is still valid in V5 if your goal is keeping everything in memory and not writing to disk.

If you are interested in an even easier way of doing this, then check out fellow MVP Matt Graeber’s PSReflect module that gives you the PSEnum function that makes this whole thing a snap!

$Mod = New-InMemoryModule -ModuleName Win32
psenum -FullName Animals -Type Int32 -Bitfield -Module $Mod -EnumElements @{
Dog = 1
Cat = 2
Bird = 4
Lizard = 8
}

If you run the usual code, you can easily see that it works!

In PowerShell V5, we are greeted with an easier way to natively build an Enum in PowerShell with the…Enum keyword! But we don’t quite care about that as we really need to have support for Flags so we can have our bit field support.

Luckily we have that available albeit not documented anywhere yet. We just have to define that it will have the Flags attribute before calling the Enum keyword and we are ready to go!

[Flags()] enum Animals {
Dog = 1
Cat = 2
Bird = 4
Lizard = 8
}

How simple was that? We just create the enum and it is ready to go with not much code or having to compile C# (not that it was that tough anyways) and we can verify once again just to make sure it works like we want it to.

image

No oddness here! It worked like a champ and we have yet another way to accomplish our goal! Just remember that this approach only works with PowerShell V5.

Enjoy!


Filed under: powershell Tagged: c#, enum, Powershell, reflection, v5

Quick Hits: Writing to a Read-Only Property

$
0
0

This post is less on doing something useful and more on just proving that I can do something even though PowerShell is trying to tell me that I cannot do it. That little thing is updating a property on an object that is set as Read-Only.

My example to show you how you can do something like this is by looking at $PSVersionTable which as we all know gives us some great information about what version of PowerShell that we are using.

$PSVersionTable

image

I am also using this as this was an example used in our previous user group meeting in which we were shown that the properties here could not be updated.

From this object, I am going to look more at the PSVersion property which of course is an object within this object.

$PSVersionTable.PSVersion

image

Looking at the properties of this object, we can see that each of the properties are shown as Read-Only by only having the Get method available to use.

$PSVersionTable.PSVersion | Get-Member

image

Furthermore, I am greeted with a nice error stating that my attempts to modify this have been foolish and that I should just give up.

$PSVersionTable.PSVersion.Major = 10

image

Yea, I guess I could just throw in the towel and move onto something more useful like updating some bugs on a module, but I think that I can do better here! And by using some reflection magic, I can make this happen!

To do this, I need to look at the hidden fields for the PSVersion object.

$PSVersionTable.PSVersion.GetType().GetFields('static,nonpublic,instance').Name

image

Here we can see that the field that we need to look at updating is _Major.  Now we need to figure out how we can set this.

$Field = $PSVersionTable.PSVersion.GetType().GetField('_Major','static,nonpublic,instance')
$Field | Get-Member

SNAGHTML32a4c8

Looking at the methods, I see a SetValue that accepts a object and a value for the object. This seems pretty simple,right? Just call the method and update the value.

$Field.SetValue($PSVersionTable.PSVersion,10)
$PSVersionTable.PSVersion

SNAGHTML59e81d

Perfect! We have now updated this “Read-Only” property to give us PowerShell V10! Now this will go away once we close and re-open PowerShell but it still a fun thing to do to show off how you can update these kinds of values.


Filed under: powershell Tagged: Powershell, quickhits, readonly, reflection

Viewing Net Sessions using PowerShell and PInvoke

$
0
0

We are all used to view net sessions on a local or remote system by calling net session to see what clients are connected to another system such as a file server or even a domain controller. This provides a nice way to determine where a user might be logged in at assuming that they have an active session or one that is just idle. The problem with net session is that it requires admin rights on the system that you are running the command against in order for it to provide the data you need.

image

If you are a server admin, then this really isn’t that much of a deal as you can just use PowerShell remoting to query a bunch of  systems and get the information that you need. I wanted a way to  do this without worrying about admin rights or being able to remote into a system to get the information so I decided to look beyond the usual .Net and native PowerShell approaches to see if anything was available. The next logical step was to look lower in the stack and the Win32API and see what functions were available for me to use. I’ve done a fair amount of work with PInvoke and wasn’t afraid to see what kind of fun would await me if I happened to find something that might fit what I need.

After a decent amount of research,  I came across the NetSessionEnum function which provided me exactly the type of data that I am looking for. As with many of these functions, it isn’t enough to create the method to use but also to set up the Structs and/or Enums that the functions require to support the marshaling of data in and out of managed memory. In this case,  I have to make use of the SESSION_INFO_10 structure as I am looking to only return back data on the session which provides the client, username, active time and idle time. The image below highlights the structure I picked and also the other available Structs if I wanted different types of data.

image

The last thing that I need to look at is adding NetApiBufferFree so I can be sure to free up the buffer and avoid any unnecessary memory leaks.

Now that we have this out of the way, we can look to put these pieces together and make a function that we can use repeatedly.

If you want to see more about using pinvoke with PowerShell and a better look at what you need to do, then check out this article I did a while back. For this article, I am going to just point out one part that  I had to do in order to allow the parameters within the NetSessionEnum to properly work with the method.

Looking at the pinvoke signature for this function out on http://www.pinvoke.net/default.aspx/netapi32/NetSessionEnum.html, you can see that the first 3 parameters are a little more unique than what I typically see in that they unmanaged type of LPWStr which is a 32 bit pointer.

SNAGHTML31a8e4

That means that my usual approach to dynamically building the method has to account for this, otherwise just adding a string type will result in the method throwing an error when used.

I will build the method just like I normally would and give it all of the proper parameter and return value types that it needs. Instead of proceeding by adding some custom attributes to the method, I am going to focus first on defining the parameters that have special requirements by building custom attributes for those first.

 

#region Custom Attribute Builder
$ctor = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructor(@([System.Runtime.InteropServices.UnmanagedType]))
$CustomAttribute = [System.Runtime.InteropServices.UnmanagedType]::LPWStr
$CustomAttributeBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder -ArgumentList $ctor, $CustomAttribute
#endregion Custom Attribute Builder

 

Notice here that I am defining the LPWStr unmanaged type within the custom attribute. This will be important to add to my parameters that need it. Fortunately, these happen to be the first 3 parameters of the method (Servername, UserClientName and Username).  I need to make use of the DefineParameter method that is within the method object that I created earlier. All I need is the position of the parameter, a parameter attribute and supply $Null for the last parameter. After that I use SetCustomAttribute and give the parameter the extra attribute that it needs and there will be no problems with these parameters causing issues on the method.

 

#Define first three parameters with custom attributes
1..3 | ForEach {
    $Parameter = $PInvokeMethod.DefineParameter(
        $_,
        [System.Reflection.ParameterAttributes]::In,
        $Null
    )
    $Parameter.SetCustomAttribute(
        $CustomAttributeBuilder
    )
}

My function, Get-NetSession will get around that limitation that we saw earlier when trying to view the sessions on a domain controller. By design, I exclude sessions that this command creates on the remote system by looking at the current user and computer and performing the exclusion. If the user happens to be on a different system also, then it will be displayed.

Get-NetSession –Computername vdc1

image

I can use the –IncludeSelf parameter to include my own sessions create by the command.

Get-NetSession –Computername vdc1 –IncludeSelf

image

I also have a UserName parameter that accepts a single string to filter for a particular user if to avoid looking at a large dump of data.

You can find the script to download below as well as the source code from my GitHub repo at the bottom.

Download Script

https://gallery.technet.microsoft.com/scriptcenter/View-Net-Sessions-locally-d6eb2ba0

Source Code

https://github.com/proxb/PInvoke/blob/master/Get-NetSession.ps1


Filed under: powershell Tagged: pinvoke, Powershell, reflection, sessions

Revisiting NetSession Function using PSReflect

$
0
0

In an article that I wrote a little while ago, I talked about how you can view the net sessions on systems by making use of some pinvoke magic to call some Win32 apis. If you have ever worked with this type of approach, you know that it can be sometimes painful in writing out the necessary code needed to build out the required methods, enums, structs and anything else that is required just to pull a particular piece of information.

So you might be asking why don’t we just use Add-Type and use the very handy pinvoke signatures that are available? Well, this is the easiest approach as it is all taken care of for you, but if you are more on the security side, you want to ensure that nothing is written to disk (which is what Add-Type does) whereas using reflection can give you the option to write to memory instead, making it leave less artifacts laying around.

Fortunately for all of us in the community, fellow MVP Matt Graeber (Blog | Twitter) has made an awesome module called PSReflect which seeks to make this process much simpler by handling all of the internal calls and building of the methods from the Win32 apis while leaving us with the necessary code to use the methods.

What I am going to do in this blog post is to highlight just how easy it is to build working code that uses pinvoke signatures by taking what I did in my post on viewing net sessions and applying the same process this time using the PSReflect module. The Github repository that I referenced earlier is one way to get a hold of the module, but if you are running PowerShell V5, you can install is simply by calling Install-Module.

Install-Module –Name PSReflect

image

And now we have our module that we can use in building out the necessary code. I won’t be using all of the commands here, but in case you are curious as to  what is available, here they are:

image

I want to show the code that is handling the reflection to dynamically build out the methods that will be used to grab the net sessions and won’t be showing everything else that happens afterwards to pull the net sessions. So with that, here is the code that I used in my Get-NetSession function to build up the types and methods:

#region Reflection
Try {
    [void][Net.Session]
}
Catch {
    Write-Verbose &quot;Building pinvoke via reflection&quot;
    #region Module Builder
    $Domain = [AppDomain]::CurrentDomain
    $DynAssembly = New-Object System.Reflection.AssemblyName('NetSession')
    $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) # Only run in memory
    $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('NetSessionModule', $False)
    #endregion Module Builder

    #region Custom Attribute Builder
    $ctor = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructor(@([System.Runtime.InteropServices.UnmanagedType]))
    $CustomAttribute = [System.Runtime.InteropServices.UnmanagedType]::LPWStr
    $CustomAttributeBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder -ArgumentList $ctor, $CustomAttribute
    #endregion Custom Attribute Builder

    #region Struct
    #region SESSION_INFO_10
    $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
    $STRUCT_TypeBuilder = $ModuleBuilder.DefineType('SESSION_INFO_10', $Attributes, [System.ValueType], 8, 0x0)
    $Field = $STRUCT_TypeBuilder.DefineField('OriginatingHost', [string], 'Public')
    $Field.SetCustomAttribute($CustomAttributeBuilder)
    $Field = $STRUCT_TypeBuilder.DefineField('DomainUser', [string], 'Public')
    $Field.SetCustomAttribute($CustomAttributeBuilder)
    [void]$STRUCT_TypeBuilder.DefineField('SessionTime', [uint32], 'Public')
    [void]$STRUCT_TypeBuilder.DefineField('IdleTime', [uint32], 'Public')
    [void]$STRUCT_TypeBuilder.CreateType()
    #endregion SESSION_INFO_10
    #endregion Struct

    $TypeBuilder = $ModuleBuilder.DefineType('Net.Session', 'Public, Class')

    #region Methods
    #region NetSessionEnum Method
    $PInvokeMethod = $TypeBuilder.DefineMethod(
        'NetSessionEnum', #Method Name
        [Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes
        [int32], #Method Return Type
        [Type[]] @(
            [string],
            [string],
            [string],
            [int32],
            [intptr].MakeByRefType(),
            [int],
            [int32].MakeByRefType(),
            [int32].MakeByRefType(),
            [int32].MakeByRefType()
        ) #Method Parameters
    )

    #Define first three parameters with custom attributes
    1..3 | ForEach {
        $Parameter = $PInvokeMethod.DefineParameter(
            $_,
            [System.Reflection.ParameterAttributes]::In,
            $Null
        )
        $Parameter.SetCustomAttribute(
            $CustomAttributeBuilder
        )
    }

    $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
    $FieldArray = [Reflection.FieldInfo[]] @(
        [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
        [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
        [Runtime.InteropServices.DllImportAttribute].GetField('ExactSpelling')
        [Runtime.InteropServices.DllImportAttribute].GetField('PreserveSig')
    )

    $FieldValueArray = [Object[]] @(
        'NetSessionEnum', #CASE SENSITIVE!!
        $True,
        $True,
        $True
    )

    $CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
        $DllImportConstructor,
        @('Netapi32.dll'),
        $FieldArray,
        $FieldValueArray
    )

    $PInvokeMethod.SetCustomAttribute($CustomAttribute)
    #endregion NetSessionEnum Method
    #region NetApiBufferFree Method
    $PInvokeMethod = $TypeBuilder.DefineMethod(
        'NetApiBufferFree', #Method Name
        [Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes
        [int], #Method Return Type
        [Type[]] @(
            [intptr]
        ) #Method Parameters
    )

    $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
    $FieldArray = [Reflection.FieldInfo[]] @(
        [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
        [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
        [Runtime.InteropServices.DllImportAttribute].GetField('ExactSpelling')
        [Runtime.InteropServices.DllImportAttribute].GetField('PreserveSig')
    )

    $FieldValueArray = [Object[]] @(
        'NetApiBufferFree', #CASE SENSITIVE!!
        $True,
        $True,
        $True
    )

    $CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
        $DllImportConstructor,
        @('Netapi32.dll'),
        $FieldArray,
        $FieldValueArray
    )

    $PInvokeMethod.SetCustomAttribute($CustomAttribute)
    #endregion NetApiBufferFree Method
    #endregion Methods

    [void]$TypeBuilder.CreateType()
}
#endregion Reflection

Yes, that is 129 lines of code that handles the building of 1 Struct and 2 Methods. Depending on the amount of data in a Struct, it could be a greater number of lines to account for more properties. Methods are usually going to be the same number of lines (~50) depending on your style of building it out. In my case this is what I would expect even for a simple method that might only take a single parameter and doesn’t return anything when called.

I want to make sure that the PSReflect module is available before running the function so I am going to add a REQUIRES statement and then import the module.

#REQUIRES -Module PSReflect
Import-Module -Name PSReflect

The first part is to create the module builder that we will then be referencing throughout the rest of the creations of the various components related to our structs and methods.

No PSReflect

#region Module Builder
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('NetSession')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) # Only run in memory
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('NetSessionModule', $False)
#endregion Module Builder

#region Custom Attribute Builder
$ctor = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructor(@([System.Runtime.InteropServices.UnmanagedType]))
$CustomAttribute = [System.Runtime.InteropServices.UnmanagedType]::LPWStr
$CustomAttributeBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder -ArgumentList $ctor, $CustomAttribute
#endregion Custom Attribute Builder

 

With PSReflect

$Module = New-InMemoryModule -ModuleName NetSessions

I am including the Custom Attribute Builder as it is required for my Struct. Next up is to build out the Struct that the method will require for handling the net sessions object.

No PSReflect

$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$STRUCT_TypeBuilder = $ModuleBuilder.DefineType('SESSION_INFO_10', $Attributes, [System.ValueType], 8, 0x0)
$Field = $STRUCT_TypeBuilder.DefineField('OriginatingHost', [string], 'Public')
$Field.SetCustomAttribute($CustomAttributeBuilder)
$Field = $STRUCT_TypeBuilder.DefineField('DomainUser', [string], 'Public')
$Field.SetCustomAttribute($CustomAttributeBuilder)
[void]$STRUCT_TypeBuilder.DefineField('SessionTime', [uint32], 'Public')
[void]$STRUCT_TypeBuilder.DefineField('IdleTime', [uint32], 'Public')
[void]$STRUCT_TypeBuilder.CreateType()

With PSReflect

$SESSION_INFO_10 = struct -Module $Module -FullName SESSION_INFO_10 -StructFields @{
    OriginatingHost = field -Position 0 -Type ([string]) -MarshalAs @('LPWStr')
    DomainUser = field -Position 1 -Type ([string]) -MarshalAs @('LPWStr')
    SessionTime = field -Position 2 -Type ([int32])
    IdleTime = field -Position 3 -Type ([int32])
}

You can already start to see the fewer lines of code that is being used and I can assure you that this trend will only continue. In fact, I don’t need to worry about a custom attribute builder with PSReflect as it is handled via the –MarshalAs parameter.

Up next are the method creations that we will be creating to round out all of the components.

No PSReflect

$TypeBuilder = $ModuleBuilder.DefineType('Net.Session', 'Public, Class')

#region Methods
#region NetSessionEnum Method
$PInvokeMethod = $TypeBuilder.DefineMethod(
    'NetSessionEnum', #Method Name
    [Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes
    [int32], #Method Return Type
    [Type[]] @(
        [string],
        [string],
        [string],
        [int32],
        [intptr].MakeByRefType(),
        [int],
        [int32].MakeByRefType(),
        [int32].MakeByRefType(),
        [int32].MakeByRefType()
    ) #Method Parameters
)

#Define first three parameters with custom attributes
1..3 | ForEach {
    $Parameter = $PInvokeMethod.DefineParameter(
        $_,
        [System.Reflection.ParameterAttributes]::In,
        $Null
    )
    $Parameter.SetCustomAttribute(
        $CustomAttributeBuilder
    )
}

$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
$FieldArray = [Reflection.FieldInfo[]] @(
    [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
    [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
    [Runtime.InteropServices.DllImportAttribute].GetField('ExactSpelling')
    [Runtime.InteropServices.DllImportAttribute].GetField('PreserveSig')
)

$FieldValueArray = [Object[]] @(
    'NetSessionEnum', #CASE SENSITIVE!!
    $True,
    $True,
    $True
)

$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
    $DllImportConstructor,
    @('Netapi32.dll'),
    $FieldArray,
    $FieldValueArray
)

$PInvokeMethod.SetCustomAttribute($CustomAttribute)
#endregion NetSessionEnum Method
#region NetApiBufferFree Method
$PInvokeMethod = $TypeBuilder.DefineMethod(
    'NetApiBufferFree', #Method Name
    [Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes
    [int], #Method Return Type
    [Type[]] @(
        [intptr]
    ) #Method Parameters
)

$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
$FieldArray = [Reflection.FieldInfo[]] @(
    [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
    [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
    [Runtime.InteropServices.DllImportAttribute].GetField('ExactSpelling')
    [Runtime.InteropServices.DllImportAttribute].GetField('PreserveSig')
)

$FieldValueArray = [Object[]] @(
    'NetApiBufferFree', #CASE SENSITIVE!!
    $True,
    $True,
    $True
)

$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
    $DllImportConstructor,
    @('Netapi32.dll'),
    $FieldArray,
    $FieldValueArray
)

$PInvokeMethod.SetCustomAttribute($CustomAttribute)
#endregion NetApiBufferFree Method
#endregion Methods

[void]$TypeBuilder.CreateType()

With PSReflect

$Functions = @(
    func -DllName Netapi32 -FunctionName NetSessionEnum -ReturnType ([int32]) -ParameterTypes @([string],[string],[string],[int32],
        [intptr].MakeByRefType(),[int],[int32].MakeByRefType(),[int32].MakeByRefType(),[int32].MakeByRefType())
    func -DllName Netapi32 -FunctionName NetApiBufferFree -ReturnType ([int]) -ParameterTypes @([intptr])
)

$Functions | Add-Win32Type -Module $Module -Namespace 'Net.Session'

This is, in my opinion, where you see the biggest gains with PSReflect in the amount of lines of code that you save using this module to build out the methods. The total lines of code that it takes to build out my code using PSReflect is 23 lines of code. Compare that to the 129 lines not using PSReflect and you can see that I saved over 100 lines! This was a pretty small amount of pinvoke happening here as some of my larger functions (Get-ChildItem2 and Get-Service2) require a lot more code to build out everything that I need.

If you also didn’t notice, the quality of the code is also much cleaner to read and understand as you are working with PowerShell functions, not just a lot of .Net code to build everything out. Defining a method via PowerShell code is so much easier to write and read than dynamically building everything out.

After this, the rest of the code is practically the same as I still need to perform the same actions to build the object, query the remote system and marshal the data back to the object.

I hope that if you work with pinvoke,  that you give this a try and see how much easier it will make your life writing code without having to worry about writing a bunch of code to create the necessary components to make everything work together.

References

http://www.powershellmagazine.com/2014/09/25/easily-defining-enums-structs-and-win32-functions-in-memory/


Filed under: powershell Tagged: community, module, pinvoke, Powershell, psreflect, reflection, win32

Yet Another Way to Get Output from a Runspace, Reflection Edition

$
0
0

While working on some possible feature updates to my module, PoshRSJob, I have been looking at ways to get the output from a runspace without relying on the usual approach of using EndInvoke() while supplying a PowerShellAsyncResult object to pull the output. I had blogged about one way to get output from a runspace, but have found another way to grab the data as well, this time using reflection.

Now why am I continuing on this path to find more ways to get data from a runspace when there are already perfectly good ways to accomplish this? Well, one of my bigger struggles with making PoshRSJob more like the typical PSJobs that we all know and love are that it is able to preserve the streams properly whereas in PoshRSJob, we have to do some dancing to make it all work…almost. Write-Host continues to be a pain point as it is hard to find a good way to ensure that the stream is outputted not only properly, but with the proper colors defined when using the cmdlet. Now, I haven’t solved this yet and don’t plan on solving this any time soon, but by doing some experimenting, I have found some other ways that I wanted to share with you in viewing output from a runspace without ending the invocation of the runspace. My thoughts are that if I can find a different way to peek into a runspace to find if information is available,then I could refactor my code to provide a one time receive of the job to show all of the streams while still keeping the output objects available to until disposed of. Will this be solved? Maybe, but it is fun to keep digging into runspaces and this time, I get to do so using reflection! One of my favorite techniques to work with.

There really is not a lot to doing this, but we will cover from setup to tear down so you can easily copy and paste this for your own testing. First off, we build of and kick off the runspace like we usually do.

#Begin using the proces that we know and love
$PowerShell = [powershell]::Create()
$Runspace = [runspacefactory]::CreateRunspace()
$Runspace.Open()
$PowerShell.Runspace = $Runspace
[void]$PowerShell.AddScript({
    [pscustomobject]@{
        Data = 1
        Text = 'Test'
    }
})

$Handle = $PowerShell.BeginInvoke()

I am holding onto the PowerShellAsyncResult just out of habit, but in the end, we can just dispose of the runspace without calling EndInvoke(), or we can still call it and verify that the output lines up with what we will see using reflection. By the way, this is a great way to still get your output if you happen to forget the object in your travels.

#Specfiy the required flags to pull the output stream
$Flags = 'nonpublic','instance','static'
$Output = $PowerShell.GetType().GetProperty('OutputBuffer',$Flags)

image

Now that we have the OutputBuffer property object, we can then make use of the GetValue() method to pull the output data from the runspace. We will this by supplying the $PowerShell variable so it knows where and what to do to get the data it needs.

$Output.GetValue($PowerShell)

image

What this gives us is another way to maybe see if there is data available by looking at the count of the results and if there are more than 0, then we could proceed with processing of the runspace or just dispose of it without any worry. And in case you are wondering about the whole count approach, keep in mind that the actual object is of the System.Management.Automation.PSDataCollection`1[[System.Management.Automation.PSObject, System.Management.Automation, Version=3.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35]] type.

Get-Member -InputObject ($Output.GetValue($PowerShell))

image

Don’t call this method prematurely if the runspace is still processing data. This actually opens up the runspace to your current console session and will block any further input until the runspace has completed.

That is all for peeking into a completed runspace using reflection and PowerShell. While this will not likely be something that you would use often, it does provide an alternative means to looking at the data in a runspace without using EndInvoke().


Filed under: powershell Tagged: Powershell, reflection, runspaces

Tracking the State of PowerShell Runspaces in a Runspacepool

$
0
0

A question that I have received a number of times has always involved a way to determine the state of each runspace that is in a runspacepool. Since a runspacepool is used to throttle the number of runspaces that are able to run at a single time, it only makes sense that there should be a way to determine what runspaces are currently running and what ones are in a ‘NotStarting’ state. Knowing when a runspace is completed is simple with the IsCompleted property of the PowerShellAsyncResult object, but beyond that, it has been a mystery.

If you use my PoshRSJob module, you may have noticed that after you begin all of the RSJobs, that they all show a state of ‘Running’, which can create some confusion even though some of the jobs are not actually running just yet. Between this issue with my module and the number of questions that I had received, it has been one of my goals with runspaces to find a way to determine the state of each runspace in a runspacepool so others can make use of whatever technique that I could find as well as adding the discovered solution into my module.

The solution that I found begins with using reflection techniques to dig deeper into the PowerShell instance that we created and used with our runspacepool to find the state of a running pipeline and then looks at the IsCompleted property of the PowerShellAsyncResult object to determine whether that particular instance is in fact running or waiting to start in the runspacepool. in order to properly test this and ensure that I am not missing anything, I will have to have at least one runspace that has already been completed, one that is going to always be running and another one that should not be running yet.

To make this happen, I will kick off 6 runspaces within a runspacepool that will only allow a maximum of 2 concurrently running runspaces. The scriptblock for those will contain a While loop that will only break if the value being checked is an odd number. This means that at some point 2 runspaces will be completed,  2 will continue to run and another 2 will be waiting to start, but will never start due to the other jobs continuously running as they contain even numbers.

My runspacepool job code is below and uses the ideas that I described to ensure that I meet my goal of having runspaces in various states.

$RSP = [runspacefactory]::CreateRunspacePool(1,2)
$RSP.Open()

$List = New-Object System.Collections.ArrayList

$Result = 1..6 | ForEach {
    $PS = [powershell]::Create()
    $PS.RunspacePool = $RSP
    [void]$PS.AddScript({
        Param($i)
        While ($True) {
            Start-Sleep -Milliseconds 1000
            If ($i%2) {BREAK}
        }
    }).AddArgument($_)
    $List.Add(([pscustomobject]@{
        Id = $_
        PowerShell = $PS
        Handle = $PS.BeginInvoke()
    }))
}

 

You will notice that I saved the results of the BeginInvoke() command as well as the Id and PowerShell instance. This way we can accurately tell what values we are checking against as the Id matches the value of the If statement.

The contents of the list looks like this:

image

Based on my code in each runspace, we can easily deduce that Ids 1 and 3 should be completed while 2 and 4 should be running which leaves 5 and 6 as the remaining jobs left to run. a quick look at the Handle property of this object should show the IsCompleted property being True for 1 and 3 whereas the others will show as False.

image

This was the easy part. Knowing what has already finished isn’t what I set out to solve as it was already easy to find. I am now going to take a long look at Id 2 to look for a running pipeline which should give me an indication that there is something already running in the runspacepool.

In this example, we will look at Id 2 (which would be $list[1]) and will see if this is truly running like I am thinking it is.

The first thing I need to pull is the System.Management.Automation.PowerShell+Worker object from the PowerShell instance. This is not publicly available to view so we now begin our first dive into using reflection to get this object.

$Flag = 'static','nonpublic','instance'
$_Worker = $list[1].PowerShell.GetType().GetField('worker',$Flag)
$Worker = $_Worker.GetValue($list[1].PowerShell)

Using the proper flags to tell what kind of values we want for the Field, we can locate the nonpublic field and then take that object and pull the value using GetValue() and providing the original object that it belongs to, in this case the original object is the PowerShell instance. We can verify that we have the object and then move onto the next property to locate.

image

We are now halfway down our reflection rabbit hole. Taking this PowerShell+Worker object, we will go down one more level deeper and pull the CurrentlyRunningPipeline property out of this which will tell us if…you guessed it… if the runspace is currently running.

$_CRP = $worker.GetType().GetProperty('CurrentlyRunningPipeline',$Flag)
$CRP = $_CRP.GetValue($Worker)
$CRP

image

Perfect! If there is data in this property, then that means that there is something running in the runspace and that therefore means the runspace in the runspacepool is currently running!

Ok, just a single test doesn’t really tell us that we are on the right path. We should definitely run this against a runspace that we know has already completed, such as Id 1 to check that piece and then run this against an Id that should not be running yet, like Id 5. If both of those do not have anything within the CurrentlyRunningPipeline property, then we can make a reasonable guess that we have a working approach to tracking runspace activity.

First, let’s run this against the completed runspace (Id1: $List[0]) and see what happens.

$Flag = 'static','nonpublic','instance'
$_Worker = $list[0].PowerShell.GetType().GetField('worker',$Flag)
$Worker = $_Worker.GetValue($list[0].PowerShell)

$_CRP = $worker.GetType().GetProperty('CurrentlyRunningPipeline',$Flag)
$CRP = $_CRP.GetValue($Worker)
$CRP

image

No data in the property on the completed runspace. Now onto the runspace that we believe to be waiting to start (Id5: $list[4]).

$_Worker = $list[4].PowerShell.GetType().GetField('worker',$Flag)
$Worker = $_Worker.GetValue($list[4].PowerShell)

$_CRP = $worker.GetType().GetProperty('CurrentlyRunningPipeline',$Flag)
$CRP = $_CRP.GetValue($Worker)
$CRP

image

Another successful test! Based on the results of both the completed and presumed pending runspace, we can see that we have a good way to determine the state of the runspaces. The only thing left to do is make sure that we know the difference between a completed and pending runspace and all we have to do is look at the IsCompleted property that we talked about earlier in the article. When it shows True and has no data in CurrentlyRunningPipeline, then it is a completed runspace but if the IsCompleted is False with no data in the other property, then we know that this hasn’t started yet.

The final script for my demo shows what I did to create the runspaces and then to determine the state of the runspaces and returning a ‘Running’, ‘NotStarted’ and ‘Completed’ state for each runspace.

$RSP = [runspacefactory]::CreateRunspacePool(1,2)
$RSP.Open()

$List = New-Object System.Collections.ArrayList

$Result = 1..6 | ForEach {
    $PS = [powershell]::Create()
    $PS.RunspacePool = $RSP
    [void]$PS.AddScript({
        Param($i)
        While ($True) {
            Start-Sleep -Milliseconds 1000
            If ($i%2) {BREAK}
        }
    }).AddArgument($_)
    $List.Add(([pscustomobject]@{
        Id = $_
        PowerShell = $PS
        Handle = $PS.BeginInvoke()
    }))
}
Start-Sleep -Seconds 2
$Flag = 'static','nonpublic','instance'
0..5 | ForEach {
    $_Worker = $list[0].PowerShell.GetType().GetField('worker',$Flag)
    $Worker = $_Worker.GetValue($list[$_].PowerShell)

    $_CRP = $worker.GetType().GetProperty('CurrentlyRunningPipeline',$Flag)
    $CRP = $_CRP.GetValue($Worker)
    $State = If ($list[$_].handle.IsCompleted -AND -NOT [bool]$CRP) {
        'Completed'
    }
    ElseIf (-NOT $list[$_].handle.IsCompleted -AND [bool]$CRP) {
        'Running'
    }
    ElseIf (-NOT $list[$_].handle.IsCompleted -AND -NOT [bool]$CRP) {
        'NotStarted'
    }
    [pscustomobject]@{
        Id = (([int]$_)+1)
        HandleComplete = $list[$_].handle.IsCompleted
        PipelineRunning = [bool]$CRP
        State = $State
    }
}

Running this code will produce the following output which will show the states for each runspace:

image

Note that I haven’t yet added this to PoshRSJob as I need to ensure that I add the appropriate code within the Type file within the module so the correct results are shown each time you run Get-RSJob. I will be sure to update this blog and post out to Twitter when that has occurred. Note that if you use this approach that you will either have to use this each time you want to view the status of the runspace, or you create a custom object with its own specific type and then supply your own type file (or use Update-TypeData) to automatically perform the checks each time you look at the object.


Filed under: powershell Tagged: Powershell, reflection, runspace, runspacepool
Viewing all 16 articles
Browse latest View live