Advertisement
Old-Lost

Automate-CoH2.ps1

Jan 21st, 2020
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. param (
  2.     [Parameter(Position = 0)] [string] $ConfigName = "0",
  3.     [switch] $StartCharacter
  4. )
  5.  
  6. enum CharState {
  7.     Active
  8.     Paused
  9.     Stopping
  10. }
  11.  
  12. class Character {
  13.     [string]$Name = ''
  14.     [bool]$Held = $false
  15.     [bool]$Stunned = $false
  16.     [bool]$Immobilized = $false
  17.     [System.Diagnostics.Process]$Process
  18.     [string]$ChatLogFile
  19.     [string]$ChatLogFolder
  20.     [hashtable]$Powers = @{ }
  21.     [hashtable]$Actions = @{ }
  22.     $TailLoopJob = $null
  23.     [datetime]$Date
  24.     $PrevWindow = $null
  25.     [bool]$Debug = $false
  26.     [CharState]$State = [CharState]::Active
  27.     Character([System.Diagnostics.Process]$Process) {
  28.         $this.Process = $Process
  29.         $this.Date = (Get-Date).Date
  30.     }
  31.     [void]StartLogMonitor() {
  32.         $loopBlock = {
  33.             Param($filePath) Get-Content $filePath -Wait -Tail 0
  34.         }
  35.         $this.TailLoopJob = Start-Job -scriptBlock $loopBlock -ArgumentList $this.ChatLogFile
  36.     }
  37.     [string[]]ReceiveJob() {
  38.         if ($this.Process.HasExited) {
  39.             $this.CleanUp()
  40.         } elseif ($this.TailLoopJob) {
  41.             if ($this.DateChanged()) {
  42.                 $this.CleanUp()
  43.                 $this.UpdateChatLog()
  44.                 if (-not $this.ChatLogFile) { return $null }
  45.                 $this.StartLogMonitor()
  46.             }
  47.             return ($this.TailLoopJob | Receive-Job)
  48.         }
  49.         return $null
  50.     }
  51.     [bool]DateChanged() {
  52.         return ((Get-Date).Date -gt $this.Date)
  53.     }
  54.     [void]CleanUp() {
  55.         if ($this.TailLoopJob) {
  56.             Stop-Job $this.TailLoopJob
  57.             Remove-Job $this.TailLoopJob
  58.             $this.TailLoopJob = $null
  59.         }
  60.     }
  61.     [void]UpdateChatLog() {
  62.         # $null = sSend -Keys (, '/tell $name, hi') -Character $this
  63.         $this.LogAction("Date of chat log file changed. Was '$($this.ChatLogFile)'")
  64.         Start-Sleep -Seconds 3
  65.         $Today = (Get-Date).Date
  66.         $this.ChatLogFile = Join-Path -Path $this.ChatLogFolder -ChildPath ('chatlog ' + $Today.ToString('yyyy-MM-dd') + '.txt')
  67.         # $this.ChatLogFile = Get-ChildItem $this.ChatLogFolder -Filter 'chatlog*.txt' | Where-Object CreationTime -gt $Today | Sort-Object CreationTime -Descending | Select-Object -First 1 -ExpandProperty Fullname
  68.         if (-not (Test-Path -Path $this.ChatLogFile)) {
  69.             $this.LogAction("Chat Log File not found in folder '$($this.ChatLogFolder)'")
  70.             return
  71.         }
  72.         $this.LogAction("Chat Log File is now '$($this.ChatLogFile)'")
  73.         $this.Date = $Today
  74.     }
  75.     [bool]IsCohWindowActive() {
  76.         return ((Get-AU3WinHandle -Title '[ACTIVE]') -eq $this.Process.MainWindowHandle)
  77.     }
  78.     [void]ActivateCoHWindow() {
  79.         if ($this.IsCohWindowActive()) { return }
  80.         $this.PrevWindow = Get-AU3WinHandle -Title '[ACTIVE]'
  81.         $this.LogAction("Activating CoH Window. Previous active window was '$(Get-AU3WinTitle -WinHandle $this.PrevWindow)'")
  82.         Show-AU3WinActivate -WinHandle $this.Process.MainWindowHandle
  83.     }
  84.     [void]ReactivatePrevWindow() {
  85.         if ($this.PrevWindow) {
  86.             Show-AU3WinActivate -WinHandle $this.PrevWindow
  87.             Set-AU3WinOnTop -WinHandle $this.PrevWindow -Flag 1
  88.             Set-AU3WinOnTop -WinHandle $this.PrevWindow -Flag 0
  89.         }
  90.         $this.PrevWindow = $null
  91.     }
  92.     [void]LogAction([string]$Action) {
  93.         if ($this.Debug) {
  94.             if ($this.Name) {
  95.                 Write-Host "[" -NoNewline
  96.                 Write-Host $this.Name -NoNewline -ForegroundColor Magenta
  97.                 Write-Host "]: " -NoNewline
  98.             }
  99.             Write-Host $Action
  100.         }
  101.     }
  102. }
  103.  
  104. enum LogLineType {
  105.     Other
  106.     Readying
  107.     Recharged
  108.     Recharging
  109.     Activated
  110.     ShuttingOff
  111.     Chat
  112. }
  113.  
  114. class LogLine {
  115.     [LogLineType]$Type = [LogLineType]::Other
  116.     [string]$Power = ''
  117.     [string]$ChatWindow = ''
  118.     [string]$Name = ''
  119.     [string]$Text = ''
  120.     LogLine([string]$Line, [Character]$Character) {
  121.         $Line = ($Line -replace '<(bg)?color.*?>') | Remove-Date
  122.         if ($Line -eq "[Tell] -->$($Character.Name): pause") {
  123.             if ($Character.State -eq [CharState]::Paused) {
  124.                 $Character.State = [CharState]::Active
  125.             } else {
  126.                 $Character.State = [CharState]::Paused
  127.                 iSend '' $Character
  128.             }
  129.         } elseif ( $Line -eq "[Tell] -->$($Character.Name): stop") {
  130.             $Character.State = [CharState]::Stopping
  131.         } elseif ($Line -eq 'You are unable to use any powers!') {
  132.             $Character.Stunned = $true
  133.         } elseif ($Line -eq 'You can use powers again.') {
  134.             $Character.Stunned = $false
  135.         } elseif ($Line -eq 'You are held!') {
  136.             $Character.Held = $true
  137.         } elseif ($Line -eq 'You are no longer held.') {
  138.             $Character.Held = $false
  139.         } elseif ($Line -eq 'You have been immobilized!') {
  140.             $Character.Immobilized = $true
  141.         } elseif ($Line -eq 'You can move again.') {
  142.             $Character.Immobilized = $false
  143.         } elseif ($Line -match 'You\sactivated\sthe\s(.*?)\spower\.') {
  144.             $this.Type = [LogLineType]::Activated
  145.             $this.Power = $Matches[1]
  146.         } elseif ($Line -match '(.*?)\sis\srecharged\.') {
  147.             $this.Type = [LogLineType]::Recharged
  148.             $this.Power = $Matches[1]
  149.         } elseif ($Line -match '(.*?)\sis\sstill\srecharging\.') {
  150.             $this.Type = [LogLineType]::Recharging
  151.             $this.Power = $Matches[1]
  152.         } elseif ($Line -match '(Readying|Now\sreadying)\s(.*?)(\sinstead\sof.*?)?\.') {
  153.             $this.Type = [LogLineType]::Readying
  154.             $this.Power = $Matches[1]
  155.         } elseif ($Line -match 'Shutting\soff\s(.*?)\.') {
  156.             $this.Type = [LogLineType]::ShuttingOff
  157.             $this.Power = $Matches[1]
  158.         } elseif ($Line -match '\[(.*?)\]\s(.*?):\s(.*)') {
  159.             $this.ChatWindow = $Matches[1]
  160.             $this.Name = $Matches[2]
  161.             $this.Text = $Matches[3]
  162.             $this.Type = [LogLineType]::Chat
  163.         }
  164.     }
  165.     [void]Out() {
  166.         if ($this.Type -eq [LogLineType]::Other) { return }
  167.         if ($this.Type -eq [LogLineType]::Chat) {
  168.             Write-Host '[' -NoNewline
  169.             Write-Host $this.ChatWindow -ForegroundColor Red -NoNewline
  170.             Write-Host '] ' -NoNewline
  171.             Write-Host $this.Name -ForegroundColor Cyan -NoNewline
  172.             Write-Host ": $($this.Text)" -ForegroundColor Green
  173.         } else {
  174.             Write-Host (($this.Type -as [string]) + '/' + $this.Power)
  175.         }
  176.     }
  177. }
  178.  
  179. # If your date format is different from mine this might have to be changed
  180. filter Remove-Date { $_ -replace '^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s' }
  181. function Get-RandomAlphaNumeric { -join ((65..90) + (97..122) | Get-Random -Count 5 | % { [char]$_ }) }
  182.  
  183. class Action {
  184.     [string]$Keys
  185.     [int64]$MinTime
  186.     [string]$Power
  187.     [System.Diagnostics.Stopwatch]$Activated
  188.     [System.Diagnostics.Stopwatch]$PerformAge
  189.     Action ([string]$Keys, [int]$MinTime, [string]$Power) {
  190.         $this.Keys = $Keys
  191.         $this.MinTime = 1000 * $MinTime
  192.         $this.Power = $Power
  193.         if ($this.MinTime -lt 1000) { $this.MinTime = 1000 }
  194.         $this.Activated = [System.Diagnostics.Stopwatch]::new()
  195.         $this.Activated.Start()
  196.         $this.PerformAge = [System.Diagnostics.Stopwatch]::new()
  197.         $this.PerformAge.Start()
  198.     }
  199.     [bool]WillPerform() {
  200.         return (($this.Activated.ElapsedMilliseconds -gt $this.MinTime) -and ($this.PerformAge.ElapsedMilliseconds -gt 2000))
  201.     }
  202.     [void]Perform ([Character]$Character) {
  203.         if ($this.WillPerform()) {
  204.             [string]$Seconds = '{0:N}' -f ($this.Activated.ElapsedMilliseconds / 1000)
  205.             $Character.LogAction("Starting Perform for power $($this.Power). Age is $Seconds. Keys are '$($this.Keys)'")
  206.             $null = iSend -Keys $this.Keys -Character $Character
  207.             $this.PerformAge.Restart()
  208.         }
  209.     }
  210.     [void]Restart() {
  211.         $this.Activated.Restart()
  212.     }
  213. }
  214.  
  215. function iSend {
  216.     param (
  217.         [Parameter(Mandatory, Position = 0)] [AllowEmptyString()] [string] $Keys,
  218.         [Parameter(Mandatory, Position = 1)] [Character] $Character
  219.     )
  220.     if ($Character.IsCohWindowActive()) {
  221.         # $Null = $AutoIt.Send('{LSHIFT DOWN}{LSHIFT UP}{RSHIFT DOWN}{RSHIFT UP}{LALT DOWN}{LALT UP}{RALT DOWN}{RALT UP}{LCTRL DOWN}{LCTRL UP}{RCTRL DOWN}{RCTRL UP}')
  222.         # $Null = $AutoIt.Send('{LSHIFT DOWN}{LSHIFT UP}{RSHIFT DOWN}{RSHIFT UP}{LALT DOWN}{LCTRL DOWN}{LCTRL UP}{RCTRL DOWN}{RCTRL UP}')
  223.         $Null = $AutoIt.Send('{LSHIFT UP}{RSHIFT UP}{LALT UP}{LCTRL UP}{RCTRL UP}')
  224.         $null = switch ($Keys) {
  225.             '' {
  226.                 break
  227.             }
  228.             '+*' {
  229.                 $Character.LogAction("Sending Shift/Left Mouse Button")
  230.                 $Null = $AutoIt.Send('{LSHIFT DOWN}')
  231.                 Invoke-AU3MouseClick -Button Left
  232.                 $Null = $AutoIt.Send('{LSHIFT UP}')
  233.                 Start-Sleep -Seconds 1
  234.                 Invoke-AU3MouseClick -Button Left
  235.                 break
  236.             }
  237.             '!*' {
  238.                 $Character.LogAction("Sending Alt/Left Mouse Button")
  239.                 $Null = $AutoIt.Send('{ALTDOWN}')
  240.                 Invoke-AU3MouseClick -Button Left
  241.                 $Null = $AutoIt.Send('{ALTUP}')
  242.                 break
  243.             }
  244.             '^*' {
  245.                 $Character.LogAction("Sending Control/Left Mouse Button")
  246.                 $Null = $AutoIt.Send('{CTRLDOWN}')
  247.                 Invoke-AU3MouseClick -Button Left
  248.                 $Null = $AutoIt.Send('{CTRLUP}')
  249.                 break
  250.             }
  251.             '*' {
  252.                 $Character.LogAction("Sending Left Mouse Button")
  253.                 Invoke-AU3MouseClick -Button Left
  254.                 break
  255.             }
  256.             Default {
  257.                 # $Character.LogAction("Sending '$Keys'")
  258.                 $a = $Keys -split '#'
  259.                 $Null = $AutoIt.Send($a[0])
  260.                 for ($i = 1; $i -lt $a.count; $i++) {
  261.                     Start-Sleep -Milliseconds 500
  262.                     if ($a[$i].Length -gt 0) {
  263.                         $Null = $AutoIt.Send($a[$i])
  264.                     }
  265.                 }
  266.             }
  267.         }
  268.         # $Null = $AutoIt.Send('{LSHIFT DOWN}{LSHIFT UP}{RSHIFT DOWN}{RSHIFT UP}{LALT DOWN}{LALT UP}{RALT DOWN}{RALT UP}{LCTRL DOWN}{LCTRL UP}{RCTRL DOWN}{RCTRL UP}')
  269.         $Null = $AutoIt.Send('{LSHIFT UP}{RSHIFT UP}{LALT UP}{LCTRL UP}{RCTRL UP}')
  270.         # $Null = $AutoIt.Send('{LSHIFT DOWN}{LSHIFT UP}{RSHIFT DOWN}{RSHIFT UP}{LALT DOWN}{LCTRL DOWN}{LCTRL UP}{RCTRL DOWN}{RCTRL UP}')
  271.         Start-Sleep -Milliseconds 200
  272.         return $true
  273.     }
  274.     return $false
  275. }
  276.  
  277. function sSend {
  278.     param (
  279.         # Parameter help description
  280.         [Parameter(Mandatory, Position = 0)] [string[]] $Keys,
  281.         [Parameter(Mandatory, Position = 1)] [Character] $Character
  282.     )
  283.     if ($Character.IsCohWindowActive()) {
  284.         $Keys | ForEach-Object {
  285.             $null = $AutoIt.Send('{ENTER}')
  286.             $null = $AutoIt.Send($_, 1)
  287.             $null = $AutoIt.Send('{ENTER}')
  288.         }
  289.     }
  290. }
  291.  
  292. function StartCharacter ([Character] $Character) {
  293.     $Character.ActivateCoHWindow()
  294.     sSend -Keys @('/optionload',
  295.         '/bind button4 "++autorun"',
  296.         '/bind c "powexectray 1 5"',
  297.         '/bind p "tell $name, pause"',
  298.         '/bind shift+p "tell $name, stop"',
  299.         '/bind F7 "team Ready!"',
  300.         '/bind TAB "powexectray 1 6"',
  301.         '/suppressCloseFxDist 99',
  302.         '/macroslot 40 GoM "powexecunqueue$$unselect$$autorun 0$$targetenemynear$$follow$$powexectray 1 1"',
  303.         '/macroslot 41 GoR "powexecunqueue$$unselect$$autorun 0$$targetenemynear$$powexectray 1 1"',
  304.         '/macroslot 42 AH "ah"',
  305.         '/macroslot 43 CosP "popmenu CostumeChange"',
  306.         '/macroslot 44 TPs "popmenu TeleTransPortals"',
  307.         '/macroslot 45 SG "enterbasefrompasscode code-1234"',
  308.         '/macroslot 46 Hide "hideall $$ tell $name, Am I hidden?"',
  309.         '/macroslot 47 UnH "tell $name, Am I hidden? $$ unhideall"',
  310.         '/macroslot 48 LFT "broadcast Level $level $archetype LFT$$lfg Level $level $archetype LFT (Blue)"',
  311.         '/macroslot 49 Grtz "team Gratz!"',
  312.         '/macroslot 50 Std "targetenemynext"',
  313.         '/macroslot 51 Spcl "targetenemynext"',
  314.         '/macroslot 60 ITF1 "targetenemynext$$targetcustomnext enemy alive Shadow"',
  315.         '/macroslot 61 ITF2 "targetenemynext$$targetcustomnext enemy alive General"',
  316.         '/macroslot 62 ITF3 "targetenemynext$$targetcustomnext enemy alive Romulus"',
  317.         '/bind ENTER "afk Wordsmithing $$ startchat"') -Character $Character
  318.     $Character.ReactivatePrevWindow()
  319. }
  320.  
  321. function Get-LogsFolder {
  322.     param ( [Parameter(Mandatory, Position = 0)] [string] $CoHFolder )
  323.     return (Get-ChildItem -Path $CoHFolder -Directory | ForEach-Object {
  324.             Get-ChildItem -Path $_.FullName -Directory -Filter logs
  325.         } | Select-Object -ExpandProperty Fullname)
  326. }
  327.  
  328. #region Initialize main variables
  329. $ProcessName = 'CityOfHeroes(?:-beta)?'
  330. $CoHProcess = Get-Process | ? Name -match $ProcessName
  331. if (-not $CoHProcess) {
  332.     Write-Host "CoH is not running. Could not find a process that matches '$ProcessName'"
  333.     return
  334. }
  335. Import-Module "$PSScriptRoot\AutoItX\AutoItX.psd1"
  336. $AutoIt = New-Object -ComObject AutoitX3.Control
  337. Initialize-AU3
  338. $Null = $AutoIt.AutoItSetOption('SendKeyDelay', 27)
  339. $Null = $AutoIt.AutoItSetOption('SendKeyDownDelay', 27)
  340. $Today = (Get-Date).Date
  341. [System.Collections.ArrayList]$CharArray = @()
  342. #endregion
  343.  
  344. #region Find logs folder in CoH path
  345. [string]$CohFolder = $CoHProcess | % { Split-Path $_.Path } | Sort-Object -Unique | Select-Object -First 1
  346. $LogsFolder = Get-LogsFolder $CohFolder
  347. if (-not $LogsFolder) {
  348.     $CohFolder = Split-Path $CohFolder -Parent
  349.     $LogsFolder = Get-LogsFolder $CohFolder
  350. }
  351. if (-not $LogsFolder) {
  352.     Write-Host "No logs folder found in '$CohFolder'"
  353.     return
  354. }
  355. #endregion
  356.  
  357. #region Find chat log file
  358. $ChatLogFile = $LogsFolder | ForEach-Object {
  359.     Get-ChildItem $_ -Filter 'chatlog*.txt' | Where-Object CreationTime -gt $Today | Sort-Object CreationTime -Descending | Select-Object -First 1 -ExpandProperty Fullname
  360. }
  361. if (-not $ChatLogFile) {
  362.     Write-Host "Chat Log File not found in Logs folder(s) '$($LogsFolder -join ''',''')'"
  363.     return
  364. }
  365. Write-Host "Chat log file(s) are '$($ChatLogFile -join ''',''')'"
  366. #endregion
  367.  
  368. if ($StartCharacter) {
  369.     $CoHProcess | ForEach-Object {
  370.         [Character]$Character = [Character]::new($_)
  371.         StartCharacter $Character
  372.     }
  373.     return
  374. }
  375.  
  376. $CoHProcess | ForEach-Object {
  377.     [Character]$Character = [Character]::new($_)
  378.     #region Get name of current char
  379.     [string]$CharName = ''; $Loops = 2; [string]$r = Get-RandomAlphaNumeric
  380.     $Character.ActivateCoHWindow()
  381.     while ($CharName -eq '' -and $Loops -gt 0) {
  382.         $null = sSend -Keys (, ('/tell $name, ' + $r)) -Character $Character
  383.         Start-Sleep -Seconds 3
  384.         $ChatLogFile | ForEach-Object {
  385.             if (-not $CharName) {
  386.                 $CharName = '' + (Get-Content $_ -Tail 100 | Remove-Date | Where-Object {
  387.                         $_ -match "\[Tell\]\s-->(.*?): $r"
  388.                     } | ForEach-Object {
  389.                         $Matches[1]
  390.                     } | Select-Object -First 1)
  391.                 if ($CharName -ne '') {
  392.                     $Character.Name = $CharName
  393.                     $Character.ChatLogFile = $_
  394.                 }
  395.             }
  396.         }
  397.         $Loops--
  398.     }
  399.     $Character.ChatLogFolder = Split-Path $Character.ChatLogFile -Parent
  400.     if ($Character.Name.Length -eq 0) {
  401.         $Character.ReactivatePrevWindow()
  402.         Write-Host "Could not retrieve character name from CoH process"
  403.         return
  404.     }
  405.     $Character.PrevWindow = $null
  406.     Write-Host "Char name is '$CharName'"
  407.     #endregion
  408.  
  409.     #region Load keys and powers from csv file
  410.     $KeysFile = $Character.ChatLogFolder + '\KeysData.csv'
  411.     $Character.LogAction("Keys file is '$KeysFile'")
  412.     if (-not (Test-Path $KeysFile)) {
  413.         $Character.LogAction("'$KeysFile' not found")
  414.         return
  415.     }
  416.     Import-Csv -Path $KeysFile | Where-Object {
  417.         ($_.CharacterName -eq $CharName) -and ($_.Config -match $ConfigName)
  418.     } | ForEach-Object {
  419.         $Character.Powers[$_.Power] = [Action]::new($_.Keys, $_.MinTime, $_.Power)
  420.     }
  421.     if ($Character.Powers.Count -eq 0) {
  422.         $Character.LogAction("No keys to watch")
  423.         return
  424.     }
  425.     $Character.LogAction("Number of keys to watch: $($Character.Powers.Count)")
  426.     $Character.Powers.Values | % { $Character.LogAction("When the $($_.Power) power is recharged, send $($_.Keys)")}
  427.     #endregion
  428.  
  429.     $null = $CharArray.Add($Character)
  430. }
  431.  
  432. #region Start log file monitoring for each character
  433. $CharArray | ForEach-Object {
  434.     $_.LogAction("Starting monitor background job")
  435.     $_.StartLogMonitor()
  436. }
  437. #endregion
  438.  
  439. #region Main action loop
  440. try {
  441.     while ($CharArray.Count -gt 0) {
  442.         for ($i = 0; $i -lt $CharArray.Count; $i++) {
  443.             [Character]$Character = $CharArray[$i]
  444.             if ($Character.Process.HasExited -or $Character.State -eq [CharState]::Stopping) {
  445.                 $Character.LogAction("Stopping")
  446.                 $Character.CleanUp()
  447.                 $CharArray.RemoveAt($i)
  448.                 break
  449.             }
  450.             $Character.ReceiveJob() | Where-Object {
  451.                 ($_ -is [string]) -and ($_.Length -gt 0)
  452.             } | ForEach-Object {
  453.                 [LogLine]::new($_, $Character)
  454.             } | Where-Object {
  455.                 $_.Type -in @([LogLineType]::Activated, [LogLineType]::Recharged, [LogLineType]::Recharging, [LogLineType]::Chat)
  456.             } | ForEach-Object {
  457.                 if ($_.Type -eq [LogLineType]::Chat) {
  458.                     $_.Out()
  459.                 } else {
  460.                     [string]$PowerName = $_.Power
  461.                     if ($_.Type -eq [LogLineType]::Recharged -and ($Character.Powers.Keys -contains $PowerName) -and (-not $Character.Actions.ContainsKey($PowerName) )) {
  462.                         $Character.LogAction("Found a power that should be acted upon: $PowerName")
  463.                         $null = $Character.Actions.Add($PowerName, $Character.Powers[$PowerName])
  464.                     } elseif ($_.Type -in @([LogLineType]::Activated, [LogLineType]::Recharging) -and $Character.Actions.ContainsKey($PowerName)) {
  465.                         $Character.LogAction("Found a power that was activated: $PowerName")
  466.                         $null = $Character.Actions.Remove($PowerName)
  467.                     }
  468.                     if ($_.Type -eq [LogLineType]::Activated -and ($Character.Powers.Keys -contains $PowerName)) {
  469.                         $Character.Powers[$PowerName].Restart()
  470.                     }
  471.                 }
  472.             }
  473.             if ($Character.State -ne [CharState]::Active) { continue }
  474.             $ToPerform = @($Character.Actions.Values | ? { $_.WillPerform() })
  475.             if ($ToPerform.Count -and (-not ($Character.Stunned -or $Character.Held))) {
  476.                 # $Character.LogAction("Found $($ToPerform.Count) actions to perform")
  477.                 $Character.ActivateCoHWindow()
  478.                 $ToPerform | % { $_.Perform($Character) }
  479.                 $Character.ReactivatePrevWindow()
  480.             }
  481.         } # end for
  482.     } # end while
  483. } finally {
  484.     Write-Host "Performing Cleanup"
  485.     $CharArray | % CleanUp
  486. }
  487. #endregion
  488.  
  489. return
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement