在Powershell脚本中使用C#代码并将结果保存在变量中

3
我正在使用 Powershell 中的 C# 代码:
$Code = @'
....................
public class RDPInfo
....................
'@
Add-Type $Code
$ListUsers = [RDPInfo]::ListUsers("ServerName")
$ListUsers -eq $null

脚本可以正常运行并返回结果——服务器上的用户列表(应该是数组,我认为),但无法保存到变量$ListUsers中——它为空。你能建议一下如何处理吗? 谢谢。
附完整代码:
# QuerySessionInformation.ps1
# Written by Ryan Ries, Jan. 2013, with help from MSDN and Stackoverflow.

$Code = @'
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
public class RDPInfo
{
    [DllImport("wtsapi32.dll")]
    static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);

    [DllImport("wtsapi32.dll")]
    static extern void WTSCloseServer(IntPtr hServer);

    [DllImport("wtsapi32.dll")]
    static extern Int32 WTSEnumerateSessions(
        IntPtr hServer,
        [MarshalAs(UnmanagedType.U4)] Int32 Reserved,
        [MarshalAs(UnmanagedType.U4)] Int32 Version,
        ref IntPtr ppSessionInfo,
        [MarshalAs(UnmanagedType.U4)] ref Int32 pCount);

    [DllImport("wtsapi32.dll")]
    static extern void WTSFreeMemory(IntPtr pMemory);

    [DllImport("Wtsapi32.dll")]
    static extern bool WTSQuerySessionInformation(System.IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned);

    [StructLayout(LayoutKind.Sequential)]
    private struct WTS_SESSION_INFO
    {
        public Int32 SessionID;
        [MarshalAs(UnmanagedType.LPStr)]
        public String pWinStationName;
        public WTS_CONNECTSTATE_CLASS State;
    }

    public enum WTS_INFO_CLASS
    {
        WTSInitialProgram,
        WTSApplicationName,
        WTSWorkingDirectory,
        WTSOEMId,
        WTSSessionId,
        WTSUserName,
        WTSWinStationName,
        WTSDomainName,
        WTSConnectState,
        WTSClientBuildNumber,
        WTSClientName,
        WTSClientDirectory,
        WTSClientProductId,
        WTSClientHardwareId,
        WTSClientAddress,
        WTSClientDisplay,
        WTSClientProtocolType
    }

    public enum WTS_CONNECTSTATE_CLASS
    {
        WTSActive,
        WTSConnected,
        WTSConnectQuery,
        WTSShadow,
        WTSDisconnected,
        WTSIdle,
        WTSListen,
        WTSReset,
        WTSDown,
        WTSInit
    }

    public static IntPtr OpenServer(String Name)
    {
        IntPtr server = WTSOpenServer(Name);
        return server;
    }

    public static void CloseServer(IntPtr ServerHandle)
    {
        WTSCloseServer(ServerHandle);
    }

    public static void ListUsers(String ServerName)
    {
        IntPtr serverHandle = IntPtr.Zero;
        List<String> resultList = new List<string>();
        serverHandle = OpenServer(ServerName);

        try
        {
            IntPtr SessionInfoPtr = IntPtr.Zero;
            IntPtr userPtr = IntPtr.Zero;
            IntPtr domainPtr = IntPtr.Zero;
            IntPtr clientNamePtr = IntPtr.Zero;
            Int32 sessionCount = 0;
            Int32 retVal = WTSEnumerateSessions(serverHandle, 0, 1, ref SessionInfoPtr, ref sessionCount);
            Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
            Int32 currentSession = (int)SessionInfoPtr;
            uint bytes = 0;
            if (retVal != 0)
            {
                for (int i = 0; i < sessionCount; i++)
                {
                    WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)currentSession, typeof(WTS_SESSION_INFO));
                    currentSession += dataSize;

                    WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSUserName, out userPtr, out bytes);
                    WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSDomainName, out domainPtr, out bytes);
                    WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSClientName, out clientNamePtr, out bytes);

                   if(Marshal.PtrToStringAnsi(domainPtr).Length > 0 && Marshal.PtrToStringAnsi(userPtr).Length > 0)
                    {
                        if(Marshal.PtrToStringAnsi(clientNamePtr).Length < 1)                       
                            /* Console.WriteLine(Marshal.PtrToStringAnsi(domainPtr) + "\\" + Marshal.PtrToStringAnsi(userPtr) + "\tSessionID: " + si.SessionID + "\tClientName: n/a");   */
                            Console.WriteLine(Marshal.PtrToStringAnsi(userPtr));
                        else
                            /* Console.WriteLine(Marshal.PtrToStringAnsi(domainPtr) + "\\" + Marshal.PtrToStringAnsi(userPtr) + "\tSessionID: " + si.SessionID + "\tClientName: " + Marshal.PtrToStringAnsi(clientNamePtr));   */
                            Console.WriteLine(Marshal.PtrToStringAnsi(userPtr));
                    }
                    WTSFreeMemory(clientNamePtr);
                    WTSFreeMemory(userPtr);
                    WTSFreeMemory(domainPtr);
                }
                WTSFreeMemory(SessionInfoPtr);
            }
        }
        catch(Exception ex)
        {
            Console.WriteLine("Exception: " + ex.Message);
        }
        finally
        {
            CloseServer(serverHandle);
        }
    }
}
'@

Add-Type $Code
$ListUsers = [RDPInfo]::ListUsers("SERVERNAME")
$ListUsers -eq $null #TRUE

输出结果:

Username1
Username2
.........
UsernameN
ListUsers :

但是 $ListUsers 变量为空!

1
没有看到 C# 代码,很难帮助你。实际上,在代码中似乎有类似 $a = write-host "something" 的内容... $a 保持为空。 - CB.
RDPInfo可能使用Console.WriteLine()或类似的功能来输出结果。 - Mathias R. Jessen
我已经在上面添加了完整的代码。谢谢。 - fapw
是的,Mathias R. Jessen,C# 代码中有 Console.WriteLine() - fapw
1个回答

3

将您的函数 public static void ListUsers(String ServerName) 修改为

public static List<string> ListUsers(String ServerName)

在for循环中将用户名添加到您的列表中:
resultList.Add(Marshal.PtrToStringAnsi(userPtr));

在函数结束时返回列表:
return resultList;

这应该可以解决问题...

太棒了,Norman。非常感谢你。它起作用了!!!现在我明白了,代码没有返回任何值,只是Console.Writeline()它。 - fapw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接