4

我正在 Powershell 中尝试添加类型。我正在使用 netapi32.dll 处理 NetSessionEnum 函数。这几乎可以工作,但不完全。当用零级查询时,我可以得到一个结果。当使用任何其他选项查询时,IDE 或 powershell 会话在尝试编组 PtrToStructure 时只会崩溃。我完全被困住了?

我认为这与结构大小有关,但不确定。如果有人能指出我正确的方向或提供一些很棒的提示。

NetSessionEnum 函数

function Get-NetSessions {

param(
[string]$ComputerName = "",
[string]$ComputerSession = "",
[string]$UserName = "",
[int]$QueryLevel

)

$DebugPreference = 'continue'

$signature = @'
[DllImport("netapi32.dll", SetLastError=true)]
public static extern int NetSessionEnum(
        [In,MarshalAs(UnmanagedType.LPWStr)] string ServerName,
        [In,MarshalAs(UnmanagedType.LPWStr)] string UncClientName,
        [In,MarshalAs(UnmanagedType.LPWStr)] string UserName,
        Int32 Level,
        out IntPtr bufptr,
        int prefmaxlen,
        ref Int32 entriesread,
        ref Int32 totalentries,
        ref Int32 resume_handle);
'@




$SessionInfoStructures = @'
namespace pinvoke {
using System;
using System.Runtime.InteropServices;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct SESSION_INFO_0
    {
    [MarshalAs(UnmanagedType.LPWStr)]
    public String sesi0_cname;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct SESSION_INFO_1
    {
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi1_cname;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi1_username;
    public uint sesi1_num_opens;
    public uint sesi1_time;
    public uint sesi1_idle_time;
    public uint sesi1_user_flag;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct SESSION_INFO_2
    {
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi2_cname;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi2_username;
    public uint  sesi2_num_opens;
    public uint  sesi2_time;
    public uint  sesi2_idle_time;
    public uint  sesi2_user_flags;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi2_cltype_name;
    }


    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct SESSION_INFO_10
    {
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi10_cname;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi10_username;
    public uint sesi10_time;
    public uint sesi10_idle_time;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct SESSION_INFO_502
    {
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi502_cname;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi502_username;
    public uint sesi502_num_opens;
    public uint sesi502_time;
    public uint sesi502_idle_time;
    public uint sesi502_user_flags;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi502_cltype_name;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string sesi502_transport;
    }

    public enum NERR
    {
    /// <summary>
    /// Operation was a success.
    /// </summary>
    NERR_Success = 0,
    /// <summary>
    /// More data available to read. dderror getting all data.
    /// </summary>
    ERROR_MORE_DATA = 234,
    /// <summary>
    /// Network browsers not available.
    /// </summary>
    ERROR_NO_BROWSER_SERVERS_FOUND = 6118,
    /// <summary>
    /// LEVEL specified is not valid for this call.
    /// </summary>
    ERROR_INVALID_LEVEL = 124,
    /// <summary>
    /// Security context does not have permission to make this call.
    /// </summary>
    ERROR_ACCESS_DENIED = 5,
    /// <summary>
    /// Parameter was incorrect.
    /// </summary>
    ERROR_INVALID_PARAMETER = 87,
    /// <summary>
    /// Out of memory.
    /// </summary>
    ERROR_NOT_ENOUGH_MEMORY = 8,
    /// <summary>
    /// Unable to contact resource. Connection timed out.
    /// </summary>
    ERROR_NETWORK_BUSY = 54,
    /// <summary>
    /// Network Path not found.
    /// </summary>
    ERROR_BAD_NETPATH = 53,
    /// <summary>
    /// No available network connection to make call.
    /// </summary>
    ERROR_NO_NETWORK = 1222,
    /// <summary>
    /// Pointer is not valid.
    /// </summary>
    ERROR_INVALID_HANDLE_STATE = 1609,
    /// <summary>
    /// Extended Error.
    /// </summary>
    ERROR_EXTENDED_ERROR= 1208,
    /// <summary>
    /// Base.
    /// </summary>
    NERR_BASE = 2100,
    /// <summary>
    /// Unknown Directory.
    /// </summary>
    NERR_UnknownDevDir = (NERR_BASE + 16),
    /// <summary>
    /// Duplicate Share already exists on server.
    /// </summary>
    NERR_DuplicateShare = (NERR_BASE + 18),
    /// <summary>
    /// Memory allocation was to small.
    /// </summary>
    NERR_BufTooSmall = (NERR_BASE + 23)
    }

    public enum SESSION_LEVEL
    {
    /// <summary>
    /// ZERO
    /// </summary>
    LEVEL_0 = 0,
    /// <summary>
    /// ONE
    /// </summary>
    LEVEL_1 = 1,
    /// <summary>
    /// TWO
    /// </summary>
    LEVEL_2 = 2,
    /// <summary>
    /// TEN
    /// </summary>
    LEVEL_10 = 10,
    /// <summary>
    /// FIVE HUNDRED AND TWO
    /// </summary>
    LEVEL_502 = 502
    }
}
'@



# Add the custom structures and enums
Add-Type $SessionInfoStructures


# Add the function definition
Add-Type -MemberDefinition $signature -Name Win32Util -Namespace Pinvoke -Using Pinvoke


if ([Pinvoke.SESSION_LEVEL]::LEVEL_0 -eq $QueryLevel) {$x = New-Object pinvoke.SESSION_INFO_0}
if ([Pinvoke.SESSION_LEVEL]::LEVEL_1 -eq $QueryLevel) {$x = New-Object pinvoke.SESSION_INFO_1}
if ([Pinvoke.SESSION_LEVEL]::LEVEL_2 -eq $QueryLevel) {$x = New-Object pinvoke.SESSION_INFO_2}
if ([Pinvoke.SESSION_LEVEL]::LEVEL_10 -eq $QueryLevel) {$x = New-Object pinvoke.SESSION_INFO_10}
if ([Pinvoke.SESSION_LEVEL]::LEVEL_502 -eq $QueryLevel) {$x = New-Object pinvoke.SESSION_INFO_502}

# Declare the reference variables
$type = $x.gettype()
Write-Debug "$type.tostring()"

$ptrInfo = 0 
$EntriesRed = 0
$TotalRead = 0
$ResumeHandle = 0

# Call the function
$Result = [pinvoke.Win32Util]::NetSessionEnum($ComputerName,$ComputerSession,$UserName,0,[ref]$ptrInfo,-1,[ref]$EntriesRed,[ref]$TotalRead,[ref]$ResumeHandle)

$Result


if ($Result -eq ([pinvoke.NERR]::NERR_Success)){

    Write-Debug 'Result is success'
    Write-Debug "IntPtr $ptrInfo"
    Write-Debug "Entries read $EntriesRed"
    Write-Debug "Total Read $TotalRead"


    # Locate the offset of the initial intPtr
    $offset = $ptrInfo.ToInt64()
    Write-Debug "Starting Offset $offset"

    # Work out how mutch to increment the pointer by finding out the size of the structure
    $Increment = [System.Runtime.Interopservices.Marshal]::SizeOf($x)
    Write-Debug "Increment $Increment"


    for ($i = 0; ($i -lt $EntriesRed); $i++){

        $newintptr = New-Object system.Intptr -ArgumentList $offset
        Write-Debug "Newintptr `[$i`] $newintptr"
        $Info = [system.runtime.interopservices.marshal]::PtrToStructure($newintptr,$type)
        $Info | Select-Object *
        $offset = $newintptr.ToInt64()
        $offset += $increment
    }

}
else 
{
    #       switch ($Result)
    #           {
    #           ([Pinvoke.NERR]::ERROR_ACCESS_DENIED)       {Write-Host "The user does not have access to the requested information."}
    #           ([Pinvoke.NERR]::ERROR_INVALID_LEVEL)       {Write-Host "The value specified for the level parameter is not valid."}
    #           ([Pinvoke.NERR]::ERROR_INVALID_PARAMETER)   {Write-Host 'The specified parameter is not valid.'}
    #           ([Pinvoke.NERR]::ERROR_MORE_DATA)           {Write-Host 'More entries are available. Specify a large enough buffer to receive all entries.'}
    #           ([Pinvoke.NERR]::ERROR_NOT_ENOUGH_MEMORY)   {Write-Host 'Insufficient memory is available.'}
    #           ([Pinvoke.NERR]::NERR_ClientNameNotFound)   {Write-Host 'A session does not exist with the computer name.'}
    #           ([Pinvoke.NERR]::NERR_InvalidComputer)      {Write-Host 'The computer name is not valid.'}
    #           ([Pinvoke.NERR]::NERR_ClientNameNotFound)   {Write-Host 'The user name could not be found.'}                
    #           }
}
}


Get-NetSessions -QueryLevel 0
4

2 回答 2

2

我早就放弃了上面的事情,转而去做其他事情,直到有什么事情再次引起了我的兴趣。

https://support.microsoft.com/en-us/help/2909958/exceptions-in-windows-powershell-other-dynamic-languages-and-dynamical

当添加这个非常小的修改时,上面的代码工作(没有抛出错误):

$Info = [system.runtime.interopservices.marshal]::PtrToStructure($newintptr,$type)

$Info = [system.runtime.interopservices.marshal]::PtrToStructure($newintptr,[System.Type]$type)

如果您对使用 Windows API 感兴趣,人有一些有趣的工作和一些其他优秀资源的链接。

感谢 NullBind 的回复,非常感谢。

于 2014-12-06T20:34:28.823 回答
0

我玩了一下这个,似乎你忘记做的唯一重要的事情就是$QueryLevel在你调用它时将变量传递给函数的“级别”参数。0当前调用函数时它静态设置的级别参数。结果,当您将 设置为结构$Querylevel以外0的任何内容时,级别返回的数据0不匹配并且脚本崩溃......或类似的东西。

这就是你所拥有的:

# Call the function<br>
$Result = [pinvoke.Win32Util]::NetSessionEnum($ComputerName,$ComputerSession,$UserName,0,[ref]$ptrInfo,-1,[ref]$EntriesRed,[ref]$TotalRead,[ref]$ResumeHandle)

这似乎有效:

# Call the function
$Result = [pinvoke.Win32Util]::NetSessionEnum($ComputerName,$ComputerSession,$UserName, $QueryLevel,[ref]$ptrInfo,-1,[ref]$EntriesRed,[ref]$TotalRead,[ref]$ResumeHandle)

我对高级 PowerShellery 有点陌生。因此,如果我不在我的摇杆上,请告诉我,但希望这会有所帮助。

于 2013-12-27T16:52:14.443 回答