Unattended Login to OneDrive with Username and Password - Feasibility test

Marcel Meurer's picture

In February I wrote a PowerShell module for the PowerShellGallery which makes some commands available to interact with OneDrive (https://www.sepago.com/blog/2016/02/21/Use-PowerShell-Module-OneDrive-from-PowerShellGallery-command-line). The command Get-ODAuthentication authenticates the user to OneDrive by opening a browser window for the live login, so that the user can enter the credentials. As far as I know it’s currently not possible to login automatically via a script.

In this blog I offer a “dirty” solution to login automatically. But careful: This method uses an Internet Explorer com object to perform the login process. If Microsoft changes something, the automatic login can fail. I also assume that this way is (for sure) not supported by Microsoft nor desired. I used this challenge to train PowerShell and Internet Explorer remoting – which is very spooky (IE 11 on Win10 and Server handles events differently, etc.). 

I tested the script with the following OS:

  • Windows 10: Englisch, Deutsch, IE11
  • Windows Server 2012 R2: Englisch, Deutsch, IE11

The script performs the following steps:

  1. Open a single IE instance and log a possible user out
  2. Go to the login page
  3. Fill out the form (username and password)
  4. Send “change” events to the fields
  5. Press submit
  6. Confirm access
  7. Extract the access token

$DebugPreference = "Continue"

#Variables
$LoginName="Marcel.Meurer@sepago.de"
$Password="------------"
$ClientID="00000000XXXXXXXXXXXXXXX"

#Add *.live.com and *.gfx.ms to trusted sites
New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains" -Name "live.com" –Force | Out-Null
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains\live.com" -Name "https" -Value 2
New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains" -Name "gfx.ms" –Force | Out-Null
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains\gfx.ms" -Name "https" -Value 2
#Enable protected mode for trusted sites
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\2" -Name "2500" -Value 0


$URIGetAccessToken="https://login.live.com/oauth20_authorize.srf?client_id="+$ClientID+"&scope=onedrive.readwrite&response_type=token&redirect_uri=https://login.live.com/oauth20_desktop.srf"

#Create IE Com-object
$ie = New-Object -com "InternetExplorer.Application.1" 
$ieLogout = New-Object -com "InternetExplorer.Application.1" 
$ie.visible = $false
$ie.silent = $true

write-debug ("Logout first")
$ieLogout.Navigate("https://login.live.com/logout.srf")
while($ieLogout.busy){Start-Sleep 1} 
$ieLogout.Quit()

write-debug ("Go to login page")
$ie.Navigate($URIGetAccessToken)
while($ie.busy){Start-Sleep 1} 

#Check, if function createEvent exist
$legacy=$false
try {$ie.document.createEvent()| Out-Null} catch {$legacy=$true}

if ($legacy) {write-debug ("Working in legacy mode")}

if (!$legacy) {
    #Prepare event
    $evt = $ie.document.createEvent("HTMLEvents")
    $evt.initEvent("change",$true,$false)
}

write-debug ("Filling the formular")
$ie.Document.IHTMLDocument3_getElementsByName("login").item().Value=$LoginName
$ie.Document.IHTMLDocument3_getElementsByName("loginfmt").item().Value=$LoginName
$ie.Document.IHTMLDocument3_getElementsByName("passwd").item().Value=$Password

write-debug ("Sending change events to the fields")
if ($legacy)
{
    $ie.Document.IHTMLDocument3_getElementsByName("loginfmt").item().FireEvent("onChange") | Out-Null
    $ie.Document.IHTMLDocument3_getElementsByName("passwd").item().FireEvent("onChange") | Out-Null
} else
{
    $ie.Document.IHTMLDocument3_getElementsByName("loginfmt").item().DispatchEvent($evt) | Out-Null
    $ie.Document.IHTMLDocument3_getElementsByName("passwd").item().DispatchEvent($evt) | Out-Null
}


write-debug ("Press submit")
$ie.Document.IHTMLDocument3_getElementsByName("idSIButton9").item().click()
while($ie.busy){Start-Sleep 1} 

write-debug ("Confirm access")
$ie.Document.IHTMLDocument3_getElementsByName("ucaccept").item().click()
while($ie.busy){Start-Sleep 1} 


$ReturnURI=($ie.LocationURL).ToString().Replace("#","&")

$ie.Quit()


$Authentication = New-Object PSObject
ForEach ($element in $ReturnURI.Split("?")[1].Split("&")) 
{
	$Authentication | add-member Noteproperty $element.split("=")[0] $element.split("=")[1]
}
if ($Authentication.PSobject.Properties.name -match "expires_in")
{
	$Authentication | add-member Noteproperty "expires" ([System.DateTime]::Now.AddSeconds($Authentication.expires_in))
}
if (!($Authentication.PSobject.Properties.name -match "expires_in"))
{
	write-warning("There is maybe an errror, because there is no access_token!")
}
$Authentication.scope=$Authentication.scope.Replace("%20"," ")

$Authentication

Comments
Firefox Web Browser
Hello, thank you for your post. But, do you have solution for Firefox Web Browser? Thanks in advance.
Marcel Meurer's picture
Firefox
Sorry. I have only this for the ie because the object comes with windows. Marcel
Thank you verymuch!!. You
Thank you verymuch!!. You save my life :D
Hi. I got a problem is
Hi. I got a problem is "Method invocation failed because [System.__ComObject] does not contain a method named 'IHTMLDocument3_getElementsByName'.". i has tried to run as administrator, install .Net Framwork 4.1 but can't help anything. Can u help me know what is happening? Thank you so much!!
Marcel Meurer's picture
Hi PwnPP4fun.
Hi PwnPP4fun. If this problem exist send me a mail: marcel.meurer (at)sepago.de and I hope we can fix it. Marcel
Add new comment
By submitting this form, you accept the Mollom privacy policy.