Sign in to follow this  
Followers 0
Tripredacus

Macro problem in Win7 x64

15 posts in this topic

I have an AutoIT program (two actually) that I use to deploy software to computers after I have put Windows on them. This program is cross-platform compatible with XP, Vista and Windows 7 32/64. A problem arose when I added a new installer for testing (Microsoft Security Essentials) that for some reason would fail to install IF Office was installed by it previously. However, it does install by itself on x64 and installs with Office on x32. Here is a rundown of symptoms:

Windows 7 Pro x86

PASS = install MSE by itself

PASS = install MSE after Office

Windows 7 Pro x64

PASS = install MSE by itself

FAIL = install MSE after Office (Office installs but MSE fails)

I took this problem to Microsoft and there is a case open for it, but since I have found a possible AutoIT problem instead, I have to post it here.

I have 2 Deployment apps, one for XP and one for Vista/7. The only difference between these programs each write to a static path for where the installer app goes. The path to the Startup folder is different in XP or Vista (but the same between Vista and 7). I also need 2 programs because the environment they run from (WinPE) they would not be able to determine what OS the target had on it. This program works fine, the problem is with the installer. The Deployment app copies the installer.exe (and a cleanup.exe) to the Hard Drive. Since the installer is placed into the Startup folder, it runs automatically when the computer reboots. And also since this app is running on the client, it can detect the OS it is on and do whatever it needs to do based on that. This app, installer.exe is compiled as x86 app, not x64!

IF @OSVersion = "WIN_VISTA" OR @OSVersion = "WIN_2008" Then 
    $StartupPath = "c:\users\administrator\appdata\roaming\microsoft\windows\startm~1\programs\startup\"
ElseIf @OSVersion = "WIN_XP" Then 
    $StartupPath = "c:\docume~1\alluse~1\startm~1\programs\startup\"
Else 
    $StartupPath = "error"
EndIf
If FileExists ( "c:\temp\nero8ste2\installnero.cmd") Then
    $nero = 1
    RunWait (@ComSpec & " /c c:\temp\nero8ste2\installnero.cmd")
EndIf
MsgBox ( 4096, "Complete", "The installer is finished. Click OK to reboot...")
RegWrite ( "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce" , "1" , "REG_SZ" , "c:\pnpdrvrs\net\cleanup.exe" )
_FileWriteLog("c:\temp\rem.bat","taskkill /f /im installer.exe")
_FileWriteToLine("c:\temp\rem.bat", 1, "taskkill /f /im installer.exe", 1)
_FileWriteToLine("c:\temp\rem.bat", 2, "del " & $StartupPath & "installer.exe", 1)
_FileWriteToLine("c:\temp\rem.bat", 3, "c:\windows\system32\shutdown.exe -r -f -t 0", 1)
Run ( "c:\temp\rem.bat" )

In the above example, I used the Nero install command. I do not believe I can post the commands for MSE or Office as their documentation is NDA, however those paths are not the issue. You can see the script first figures out what OS it is running on, and sets variables to be used at the end to "delete itself."

Previously to me releasing this program for use on Windows 7 deployments, I had to verify what OS variable was being reported to AutoIT. To test this, I used this very small program:

MsgBox (4096, "Test", @OSVersion )

This program told me that all of our Windows 7 installs reported back "WIN_2008", so that was added to the script. Since the install fails during the above circumstance, I created a new installer that logs information as it runs, and here is where the problem starts. First, here is the new logging code:

_FileWriteToLine("c:\windows\test.log",3,"AutoIT detects OS is: " & @OSVersion & "and Arch is: " & @CPUArch & ".",1)
    _FileWriteToLine("c:\windows\test.log",4,"Windows Reports Environment Path for PROCESSOR_ARCHITECTURE is: " & $envVar & ".",1)

And the resultant log file entries:

AutoIT detects OS is: WIN_VISTAand Arch is: X64.

Windows Reports Environment Path for PROCESSOR_ARCHITECTURE is: x86.

So, @OSVersion run from 1 program returns "WIN_2008" but from another it returns "WIN_VISTA". Secondly, reading the System Variable for CPU reads incorrectly as well. Here is a screenshot from the system this was tested on:

Posted Image

Let me know if I left something out. Oh, I did leave a peice out. Before installing MSE, I have my installer program check the OS version. If it is WIN_2008, it installs, if WIN_XP or WIN_VISTA, the script is supposed to open a MsgBox saying not supported. The install fails because when it checks the @OSVersion on Win7 x64 it returns WIN_VISTA, but not all the time.

Any ideas?

Share this post


Link to post
Share on other sites



Hi,

Maybe this will help, try to resolve Windows 7 using WMI

$objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & "localhost" & "\root\cimv2")
$colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
For $objItem In $colItems
    If StringInStr($objItem.Caption, "Windows 7") Then $Windows7 = "YES"
Next

You should also take a look at the following URL Look at the post from Raven1


Best regards,Emiel Wieldraaijer

Share this post


Link to post
Share on other sites

_FileWriteToLine("c:\windows\test.log",3,"AutoIT detects OS is: " & @OSVersion & "and Arch is: " & @CPUArch & ".",1)
    _FileWriteToLine("c:\windows\test.log",4,"Windows Reports Environment Path for PROCESSOR_ARCHITECTURE is: " & $envVar & ".",1)

The reporting of PROCESSOR_ARCHITECTURE is an odd result as all Core2Duo CPUs are 64 Architecture as mentioned at Intel. So when @CPUArch returns 64 bit CPU and PROCESSOR_ARCHITECTURE can return 32 CPU on a 32 bit installed OS then that seems odd with the value of PROCESSOR_ARCHITECTURE. PROCESSOR_ARCHITECTURE seems to be more like OS_ARCHITECTURE (non existant variable) as like @OSArch does in AutoIt as it determines whether a 32 bit or 64 bit OS is installed.

I would consider that you may need to use @OSArch rather then @CPUArch to determine the type of the OS that the script will handle. As for @OSVersion, that may depend on the OS release, i.e apparently beta/RC of Win7 were identified as Vista and the same may have been for Win2008 as they were created from the Vista code base.

Share this post


Link to post
Share on other sites

Both of these replies are helpful.

The first brings to light the use of different cmd.exe types in 64bit OS. When I use the @ComSpec command in my script from an x86 compiled AU3 on an x64 OS, what arch ComSpec is made available to the program? This is a lead I was not aware of. Really makes me want to get the Internals book.

The second about the arch macros. Yes @OSArch sounds like it would be the best to use. I had only added that to my program on behalf of MS. They were wondering if the Office installer had changed the PROCESSOR_ARCHITECTURE variable at any point in its install, to make MSE fail. However, this does not explain why AutoIT shows different information for that variable than the system does! If EnvGet is supposed to pull these variables from the system, it still should be the same right?

Lastly, the OSVersion problem still does not make sense. I understand what you mean about different OS releases and getting different results. I cannot tell you too much information about the OS I am using, however it is Windows 7 Professional x64 RTM. It is not Retail, VLK, OEM Channel (DSP), MSDN, Technet or NFR version. The @OSVersion was able to show different results on the same machine, albeit from different apps. The older program (osversion.exe/au3) reports it as WIN_2008, but the newer one (installer.exe/au3) reports it as WIN_VISTA. I do not know what version of the AutoIT library I used to create the older program, installer was built with, well appears to be based on the help file v3.3.0.0.

Share this post


Link to post
Share on other sites

I have opened a case regarding MSE with Microsoft, so it may yet be a problem on that end. However, I was brought under the idea that perhaps MSE needs the x64 @ComSpec to install properly. But then again, it DOES install fine by itself...

Anyways, if there are 2 ComSpecs on an x64 system, this is interesting to find out. I made 2 apps, both do the same thing, but one is compiled for x64.

MsgBox (4096, "Test", @Comspec )

The x86 returns: c:\windows\system32\cmd.exe

The x64 returns: c:\windows\system32\cmd.exe

Hmmm... Any other ideas?

Share this post


Link to post
Share on other sites

Is it possible for AutoIT to get the one in syswow64 using @comspec? Why wouldn't a 64bit compiled AutoIT use the 64bit cmd.exe?

Share this post


Link to post
Share on other sites

Is it possible for AutoIT to get the one in syswow64 using @comspec? Why wouldn't a 64bit compiled AutoIT use the 64bit cmd.exe?

You are lost in some gray area where all is mixed up and only something make sense.

But to paraphrase the spoon boy: "Don't try and bend the spoon, you'll fuck something up. All is good, bend yourself."


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

I'm starting to think Tripredacus doesn't know about the "File System Redirector" and such things employed by x64 Windows, which would explain (some) of his confusion or whatever you wanna call it.

Here's a nice msdn article: Programming Guide for 64-bit Windows, pay special attention to the "Running 32-bit Applications"-part.

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

I'm having a sort of same problem with the topic author. I'm trying to run bcdedit command as a part of the script, but the problem in x64 (Vista & Win7) is that file just ain't there.

If I start cmd.exe (under \windows\system32) from start menu, and list \windows\system32 folder contents, it founds 2237 files and 88 folders.

But if I start cmd.exe from AutoIT (with @ComSpec pointing to \windows\system32\cmd.exe), file contains only 1984 files and 80 directories. Orwell would be proud.

If I start \windows\syswow64\cmd.exe from autoit, result is the same as with @ComSpec. Neither can FileExists function locate it.

http://horna.kicks-ass.net/tmp/diff_in_dir.jpg

output of set-command, diff -u between results of "native" and "script" started command prompts;

--- set_nat.txt 2010-04-08 19:27:59.000000000 +0300

+++ set_sci.txt 2010-04-08 19:28:00.000000000 +0300

@@ -1,7 +1,8 @@

ALLUSERSPROFILE=C:\ProgramData

APPDATA=C:\Users\John\AppData\Roaming

-CommonProgramFiles=C:\Program Files\Common Files

+CommonProgramFiles=C:\Program Files (x86)\Common Files

CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files

+CommonProgramW6432=C:\Program Files\Common Files

COMPUTERNAME=WIN-VISTA-MJ

ComSpec=C:\Windows\system32\cmd.exe

DFSTRACINGON=FALSE

@@ -14,13 +15,15 @@

OS=Windows_NT

Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem

PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

-PROCESSOR_ARCHITECTURE=AMD64

+PROCESSOR_ARCHITECTURE=x86

+PROCESSOR_ARCHITEW6432=AMD64

PROCESSOR_IDENTIFIER=AMD64 Family 15 Model 67 Stepping 3, AuthenticAMD

PROCESSOR_LEVEL=15

PROCESSOR_REVISION=4303

ProgramData=C:\ProgramData

-ProgramFiles=C:\Program Files

+ProgramFiles=C:\Program Files (x86)

ProgramFiles(x86)=C:\Program Files (x86)

+ProgramW6432=C:\Program Files

PROMPT=$P$G

PUBLIC=C:\Users\Public

SystemDrive=C:

Could PROCESSOR_ARCHITECTURE=x86 be causing the problem like this? And any ideas, how to workaround it?

In 32-bit environments (XP, Vista, Win7, 2003, 2008) everything works fine.

Also, if I copy bcdedit.exe from \windows\system32 with start menu-launched command prompt to e.g. root of C-drive, also autoit-started cmd.exe can see and execute the file.

Edited by maerkus

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

I guess it has to do with OS low-level file redirection under Win64, stumbled over that while doing some research for ICU...

Compile this code to win32.exe and win64.exe using the respective Output arch (32 and 64 bit :) ). Prerequisite is of course that you're running a 64bit OS to test it :( ...

#include <Constants.au3>

Global $res_1, $res_2, $res_3

$foo = Run(@ComSpec & " /c dir", @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
$line = ""
While 1
    $line &= StdoutRead($foo)
    If @error Then ExitLoop
Wend
$aSplit = StringSplit($line,@crlf)
for $i = 0 to $aSplit[0]
    if StringInStr($aSplit[$i]," Bytes") then
        ConsoleWrite($aSplit[$i] & @crlf)
        $res_1 = $aSplit[$i]
        ExitLoop
    endif
Next
ConsoleWrite(@CRLF)

$foo = Run("c:\windows\system32\cmd.exe /c dir", @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
$line = ""
While 1
    $line &= StdoutRead($foo)
    If @error Then ExitLoop
Wend
$aSplit = StringSplit($line,@crlf)
for $i = 0 to $aSplit[0]
    if StringInStr($aSplit[$i]," Bytes") then
        ConsoleWrite($aSplit[$i] & @crlf)
        $res_2 = $aSplit[$i]
        ExitLoop
    endif
Next
ConsoleWrite(@CRLF)

$foo = Run("c:\windows\SysWOW64\cmd.exe /c dir", @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
$line = ""
While 1
    $line &= StdoutRead($foo)
    If @error Then ExitLoop
Wend
$aSplit = StringSplit($line,@crlf)
for $i = 0 to $aSplit[0]
    if StringInStr($aSplit[$i]," Bytes") then
        ConsoleWrite($aSplit[$i] & @crlf)
        $res_3 = $aSplit[$i]
        ExitLoop
    endif
Next
ConsoleWrite(@CRLF)

MsgBox(0,"Res",$res_1 & @crlf  & @crlf & $res_2  & @crlf  & @crlf & $res_3)
ClipPut($res_1 & @crlf  & @crlf & $res_2  & @crlf  & @crlf & $res_3)

Result of win32.exe on my system is

2196 Datei(en),    917.095.910 Bytes
2196 Datei(en),    917.095.910 Bytes
2196 Datei(en),    917.095.910 Bytes

Result of win64.exe on my system is

2597 Datei(en),  1.173.304.438 Bytes
2597 Datei(en),  1.173.304.438 Bytes
2196 Datei(en),    917.095.910 Bytes

where the results are created respectivly by

@ComSpec & " /c dir"
"c:\windows\system32\cmd.exe /c dir"
"c:\windows\SysWOW64\cmd.exe /c dir"

... and you'll have to know, that Win64 stores it's 32bit exes in SysWOW64, sounds strange but it's a fact.

So the only way to ensure the 32bit version of cmd.exe is called is to use c:\windows\SysWOW64\cmd.exe on a 64bit system. Make a switch at top of the script like this:

Global $comspec = @ComSpec
if StringInStr(@OSArch,"64") then $comspec = @WindowsDir & "\SysWOW64\cmd.exe"

and use $comspec instead of @comspec...

Edit:

$comspec = @WindowsDir & "\SysWOW64\cmd.exe" looks more compatible then $comspec = "c:\windows\SysWOW64\cmd.exe" :)...

Edited by KaFu

Share this post


Link to post
Share on other sites

If I start cmd.exe (under \windows\system32) from start menu, and list \windows\system32 folder contents, it founds 2237 files and 88 folders.

But if I start cmd.exe from AutoIT (with @ComSpec pointing to \windows\system32\cmd.exe), file contains only 1984 files and 80 directories. Orwell would be proud.

The attempts will be redirected if you are running a 32 bit process. To prevent this redirection when suitable, disable it and immediately revert it when done.

This has been tested on Win7 64bit with AutoIt 32bit and 64 bit. The 2nd RunWait() run under 32bit AutoIt will not find bcdedit.exe as the redirection is reverted to enabled.

; disable filesystem redirection for 32 bit process
_Wow64FsRedirection(False)
; run bcdedit with redirection disabled
RunWait('"' & @ComSpec & '" /k bcdedit.exe')
; revert filesystem redirection for 32 bit process
_Wow64FsRedirection(True)
Sleep(500)
; run bcdedit with redirection enabled
RunWait('"' & @ComSpec & '" /k bcdedit.exe')

Func _Wow64FsRedirection($state)
    ; Disables or reverts the filesystem redirector for a 32 bit process running on 64bit OS
    If Not @AutoItX64 And @OSArch = 'X64' Then
        If $state Then
            DllCall("kernel32.dll", "int", "Wow64RevertWow64FsRedirection", "int", 0)
        Else
            DllCall("kernel32.dll", "int", "Wow64DisableWow64FsRedirection", "int", 0); or 1 as per help
        EndIf
        If @error Then Return SetError(1)
    EndIf
EndFunc
2 people like this

Share this post


Link to post
Share on other sites

This has been tested on Win7 64bit with AutoIt 32bit and 64 bit. The 2nd RunWait() run under 32bit AutoIt will not find bcdedit.exe as the redirection is reverted to enabled.

Great, this one solved the problem. Thanks!

Share this post


Link to post
Share on other sites

Awesome solution MHz!!! I spent such a long time trying to get @compsec to do this! Thanks heaps

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
Sign in to follow this  
Followers 0