Chuckero Posted May 10, 2021 Share Posted May 10, 2021 (edited) Hello, I'm working on a big AutoIt script that takes information from the network, from the user computer, from other places and sets up some Windows configurations for all users in the department. This scripts runs directly in the user's computer, not remotely, all computers runs the same AutoIt script. At this moment everything is working well, but, the steps that calls PowerShell are not good enough. Problem 1: each one of the PowerShell calls is totally independent of the others, which means, every step that uses these smalls PowerShell Cmdlet, it creates a new instance of the PS, executes the Cmdlet and closes. This takes around 2 to 5 seconds, depending the Cmdlet. This happens a lot. Problem 2: some of the PS Cmdlet needs to be elevated to runs as Admin, so, the user have to allow it to run it as Admin many times. Really annoying. Is there a way to create an instance of the PowerShell, fills the Cmdlet, run it, get the response and then fills a new Cmdlet, run again, get the new response, and repeat over and over again with no need to elevate and restart the PS every new step? If is possible, with no big dependencies, other wise I have to install the dependencies in many computers. One example of the Cmdlet: ; Change region settings. In the second instance of PowerShell there is no way to get the STDOUT values. $sCommands = "powershell -Command Start-Process powershell -verb runas -ArgumentList {" & _ ; Runs a second instance of PowerShell in elevated level (admin). " Set-ItemProperty -Path 'HKCU:\Control Panel\International' -Name sList -Value '.';" & _ " $culture = Get-Culture;" & _ " $culture.DateTimeFormat.ShortDatePattern = 'dd/mm/yyyy'; ; 'Short date' in 'Region' window.;" & _ " Set-Culture $culture;" & _ " } " ; End of command line. RunWait(@ComSpec & " /c " & $sCommands, "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) ; Check if it's ok. $sCommands = "powershell -Command "" " & _ ; Runs the PowerShell in the regular way. " if ((Get-ItemProperty -Path 'HKCU:\Control Panel\International').sShortDate -eq 'dd/mm/yyyy')" & _ " {" & _ " Write-Output 'Result: ok';" & _ " }" & _ " else{" & _ " Write-Output 'Result: error';" & _ " }" & _ " "" " ; End of command line. $iPID = Run(@ComSpec & " /c " & $sCommands, "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) Do Sleep(1000) Until (Not ProcessExists($iPID)) $sOutput &= StdoutRead($iPID) ; Any error. If (StringInStr($sOutput, "error") > 0) Then Return 0 ; Error. EndIf Return 1 ; Ok. I'm thinking to do something like this, but I didn't find any information about how to do it exactly: ; First run. Local $oPwrS = ObjCreate("PowerShell.exe") Local $sCmd = "Get-ItemPropertyValue 'Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name 'EnableLUA'" Local $sResult = $oPwrS.Execute($sCmd) If ($sResult... do somethink ; Second run. $sCmd = "Get-ItemPropertyValue 'Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name 'EnableLUA'" $sResult = $oPwrS.Execute($sCmd) If ($sResult... do somethink Any clue? Thanks in advance. Edited May 11, 2021 by Chuckero Link to comment Share on other sites More sharing options...
Moderators JLogan3o13 Posted May 10, 2021 Moderators Share Posted May 10, 2021 My first question would be why you need to mix languages? If you're just getting/setting registry entries, why bother with PowerShell when you can do so natively with AutoIt? And if you are doing more, what is it that you are doing with PS that you cannot do with AutoIt? "Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball How to get your question answered on this forum! Link to comment Share on other sites More sharing options...
Chuckero Posted May 11, 2021 Author Share Posted May 11, 2021 16 hours ago, JLogan3o13 said: My first question would be why you need to mix languages? If you're just getting/setting registry entries, why bother with PowerShell when you can do so natively with AutoIt? And if you are doing more, what is it that you are doing with PS that you cannot do with AutoIt? Hello @JLogan3o13, I'm working in 5 different AutoIt scripts (for now), all of them have dozens of specific tasks and a user interface with check boxes to select each task the user needs to do. So I'm using the same sketch for all scripts, very similar each other, this is very ease to do and maintain in AutoIt, in really 95% of the tasks were done in AutoIt native code, but there are some tasks much much easier to do in PowerShell, mainly when I have to set some Windows configuration. So why not use the best of the both worlds? PS: That code I shared is a very small part with no sensitive information. Link to comment Share on other sites More sharing options...
Nine Posted May 11, 2021 Share Posted May 11, 2021 Maybe this ? #include <Array.au3> Local $objShell = ObjCreate("WScript.Shell") Local $FileName = "data.txt" Local $cmdString = "Powershell get-childItem -recurse > " & $FileName $objShell.Run($cmdString, 0, True) ;Local $array = FileReadToArray($FileName) ; put result in array ;_ArrayDisplay($array) Local $sResult = FileRead($FileName) ; put result in string ConsoleWrite ($sResult & @CRLF) Just make a function that wraps the run method the way you want. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Chuckero Posted May 12, 2021 Author Share Posted May 12, 2021 (edited) On 5/11/2021 at 11:56 AM, Nine said: Maybe this ? #include <Array.au3> Local $objShell = ObjCreate("WScript.Shell") Local $FileName = "data.txt" Local $cmdString = "Powershell get-childItem -recurse > " & $FileName $objShell.Run($cmdString, 0, True) ;Local $array = FileReadToArray($FileName) ; put result in array ;_ArrayDisplay($array) Local $sResult = FileRead($FileName) ; put result in string ConsoleWrite ($sResult & @CRLF) Just make a function that wraps the run method the way you want. Thanks @Nine, but this approach looks like the same I'm already doing. Each time I call $objShell.Run() it seems to open a new PS session. And I didn't figure out a way to elevate it to run admin Cmdlet. Other than that, I found this way to get the results, a little bit easier but with the same behavior: $sResult = $objShell.Exec($cmdString).StdOut.ReadAll Edited May 12, 2021 by Chuckero Link to comment Share on other sites More sharing options...
Chuckero Posted May 12, 2021 Author Share Posted May 12, 2021 Is there a way to call PowerShell as a COM Object? Link to comment Share on other sites More sharing options...
Gianni Posted May 12, 2021 Share Posted May 12, 2021 6 hours ago, Chuckero said: Is there a way to call PowerShell as a COM Object? ...I do not know, however you could use a running powershell instance started with redirected I/O streams and use it to execute multiple commands without having to rerun it with each new command. Since it is necessary to be able to identify the beginning and the end of the output stream of the various commands, I thought of "injecting" two "flags", one for the beginning and one for the end, for each command executed, so as to be able to extract only the body of the output of the different commands. This little script perhaps clarifies it better than many words. I hope it will be useful to you expandcollapse popup#include <constants.au3> #include <string.au3> #RequireAdmin ; Use RunAs if you want use a fixed username/password within the script: ; Global $hPowerShellPID = RunAs("UserName", "Domain", "Password", "", "powershell.exe", '', @SW_HIDE, BitOR($STDIN_CHILD, $STDERR_MERGED)) ; or use #RequireAdmin and a simple Run Statement to enter Admin credentials (if needed) at runtime ; Here we start a "permanent" powershell prompt with redirected streams Global $hPowerShellPID = Run("powershell.exe", '', @SW_HIDE, BitOR($STDIN_CHILD, $STDERR_MERGED)) ; this little loop is to wait for the "welcome" message from powershell ; just a way to be sure that the powershell is running and "streaming" Do StdoutRead($hPowerShellPID) Until @extended ; out stream started ; example: ; Here we "execute a command via the Powershell that is running in background... ; ...and we get back to resulting output Local $Out = _Run_Cmdlet("Get-ItemPropertyValue 'Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name 'EnableLUA'", $hPowerShellPID) ConsoleWrite($Out) ; here another command ConsoleWrite(_Run_Cmdlet("dir c:\", $hPowerShellPID)) ; .... and so on ... ; this function execute the passed powershell command and returns the resulting output Func _Run_Cmdlet($sCmd, ByRef $hPS) Local $sStdOut = '' ; we insert a start and an end message in order to identify the "body" of the result of the command executed $sCmd = 'write-host "->StartOfStream<-"; ' & $sCmd & '; write-host "->EndOfStream<-"' & @CRLF StdinWrite($hPS, $sCmd) Do Sleep(250) $sStdOut &= StdoutRead($hPS) ; the presence of the known end message signals the end of the execution Until StringInStr($sStdOut, "->EndOfStream<-" & @LF) ; return only the body of the outpu of the passed command Return _StringBetween($sStdOut, "->StartOfStream<-" & @LF, "->EndOfStream<-" & @LF)[0] EndFunc ;==>_Run_Cmdlet caramen and Chuckero 2 Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
Confuzzled Posted May 13, 2021 Share Posted May 13, 2021 Batch processing: Send all your powershell commands to a temporary file to execute from powershell, and then once the AutoIt processes are complete, run this one temporary file in powershell before deleting it. One lua process to elevate, run, and downgrade and it is done. Link to comment Share on other sites More sharing options...
Chuckero Posted May 19, 2021 Author Share Posted May 19, 2021 (edited) On 5/12/2021 at 7:34 PM, Chimp said: ...I do not know, however you could use a running powershell instance started with redirected I/O streams and use it to execute multiple commands without having to rerun it with each new command. Since it is necessary to be able to identify the beginning and the end of the output stream of the various commands, I thought of "injecting" two "flags", one for the beginning and one for the end, for each command executed, so as to be able to extract only the body of the output of the different commands. This little script perhaps clarifies it better than many words. I hope it will be useful to you Wow, that's a great idea using StdinWrite() and StdoutRead()! It's working almost perfectly, it's just missing the admin rights for PowerShell. I tried RunAs() but I have to provide the user and password, this is not a good option because the script will run in different computers and the user doesn't have the admin password (and there are different passwords). The other option I tried is something like this: Local $objShell = ObjCreate("Shell.Application") $sRet = $objShell.ShellExecute("powershell.exe", "", "", "runas", 1) ; 0=hide, 1=normal, 2=minimized, 3=maximized, In this case I have the admin rights (with that Windows message asking to allow the app to make changes, and YES and NO buttons), but I can't send or get anything from that window, the functions StdinWrite() and StdoutRead() doesn't work, maybe there is some parameters in ShellExecute() that I didn't figured out? Edited May 19, 2021 by Chuckero Link to comment Share on other sites More sharing options...
Chuckero Posted May 19, 2021 Author Share Posted May 19, 2021 I found another solution, using the directive: #RequireAdmin In this case everything works, but I loose the returns of ConsoleWrite(), not a big deal since now everything is working as expected. Thanks to all! Link to comment Share on other sites More sharing options...
Nine Posted May 19, 2021 Share Posted May 19, 2021 13 minutes ago, Chuckero said: but I loose the returns of ConsoleWrite() You don't have to. Just add directive #AutoIt3Wrapper_Change2CUI=y Compile your script, run from DOS console, there you go... Chuckero 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Gianni Posted May 19, 2021 Share Posted May 19, 2021 even if you use #requireadmin and the current user is not an administrator, you still need to provide an administrator username and password to allow the program to run. Simply pressing OK is not enough ... Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
JockoDundee Posted May 20, 2021 Share Posted May 20, 2021 11 hours ago, Nine said: 11 hours ago, Chuckero said: but I loose the returns of ConsoleWrite() You don't have to. Just add directive #AutoIt3Wrapper_Change2CUI=y Or, since I see no references to the Scite editor, you can just add the directive: #pragma compile(Console, True) to the top of your program. Chuckero 1 Code hard, but don’t hard code... Link to comment Share on other sites More sharing options...
Chuckero Posted August 19, 2021 Author Share Posted August 19, 2021 I did some tests and it seems that #pragma compile(Console, True) and #AutoIt3Wrapper_Change2CUI=y have exactly the same result. Anyway, it's working! Thanks to all! Link to comment Share on other sites More sharing options...
Developers Jos Posted August 19, 2021 Developers Share Posted August 19, 2021 10 minutes ago, Chuckero said: I did some tests and it seems that #pragma compile(Console, True) and #AutoIt3Wrapper_Change2CUI=y have exactly the same result. Correct... the #pragma option has been implemented much later than the similar #AutoIt3Wrapper options, so there are now both available and I will leave the #AutoIt3Wrapper one in there for easy and backward compatibility. Jos Chuckero 1 SciTE4AutoIt3 Full installer Download page - Beta files Read before posting How to post scriptsource Forum etiquette Forum Rules Live for the present, Dream of the future, Learn from the past. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now