david1337

Run powershell script with AutoIt

27 posts in this topic

#1 ·  Posted (edited)

Hi guys,

I need a little help here :)

I have this simple Powershell script, that is able to set "sig.htm" as signature in OWA for the mail account specified.
First part of the script just loads the Exchange snapin, since this is needed for the Get-Mailbox command.

#Add Exchange 2010/2013 snapin if not already loaded in the PowerShell session
if (!(Get-PSSnapin | where {$_.Name -eq "Microsoft.Exchange.Management.PowerShell.E2010"}))
{
	try
	{
		Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction STOP
	}
	catch
	{
		#Snapin was not loaded
		Write-Warning $_.Exception.Message
		EXIT
	}
	. $env:ExchangeInstallPath\bin\RemoteExchange.ps1
	Connect-ExchangeServer -auto -AllowClobber
}



$mailboxes = Get-Mailbox -Identity user@domain.com
$mailboxes| foreach {$file= "sig.htm"; Set-MailboxMessageConfiguration -identity $_.alias -SignatureHtml "$(Get-Content -Path $file -ReadCount 0)"}

What I want is for AutoIt to use Powershell.exe to run the script somehow. This way I would be able to use AutoIt variables and arrays together with the PS script.

 I guess the solution would be to run Powershell.exe with command line arguments?

If that is not possible, maybe have the script stored as a "ps1" file, and interact with it that way? (not preferred)

Edited by david1337

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Try: 

or
 

Powershell.exe -File C:\my_path\run_import_script.ps1

powershell -executionpolicy bypass -File C:\my_path\run_import_script.ps1

powershell.exe -noexit "& 'C:\my_path\run_import_script.ps1'"

 

Edited by You

Regards,
 

Share this post


Link to post
Share on other sites

#3 ·  Posted

Hi You,

Thank you for your answer! :)

Your suggestion is fine to just start the ps1 script from AutoIt, but I want to use it with AutoIt variables.
-> For instance: When the PS script uses "user@domain.com", it should use the $email variable from AutoIt instead.
Or run the PS script for each email address found in my Autoit Array.

 

Share this post


Link to post
Share on other sites

#4 ·  Posted

Try:

Global Const $iPSfile=@TempDir&"\exc.ps1"
Global Const $iHTMLfile="sig.htm"
Global Const $iDefaultEmail="user@domain.com"
Global Const $exPSscript="#Add Exchange 2010/2013 snapin if not already loaded in the PowerShell session"&@CRLF
$exPSscript&='if (!(Get-PSSnapin | where {$_.Name -eq "'&'Microsoft.Exchange.Management.PowerShell.E2010"}))'&@CRLF
$exPSscript&="{"&@CRLF
$exPSscript&="  try"&@CRLF
$exPSscript&="  {"&@CRLF
$exPSscript&="      Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction STOP"&@CRLF
$exPSscript&="  }"&@CRLF
$exPSscript&="  catch"&@CRLF
$exPSscript&="  {"&@CRLF
$exPSscript&="      #Snapin was not loaded"&@CRLF
$exPSscript&="      Write-Warning $_.Exception.Message"&@CRLF
$exPSscript&="      EXIT"&@CRLF
$exPSscript&="  }"&@CRLF
$exPSscript&="  . $env:ExchangeInstallPath\bin\RemoteExchange.ps1"&@CRLF
$exPSscript&="  Connect-ExchangeServer -auto -AllowClobber"&@CRLF
$exPSscript&="}"&@CRLF
$exPSscript&=""&@CRLF
$exPSscript&="$mailboxes = Get-Mailbox -Identity "&$iDefaultEmail&@CRLF
$exPSscript&='$mailboxes| foreach {$file= "'&$iHTMLfile&'"; Set-MailboxMessageConfiguration -identity $_.alias -SignatureHtml '&'"$(Get-Content -Path $file -ReadCount 0)'&'"}'&@CRLF

Global $PSscript, $ListEmail=StringSplit("my@gmail.com|ceo@viper.com|xxx@xxx.com","|")

For $i=1 to $ListEmail[0]-1
    $PSscript=StringReplace($exPSscript,$iDefaultEmail,$ListEmail[$i])
    _SaveExecute($PSscript)
    $PSscript=""
Next

Func _SaveExecute($PSscript)
    Local $hFile=FileOpen($iPSfile,2+8)
    FileWrite($hFile,$PSscript)
    FileClose($hFile)
;~  _ExecutePSfile($iPSfile)
;~ Do more somethink
EndFunc

 


Regards,
 

Share this post


Link to post
Share on other sites

#5 ·  Posted

You should be able to add the following to your PowerShell Script to accept parameters:

Example: PScript.ps1 -Email mail@gmail.com, -File @ScriptDir\Sig.htm

param (
    [Parameter(Mandatory=$true)][string]$Email,
    [string]$File)
 )

 

Share this post


Link to post
Share on other sites

#6 ·  Posted

Hi again You,

Wow this looks very interesting! :)

I get Error: Line 5 - Cannot assign values to constants

Share this post


Link to post
Share on other sites

#7 ·  Posted

Hi Subz,

Thanks for your answer!

Okay so I add this to my ps1 file:

param (
    [Parameter(Mandatory=$true)][string]$Email,
    [string]$File)
 )

 

and how would I call the file correctly from AutoIt?

Share this post


Link to post
Share on other sites

#8 ·  Posted

5 hours ago, You said:

Try: 

or
 

Powershell.exe -File C:\my_path\run_import_script.ps1

powershell -executionpolicy bypass -File C:\my_path\run_import_script.ps1

powershell.exe -noexit "& 'C:\my_path\run_import_script.ps1'"

 

FYI, You, I have actually looked into the first suggestion you made concerning the Powershell Com object, but if you dig into the issue a little more, you will find that that method is only useful up to powershell version 3.  If you have any version greater than that, it is useless.

Share this post


Link to post
Share on other sites

#9 ·  Posted

Here is a really basic example:

Example.ps1

param (
    [Parameter(Mandatory=$true)][string]$Email,
    [string]$File)

write-output $Email
write-output $File

Example.au3

Global $aUserInfo[2][2]
    $aUserInfo[0][0] = 'First.User@google.com'
    $aUserInfo[0][1] = @TempDir & '\First.User-Sig'
    $aUserInfo[1][0] = 'Second.User@google.com'
    $aUserInfo[1][1] = @TempDir & '\Second.User-Sig.htm'

For $i = 0 To UBound($aUserInfo) - 1
    RunWait(@ComSpec & ' /k PowerShell.exe -ExecutionPolicy Bypass -File "' & @ScriptDir & '\Example.ps1" -Email ' & $aUserInfo[$i][0] & '-File "' & $aUserInfo[$i][1] & '"')
Next

 

Share this post


Link to post
Share on other sites

#10 ·  Posted

Here is another options similar to @You suggestion although haven't tested this, you will need to uncomment the RunWait to test.

Global $sPSScript = @TempDir & "\PSScript.ps1"
Global $aUserInfo[2][2]
    $aUserInfo[0][0] = 'First.User@google.com'
    $aUserInfo[0][1] = @TempDir & '\First.User-Sig'
    $aUserInfo[1][0] = 'Second.User@google.com'
    $aUserInfo[1][1] = @TempDir & '\Second.User-Sig.htm'

    For $i = 0 To UBound($aUserInfo) - 1
        _PSScript($aUserInfo[$i][0], $aUserInfo[$i][1])
    Next

Func _PSscript($sEmail, $sFile)
    Local $hPSScript, $sPSWrite = ""
        $sPSWrite &= "#Add Exchange 2010/2013 snapin if not already loaded in the PowerShell session" & @CRLF
        $sPSWrite &= 'if (!(Get-PSSnapin | where {$_.Name -eq "'&'Microsoft.Exchange.Management.PowerShell.E2010"}))' & @CRLF
        $sPSWrite &= "{" & @CRLF
        $sPSWrite &= "  try" & @CRLF
        $sPSWrite &= "  {" & @CRLF
        $sPSWrite &= "      Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction STOP" & @CRLF
        $sPSWrite &= "  }" & @CRLF
        $sPSWrite &= "  catch" & @CRLF
        $sPSWrite &= "  {" & @CRLF
        $sPSWrite &= "      #Snapin was not loaded" & @CRLF
        $sPSWrite &= "      Write-Warning $_.Exception.Message" & @CRLF
        $sPSWrite &= "      EXIT" & @CRLF
        $sPSWrite &= "  }" & @CRLF
        $sPSWrite &= "  . $env:ExchangeInstallPath\bin\RemoteExchange.ps1" & @CRLF
        $sPSWrite &= "  Connect-ExchangeServer -auto -AllowClobber" & @CRLF
        $sPSWrite &= "}" & @CRLF
        $sPSWrite &= "" & @CRLF
        $sPSWrite &= "$mailboxes = Get-Mailbox -Identity " & $sEmail & @CRLF
        $sPSWrite &= '$mailboxes| foreach {$file= "' & $sFile & '"; Set-MailboxMessageConfiguration -identity $_.alias -SignatureHtml ' & '"$(Get-Content -Path $file -ReadCount 0)' & '"}' & @CRLF
        $hPSScript = FileOpen($sPSScript, 10)
            If @error Then Return
        FileWrite($sPSScript, $sPSWrite)
        FileClose($hPSScript)
;~  RunWait(@ComSpec & ' /k PowerShell.exe -ExecutionPolicy Bypass -File "' & $sPSScript & '"')
EndFunc

 

1 person likes this

Share this post


Link to post
Share on other sites

#11 ·  Posted

53 minutes ago, Subz said:

Here is another options similar to @You suggestion although haven't tested this, you will need to uncomment the RunWait to test.

Global $sPSScript = @TempDir & "\PSScript.ps1"
Global $aUserInfo[2][2]
    $aUserInfo[0][0] = 'First.User@google.com'
    $aUserInfo[0][1] = @TempDir & '\First.User-Sig'
    $aUserInfo[1][0] = 'Second.User@google.com'
    $aUserInfo[1][1] = @TempDir & '\Second.User-Sig.htm'

    For $i = 0 To UBound($aUserInfo) - 1
        _PSScript($aUserInfo[$i][0], $aUserInfo[$i][1])
    Next

Func _PSscript($sEmail, $sFile)
    Local $hPSScript, $sPSWrite = ""
        $sPSWrite &= "#Add Exchange 2010/2013 snapin if not already loaded in the PowerShell session" & @CRLF
        $sPSWrite &= 'if (!(Get-PSSnapin | where {$_.Name -eq "'&'Microsoft.Exchange.Management.PowerShell.E2010"}))' & @CRLF
        $sPSWrite &= "{" & @CRLF
        $sPSWrite &= "  try" & @CRLF
        $sPSWrite &= "  {" & @CRLF
        $sPSWrite &= "      Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction STOP" & @CRLF
        $sPSWrite &= "  }" & @CRLF
        $sPSWrite &= "  catch" & @CRLF
        $sPSWrite &= "  {" & @CRLF
        $sPSWrite &= "      #Snapin was not loaded" & @CRLF
        $sPSWrite &= "      Write-Warning $_.Exception.Message" & @CRLF
        $sPSWrite &= "      EXIT" & @CRLF
        $sPSWrite &= "  }" & @CRLF
        $sPSWrite &= "  . $env:ExchangeInstallPath\bin\RemoteExchange.ps1" & @CRLF
        $sPSWrite &= "  Connect-ExchangeServer -auto -AllowClobber" & @CRLF
        $sPSWrite &= "}" & @CRLF
        $sPSWrite &= "" & @CRLF
        $sPSWrite &= "$mailboxes = Get-Mailbox -Identity " & $sEmail & @CRLF
        $sPSWrite &= '$mailboxes| foreach {$file= "' & $sFile & '"; Set-MailboxMessageConfiguration -identity $_.alias -SignatureHtml ' & '"$(Get-Content -Path $file -ReadCount 0)' & '"}' & @CRLF
        $hPSScript = FileOpen($sPSScript, 10)
            If @error Then Return
        FileWrite($sPSScript, $sPSWrite)
        FileClose($hPSScript)
;~  RunWait(@ComSpec & ' /k PowerShell.exe -ExecutionPolicy Bypass -File "' & $sPSScript & '"')
EndFunc

 

 

Wow, I think that we are very close now.
But there seems to be a problem with running a ps1 script that includes the Exchange snapin.
I get the below error in the cmd window:

WARNING: The Windows PowerShell snap-in
'Microsoft.Exchange.Management.PowerShell.E2010' is not installed on this
machine.

 

I tried to run another ps1 script that didn't contain the exchange snapin, and that worked fine using the Run command from AutoIt.

What could be the problem?

Share this post


Link to post
Share on other sites

#12 ·  Posted

The creation of the ps1 scripts works perfectly though.

I tried (Run with Powershell) on the ps1 script that was created in the temp folder by AutoIt, and it worked just as expected!

So the only problem is to execute the ps1 script directly from AutoSig :)

Share this post


Link to post
Share on other sites

#13 ·  Posted

You could try adding #RequireAdmin to the top of you Au3 Script if that doesn't work you can try using the line below which will Start PowerShell in Admin mode

RunWait(@ComSpec & ' /k PowerShell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList ' & "'-ExecutionPolicy Bypass -File " & '""' & $sPSScript & '"' & "' -Verb RunAs}")

 

Share this post


Link to post
Share on other sites

#14 ·  Posted

Its 4am in the morning here and got work in 4 hours so going to go now to get some zzz, I'm fairly sure that the issue is running PowerShell in Admin mode so hopefully either of the commands above will work for you.

Share this post


Link to post
Share on other sites

#15 ·  Posted

Wow okay you must be pretty tired atm then. have a good nights sleep!

I tried both RequireAdmin and starting PS in Admin mode, but both gave the result to just leave an empty cmd window open, and no signature was set. (No errors this time though)

You got me very close to the finish line, and I will just have to figure out why the script won't run from AutoIT!

Thank you very much for the help!

 

Share this post


Link to post
Share on other sites

#16 ·  Posted

After 

FileClose($hPSScript)

Can you try using:

ShellExecute($sPSScript)

Share this post


Link to post
Share on other sites

#17 ·  Posted

ShellExecute will open the file with Windows' default behavior. In this case it will just open the ps1 file in edit mode.

 

But I found out that if I start the script with a batch file like this, it works:
 

Powershell.exe -executionpolicy Bypass -File  "TempFolder...\PSScript.ps1"

So I'm sure that I can get it to work from AutoIt somehow also! :)

Share this post


Link to post
Share on other sites

#18 ·  Posted

Can you try:

ShellExecute('PowerShell.exe', '-executionpolicy Bypass -File "' & $sPSScript & '"')

 

Share this post


Link to post
Share on other sites

#19 ·  Posted

Same result:
'Microsoft.Exchange.Management.PowerShell.E2010' is not installed on this
machine.


Weird !

Share this post


Link to post
Share on other sites

#20 ·  Posted

Do you run CMD in Administrative mode?  When running PowerShell?  Can you manually try using the same command line and see what the result is?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Similar Content

    • hemichallenger
      By hemichallenger
      Not sure if this is possible or if someone has already tackled this. Is it possible to embed PowerShell into a GUI? Autoit is great for quick function but sometime I need to run a command thru PowerShell. It be great to have PowerShell console embedded into the gui.
    • BigDaddyO
      By BigDaddyO
      After much searching I finally found a method to get eMails from an Exchange eMail account inbox.  I was hoping for AutoIT or vbscript but I couldn't find any that would read the inbox messages without using Outlook.
      I needed this because I'm testing a web-form that generates an eMail sent to a shared mailbox "not what my current outlook is configured for".  so, I needed to connect to a different account, then get the inbox messages, and see if the auto-generated eMail message body contains what I submitted in the form.
       
      I found a PowerShell script that was close and modified it to do just what I want, but I'd still like it to run in AutoIT but I'm not sure how to use the Microsoft.Exchange.WebServices.dll
      Anybody have some ideas? 
      #To Launch! # C:\Windows\System32> powershell -ExecutionPolicy ByPass #This launches PowerShell and allows execution of .ps1 files # PS C:\Windows\System32> . "C:\Temp\eMail\getInbox.ps1" #The period . in front of the .ps1 file forces PS to display results on-screen # Where is the EWS .DLL file that you are using # Get the installer from https://www.microsoft.com/en-us/download/details.aspx?id=42022 # We only need 2 dll's from the install and they can be stored anywhere: "Microsoft.Exchange.WebServices.Auth.dll" & "Microsoft.Exchange.WebServices.dll" $EWSdll = "C:\Temp\eMail\Microsoft.Exchange.WebServices.dll" # Where do you want the output text file to be saved $Output = "C:\Temp\eMails.txt" # replace with your email address $email = "MyemailAddress@work.net" # only need to populate these if you're impersonating... $username = "myemail" $password = "Sup3rS3cre+" $domain = "ad.work.net" # load the assembly : point to the dll in the location you have the .dll file [void] [Reflection.Assembly]::LoadFile($EWSdll) # set ref to exchange, first references 2007, 2nd is 2010 (default) #$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1) $s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService # use first option if you want to impersonate, otherwise, grab your own credentials with the 3rd one. not sure what the 2nd one is for $s.Credentials = New-Object Net.NetworkCredential($username, $password, $domain) ##$s.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials #$s.UseDefaultCredentials = $true # discover the url from your email address $s.AutodiscoverUrl($email) # get a handle to the inbox $inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox) #create a property set (to let us access the body & other details not available from the FindItems call) $psPropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $psPropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text; # If you have a set number of items you want to get, use this and insert the # in the () # $items = $inbox.FindItems(5) # If you want to retrieve all items (Server limit is usually at 1000) then use this line # Details on the max returned by server: https://blogs.msdn.microsoft.com/exchangedev/2010/03/12/throttling-policies-and-the-ewsfindcountlimit/ $items = $inbox.FindItems($inbox.TotalCount) # Put some counts at the top of the output Write-host "Total Inbox count: $($inbox.TotalCount)" Write-host "Unread count: $($inbox.UnreadCount)" #These two lines, write the output to the specified text file Add-Content $Output "Total Inbox count: $($inbox.TotalCount)" Add-Content $Output "Unread count: $($inbox.UnreadCount)" foreach ($item in $items.Items) { # load the property set to allow us to get to the body $item.load($psPropertySet) # Get the Body text as-is $bod = $item.Body.Text #if you only want a short summary of the Body, then comment the above line and un-comment these 4 lines # $bod = $item.Body.Text -replace '\s+', ' ' # $bodCutOff = (100,$bod.Length | Measure-Object -Minimum).Minimum # $bod = $bod.Substring(0,$bodCutOff) # $bod = "$bod..." # output the results - first of all the From, Subject, References and Message ID write-host "====================================================================" Write-host "From: $($item.From.Name)" Write-host "Subject: $($item.Subject)" Write-host "Body: $($bod)" write-host "====================================================================" "" # Output the results to the specified Text file Add-Content $Output "" Add-Content $Output "====================================================================" Add-Content $Output "From: $($item.From.Name)" Add-Content $Output "Subject: $($item.Subject)" Add-Content $Output "Body:",$($bod) Add-Content $Output "====================================================================" Add-Content $Output "" } #see these URLs for more info # EWS Stuff # folder members: https://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.folder_members%28v=exchg.80%29.aspx # exporting headers: https://www.allabout365.com/2010/10/export-email-headers-exchange-powershell/ # read emails with EWS: https://social.technet.microsoft.com/Forums/en-US/3fbf8348-2945-43aa-a0bc-f3b1d34da27c/read-emails-with-ews?forum=exchangesvrdevelopment  
      Thanks,
      Mike
    • Jibberish
      By Jibberish
      Hi all,
      I need to read a log file into an array, but the log file is encoded as $FO_UTF16_BE_NOBOM (2048) = Use Unicode UTF16 Big Endian (without BOM) per FileGetEncoding (it returns 2048).
      I have searched how to convert these log files to UTF-8 and finally found a Powershell command. Since then I have been racking my brain trying to get the function to work. The command itself works from a Powerscript prompt:
      C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command Get-Content C:\Logs\Myplayer_10-10-17-02-31.log | Set-Content -Encoding utf8 C:\Logs\Myplayer1.log This is my sandbox;
      #include <array.au3> #include <File.au3> Local $aArrayLogFile Local $sLogDir = "C:\Logs\" Local $sLogFile = "Myplayer_10-10-17-02-31.log" Local $sConvertedLog = "ConvertedLog.log" Local $sLogDirFile = $sLogDir&$sLogFile RunWait("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command Get-Content "&$sLogDirFile&" | Set-Content -Encoding utf8 "&$sConvertedLog,$sLogDir) _FileReadToArray($sLogDirFile, $aArrayLogFile) _ArrayDisplay($aArrayLogFile) Also tried
      RunWait("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command Get-Content "&$sLogDirFile&" | Set-Content -Encoding utf8 "&$sConvertedLog,$sLogDir) and
      ShellExecuteWait("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"," -Command Get-Content "&$sLogDirFile&" | Set-Content -Encoding utf8 "&$sConvertedLog,$sLogDir) Tried without -Command and a bunch of other parameters that were sprinkled throughout the internet from people trying to get this to work.
      Thanks
      Jibs
    • ur
      By ur
      I am maintaining all the reusable code in a separate file as library.au3.
      In that file I have referenced some dependent files using fileinstall, so that they will be extracted when necessary.
       
      Problem is, if I use a function in the library.au3 in another script which doesn't require this dependent file, as I am including the whole file using include tag, it is embedding that file also.
      Is there any way to exclude that.
       
    • tcox8
      By tcox8
      Hello,
      Currently I am running a script that calls a powershell script. To read the results of that I am reading StdOut. I am parsing things accordingly but unfortunately it doesn't parse correctly all the time and I end up missing parts of the string or other problems. My question then is, what is the best results for reading what is returned when running a powershell script or something similar?