本篇就来兑现在《PowerShell UI自动化测试框架》中的承诺:自动给QQ群发消息。
知识点
- 假定QQ正在运行,并且已经登录。如若自动给QQ群发送消息,须要三步:第一步,点击QQ群,弹出聊天窗口;第二步,在消息框输入消息;第三步,点击“发送”按钮。
 - 在“UI Automation PowerShell扩展”找出一个窗口,然后再找其中的一个按钮,默认是支持递归遍历的。但是如果窗口中控件错综,要找的目标按钮节点较深,递归起来效率非常低。所以我简单的写了个小函数 Get-UiaControlByChildrenIndex,能根据控件的索引路径来查找,避免走弯路。
 - 第三个是一个坎,之前和Victor讨论过,QQ的发送消息的发送框,不是一个标准的windows文本框,如果是,直接可以用Set-UiaEditText赋值。但是可惜了,它不是。我给出的解决方法是:鼠标右击,弹出上下文菜单,然后将内容粘贴过去。
 - 最后就是发挥PowerShell自定义对象的魅力了:自定义属性,自定义方法。
 
因为我不在腾讯上班,所以没必要把所有东西都写完。只是为朋友们做个演示。
脚本
<#
 # 操作系统  :Windows 8.1(中文简体)
 # PowerShell:4.0
 # QQ版本    :qq5.2 10446
#>
Import-Module E:\Powershell\UIA\UIAutomation.dll
# QQ 上下文
$QQContext = [PSCustomObject]@{
 MainWindow = $null  # 主界面
 Process = $null     # 进程
 TaskBar = $null     #任务栏图标
}
#############################
##通过粘切按钮设置QQ中编辑框文本
#############################
Function Set-QQEditTextByCopy
{
    param
    (
    [Parameter(ValueFromPipeline=$true)]
    [UIAutomation.UiElement]$EditControl,
    [string]$Text
    )
    $Text | clip.exe
    #弹出上下文菜单
    $EditControl.InvokeContextMenu()
    #粘切按钮
    $pasterMenu = (Get-UiaWindow -Class 'TXGuiFoundation' -Name 'TXMenuWindow' | Get-UiaControlChildren)[2]
    $pasterMenu| Invoke-UiaControlClick -DoubleClick | Out-Null
}
######################
##根据索引联获取子窗口
######################
function Get-UiaControlByChildrenIndex
{
    param(
    [Parameter(ValueFromPipeline=$true)]
    #父控件
    $Parent,
    #索引联数组,比如@(1,3,2),逻辑类似 Children[1].Children[3].Children[2]
    [int[]]$IndexChain
    )
    $result=$Parent
    $IndexChain | foreach {
        $result = ($result | Get-UiaControlChildren)[$_]
    }
    return $result
}
######################
##初始化QQ主窗口
######################
function Get-QQ
{
  $QQContext.MainWindow
  #主窗口
  $qqWindow = Get-UiaWindow -Name 'QQ' -Class 'TXGuiFoundation' -ProcessId $QQContext.Process.Id
  $searchControl = Get-UiaControlByChildrenIndex -Parent  $qqWindow -IndexChain @(4,1,1) | Get-UiaControlChildren
  $HubMenus =  Get-UiaControlByChildrenIndex -Parent  $qqWindow -IndexChain @(4,1,3,0,0,0,0) | Get-UiaTab | Get-UiaTabItem
  $QQContext.MainWindow = [PSCustomObject]@{
      #窗口缓存
      Window = $qqWindow
      #关闭按钮
      CloseButton = Get-UiaControlByChildrenIndex -Parent  $qqWindow -IndexChain @(5,0)
      #最小化按钮
      MinimizeButton = Get-UiaControlByChildrenIndex -Parent  $qqWindow -IndexChain @(5,1)
      #群与联系人切换按钮
      HubMenus = [PSCustomObject]@{
        #好友按钮
        Friends = $HubMenus[0]
        #群组按钮
        Group = $HubMenus[1]
        #会话按钮
        Conversation = $HubMenus[2]
        #QQ空间
        QZone=$HubMenus[3]
        #腾讯微博
        Weibo=$HubMenus[4]
      }
      #搜索
      Search = [PSCustomObject]@{
        Box = $searchControl[1] 
        Button = $searchControl[0]
      } 
  }
  #搜索方法
  $QQContext.MainWindow.Search | Add-Member -MemberType ScriptMethod 'Search' {
    param(
    $Text
    )
    #清空当前值
    if($QQContext.MainWindow.Search.Box.Value)
    {
        $QQContext.MainWindow.Search.Button.Click()
    }
    $QQContext.MainWindow.Search.Box |  Set-QQEditTextByCopy -Text $Text
  }
}
######################
##从任务栏弹出QQ主窗口
######################
function Show-QQ
{
    # QQ 进程
    $QQContext.Process = Get-Process -Name 'QQ'
    # 当有多个用户登录到时,其它用户的CPU为空,不为空的为当前用户对应的explorer
    $explorer = Get-Process 'explorer' | where {$_.CPU} | Select-Object -First 1
    #任务栏
    $taskBarWindow = Get-UiaWindow -ProcessId $explorer.Id -Class 'Shell_TrayWnd' 
    $QQContext.TaskBar = $taskBarWindow | Get-UiaToolBar -Name '用户显示的通知区域' | Get-UiaButton  -Name '*qq*' 
    $QQContext.TaskBar.Click()
    # 刷新主窗口
    Get-QQ
}
######################
##新建QQ群会话
######################
function New-QQGroupTalk
{
    param(
    [string]$ContactName
    ) 
    #先点击“微博”,可以避免组合好友列表折叠起来
    $QQContext.MainWindow.HubMenus.Weibo.Click() | Out-Null
    #再点击“QQ群组”选项卡
    $QQContext.MainWindow.HubMenus.Group.Click() | Out-Null
    #打开会话
    $QQContext.MainWindow.Window | 
    Get-UiaControlByChildrenIndex  -IndexChain @(4,1,3,0,0,0,0,1) |
    Get-UiaListItem -Name $ContactName |
    Invoke-UiaControlClick |
    Invoke-UiaControlClick -DoubleClick | Out-Null
    sleep -Milliseconds 100
    #聊天窗口
    $talkWindow = Get-UiaWindow -Class 'TXGuiFoundation' -Name $ContactName
    #消息框
    $editBox = $talkWindow | 
        Get-UiaControlByChildrenIndex -IndexChain @(1,0,0,0,2,3,0) |
        Get-UiaEdit
    #发送消息按钮
    $sendButton = $talkWindow |  Get-UiaButton -Name '发送(&S)'
    #关闭窗口按钮
    $closeButton = $talkWindow | Get-UiaControlByChildrenIndex -IndexChain @(2,2)
    #发送消息窗口   
    $talkObj = [PSCustomObject]@{
        Window = $talkWindow
        EditBox = $editBox
        SendButton = $sendButton
        CloseButton = $closeButton
    }
   #发送消息方法
   $talkObj | Add-Member -MemberType ScriptMethod 'SendMessage' {
    param(
    [string]$Text
    )
    $this.EditBox |  Set-QQEditTextByCopy -Text $Text
    $this.SendButton  | Set-UiaFocus | Invoke-UiaControlClick | Out-Null
  }
  return $talkObj
}
######################
#测试代码
######################
#初始化QQ上下文
Get-QQ
#会话窗口
$talkWindow = New-QQGroupTalk -ContactName 'PowerShell交流群'
#发送消息
$talkWindow.SendMessage("PowerShell中文博客:https://www.pstips.net")
本文链接: https://www.pstips.net/send-message-to-qq-group.html
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
                                      请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!

不错,晚上回家一定学习。我觉得这个挺好的。
所以我简单的写了个小函数 Get-UiaControlByChildrenIndex,能根据控件的索引路径来查找,避免走弯路。不好意思,想问一下,你怎么知道哪个控件的索引路径是多少???
这要用到你个工具UISpy,你可以在网上找下。
已在微博发了私信!
执行到”SendMessage“总是有问题
有问题,极有可以是控件没有找对,或者权限问题。你用UISpy调试一下控件树。
咱有技术群吗,方便加一下吗
3q
学习一下 感谢分享
为啥现在Set-UiaFocus和$element.Focus跟失效了一样……至少对于QQ如此。
对于编辑框,我发现可以用$editBox.Value=”12312312312323″的方式来获取焦点(虽然它并不能改变编辑框的值,但至少允许我ctrl+V了)
但如何获取消息框内的信息呢……尝试以各种方式发送ctrl+C未果,都是焦点的问题。右键->全部选择–>右键–>复制虽然可以,但可靠性实在值得怀疑……
好吧。其实在编辑框tab一下就好了……
那个。。我是用别的语言开发,我可以取得消息记录,群成员等信息。
已有成熟的小软件,用来监控群的消息,对于各种自定义命令做出反应,
但是还有几个问题。。
1。无法取得聊天的图片内容。
2。群成员,是否在线,是否手机在线,等,就是人名前的小图标,头像小图标,这个也无法取到。
这些我试着在UISPY里,根本连位置都无法检测到。。好困惑。。