Caling UnManaged Code from Powershell - Handling Enum Type

23 views Asked by At

I am using Powershell to call the group policy update API from userenv.dll (see here and here). This works fine:

$sig =@'
[DllImport("userenv.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RefreshPolicy([MarshalAs(UnmanagedType.Bool)] bool bMachine);
'@
$mytype = add-type -memberdefinition $sig -Name "Win32RefreshGP" -Namespace Win32Functions -PassThru
$mytype::RefreshPolicy($false) # Refresh the user policy

When I import this type though as follows:

$sigEx =@'
public enum RefreshPolicyOption:uint
{ 
    RP_FORCE = 1,
    RP_SYNC = 2 
}

[DllImport("userenv.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RefreshPolicyEx([MarshalAs(UnmanagedType.Bool)] bool bMachine, RefreshPolicyOption dwOptions = 0);
'@
$mytypeEx = add-type -memberdefinition $sigEx -Name "Win32RefreshGP" -Namespace Win32Functions -PassThru
$mytypeEx::RefreshPolicyEx($false) # Refresh the user policy

The following is raised calling $mytypeEx::RefreshPolicyEx($false)

Method invocation failed because [System.Object[]] does not contain a method named 'RefreshPolicyEx'.
At line:1 char:1
+ $mytypeEx::RefreshPolicyEx($false) # Refresh the user policy
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

This seems to be because of the attempt to use the enum in the type defintion. Any ideas?

I have tried using single/double quotes. I'd epxect the type definition to work as it works in C#.

1

There are 1 answers

2
Santiago Squarzon On BEST ANSWER

The issue is fairly simple, when you use -PassThru, Add-Type will output a type instance for every type defined in your C# inline code, in this case $mytypeEx will have 2 types, thus the error you're getting:

PS /> $mytypeEx

   Namespace: Win32Functions

Access        Modifiers           Name
------        ---------           ----
public        class               Win32RefreshGP : object
public        enum                Win32RefreshGP.RefreshPolicyOption : uint

PS /> $mytypeEx.Count
2

Solution is as simple as indexing the Win32RefreshGP type and then call its static member:

PS /> $mytypeEx[0]::RefreshPolicyEx($false)

Or you can remove -PassThru and then call the static member from the type itself:

PS /> [Win32Functions.Win32RefreshGP]::RefreshPolicyEx($false)