PowerShell – Module for AutoIT

August 24, 2014

In the last Beta releases AutoIT is shipped with a .NET Assembly as well as a Powershell Module

You can find it here :

image

First import the module and run this example.

CLS

# Import the module manfiest
Import-Module (${Env:ProgramFiles(x86)} + "\AutoIt3\Beta\AutoItX\AutoItX3.psd1")

Invoke-AU3Run("Notepad")

Wait-AU3WinActive("Untitled")

Send-AU3Key("I'm in notepad");

$winHandle = Get-AU3WinHandle("Untitled");

Sleep -Seconds 2

Close-AU3Win($winHandle)

# Get the list of AutoItX cmdlets
Get-Command *AU3*

# Get detailed help for a particular cmdlet
Get-Help Get-AU3WinHandle

Getting help on the cmdlets and commands using the Get-Command and Get-Help will list you all needed information to get started.

image

image

Even if the functionality is limited at the moment, it is a good sign AU3 is moving towards PS. Smile

Advertisements

PowerShell – Export HTML content to CSV or Excel

August 22, 2014

Let’s say you are interested in downloading some HTML content from a website based on some filters.

PowerShell it the tool to use. It just takes a few lines Smile

let’s take this blog as an example.

I would like to get hold of all Title Posts of the category ‘PowerShell’

The URL for this is this https://audministrator.wordpress.com/category/Sharepoint/

If you run it in a browser you get all the post content listed. But we need only the Title ?

Therefor we need to use the DOM (Document Object Model). In order to find what we need.

Here we go :

Open up the IE browser and press F12. This will open up the DOM explorer.

In the right corner fill in a search key word of a post Title

image

Next inspect the section needed.

Next we are going to need a DOM method to access the data, in this case.

getElementsByTagName = “h2”

Next I wanted to get the text of the Title.

So we can use the method

innerText

here is the coded plus some in between debugging information for you to get more information out of this example.

CLS

$URI ="https://audministrator.wordpress.com/category/powershell/"
$HTML= Invoke-WebRequest -uri $URI

# echo $HTML

# $HTML | Get-Member

# $HTML.ParsedHtml | Get-Member

<#
Check out these Members

getElementById
getElementsByName
getElementsByTagName
#>

$Ret = $HTML.ParsedHtml.getElementsByTagName("h2" #| Where { $_.className  }
echo $Ret.innerText

$Ret = $HTML.ParsedHtml.getElementsByTagName("h2" | Where { [int]$_.className.trim.length -eq 0  } | % { ([String]$_.sourceindex + " " + $_.innerText) }
$Ret | Select-Object @{Name='Name';Expression={$_}} | Export-Csv ($Env:USERPROFILE+"\Desktop\Test.csv") -NoTypeInformation

Invoke-item ($Env:USERPROFILE+"\Desktop\Test.csv")

echo $Ret
echo

Next I got a bit too much information. As you can see the last items are not post but are the headers of the right widgets.

image

So we have to filter them out. See code

className.trim.length -eq 0

image

Finally we got what we wanted. And we can now export it to a CSV file if we want.

image


PowerShell – The ‘Microsoft.Jet.OLEDB.4.0’ provider is not registered on the local machine

August 22, 2014

If you get this error

Exception calling “Open” with “0” argument(s): “The ‘Microsoft.Jet.OLEDB.4.0’ provider is not registered on the local machine.”

image

Background
Microsoft OLEDB Drivers work on 32 or 64 bit architecture, running Windows XP, Vista, 7 or Windows 8.

Some of the drivers are only 32 Bit compatible ! like this above one.

Additionally on some Windows 64 bit systems, it is possible that some of the Microsoft OLEDB DLLs have not been registered.

Solution No. 1

Check that you are running the 32 bit PowerShell Console or ISE. In the past with Powershell v1.0 you could start it form here :

image

 

 

 

 

 

 

 

But later on after upgrading to v3.0 it disappeared.There are still 2 hints where you can see if you are running x64 or x86.After starting the ISE

image

you will see it here in the Title Bar it says … x86image

The command window you see the location SysWOW64

You can start it from here :

image

The Solution No. 2.
The solution is to manually register those DLLs.
go to Start->Run and type cmd
this starts the Command Prompt

Go to a special folder
cd c:\windows\sysWOW64

Now you need to register the OLE DB 4.0 DLLs by typing these commands and pressing return after each. Might be only the first 2 will register, no problem.

regsvr32 Msjetoledb40.dll
regsvr32 Msjet40.dll
regsvr32 Mswstr10.dll
regsvr32 Msjter40.dll
regsvr32 Msjint40.dll

http://support.microsoft.com/kb/278604

image

If errors appear.

Install AccessDatabaseEngine.exe from the MS site and try again.

http://www.microsoft.com/en-us/download/details.aspx?id=13255

x86 for MS Office x32 bit and

x64 for MS Office x64 bit

image

Hope this will help solving some frustrations.


AutoIT – Meeting PowerShell

August 21, 2014

Both scripting languages have their advandtages.

AutoIT is good at Windows API’s, GUI automation, and more …

Powershell is good at using .Net Classes and more …

So making this a couple would be just great Smile

Well here we go.

This code here will take AU3 output and PS will re-use them by means of objects.

CLS

function Au3_cmd ($sEnv = "env:programfiles(x86)" $sArch = "\AutoIt3\AutoIt3_x64.exe "$sType = " /AutoIt3ExecuteLine ", $sCmd = "" )
{

$sPath = get-content $sEnv

$sPath =  $sPath + $sArch

$oObj = New-Object -ComObject Scripting.FileSystemObject

$sf = $oObj.GetFile($sPath) # GetFile gets the dir ShortPath

    Return $sPath, $sf.ShortPath, $sType, $sCmd
}

$sCmd1 = Au3_cmd -sCmd "InputBox('Question', 'Where were you born?', 'Planet Earth 1', '', -1, -1, 0, 0)" 
$sCmd1 = Au3_cmd -sCmd "InputBox('Question', 'Where were you born?', 'Planet Earth 1', '', -1, -1, 0, 0)"
$sCmd2 = Au3_cmd -sCmd "MsgBox(0,'Au3 => PS Test','Hello World 2')"
$sCmd3 = Au3_cmd -sCmd "ConsoleWrite(@CRLF & 'Hello World 3' & @CRLF)"
$sCmd4 = Au3_cmd -sCmd "ConsoleWrite(@CRLF & 'Hello World 4' & ' - ' & @IPAddress1 & @CRLF)"

invoke-expression  ($sCmd1[1] + $sCmd1[2] + [CHAR]34 + $sCmd1[3] + [CHAR]34) | % { "processing Au3 Output 4 : $_ " } 
invoke-expression  ($sCmd2[1] + $sCmd2[2] + [CHAR]34 + $sCmd2[3] + [CHAR]34) 

# 2 ways to capture the invoke-expression Pipe output 
# 1. Write-Host 2. using the tee-object where objects can be re-used via the pipe.

$Ret3 =  ($sCmd3[1] + $sCmd3[2] + [CHAR]34 + $sCmd3[3] + [CHAR]34) 
invoke-expression  "$Ret3  | Write-Host"

$Ret4 =  ($sCmd4[1] + $sCmd4[2] + [CHAR]34 + $sCmd4[3] + [CHAR]34) 
invoke-expression "$Ret4 | tee-object -variable return" | % { "processing Au3 Output 4 : $_ " }

echo "Number of Objects $($Return.Count) :)" 

# -----------------------------------------------

$sCmd5 = Au3_cmd -sType " /AutoIt3ExecuteScript " -sCmd "C:\_\Apps\_PowerShell\_Au3 & VBScript in PS\test.au3"
$Ret5 = ($sCmd5[1] + $sCmd5[2] + [CHAR]34 + $sCmd5[3] + $sCmd5[4] + [CHAR]34)

Echo ' --- ' # All object as output
invoke-expression  "$Ret5 | Write-Host" 

Echo ' --- ' # All objects moved to a variable and passed on to PS.
invoke-expression "$Ret5 | tee-object -variable script" | % { "processing Au3 Output 5 : $_ " } | Where-object {$_ -notlike '*Idle*'}


rv sCmd1
rv sCmd2
rv sCmd3
rv sCmd4
rv sCmd5

rv ret3
rv ret4
rv ret5

rv script

And call some Windows GUI’s like Msg boxes or Input boxes as well. AutoIT can use command line and script file input.

image

This output comes from AU3 calling some Windows API’s

image

And passes it to PS as Object where we can apply filters to it etc.

image

This is the AU3 script file code.

ConsoleWrite(test() & @CRLF)

Func test()
	$sRet = StringLeft("I am a string", 3)
 Return $sRet
EndFunc

; ------------------------------------------

ConsoleWrite("Idle since " &_IdleTicks() & " MSecs"& @CRLF)

Func _IdleTicks()
    Local $aTSB, $ticksSinceBoot, $struct, $ticksSinceIdle

    $aTSB = DllCall ("kernel32.dll", "long", "GetTickCount")
    $ticksSinceBoot = $aTSB[0]

    $struct = DllStructCreate("uint;dword");
    DllStructSetData($struct, 1, DllStructGetSize($struct));
    DllCall("user32.dll", "int", "GetLastInputInfo", "ptr", DllStructGetPtr($struct))
    $ticksSinceIdle = DllStructGetData($struct, 2)

    return $ticksSinceBoot - $ticksSinceIdle
endfunc

; ------------------------------------------

Dim $idays
Dim $ihours
Dim $imins
Dim $isecs

_uptime($idays,$ihours,$imins,$isecs)

MsgBox(0,"Uptime","Days: " & $idays & " - Hours: " & $ihours & " - mins: " & $imins & " - secs: " & $isecs)

ConsoleWrite("Days: " & $idays & " - Hours: " & $ihours & " - mins: " & $imins & " - secs: " & $isecs & @CRLF)

Func _uptime(ByRef $iDays, ByRef $iHours, ByRef $iMins, ByRef $iSecs)
    $iTicks = DllCall("kernel32.dll", "long", "GetTickCount")
    $iTicks = $iTicks[0]
    If Number($iTicks) > 0 Then
        $iTicks = Round($iTicks / 1000)
        $iDays  = Int($iTicks / 86400)
        $iHours = Int($iTicks / 3600)
        $iTicks = Mod($iTicks, 3600)
        $iMins = Int($iTicks / 60)
        $iSecs = Round(Mod($iTicks, 60))
        Return 1
    ElseIf Number($iTicks) = 0 Then
        $iDays = 0
        $iHours = 0
        $iTicks = 0
        $iMins = 0
        $iSecs = 0
        Return 1
    Else
        SetError(1)
        Return 0
    EndIf
EndFunc   ;==>_uptime

As you can see PS can handle this perfectly for further processing.

Great marriage !


Windows – ERROR: The RPC server is unavailable

August 21, 2014

When trying to perform some basic remote admin tasks you often get this error Sad smile

Solutions :

Review some typical issues and solutions for the “RPC server is unavailable” error:

  1. The remote computer may be blocked by the firewall.

Solution: Configure firewall properly.
NOTE. If you are using WIndows firewall, open the Group Policy Object Editor snap-in (gpedit.msc) to edit the Group Policy object (GPO) that is used to manage Windows Firewall settings in your organization.
Navigate to Computer Configuration – Administrative Templates – Network – Network Connections – Windows Firewall, and then open either Domain Profile or Standard Profile, depending on which profile you are using.
Enable the following exceptions: Allow Remote Administration Exception and Allow File and Printer Sharing Exception.

image

  1. Hostname or IP address is wrong or the remote computer is shutdown.

Solution: Make sure that hostname and IP address. are correct, make sure the machine is turned on and reachable. Also make sure FQDN name is resolved to correct IP address.

 

  1. The Windows Management Instrumentation service is not running on the remote computer.

Solution: Verify that the Windows Management Instrumentation service is running and set to auto start after restart.

 

  1. The TCP/IP NetBIOS Helper service is not running.

Solution: Verify that TCP/IP NetBIOS Helper service is running and set to auto start after restart.

 

  1. The Remote Procedure Call (RPC) service is not running on the remote computer.

Solution: Verify that Remote Procedure Call (RPC) service is running and set to auto start after restart.

To check that machine is reachable, perform the following steps:

  1. Log on a remote computer.
  2. Go to Start –> Run and  type eventvwr and click OK.
  3. Run Services.msc and select Connect To Another Computer.
  4. In the Select Computer dialog, type the name of the domain controller reporting the error in the Another Computer entry field. Click OK to connect to the domain controller.
  5. Select Security log. The list should show you valid events.

AutoIT – Getting data from a Web Service

August 20, 2014

Web Services are a nice feature on the internet. But accessing it as a scripter is not so obvious.

Let’s see here how it goes.

First we need to have the URL of the Web Service and peak into the SOAP Envelop structure.

http://www.webservicex.net/uszip.asmx

image

This API returns 4 methods to retrieve data back depending on some input.

Let’s take the GetInfoByZIP for Example. You see and input field and a SOAP envelope structure which we need later on.

image

If you enter some ZIP CODE you will get an XML response.

image

But if we want to script is we need to get WSDL definition.

This site offers an online WSDL browser.

http://wsdlbrowser.com

image

Look at the ?WSDL extention after the URL

Now we have everuthin we setup our script to get the data.

image

In the script I added some debug information output.

You can capture the Debug XML response, and add it to an XML Parser for further investigation.

image

Once you know how the XML is formatted, we can capture the data in it.

image

Here is the full code.

Dim $objHTTP
Dim $strEnvelope
Dim $strReturn
Dim $objReturn
Dim $strQuery
Dim $strValue

$strValue = InputBox("Testing", "Enter your new value here.", 60007)

; Initialize COM error handler
$oMyError = ObjEvent("AutoIt.Error","MyErrFunc")

$objHTTP = ObjCreate("Microsoft.XMLHTTP")
$objReturn = ObjCreate("Msxml2.DOMDocument.3.0")

; Create the SOAP Envelope
$strEnvelope = '<?xml version="1.0" encoding="utf-8"?>' & _
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' & _
'<soap:Body>' & _
'<GetInfoByZIP xmlns="http://www.webserviceX.NET">' & _
'<USZip>'&$strValue&'</USZip>' & _
'</GetInfoByZIP>' & _
'</soap:Body>' & _
'</soap:Envelope>'

; Set up to post to the server
$objHTTP.open ("post", "http://www.webservicex.net/uszip.asmx?op=GetInfoByZIP", False)

; Set a standard SOAP/ XML header for the content-type
$objHTTP.setRequestHeader ("Content-Type", "text/xml")

; Set a header for the method to be called
$objHTTP.setRequestHeader ("SOAPMethodName", "urn:myserver/soap:TaxCalculator#Getsalestax")

ConsoleWrite("Content of the Soap envelope : "& @CR & $strEnvelope & @CR & @CR)

; Make the SOAP call
$objHTTP.send ($strEnvelope)

; Get the return envelope
$strReturn = $objHTTP.responseText

ConsoleWrite("-----------" & @CRLF)
ConsoleWrite ("Debug Response : "& @CR & $strReturn & @CR & @CR)
ConsoleWrite("-----------" & @CRLF)

; Load the return envelope into a DOM
$objReturn.loadXML ($strReturn)

ConsoleWrite("Return of the SOAP Msg : " & @CR & @CR & $objReturn.XML & @CR & @CR)

; Query the return envelope
$strQuery = "SOAP:Envelope/SOAP:Body"

$objReturn.selectSingleNode($strQuery)

$Soap = $objReturn.Text

MsgBox(0,"SOAP Response","The Response is  : " & $Soap)

Func MyErrFunc()
  $HexNumber=hex($oMyError.number,8)
  Msgbox(0,"COM Test","We intercepted a COM Error !"       & @CRLF  & @CRLF & _
			 "err.description is: "    & @TAB & $oMyError.description    & @CRLF & _
			 "err.windescription:"     & @TAB & $oMyError.windescription & @CRLF & _
			 "err.number is: "         & @TAB & $HexNumber              & @CRLF & _
			 "err.lastdllerror is: "   & @TAB & $oMyError.lastdllerror   & @CRLF & _
			 "err.scriptline is: "     & @TAB & $oMyError.scriptline     & @CRLF & _
			 "err.source is: "         & @TAB & $oMyError.source         & @CRLF & _
			 "err.helpfile is: "       & @TAB & $oMyError.helpfile       & @CRLF & _
			 "err.helpcontext is: "    & @TAB & $oMyError.helpcontext _
			)
  SetError(1)
Endfunc

In Powershell this is only a few lines 2 to be exact.But at least now you know what is going on behind the scene. Smile

See Example here


AutoIT- Sending a mail using the hMailer COM library

August 18, 2014

Just a simple example on how to use the hMailServer interface.

; Send a mail using the hMailer COM library
$oMyError = ObjEvent("AutoIt.Error","MyErrFunc")

dim $oMessage

$oMessage = ObjCreate("hMailServer.Message")
$oMessage.From = "Me"
$oMessage.FromAddress = "myaddress@mydomain.com"
$oMessage.Subject = "Hi"
$oMessage.AddRecipient "My friend", "myfriend@myfriend.com"
$oMessage.Body = "Test - This is the contents of the email."
$oMessage.Save

Func MyErrFunc()
  $HexNumber=hex($oMyError.number,8)
  Msgbox(0,"COM Test","We intercepted a COM Error !"       & @CRLF  & @CRLF & _
			 "err.description is: "    & @TAB & $oMyError.description    & @CRLF & _
			 "err.windescription:"     & @TAB & $oMyError.windescription & @CRLF & _
			 "err.number is: "         & @TAB & $HexNumber              & @CRLF & _
			 "err.lastdllerror is: "   & @TAB & $oMyError.lastdllerror   & @CRLF & _
			 "err.scriptline is: "     & @TAB & $oMyError.scriptline     & @CRLF & _
			 "err.source is: "         & @TAB & $oMyError.source         & @CRLF & _
			 "err.helpfile is: "       & @TAB & $oMyError.helpfile       & @CRLF & _
			 "err.helpcontext is: "    & @TAB & $oMyError.helpcontext _
			)
  SetError(1)
Endfunc

See here for more information.