PoshCode Logo PowerShell Code Repository

PowerBot 2.0 by Joel Bennett 30 months ago
diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/1236"></script>download | new post

PowerBot is my IRC bot written in PowerShell script using SmartIrc4Net There’s a bit more to it than this, but this is the basic script, and all you have to do is add your own commands! Of course, you could also add your own additional message handlers and make a chatter-bot or whatever you like. Please share your mods back here!

  1. ## This script requires ...\WindowsPowerShell\Libraries\Meebey.SmartIrc4net.dll
  2. ## You can get Meebey.SmartIrc4net.dll from
  3. ## http://voxel.dl.sourceforge.net/sourceforge/smartirc4net/SmartIrc4net-0.4.0.bin.tar.bz2
  4. ## And the docs are at http://smartirc4net.meebey.net/docs/0.4.0/html/
  5. ############################################################################################
  6. ## Configure with a .psd1 file for the module, with Private data like:
  7. ## FunctionsToExport = 'Start-PowerBot', 'Resume-PowerBot', 'Stop-PowerBot'
  8. ## RequiredAssemblies = 'Meebey.SmartIrc4net.dll', 'Starksoft.Net.Proxy.dll'
  9. ## PrivateData = @{
  10. ##    Nick = @('ABot', 'PowershellBot')
  11. ##    RealName = 'Jaykul''s PowerShell Bot'
  12. ##    Pass = 'bot'
  13. ##    Server = "irc.freenode.net"
  14. ##    Port = 8001
  15. ##    Channels = @('#PowerShell')
  16. ## #  ProxyServer = "www.proxy.com"
  17. ## #  ProxyPort = "8000"
  18. ## }
  19. ############################################################################################
  20. ## Add-Type -path $ProfileDir\Libraries\Meebey.SmartIrc4net.dll
  21. ## $null = [Reflection.Assembly]::LoadFrom("$ProfileDir\Libraries\Meebey.SmartIrc4net.dll")
  22.  
  23. function Start-PowerBot {
  24. [CmdletBinding()]
  25. PARAM(
  26.   [Parameter(Position=0)]
  27.   [string[]]$channels = $ExecutionContext.SessionState.Module.PrivateData.Channels
  28. ,
  29.   [Parameter(Position=1)]
  30.   [string[]]$nick     = $ExecutionContext.SessionState.Module.PrivateData.Nick
  31. ,
  32.   [Parameter(Position=2)]
  33.   [string]$password   = $ExecutionContext.SessionState.Module.PrivateData.Password
  34. ,
  35.   [Parameter(Position=5)]
  36.   [string]$server     = $ExecutionContext.SessionState.Module.PrivateData.Server
  37. ,
  38.   [Parameter(Position=6)]
  39.   [int]$port          = $ExecutionContext.SessionState.Module.PrivateData.Port
  40. ,
  41.   [Parameter(Position=10)]
  42.   [string]$realname   = $ExecutionContext.SessionState.Module.PrivateData.RealName
  43. ,
  44.   [Parameter(Position=5)]
  45.   [string]$ProxyServer= $ExecutionContext.SessionState.Module.PrivateData.ProxyServer
  46. ,
  47.   [Parameter(Position=6)]
  48.   [int]$ProxyPort     = $ExecutionContext.SessionState.Module.PrivateData.ProxyPort
  49. )
  50.  
  51.    Write-Host "Private Data:`n`n$( $ExecutionContext.SessionState.Module.PrivateData | Out-String )" -Fore Cyan
  52.    Write-Host "Proxy Server: $ProxyServer, $ProxyPort" -Fore Yellow
  53.  
  54.    if(!$global:irc) {  
  55.       $global:irc = New-Object Meebey.SmartIrc4net.IrcClient
  56.      
  57.       if($ProxyServer) {
  58.          $global:proxy = New-Object Starksoft.Net.Proxy.HttpProxyClient $ProxyServer, $ProxyPort
  59.          Write-Host "Creating Proxy: ${global:proxy}"
  60.          $global:irc.Proxy = $global:proxy
  61.       }
  62.       # $irc.Encoding = [Text.Encoding]::UTF8
  63.       # $irc will track channels for us
  64.       $irc.ActiveChannelSyncing = $true  
  65.       $irc.Add_OnError( {Write-Error $_.ErrorMessage} )
  66.       $irc.Add_OnQueryMessage( {OnQueryMessage_ProcessCommands} )
  67.       $irc.Add_OnChannelMessage( {OnChannelMessage_ProcessCommands} )
  68.       $irc.Add_OnChannelMessage( {OnChannelMessage_ResolveUrls} )
  69.    }
  70.    
  71.    $irc.Connect($server, $port)
  72.    $irc.SendDelay = 300
  73.    $irc.Login($nick, $realname, 0, $nick[0], $password)
  74.    ## $channels | % { $irc.RfcJoin( $_ ) }
  75.    foreach($channel in $channels) { $irc.RfcJoin( $channel ) }
  76.  
  77.    $global:PBC = Get-BotCommands
  78.  
  79.    Resume-PowerBot # Shortcut so starting this thing up only takes one command
  80. }
  81.  
  82. ## Note that PowerBot stops listening if you press a key ...
  83. ## You'll have to re-run Resume-Powerbot to get him to listen again
  84. function Resume-PowerBot {
  85.    while(!$Host.UI.RawUI.KeyAvailable) { $irc.Listen($false) }
  86. }
  87.  
  88. function Stop-PowerBot {
  89. [CmdletBinding()]
  90. PARAM(
  91.   [Parameter(Position=0)]
  92.   [string]$QuitMessage = "If people listened to themselves more often, they would talk less."
  93. )
  94.    $irc.RfcQuit($QuitMessage)
  95.    sleep 2
  96.    $irc.Disconnect()
  97. }
  98.  
  99.  
  100. function Resolve-Parameters {
  101. Param($command)
  102.    $Tokens = [System.Management.Automation.PSParser]::Tokenize($command,[ref]$null)
  103.    for($t = $Tokens.Count; $t -ge 0; $t--) {
  104.       # DEBUG $token | fl * | out-host
  105.       if($Tokens[$t].Type -eq "CommandParameter") {
  106.          $token = $Tokens[$t]
  107.          for($c = $t; $c -ge 0; $c--) {
  108.             if( $Tokens[$c].Type -eq "Command" ) {
  109.                $cmd = which $Tokens[$c].Content
  110.                # if($cmd.CommandType -eq "Alias") {
  111.                   # $cmd = @(which $cmd.Definition)[0]
  112.                # }
  113.                $short = $token.Content -replace "^-?","^"
  114.                Write-Debug "Parameter $short"
  115.                $parameters = $cmd.ParameterSets | Select -expand Parameters
  116.                $param = @($parameters | Where-Object { $_.Name -match $short -or $_.Aliases -match $short} | Select -Expand Name -Unique)
  117.                if("Verbose","Debug","WarningAction","WarningVariable","ErrorAction","ErrorVariable","OutVariable","OutBuffer","WhatIf","Confirm" -contains $param ) {
  118.                   $command = $command.Remove( $token.Start, $token.Length )
  119.                } elseif($param.Count -eq 1) {
  120.                   $command = $command.Remove( $token.Start, $token.Length ).Insert( $token.Start, "-$($param[0])" )
  121.                }
  122.                break
  123.             }
  124.          }
  125.       }
  126.    }
  127.    return $command
  128. }
  129.  
  130. function Bind-Parameters {
  131. Param([string[]]$params)
  132.    $bound = @{}
  133.    $unbound = @()
  134.  
  135.    while($params) {
  136.       Write-Host "$params"
  137.       [string]$name, [string]$value, $params = @($params)
  138.       if($name.StartsWith("-")) {
  139.          $name = $name.trim("-"," ")
  140.          if($value.StartsWith("-")) {
  141.             $bound[$name.trim("-"," ")] = New-Object System.Management.Automation.SwitchParameter $true
  142.             $params = @($value) + $params
  143.          } else {            
  144.             $bound[$name] = $value      
  145.          }
  146.       } else {
  147.          $unbound += "$name"
  148.          if($value) {
  149.             $params = @($value) + $params
  150.          }
  151.       }
  152.    }
  153.    $bound, $unbound
  154. }
  155.  
  156. ####################################################################################################
  157. ## Event Handlers
  158. ####################################################################################################
  159. ## Event handlers in powershell have TWO automatic variables: $This and $_
  160. ##   In the case of SmartIrc4Net:
  161. ##   $This  - usually the connection, and such ...
  162. ##   $_     - the IrcEventArgs, which just has the Data member:
  163. ##
  164.  
  165. function OnQueryMessage_ProcessCommands {
  166.    $Data = $_.Data
  167.    Write-Verbose $Data.From
  168.    # Write-Verbose $Data.Message
  169.    Write-Debug $( $Data | Out-String )
  170.    # Write-Debug $( $Data | Get-Member | Out-String )
  171.    
  172.    $command, $params = $Data.MessageArray
  173.    Write-Verbose "`nCommand: $command `nParams: $params"
  174.    if($PBC.ContainsKey($command)) {
  175.       $Command, $Params = (Resolve-Parameters $((@($command) + @($Params)) -join " ")) -split " +"
  176.       $bound, $unbound = Bind-Parameters @($params)
  177.       trap { Write-Error "Error in ProcessCommands:`n$($_|out-string)"; Continue }
  178.       Write-Debug "$Data | `&$($PBC[$command]) $bound $unbound"
  179.       $Data | &$PBC[$command] @bound @unbound |
  180.          Out-String -width (510 - $Data.From.Length - $nick.Length - 3) |
  181.             % { $_.Trim().Split("`n") | %{ $irc.SendMessage("Message", $Data.Nick, $_.Trim() ) }}
  182.    }
  183. }
  184.  
  185. function OnChannelMessage_ProcessCommands {
  186.    $Data = $_.Data
  187.    Write-Verbose $Data.From
  188.    # Write-Verbose $Data.Channel
  189.    # Write-Verbose $Data.Message  
  190.    Write-Debug $($Data | Out-String)
  191.    # Write-Debug $($Data | Get-Member | Out-String)
  192.    
  193.    [string]$command, [string[]]$params = $Data.MessageArray
  194.    if($PBC.ContainsKey($command)) {
  195.       $Command, $Params = (Resolve-Parameters $((@($command) + @($Params)) -join " ")) -split " +"
  196.       $bound, $unbound = Bind-Parameters @params
  197.       trap { Write-Error "Error in ProcessCommands:`n$($_|out-string)"; Continue }
  198.       Write-Debug "$Data | `&$($PBC[$command]) $bound $unbound"
  199.       $Data | &$PBC[$command] @bound @unbound |
  200.          Out-String -width (510 - $Data.Channel.Length - $nick.Length - 3) |
  201.             % { $_.Trim().Split("`n") | %{ $irc.SendMessage("Message", $Data.Channel, $_.Trim() ) }}
  202.    }
  203. }
  204.  
  205. function OnChannelMessage_ResolveUrls {
  206.    $c = $_.Data.Channel
  207.    $n = $_.Data.Nick
  208.    $m = $_.Data.Message
  209.    Resolve-URL $m | % { $irc.SendMessage("Message", $c, "<$($n)> $_" ) }
  210.  
  211. }
  212.  
  213.  
  214. Import-Module "$PSScriptRoot\PowerBotCommands.psm1" -Force

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me