Search code examples
powershellautoit

How can I run AutoIT scripts from powershell


I have this script:

#Region
#AutoIt3Wrapper_UseUpx=n
#EndRegion

Global $SUPERBARPOS
$SUPERBARPOS = WinGetPos("[CLASS:Shell_TrayWnd]")

MsgBox(0, "Testing...", _
    "Taskbar's attributes: x:" & $SUPERBARPOS[0] & _
    " y:" & $SUPERBARPOS[1] & _
    " w:" & $SUPERBARPOS[2] & _
    " h:" & $SUPERBARPOS[3] & @CRLF & _
    "Superbar condition: " & _taskbarHidden())

Func _taskbarHidden()
    Local Const $ABM_GETSTATE = 4, $ABS_AUTOHIDE = 1, $ABS_ONTOP = 2
    Local $ARETURN

    $ARETURN = DllCall("shell32.dll", "uint", "SHAppBarMessage", "dword", $ABM_GETSTATE, "ptr*",  0)
    If @error Then Return SetError(1, 0, 0)

    If BITAND($ARETURN[0], $ABS_AUTOHIDE) Then
        Return "Auto hide is enabled"
    Else
        Return "Auto hide is disabled"
    EndIf
EndFunc

Func _getSuperbarPos2()
    Local Const $ABM_GETTASKBARPOS = 5
    Local Const $ABE_LEFT          = 0
    Local Const $ABE_TOP           = 1
    Local Const $ABE_RIGHT         = 2
    Local Const $ABE_BOTTOM        = 3

    Local $ARETURN

    Global $_POSITIONS[4]  = ["Left", "Top", "Right", "Bottom"]
    Global $TAG_APPBARDATA = "LONG;HWND;INT;INT;STRUCT;INT;INT;INT;INT;ENDSTRUCT"

    Local $PDATA = DllStructCreate($TAG_APPBARDATA)

    DllStructSetData($PDATA, 1, DllStructGetSize($PDATA))
    DllStructSetData($PDATA, 2, WinGetHandle("[CLASS:Shell_TrayWnd]", ""))

    Local $ARESULT = DllCall("Shell32.dll", "BOOL", "SHAppBarMessage", "DWORD", $ABM_GETTASKBARPOS, "ptr", DllStructGetPtr($PDATA))
    If @error Then Return SetError(@error, 0, -1)

    If Not $ARESULT[0] Then Return SetError($ARESULT[0], 0, -2)

    Return $_POSITIONS[DllStructGetData($PDATA, 4)]
EndFunc

Is there a way to convert it to Powershell, or if this isn't possible, how can I extract for example "&$SUPERBARPOS[1]&" using, again, powershell? More specific, I want to write a command in the powershell and see the outcome printed in powershell using that AutoIT script.


Solution

  • Calling Autoit script from Powershell one

    This is the easiest option.

    PowerShell allows to execute arbitrary programs by function-call operator & followed by program path and its arguments:

    & "c:\path\to\program.exe" "parameter1" "parameter2" "parameter3"
    

    so in case of AutoIT to run a script you need to write:

    On 64-bit system:

    & "${env:ProgramFiles(x86)}\AutoIt3\AutoIt3.exe" "/AutoIt3ExecuteScript" "c:\your_script.au3"
    

    On 32-bit system:

    & "${env:ProgramFiles}\AutoIt3\AutoIt3.exe" "/AutoIt3ExecuteScript" "c:\your_script.au3"
    

    ${env:ProgramFiles(x86)} is substituted for environment variable that has full path to Program files (x86) folder, most likely c:\Program files (x86)

    AutoIt3.exe is the program that actually executes uncompiled autoit scripts (au3 text files). /AutoIt3ExecuteScript tells it to execute next parameter as a script, but may normally be ommited.

    Passing data from AutoIT to PowerShell through a file

    There are a lot of ways to pass data from one script to another, however most sure-fire beginner-friendly way seems to be by storing data in a temporary text file, though it is somewhat inefficient.

    In AutoIT script replace line starting with MSGBOX with:

    FileDelete("c:\myfile.txt")
    FileWrite("c:\myfile.txt", $SUPERBARPOS[1])
    

    First line deletes file if it already exists - otherwise it would be appended.

    Second line writes contents of $SUPERBARPOS[1] into the file.

    After the script completes, you can just open the file with notepad to check if this file contains what you wanted.

    Reading the file in Powershell is also easy:

    $myvar = [IO.File]::ReadAllText("c:\myfile.txt")
    

    This copies contents of an entire file into a variable named $myvar

    Passing data without creating files

    Of course littering hard drive with temporary files is not the most optimal idea ever.

    A good way to pass data between programs that are executed in sequence are pipes, most notably STDIN and STDOUT.

    To do that:

    1. Compile AutoIT script as a console application (see Autoit2exe command-line documentation and/or #AutoIt3Wrapper_Change2CUI=y editor directive )
    2. Replace the MSGBOX line with something like ConsoleWrite($SUPERBARPOS[1] & @CRLF) or similar. This should dump the variable as text to the console window by default (you won't see it unless you run your script from a commandline or powershell window)
    3. To redirect the text into a variable instead, simply call your script like this:

      $myvar = & c:\your_script.exe
      
    4. If you need to pass multiple variables, you will need to separate them on PowerShell side. To do that you may want to do something like:

      $a = $myvar -split "`r`n"
      

    Converting a script to PowerShell

    Because AutoIT and PowerShell are two entirely different languages, there are no automated conversion tools. To translate the code you need to understand AutoIT code and manually write similar code in PowerShell. To do this you obviously need to know both AutoIT and PowerShell languages well enough.

    As far as I can tell, this script basically calls several WinAPI DLL functions. The autoit side of process is quite well described in DllCall(). PowerShell appears to allow this with Add-Type.

    If you ever run into a hurdle doing the conversion, please ask a more specific question.