# Creates a web session with given cookie header function Create-WebSession { [cmdletbinding()] Param( [Parameter(Mandatory=$True)] [string]$SetCookieHeader, [Parameter(Mandatory=$True)] [string]$Domain ) Process { $session = New-Object Microsoft.PowerShell.Commands.WebRequestSession # login.live.com: MSPRequ=lt=1540361812&co=1&id=N; secure= ;path=/;HTTPOnly=;version=1,uaid=bf4b7f37ec1d4084aa68952b9edebb6b; domain=login.live.com;secure= ;path=/;HTTPOnly= ;version=1,MSPOK=$uuid-f4f5ef25-7343-4de8-84cb-266ea1b47bc2; domain=login.live.com;secure= ;path=/;HTTPOnly= ;version=1 if($domain -eq "login.live.com") { $SetCookie = $SetCookieHeader.Split(";,") foreach($Cookie in $SetCookie) { $name = $Cookie.Split("=")[0].trim() $value = $Cookie.Substring($name.Length+1) switch($name) { "secure" {} "path" {} "HTTPOnly" {} "domain" {} "version" {} default { $webCookie = New-Object System.Net.Cookie $webCookie.Name = $name $webCookie.Value = $value $webCookie.Domain = $Domain $session.Cookies.Add($webCookie) Write-Verbose "COOKIE [$Domain]: $webCookie" } } } } elseif($domain.EndsWith(".sharepoint.com")) # Sharepoint { $SetCookie = $SetCookieHeader.Replace("HttpOnly","|").Split("|") foreach($Cookie in $SetCookie) { if(![String]::IsNullOrEmpty($Cookie)) { $Cookie = $Cookie.Split(";")[0].trim() $name = $Cookie.Split("=")[0].trim() $value = $Cookie.Substring($name.Length+1) # Strip the trailing semi colon $value=$value.Split(";")[0] $webCookie = New-Object System.Net.Cookie $webCookie.Name = $name $webCookie.Value = $value $webCookie.Domain = $Domain $session.Cookies.Add($webCookie) Write-Verbose "COOKIE [$Domain]: $webCookie" } } } else # login.microsoftonline.com: { # Split the cookie string $SetCookie = $SetCookieHeader.Replace("HttpOnly","|").Split("|") foreach($Cookie in $SetCookie) { # Split the individual cookie and remove possible trailing comma $Cookie=($Cookie.Split(";")[0]).Replace(',','') if(![string]::IsNullOrEmpty($Cookie)) { $webCookie = New-Object System.Net.Cookie $webCookie.Name = $Cookie.Split("=")[0] $webCookie.Value = $Cookie.Substring($webCookie.Name.Length+1) $webCookie.Domain = $Domain $session.Cookies.Add($webCookie) Write-Verbose "COOKIE [$Domain]: $webCookie" } } } return $session } } # Creates a web session with given cookie header function Create-WebSession2 { [cmdletbinding()] Param( [Parameter(Mandatory=$True)] [System.Security.]$Headers, [Parameter(Mandatory=$True)] [string]$Domain ) Process { $session = New-Object Microsoft.PowerShell.Commands.WebRequestSession # Split the cookie string $SetCookie = $SetCookieHeader $SetCookie = $SetCookie.Replace("HttpOnly","|").Replace("HTTPOnly","|").Split("|") foreach($Cookie in $SetCookie) { # Split the individual cookie and remove possible trailing comma $Cookie=($Cookie.Split(";")[0]).Replace(',','') if(![string]::IsNullOrEmpty($Cookie)) { $webCookie = New-Object System.Net.Cookie $webCookie.Name = $Cookie.Split("=")[0] $webCookie.Value = $Cookie.Split("=")[1] $webCookie.Domain = $Domain $session.Cookies.Add($webCookie) } } return $session } } # Gets the access token for Azure Management API # Uses totally different flow than other access tokens. # Oct 23rd 2018 # TODO: Add support for form based & SAML authentication function Get-AccessTokenForAzureMgmtAPI { <# .SYNOPSIS Gets OAuth Access Token for Azure Management API .DESCRIPTION Gets OAuth Access Token for Azure Management API .Parameter Credentials Credentials of the user. .Example PS C:\>$cred=Get-Credential PS C:\>Get-AADIntAccessTokenForAzureMgmtAPI -Credentials $cred #> [cmdletbinding()] Param( [Parameter()] [System.Management.Automation.PSCredential]$Credentials, [Parameter()] [Switch]$SaveToCache ) Process { $accessToken="" $refreshToken="" # Check if we got credentials if([string]::IsNullOrEmpty($Credentials) -and [string]::IsNullOrEmpty($SAMLToken)) { # No credentials given, so prompt for credentials $tokens = Prompt-AzureADCredentials $accessToken = $tokens["access_token"] $refreshToken = $tokens["refresh_token"] } else { $userName = $Credentials.UserName $password = $credentials.GetNetworkCredential().Password # Step 1: Go to portal.azure.com to get cookies and authentication url $headers=@{ "Sec-Fetch-Dest" = "script" "Sec-Fetch-Site" = "same-origin" "Sec-Fetch-Mode" = "no-cors" "Referer"="https://portal.azure.com" } $response = Invoke-WebRequest -UseBasicParsing -uri "https://portal.azure.com/signin/idpRedirect.js/?feature.settingsportalinstance=&feature.refreshtokenbinding=true&feature.usemsallogin=true&feature.snivalidation=true&feature.setsamesitecookieattribute=true&feature.argsubscriptions=&feature.showservicehealthalerts=&idpRedirectCount=0" -Headers $headers $html=$response.Content $s=$html.IndexOf('https://login.microsoftonline.com') $e=$html.IndexOf('"',$s) $url=$html.Substring($s,$e-$s) $azureWebSession = Create-WebSession -SetCookieHeader $response.Headers.'Set-Cookie' -Domain "portal.azure.com" # Step 2: Go to login.microsoftonline.com to get configuration and cookies $response = Invoke-WebRequest -UseBasicParsing -uri $url -Headers @{Cookie="x-ms-gateway-slice=004; stsservicecookie=ests; AADSSO=NANoExtension; SSOCOOKIEPULLED=1"} $html = $response.Content $s=$html.IndexOf('$Config=') $e=$html.IndexOf('};',$s+8) $config=$html.Substring($s+8,$e-$s-7) | ConvertFrom-Json $MSOnlineComwebSession = Create-WebSession -SetCookieHeader $response.Headers.'Set-Cookie' -Domain "login.microsoftonline.com" # Step3: Get user information, including Flow Token $userInfo=Get-CredentialType -UserName $userName -FlowToken $config.sFT # LOGIN.LIVE.COM if($userInfo.EstsProperties.DomainType -eq 2) # =live account { # Step L1: Go to login.live.com to get configuration and cookies $response = Invoke-WebRequest -UseBasicParsing -uri $config.urlGoToAADError $html = $response.Content $s=$html.IndexOf('ServerData =') $e=$html.IndexOf('};',$s+13) $config=$html.Substring($s+13,$e-$s-12) # ConvertFrom-Json is caseinsensitive so need to use this one $config = (New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer -Property @{MaxJsonLength=67108864}).DeserializeObject($config) $liveWebSession = Create-WebSession -SetCookieHeader $response.Headers.'Set-Cookie' -Domain "login.live.com" $sFTTag= [xml]$config.sFTTag $PPFT = $sFTTag.SelectSingleNode("//input[@name='PPFT']").value # Step L2: Login to login.live.com $body=@{ "login" = $userName "loginFmt" = $userName "i13"="0" "type"="11" "LoginOptions"="3" "passwd"=$password "ps"="2" "canary"="" "ctx"="" "NewUser"="1" "fspost"="0" "i21"="0" "CookieDisclosure"="1" "IsFidoSupported"="1" "hpgrequestid"="" "PPSX"="Pa" "PPFT"=$PPFT "i18"="__ConvergedLoginPaginatedStrings|1,__OldConvergedLogin_PCore|1," "i2"="1" } $headers=@{ "User-Agent"="Mozilla/5.0 (Windows NT 10.0; Win64; x64)" "Upgrade-Insecure-Requests" = "1" } $response = Invoke-WebRequest -UseBasicParsing -Uri $config.urlPost -Method Post -ContentType "application/x-www-form-urlencoded" -Body $body -Headers $headers -WebSession $liveWebSession $html = $response.Content # No well formed xml, so need to do some tricks.. First, find the form start and end tags $s=$html.IndexOf("