#Requires -RunAsAdministrator [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$tenantId, [Parameter(Mandatory=$true)] [string]$tenantName ) # Log file for deployment script $DeploymentLogFile = "C:\Windows\Temp\HybridJoin-Deployment.log" function Write-DeploymentLog { param( [string]$Message, [ValidateSet('Info', 'Success', 'Warning', 'Error')] [string]$Level = 'Info' ) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logEntry = "[$timestamp] [$Level] $Message" Write-Output $logEntry try { Add-Content -Path $DeploymentLogFile -Value $logEntry -ErrorAction SilentlyContinue } catch { } } Write-DeploymentLog "========================================" -Level Info Write-DeploymentLog "Entra Hybrid Join Orchestration Started" -Level Info Write-DeploymentLog "Timestamp: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -Level Info Write-DeploymentLog "Deployment Method: Azure Run Command (External Script)" -Level Info Write-DeploymentLog "Script Version: 3.2" -Level Info Write-DeploymentLog "========================================" -Level Info Write-DeploymentLog "" -Level Info Write-DeploymentLog "Reading configuration from parameters..." -Level Info $TenantIdValue = $tenantId $TenantNameValue = $tenantName Write-DeploymentLog " TenantId: $TenantIdValue" -Level Info Write-DeploymentLog " TenantName: $TenantNameValue" -Level Info Write-DeploymentLog "" -Level Info Write-DeploymentLog "Validating configuration..." -Level Info $configValid = $true if ([string]::IsNullOrWhiteSpace($TenantIdValue) -or $TenantIdValue -eq "00000000-0000-0000-0000-000000000000") { Write-DeploymentLog "ERROR: TenantId is not configured or using placeholder value" -Level Error $configValid = $false } if ([string]::IsNullOrWhiteSpace($TenantNameValue)) { Write-DeploymentLog "ERROR: TenantName is not configured" -Level Error $configValid = $false } if (-not $configValid) { Write-DeploymentLog "Configuration validation failed" -Level Error exit 1 } Write-DeploymentLog "Configuration validated successfully" -Level Success # ------------------------------------------ # Create Hybrid Join Registry Keys # ------------------------------------------ $RegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\CDJ\AAD" try { if (-not (Test-Path $RegistryPath)) { New-Item -Path $RegistryPath -Force | Out-Null Write-DeploymentLog "Registry path created successfully" -Level Success } Set-ItemProperty -Path $RegistryPath -Name "TenantId" -Value $TenantIdValue -Type String -Force Write-DeploymentLog "TenantId registry value created and verified" -Level Success Set-ItemProperty -Path $RegistryPath -Name "TenantName" -Value $TenantNameValue -Type String -Force Write-DeploymentLog "TenantName registry value created and verified" -Level Success $WorkplaceJoinPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WorkplaceJoin" if (-not (Test-Path $WorkplaceJoinPath)) { New-Item -Path $WorkplaceJoinPath -Force | Out-Null } Set-ItemProperty -Path $WorkplaceJoinPath -Name "autoWorkplaceJoin" -Value 1 -Type DWord -Force Write-DeploymentLog "autoWorkplaceJoin registry key created and verified" -Level Success } catch { Write-DeploymentLog "Registry configuration failed: $($_.Exception.Message)" -Level Error } # ------------------------------------------ # Create Scheduled Task for Retry Logic # ------------------------------------------ $RetryScriptContent = @' # Azure Hybrid Join Retry Script # Runs as a scheduled task to manage Hybrid Join $LogFile = "C:\Windows\Temp\HybridJoinRetry.log" $TaskName = "EntraHybridJoinRetry" function Write-Log { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logMessage = "[$timestamp] $Message" try { Add-Content -Path $LogFile -Value $logMessage -ErrorAction SilentlyContinue } catch { } Write-Output $logMessage } function Test-HybridJoinStatus { try { Write-Log "Checking Hybrid Join status..." $dsregPath = "c:\windows\System32\dsregcmd.exe" $tempFile = "C:\Windows\Temp\dsregcmd_output.txt" # Run dsregcmd and capture output to file $process = Start-Process -FilePath $dsregPath -ArgumentList "/status" -Wait -NoNewWindow -RedirectStandardOutput $tempFile -PassThru if (Test-Path $tempFile) { $dsregOutput = Get-Content $tempFile -Raw Remove-Item $tempFile -Force -ErrorAction SilentlyContinue } else { Write-Log "ERROR: Could not read dsregcmd output" return $false } $azureAdJoinedLine = $dsregOutput | Select-String -Pattern "AzureAdJoined" $domainJoinedLine = $dsregOutput | Select-String -Pattern "DomainJoined" $azureJoined = $false $domainJoined = $false if ($azureAdJoinedLine -match "AzureAdJoined\s*:\s*(\w+)") { $azureJoined = $matches[1].ToUpper() -eq 'YES' } if ($domainJoinedLine -match "DomainJoined\s*:\s*(\w+)") { $domainJoined = $matches[1].ToUpper() -eq 'YES' } Write-Log "AzureAdJoined: $azureJoined" Write-Log "DomainJoined: $domainJoined" if ($azureJoined -eq $true -and $domainJoined -eq $true) { Write-Log "Hybrid Join status: SUCCESS - Device is Hybrid Joined" return $true } Write-Log "Hybrid Join status: INCOMPLETE - Device is not yet Hybrid Joined" return $false } catch { Write-Log "ERROR checking Hybrid Join status: $($_.Exception.Message)" return $false } } function Start-HybridJoinTask { try { Write-Log "Attempting to trigger Hybrid Join..." Start-ScheduledTask -TaskName "Automatic-Device-Join" -TaskPath "\Microsoft\Windows\Workplace Join\" Write-Log "Successfully triggered 'Automatic-Device-Join' scheduled task" } catch { Write-Log "ERROR triggering scheduled task: $($_.Exception.Message)" } } function Remove-SelfTask { Write-Log "Hybrid Join complete - removing retry scheduled task" Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue Write-Log "Retry task removed successfully" } Write-Log "========================================" Write-Log "Entra Hybrid Join Retry Task Started" Write-Log "========================================" $isHybridJoined = Test-HybridJoinStatus if ($isHybridJoined -eq $true) { Remove-SelfTask Write-Log "Task execution completed - Hybrid Join verified" exit 0 } Start-HybridJoinTask Write-Log "Hybrid Join trigger attempted - task will retry in 2 minutes" Write-Log "========================================" exit 0 '@ try { $ScriptPath = "C:\Windows\Temp\HybridJoinRetry.ps1" Set-Content -Path $ScriptPath -Value $RetryScriptContent -Force Write-DeploymentLog "Retry script created successfully" -Level Success $TaskName = "EntraHybridJoinRetry" $Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$ScriptPath`"" $Trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 2) $Principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest $Settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -MultipleInstances IgnoreNew Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -Principal $Principal -Settings $Settings -Force | Out-Null Write-DeploymentLog "Scheduled task created successfully" -Level Success Start-ScheduledTask -TaskName "Automatic-Device-Join" -TaskPath "\Microsoft\Windows\Workplace Join\" -ErrorAction SilentlyContinue Write-DeploymentLog "Initial join task triggered" -Level Success } catch { Write-DeploymentLog "Failed to create scheduled task: $($_.Exception.Message)" -Level Error exit 1 } exit 0