SYSTEM用户和登录用户之间的Powershell交互

时间:2019-05-21 13:32:39

标签: powershell automation symantec

我希望以SYSTEM用户身份运行的Powershell脚本在另一个用户会话上显示Windowsform,并与其控件进行交互。

我正在尝试使用Solarwinds N-Able自动化Symantec Endpoint Protection的安装/修复。该平台使用安装在客户端上的代理软件来监视和执行客户端上的任务。

代理使用NT AUTHORITY \ SYSTEM用户在计算机上执行任务。到目前为止,SEP的安装工作正常,但是在卸载/安装阶段之间的重新引导仍然无法作为计算机上的常规用户来控制。我希望当前活动的用户能够控制此重新启动周期。 Windows更新重启提示之类的东西。

我的想法是在登录的用户桌面上显示一个Windowsform,并在其上执行或延迟重新启动的控件。现在我的问题是如何在另一个用户的会话上显示在powershell中定义的Windows窗体,以及如何在SYSTEM用户上运行的脚本中获取控件的操作。

我已经尝试过msg命令向系统上的所有用户发送消息。但这只是单向通信,并不是真的要在这种情况下使用。

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法。我使用了boxdog在注释中建议的WTSSendMessage函数。我将其与脚本结合使用,该脚本获取已登录用户的sessionID。我最小化了此脚本,以仅获取“活动”用户的sessionID。然后用于发送消息给用户。我已经在Solarwinds中对其进行了测试,到目前为止,它仍然完美无缺。

我的编码技能非常基础,但这是最终结果。

function Send-MessageBox
{
[CmdletBinding()]
[OutputType([string])]
Param
(        
    [Parameter(Mandatory=$true, Position=0)]
    [string]$title,
    [Parameter(Mandatory=$true, Position=1)]
    [string]$message,
    [Parameter(Mandatory=$true, Position=2)]
    [int]$duration,
    [Parameter(Mandatory=$true, Position=3)]
    [int]$style
)

Begin
{
    $typeDefinition = @"
        using System;
        using System.Runtime.InteropServices;

        public class WTSMessage {
            [DllImport("wtsapi32.dll", SetLastError = true)]
            public static extern bool WTSSendMessage(
                IntPtr hServer,
                [MarshalAs(UnmanagedType.I4)] int SessionId,
                String pTitle,
                [MarshalAs(UnmanagedType.U4)] int TitleLength,
                String pMessage,
                [MarshalAs(UnmanagedType.U4)] int MessageLength,
                [MarshalAs(UnmanagedType.U4)] int Style,
                [MarshalAs(UnmanagedType.U4)] int Timeout,
                [MarshalAs(UnmanagedType.U4)] out int pResponse,
                bool bWait
            );

            static int response = 0;

            public static int SendMessage(int SessionID, String Title, String Message, int Timeout, int MessageBoxType) {
                WTSSendMessage(IntPtr.Zero, SessionID, Title, Title.Length, Message, Message.Length, MessageBoxType, Timeout, out response, true);

                return response;
            }
        }
"@
}

Process
{
    if (-not ([System.Management.Automation.PSTypeName]'WTSMessage').Type)
    {
        Add-Type -TypeDefinition $typeDefinition
    }

    $RawOuput = (quser) -replace '\s{2,}', ',' | ConvertFrom-Csv
    $sessionID = $null

    Foreach ($session in $RawOuput) {  
        if(($session.sessionname -notlike "console") -AND ($session.sessionname -notlike "rdp-tcp*")) {
            if($session.ID -eq "Active"){    
                $sessionID = $session.SESSIONNAME
            }                        
        }else{
            if($session.STATE -eq "Active"){      
                $sessionID = $session.ID
            }        
        }   
    }
    $response = [WTSMessage]::SendMessage($sessionID, $title, $message, $duration, $style )
}
End
{
    Return $response
}
}

Send-MessageBox -title "Title" -message "Message" -duration 60 -style 0x00001034L