Public/Connect-Windows365.ps1
function Connect-Windows365 { <# .SYNOPSIS Connect to Windows 365 via Powershell .DESCRIPTION Connect to Windows 365 via Powershell via Interactive Browser or Service Principal .PARAMETER Authtype Type of Authentication to use Interactive, ServicePrincipal or DeviceCode .PARAMETER ClientSecret Client Secret for Service Principal Authentication .PARAMETER TenantID Tenant ID for all Authentication types .PARAMETER ClientID Client ID for Service Principal Authentication .EXAMPLE Connect-Windows365 -TenantID contoso.onmicrosoft.com .EXAMPLE Connect-Windows365 -AuthType DeviceCode -TenantID contoso.onmicrosoft.com .EXAMPLE Connect-Windows365 -Authtype ServicePrincipal -TenantID contoso.onmicrosoft.com -ClientID 12345678-1234-1234-1234-123456789012 -ClientSecret 12345678-1234-1234-1234-123456789012 #> [CmdletBinding(DefaultParameterSetName = 'Interactive')] param ( [parameter(ParameterSetName = "Interactive")] [parameter(ParameterSetName = "ServicePrincipal")] [parameter(ParameterSetName = "DeviceCode")] [ValidateSet('ServicePrincipal', 'Interactive', 'DeviceCode')] [string]$Authtype = 'Interactive', [parameter(Mandatory, ParameterSetName = "ServicePrincipal")] [string]$ClientSecret, [parameter(Mandatory, ParameterSetName = "DeviceCode")] [parameter(Mandatory, ParameterSetName = "ServicePrincipal")] [string]$TenantID, [parameter(Mandatory, ParameterSetName = "ServicePrincipal")] [string]$ClientID ) begin { # Set the profile to beta Set-GraphVersion } process { switch ($Authtype) { Interactive { $environment = Get-ChildItem -Path C:\Windows -ErrorAction SilentlyContinue If ($null -eq $environment) { Write-Error "Using Powershell Core on Mac or Linux, please use the DeviceCode or ServicePrincipal Authentication" Break } else { Write-Verbose "Using Windows Powershell Core, continue with the script" } Write-Verbose "Use Interactive Authentication" Write-Verbose "Using Windows Powershell" # Add required assemblies $ClientID = "14d82eec-204b-4c2f-b7e8-296a70dab67e" $Scopes = "CloudPC.ReadWrite.All%20DeviceManagementConfiguration.ReadWrite.All%20DeviceManagementManagedDevices.ReadWrite.All%20Directory.Read.All" $redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient" # With User Interaction for Delegated Permission Add-Type -AssemblyName System.Web Function Get-AuthCode { Add-Type -AssemblyName System.Windows.Forms $form = New-Object -TypeName System.Windows.Forms.Form -Property @{Width = 640; Height = 840 } $web = New-Object -TypeName System.Windows.Forms.WebBrowser -Property @{Width = 620; Height = 800; Url = ($url -f ($Scope -join "%20")) } $DocComp = { $Script:uri = $web.Url.AbsoluteUri if ($Script:uri -match "error=[^&]*|code=[^&]*") { $form.Close() } } $web.ScriptErrorsSuppressed = $true $web.Add_DocumentCompleted($DocComp) $form.Controls.Add($web) $form.Add_Shown( { $form.Activate() }) $form.ShowDialog() | Out-Null $queryOutput = [System.Web.HttpUtility]::ParseQueryString($web.Url.Query) $output = @{} foreach ($key in $queryOutput.Keys) { $output["$key"] = $queryOutput[$key] } } $url = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=$($ClientID)&response_type=code&redirect_uri=$($redirectUri)&response_mode=query&scope=$($Scopes)&state=12345" Get-AuthCode # Extract Access token from the returned URI $regex = '(?<=code=)(.*)(?=&)' $authCode = ($uri | Select-string -pattern $regex).Matches[0].Value Write-Verbose "Received an authCode, $authCode" # get Access Token $body = "grant_type=authorization_code&redirect_uri=$redirectUri&client_id=$clientId&code=$authCode" $connection = Invoke-RestMethod https://login.microsoftonline.com/common/oauth2/token ` -Method Post -ContentType "application/x-www-form-urlencoded" ` -Body $body ` -ErrorAction STOP # Access Token $Token = $connection.access_token $script:Authtime = [System.DateTime]::UtcNow $script:Authtoken = $connection $script:Authheader = @{Authorization = "Bearer $($Token)" } } DeviceCode { Write-Verbose "Using Device Code" $clientId = "14d82eec-204b-4c2f-b7e8-296a70dab67e" $resource = "https://graph.microsoft.com/" $scope = "CloudPC.ReadWrite.All%20DeviceManagementConfiguration.ReadWrite.All%20DeviceManagementManagedDevices.ReadWrite.All%20Directory.Read.All" $codeBody = @{ resource = $resource client_id = $clientId scope = $scope } # Get OAuth Code $codeRequest = Invoke-RestMethod -Method POST -Uri "https://login.microsoftonline.com/$tenantId/oauth2/devicecode" -Body $codeBody # Print Code to console Write-Output "`n$($codeRequest.message)" $tokenBody = @{ grant_type = "urn:ietf:params:oauth:grant-type:device_code" code = $codeRequest.device_code client_id = $clientId } # Get OAuth Token while ([string]::IsNullOrEmpty($connection.access_token)) { $connection = try { Invoke-RestMethod -Method POST -Uri "https://login.microsoftonline.com/$tenantId/oauth2/token" -Body $tokenBody Write-Verbose "Completed Authentication" } catch { $errorMessage = $_.ErrorDetails.Message | ConvertFrom-Json # If not waiting for auth, throw error if ($errorMessage.error -ne "authorization_pending") { throw } } } $Token = $connection.access_token $script:Authtime = [System.DateTime]::UtcNow $script:Authtoken = $connection $script:Authheader = @{Authorization = "Bearer $($Token)" } } ServicePrincipal { $body = @{ Grant_Type = "client_credentials" Scope = "https://graph.microsoft.com/.default" Client_Id = $ClientID Client_Secret = $ClientSecret } $connection = Invoke-RestMethod ` -Uri https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token ` -Method POST ` -Body $body $Token = $connection.access_token $script:Authtime = [System.DateTime]::UtcNow $script:Authtoken = $connection $script:Authheader = @{Authorization = "Bearer $($Token)" } } } } } |