Underpaid Posted March 28 Share Posted March 28 I have a project that requires I log into a specific wifi connection that is WPA2-enterprise PEAP. I have a username and a password that must be passed to authenticate. I have already created an XML to import the settings, so the profile is in place and that part works fine. Having searched around on this site, I found numerous other examples of using just a password or passphrase but nothing that seems to suggest using a username/password combo, nothing that works anyhow. The computer(s) that this will run on will all be standalone kiosk-likes, must reconnect daily, and must "repair" themselves as best it can. The end users are general menial workers that will not be able to enter the authentication (read: not trusted with the network password), hence the automation. I found this snippet to "work" but only if I click on the systray area to bring up the WiFi connection screen. Then the Windows Security box pops right up and populates, indicating that it "would" work. However this is not tenable as the user cannot interact with this. From the end-user's perspective it should "just work" with them not interacting with anything but the kiosk program. $sSSID = "TEST_SSID" $cmd = "netsh wlan connect name=" & $sSSID & " ssid=" & $sSSID $dosOut = Run(@ComSpec & " /c " & $cmd, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) ProcessWaitClose($dosOut) WinWaitActive("Windows Security") Send("username") Send("{TAB}") Send("password", 1) ;changed optional field of send function from 0 to 1. ;Send("{ENTER}") In my ideal scenario, there'd be a UDF or better yet a built-in Windows function that I could run that would accept the username and password. Is there a way to enter the credentials and pass it to the wifi all command line like? Am I just looking at this the wrong way? Link to comment Share on other sites More sharing options...
rsn Posted March 28 Share Posted March 28 When you say Wifi Connection screen, do you mean what pops up when this is run: "%windir%\explorer.exe" ms-availablenetworks: Link to comment Share on other sites More sharing options...
Underpaid Posted March 28 Author Share Posted March 28 Ooh, I didn't know of that little shortcut. I'll tuck that little nugget of wisdom away for later. But to answer the question, yes when I manually click that dialog it opens the Windows Security dialog. I've included that in my script and it does automagically pop the windows security dialog up. Worst case scenario that might work, still I'd rather it all be silent and invisible to the user. Link to comment Share on other sites More sharing options...
rsn Posted March 28 Share Posted March 28 I agree that fully silent is the best but Microsoft has made some weird decisions window and dialog wise in the last few years. In those cases I couldn't make it hidden, I used #include <AutoItConstants.au3> BlockInput($BI_DISABLE) ; ... code here ... BlockInput($BI_ENABLE) There may be other ways to programmatically access what availablenetworks does, but we're at my knowledge limit at this point. Perhaps poll the IP status and when it goes APIPA (or otherwise not connected, not sure how it might work in your environment) then run your not-quite-invisible script? As long as the users are aware, it might not be so bad. 🤞 Link to comment Share on other sites More sharing options...
Moderators SmOke_N Posted March 29 Moderators Share Posted March 29 (edited) You can't directly connect to your wifi through the command prompt (eg. netsh), however there's always some work around. I've never worked with NETSH before, but I played around for a while with it. I'll be honest, I've never been a fan of using the command prompts of apps, for some reason I feel like I have less control. These are make-shift udfs I just put together, some were my practice funcs, but if you look at the ones I point out at the top, they may help you. The last one, if the first two function calls fail, is one where you can create a tmp xml file, add that profile, run the netsh command then delete the tmp xml file. All of these worked on the my Windows 10 machine. Should work on Windows 11 too from what I was reading. expandcollapse popup;~ #RequireAdmin ; may need to have admin priviliges #include-once #include <AutoItConstants.au3> #include <StringConstants.au3> #include <FileConstants.au3> Global $gsMySSID_WifiName = "MyNetwork" ; obviously change it to your own network name If Not _AutNETSH_WLan_IsConnectedBy("SSID", $gsMySSID_WifiName) Then ConsoleWrite("Going to attempt to connect.." & @CRLF) _AutNETSH_WLan_ConnectionRequest($gsMySSID_WifiName) Sleep(5000) ; give it 5 seconds and check if it worked If Not _AutNETSH_WLan_IsConnectedBy("SSID", $gsMySSID_WifiName) Then ConsoleWrite("Still not connected, does the profile exist yet?" & @CRLF & _ "If the profile doesn't exist, or the password/username changes often, try using: " & @CRLF & _ "_AutNETSH_WLan_AddConnectionRequest() below somwwhere..." & @CRLF) EndIf EndIf Func _AutNETSH_WLan_IsConnectedBy($sType, $sFind, $sWkDir = Default) ; because @error may return error text ; we'll just return yes or no string If $sWkDir = Default Or $sWkDir = -1 Then $sWkDir = @UserProfileDir EndIf Local $iPID = Run("netsh wlan show interface", $sWkDir, @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD)) Local $aRead = _AutNETSH_WLan_STDRead($iPID) If @error Then Return SetError(1, 0, StringRegExpReplace($aRead[1], "(?s)^\s*|\s*$", "")) EndIf ; escape type and value to find $sType = __AutNETSH_WLan_EscapeDelimiters($sType) $sFind = __AutNETSH_WLan_EscapeDelimiters($sFind) Local $sStRE = "(*UCP)(?mi)\h*" & $sType & "\h*\:\h*" & $sFind & "\h*$" Return (StringRegExp($aRead[0], $sStRE) <> 0) EndFunc Func _AutNETSH_WLan_IsConnected($sWkDir = Default) ; because @error may return error text ; we'll just return yes or no string If $sWkDir = Default Or $sWkDir = -1 Then $sWkDir = @UserProfileDir EndIf Local $iPID = Run("netsh wlan show interface", $sWkDir, @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD)) Local $aRead = _AutNETSH_WLan_STDRead($iPID) If @error Then Return SetError(1, 0, StringRegExpReplace($aRead[1], "(?s)^\s*|\s*$", "")) EndIf Local Const $sStRE = "(*UCP)(?mi)\h*state\h*\:\h*(\w+)" Local $aRet = StringRegExp($aRead[0], $sStRE, $STR_REGEXPARRAYGLOBALMATCH) If Not IsArray($aRet) Then Return SetError(2, 0, "") EndIf Return $aRet[0] EndFunc Func _AutNETSH_WLan_ConnectionRequest($sSSID, $sWkDir = Default) If $sWkDir = Default Or $sWkDir = -1 Then $sWkDir = @UserProfileDir EndIf ; connect to profile Local $iPID = Run('netsh wlan connect name="' & $sSSID & '"', $sWkDir, @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD)) Local $aRead = _AutNETSH_WLan_STDRead($iPID) If @error Then Return SetError(1, 0, StringRegExpReplace($aRead[1], "(?s)^\s*|\s*$", "")) EndIf Return $aRead[0] EndFunc Func _AutNETSH_WLan_AddConnectionRequest($sSSID, $sPassword, $sConnectionType = Default, _ $sConnectionMode = Default, $sAuthentication = Default, _ $sEncryption = Default, $sUseOneX = Default, $sKeyType = Default, _ $sProtected = Default, $sEnableRandomization = Default, _ $sWkDir = Default, $sTmpPath = Default) If $sConnectionType = Default Or $sConnectionType = -1 Then $sConnectionType = "ESS" EndIf If $sConnectionMode = Default Or $sConnectionMode = -1 Then $sConnectionMode = "auto" EndIf If $sAuthentication = Default Or $sAuthentication = -1 Then $sAuthentication = "WPA2PSK" EndIf If $sEncryption = Default Or $sEncryption = -1 Then $sEncryption = "AES" EndIf If $sUseOneX = Default Or $sUseOneX = -1 Then $sUseOneX = "false" EndIf If $sKeyType = Default Or $sKeyType = -1 Then $sKeyType = "passPhrase" EndIf If $sProtected = Default Or $sProtected = -1 Then $sProtected = "false" EndIf If $sEnableRandomization = Default Or $sEnableRandomization = -1 Then $sEnableRandomization = "false" EndIf If $sWkDir = Default Or $sWkDir = -1 Then $sWkDir = @UserProfileDir EndIf If $sTmpPath = Default Or $sTmpPath = -1 Or Not FileExists($sTmpPath) Then $sTmpPath = @ScriptDir EndIf Local $sXMLFile = "WLAN." & StringRegExpReplace($sSSID, "(*UCP)\W", "") $sXMLFile &= ".tmp(" & @YEAR & @MON & @MDAY & @HOUR & @MIN & @SEC & @MSEC & ").xml" Local $sOutXML = StringRegExpReplace($sTmpPath, "[\\/]+$", "") & "\" & $sXMLFile Local $sXML = "" $sXML &= '<?xml version="1.0"?>' & @CRLF $sXML &= ' <WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">' & @CRLF $sXML &= ' <name>' & $sSSID & '</name>' & @CRLF $sXML &= ' <SSIDConfig>' & @CRLF $sXML &= ' <SSID>' & @CRLF $sXML &= ' <name>' & $sSSID & '</name>' & @CRLF $sXML &= ' </SSID>' & @CRLF $sXML &= ' </SSIDConfig>' & @CRLF $sXML &= ' <connectionType>' & $sConnectionType & '</connectionType>' & @CRLF $sXML &= ' <connectionMode>' & $sConnectionMode & '</connectionMode>' & @CRLF $sXML &= ' <MSM>' & @CRLF $sXML &= ' <security>' & @CRLF $sXML &= ' <authEncryption>' & @CRLF $sXML &= ' <authentication>' & $sAuthentication & '</authentication>' & @CRLF $sXML &= ' <encryption>' $sEncryption & '</encryption>' & @CRLF $sXML &= ' <useOneX>' & $sUseOneX & '</useOneX>' & @CRLF $sXML &= ' </authEncryption>' & @CRLF $sXML &= ' <sharedKey>' & @CRLF $sXML &= ' <keyType>' & $sKeyType & '</keyType>' & @CRLF $sXML &= ' <protected>' & $sProtected & '</protected>' & @CRLF $sXML &= ' <keyMaterial>' & $sPassword & '</keyMaterial>' & @CRLF $sXML &= ' </sharedKey>' & @CRLF $sXML &= ' </security>' & @CRLF $sXML &= ' </MSM>' & @CRLF $sXML &= ' <MacRandomization xmlns="http://www.microsoft.com/networking/WLAN/profile/v3">' & @CRLF $sXML &= ' <enableRandomization>' & $sEnableRandomization & '</enableRandomization>' & @CRLF $sXML &= ' </MacRandomization>' & @CRLF $sXML &= '</WLANProfile>' Local $hOpen = FileOpen($sOutXML, $FO_OVERWRITE) FileWrite($hOpen, $sXML) FileClose($hOpen) ; add profile to cache Local $iPID = Run('netsh wlan add profile filename="' & $sOutXML & '"', $sWkDir, @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD)) Local $aRead = _AutNETSH_WLan_STDRead($iPID) If @error Then FileDelete($sOutXML) Return SetError(1, 0, StringRegExpReplace($aRead[1], "(?s)^\s*|\s*$", "")) EndIf Local $sRet = $aRead[0] ; connect to profile $iPID = Run('netsh wlan connect name="' & $sSSID & '"', $sWkDir, @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD)) $aRead = _AutNETSH_WLan_STDRead($iPID) If @error Then FileDelete($sOutXML) Return SetError(2, 0, StringRegExpReplace($aRead[1], "(?s)^\s*|\s*$", "")) EndIf FileDelete($sOutXML) $sRet &= " : " & $aRead[0] Return $sRet EndFunc Func _AutNETSH_WLan_ShowNetworks($sWkDir = Default) ; return network array If $sWkDir = Default Or $sWkDir = -1 Then $sWkDir = @UserProfileDir EndIf Local $iPID = Run("netsh wlan show networks", $sWkDir, @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD)) Local $aRead = _AutNETSH_WLan_STDRead($iPID) If @error Or Not IsArray($aRead) Then Return SetError(1, @error, StringRegExpReplace($aRead[1], "(?s)^\s*|\s*$", "")) EndIf Local Const $sSSIDRE = "(?si)(SSID\h*\d+\h*\:\h*.+?)(?:\v{3,}|$)" Local $aSSIDs = StringRegExp($aRead[0], $sSSIDRE, $STR_REGEXPARRAYGLOBALMATCH) If @error Or Not IsArray($aSSIDs) Then Return SetError(2, @error, "") EndIf Local $aHeaders = __AutNETSH_WLan_stdoutgetheader($aSSIDs) If @error Then Return SetError(3, @error, "") EndIf Local $aHData = __AutNETSH_WLan_stdoutgethdata($aSSIDs, $aHeaders) If @error Then Return SetError(4, @error, "") EndIf Return $aHData EndFunc ; See RunAs() in help file, may need to sign on as admin acct Func _AutNETSH_WLan_ShowNetworksAsUser($sUserName, $sDomain, $sPassword, $sLogonFlag, $sWkDir = Default) ; return network array If $sWkDir = Default Or $sWkDir = -1 Then $sWkDir = @UserProfileDir EndIf Local $iPID = RunAs($sUserName, $sDomain, $sPassword, $sLogonFlag, _ "netsh wlan show networks", $sWkDir, @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD)) Local $aRead = _AutNETSH_WLan_STDRead($iPID) If @error Or Not IsArray($aRead) Then Return SetError(1, 0, StringRegExpReplace($aRead[1], "(?s)^\s*|\s*$", "")) EndIf Local Const $sSSIDRE = "(?si)(SSID\h*\d+\h*\:\h*.+?)(?:\v{3,}|$)" Local $aSSIDs = StringRegExp($aRead[0], $sSSIDRE, $STR_REGEXPARRAYGLOBALMATCH) If @error Or Not IsArray($aSSIDs) Then Return SetError(2, @error, "") EndIf Local $aHeaders = __AutNETSH_WLan_stdoutgetheader($aSSIDs) If @error Then Return SetError(3, @error, "") EndIf Local $aHData = __AutNETSH_WLan_stdoutgethdata($aSSIDs, $aHeaders) If @error Then Return SetError(4, @error, "") EndIf Return $aHData EndFunc Func _AutNETSH_WLan_STDRead($iPID) $iPID = ProcessExists($iPID) If Not $iPID Then Return SetError(1, 0, 0) EndIf Local $sTmp, $sORead, $sOErr While ProcessExists($iPID) $sTmp = StdoutRead($iPID) If @error Then $sOErr = StderrRead($iPID) ExitLoop EndIf $sORead &= $sTmp WEnd ; clean up leading and traling $sORead = StringRegExpReplace($sORead, "(?s)^\s*|\s*$", "") $sOErr = StringRegExpReplace($sOErr, "(?s)^\s*|\s*$", "") Local $aRet[2] = [$sORead, $sOErr] If StringLen($sORead) = 0 Then Return SetError(1, 0, $aRet) EndIf Return $aRet EndFunc Func __AutNETSH_WLan_stdoutgetheader(ByRef $aData) If Not IsArray($aData) Then Return SetError(1, 0, 0) EndIf ; how many heades, some will have more/less based on connection type Local $iExt, $iHeaderCount = 0, $aHeaders For $i = 0 To UBound($aData) - 1 StringRegExpReplace($aData[$i], "(?m)\h+\:", "") $iExt = @extended If $iExt > $iHeaderCount Then $iHeaderCount = $iExt $aHeaders = StringRegExp($aData[$i], "(?m)\h*(.+?)\h+\:", $STR_REGEXPARRAYGLOBALMATCH) If IsArray($aHeaders) Then For $j = 0 To UBound($aHeaders) - 1 If StringInStr($aHeaders[$j], "SSID") Then $aHeaders[$j] = "SSID" ExitLoop EndIf Next EndIf EndIf Next If $iHeaderCount = 0 Then Return SetError(2, 0, 0) EndIf Return SetExtended($iHeaderCount, $aHeaders) EndFunc Func __AutNETSH_WLan_stdoutgethdata(ByRef $aData, ByRef $aHeaders) If Not IsArray($aData) Then Return SetError(1, 0, 0) EndIf If Not IsArray($aHeaders) Then Return SetError(2, 0, 0) EndIf ; [0][n] = headers Local $aRet[UBound($aData) + 1][UBound($aHeaders)] ; fill headers into ret array For $i = 0 To UBound($aHeaders) - 1 $aRet[0][$i] = $aHeaders[$i] ; turn headers into escaped chars $aHeaders[$i] = __AutNETSH_WLan_EscapeDelimiters($aHeaders[$i]) Next Local $aFound, $aLines, $iEnum, $iColCount = 0 ; start at 1, 0 is headers For $i = 0 To UBound($aData) - 1 $iEnum = 0 ; split into individual rows $aLines = StringRegExp($aData[$i], "\h*(.+?)\h*(\v+|$)", $STR_REGEXPARRAYGLOBALMATCH) For $x = 0 To UBound($aLines) - 1 For $j = 0 To UBound($aHeaders) - 1 If StringRegExp($aLines[$x], "(?i)^\h*" & $aHeaders[$j]) Then $aFound = StringRegExp($aLines[$x], "(?mi)\h*" & $aHeaders[$j] & ".*?\:\h*(.+?)\h*$", $STR_REGEXPARRAYGLOBALMATCH) If @error Or Not IsArray($aFound) Then ContinueLoop $aRet[$i + 1][$j] = $aFound[0] $iEnum += 1 ExitLoop EndIf Next Next If $iEnum > 0 Then $iColCount += 1 Next If $iColCount < UBound($aData) Then ; oops EndIf Return $aRet EndFunc Func __AutNETSH_WLan_EscapeDelimiters($sData) Local Const $sRE = "([\\\.\^\$\|\[|\]\(\)\{\}\*\+\?\#])" Local Const $sRep = "\\$1" Return StringRegExpReplace($sData, $sRE, $sRep) EndFunc If you're going to do this across a private network, you may want to look into RunAs(), I have one example function in there with that that you can kind of get the idea from. Anyway, I did more than I thought I would for something I can never see myself using... so hope it helps. Edit: You may need to change this section for enterprise: $sXML &= ' <authEncryption>' & @CRLF $sXML &= ' <authentication>WPA2PSK</authentication>' & @CRLF $sXML &= ' <encryption>AES</encryption>' & @CRLF $sXML &= ' <useOneX>false</useOneX>' & @CRLF $sXML &= ' </authEncryption>' & @CRLF I'm to lazy to make something that does it atm. Edit2: Changed _AutNETSH_WLan_AddConnectionRequest() so you can customize all the xml options if needed. I'm not 100% on WPA2 Enterprise, but it looks like you can change Authentication = WPA2 and Encryption to TKIP... anyway, really really really done this time Edited March 29 by SmOke_N argumentum, rsn and guaikahenguai 3 Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer. Link to comment Share on other sites More sharing options...
rsn Posted March 29 Share Posted March 29 @Underpaid So I was thinking about how it can't possibly be that Windows can't do true enterprise Wi-Fi management on the command line and I remembered that it's something it did do up until about 6 ish years ago. Microsoft had a tool pre-1809 that only shipped in the IoT build of LTSB: netcmd.exe! Spoiler expandcollapse popupNetCmd.exe /ActionType:Help Running command Help /ActionType:<AddProfile,DeleteProfile,DeleteAllProfiles,ExportProfiles,ConnectProfile,ConnectName,Disconnect,ShowInterfaces,ShowProfiles,SetAutoConfig,ShowNetworks,ShowNetDevices,ShowSystemCapabilities,ShowAdapterCapabilities,ShowRoutes,AddRoute,DeleteRoute,Help> /ActionType:AddProfile /FilePath:<String> [/Password:<String>] (short form /p) [/UserName:<String>] (short form /u) [/Domain:<String>] (short form /d) [/Enterprise:<Boolean>] (short form /e) [/InterfaceName:<String>] (short form /i) /ActionType:DeleteProfile /ProfileName:<String> [/InterfaceName:<String>] (short form /i) /ActionType:DeleteAllProfiles [/InterfaceName:<String>] (short form /i) /ActionType:ExportProfiles /FilePath:<String> [/InterfaceName:<String>] (short form /i) /ActionType:ConnectProfile /ProfileName:<String> [/Password:<String>] (short form /p) [/UserName:<String>] (short form /u) [/Domain:<String>] (short form /d) [/Enterprise:<Boolean>] (short form /e) [/InterfaceName:<String>] (short form /i) /ActionType:ConnectName /Ssid:<String> [/ManualConnect:<Boolean>] (short form /m) [/Password:<String>] (short form /p) [/UserName:<String>] (short form /u) [/Domain:<String>] (short form /d) [/Enterprise:<Boolean>] (short form /e) [/RootCAS:<String>] (short form /r) [/InterfaceName:<String>] (short form /i) /ActionType:Disconnect [/InterfaceName:<String>] (short form /i) /ActionType:ShowInterfaces /ActionType:ShowProfiles [/InterfaceName:<String>] (short form /i) /ActionType:SetAutoConfig /AutoConfig:<Boolean> [/InterfaceName:<String>] (short form /i) /ActionType:ShowNetworks [/InterfaceName:<String>] (short form /i) /ActionType:ShowNetDevices /ActionType:ShowSystemCapabilities /ActionType:ShowAdapterCapabilities /ActionType:ShowRoutes [/InterfaceName:<String>] (short form /i) /ActionType:AddRoute /Destination:<IPAddress> /Gateway:<IPAddress> /PrefixLength:<UInt16> /AdapterIndex:<Int32> /ActionType:DeleteRoute /Destination:<IPAddress> /Gateway:<IPAddress> /PrefixLength:<UInt16> /AdapterIndex:<Int32> /ActionType:Help  It looks like if you can secure a copy of the above, "/ActionType:ConnectName" or "/ActionType:ConnectProfile" would be the way to quietly do what you want. Link to comment Share on other sites More sharing options...
Moderators SmOke_N Posted March 29 Moderators Share Posted March 29 (edited) wpa+tkip or wpa2+tkip does give authentication of WPA/WPA2 Enterprise Edited March 29 by SmOke_N Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer. 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