sources/Google.Solutions.IapDesktop.Extensions.Management/GuestOs/ActiveDirectory/DomainJoinService.StartupScript.ps1 (116 lines of code) (raw):

# # Copyright 2022 Google LLC # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # $ErrorActionPreference = "Stop" Import-Module "${Env:ProgramFiles}\Google\Compute Engine\sysprep\gce_base.psm1" $OperationId = "{{OPERATION_ID}}" $MetadataKey = "iapdesktop-join"; # # Create a new, ephemeral RSA key. # $Key = New-Object -TypeName System.Security.Cryptography.RSACng -ArgumentList 2048 $KeyParameters = $Key.ExportParameters($false) # # Write "hello" message to serial port. This message # contains the public key portion of the ephemeral RSA key. # The client uses that public key to encrypt credentials. # Write-SerialPort -portname COM4 -Data (@{ "OperationId" = $OperationId "MessageType" = "hello" "Modulus" = [Convert]::ToBase64String($KeyParameters.Modulus) "Exponent" = [Convert]::ToBase64String($KeyParameters.Exponent) } | ConvertTo-Json -Compress) # # Wait for "join-request" message in metadata. # Write-Host "Waiting for request to initiate domain join..." $TotalWaitMillis = 20000 do { $WaitMillis = 500 $TotalWaitMillis = $TotalWaitMillis - $WaitMillis Start-Sleep -Milliseconds $WaitMillis $MetadataValue = Get-MetaData -Property "attributes/$MetadataKey" } while (-not $MetadataValue -and $TotalWaitMillis -gt 0) if (-not $MetadataValue) { throw [System.TimeoutException]::new( "Timeout elapsed waiting for 'join-request' message from client") } try { $JoinRequest = $MetadataValue | ConvertFrom-Json if (($JoinRequest.OperationId -ne $OperationId) -or ($JoinRequest.MessageType -ne "join-request")) { throw [System.ArgumentException]::new( "Encountered unexpected request message $($JoinRequest.MessageType) in metadata") } # # Decrypt password using our ephemeral key. # $PlainTextPassword = [System.Text.Encoding]::UTF8.GetString( $Key.Decrypt( [Convert]::FromBase64String($JoinRequest.EncryptedPassword), [System.Security.Cryptography.RSAEncryptionPadding]::OaepSHA256)) $Password = ConvertTo-SecureString ` -AsPlainText ` -Force ` -String $PlainTextPassword # # Join and restart. # if ($JoinRequest.NewComputerName -ne $null) { Write-Host "Joining computer as $($JoinRequest.NewComputerName) to domain $($JoinRequest.DomainName)..." Add-Computer ` -ComputerName localhost ` -DomainName $JoinRequest.DomainName ` -NewName $JoinRequest.NewComputerName ` -Credential (New-Object PSCredential ($JoinRequest.Username, $Password)) ` -Force } else { Write-Host "Joining computer to domain $($JoinRequest.DomainName)..." Add-Computer ` -ComputerName localhost ` -DomainName $JoinRequest.DomainName ` -Credential (New-Object PSCredential ($JoinRequest.Username, $Password)) ` -Force } # # Join succeeded, write response message. # Write-SerialPort -portname COM4 -Data (@{ "OperationId" = $OperationId "MessageType" = "join-response" "Succeeded" = $True } | ConvertTo-Json -Compress) Write-Host "Domain join completed, restarting..." & shutdown /r /f /d P:2:4 /c "Completing domain join" /t 0 } catch { # # Join failed, write response message. # Write-Host "Domain join failed: $($_.Exception.Message)" Write-SerialPort -portname COM4 -Data (@{ "OperationId" = $OperationId "MessageType" = "join-response" "Succeeded" = $False "ErrorDetails" = $($_.Exception.Message) } | ConvertTo-Json -Compress) }