Skip to content

Instantly share code, notes, and snippets.

@Geofferey
Last active December 18, 2024 12:45
Show Gist options
  • Select an option

  • Save Geofferey/98dd0664e7c9df3f7fd7b76d11bfd145 to your computer and use it in GitHub Desktop.

Select an option

Save Geofferey/98dd0664e7c9df3f7fd7b76d11bfd145 to your computer and use it in GitHub Desktop.
A Script for logging into Tailscale via preauth key stored in Active Direcotry
## I am a custom Script for logging TailScale in on boot using tsPreAuthKey attribute stored in AD Schema
# This requires permanent modification to the schema for storing the PreAuthKey:
# https://www.rebeladmin.com/step-step-guide-create-custom-active-directory-attributes/
# https://legacy.support.exclaimer.com/hc/en-gb/articles/360028648572-How-to-create-new-custom-AD-attributes-for-use-in-a-signature-template
# Do NOT issue re-useable PreAuthTokens and store in AD, that would be foolish, storing them period might be ;))
# Execute me as a Computer policy based powershell startup script
# Schduled task is also an option, may not work on first run
#
$env:Path = 'C:\Program Files\Tailscale;' + $env:Path
$logF = "C:\ProgramData\Tailscale\tailscale-login.log"
$serviceTimeout = 60
$jobTimeout = 60
$startTime = Get-Date
$serviceName = 'tailscale'
$tailscaleExe = "C:\Program Files\Tailscale\tailscale.exe"
$tailscaleipnExe = "C:\Program Files\Tailscale\tailscale-ipn.exe"
$preAuthTestF = "C:\ProgramData\TailScale\preauth"
##HINT: If a TS_LOGINURL specified in .msi/.mst/registry this cannot be changed, likely for security reasons
$loginServer = "https://controlplane.tailscale.com"
## Function for getting AD computer attributes since RSAT is not available on every computer, duh
function Get-Attributes ($arg1) {
$searcher = New-Object system.directoryservices.directorysearcher
$searcher.PropertiesToLoad.AddRange(@($arg1))
$null = $searcher.Filter = "(name=$env:ComputerName)"
$result = $searcher.FindOne()
$attribute = $result.properties.$arg1
echo $attribute
}
if (Test-Path -Path $preAuthTestF) {
Move-Item $logF $logF'.old'
}
Start-Transcript -path $logF
Write-Host $(Date)
$domainName = (Get-CimInstance -ClassName Win32_ComputerSystem).Domain
$compatMod = "\\$DomainName\SYSVOL\$domainName\Installers\tailscale.sdb"
Write-Host "Grabbing the current machine's PreAuthKey from $domainName Active Directory..."
$tspreauthkey = (Get-Attributes tspreauthkey)
$tsloginurl = (Get-Attributes tsloginurl)
## This method left for historical purposes
#$tsloginurl = (Get-ADComputer -identity $Env:ComputerName -properties tsloginurl).tsloginurl
#$tspreauthkey = (Get-ADComputer -identity $Env:ComputerName -properties tspreauthkey).tspreauthkey
Write-Host "Current PreAuthKey: $tspreauthkey"
## A script block for Job-Start because the variables will not be evaluated otherwise
# https://stackoverflow.com/questions/19834643/powershell-how-to-pre-evaluate-variables-in-a-scriptblock-for-start-job
$tsLogin = [scriptblock]::Create("tailscale up --reset --force-reauth --login-server=$loginServer --shields-up --authkey=$tspreauthkey --accept-dns --accept-routes --unattended")
if ($tsloginurl -ne $null) {
$loginServer = $tsloginurl
}
## Log off if no key defined and no error when pulling key
if ($tspreauthkey -eq $null -and (Get-Attributes tspreauthkey)) {
Write-Host "No key defined in AD, logging out..."
tailscale logout
exit 0
}
Write-Host "Current LoginURL: $loginServer"
if (-Not (Test-Path -Path $tailscaleExe)) {
Write-Host "tailscale.exe not found, quitting.."
exit 1
}
## Install custom application compatibility db mod to force GUI app to run-as admin when executed
Write-Host "Installing compatibility admin database run-as admin"
sdbinst.exe -p -q $compatMod
## Wait for the tailscaled service to start
do {
$serviceStatus = (Get-Service -Name $serviceName).Status
if ($serviceStatus -eq "Running") {
Write-Host "The '$serviceName' service started successfully."
break
}
Start-Sleep -Seconds 1
} while ((New-TimeSpan -Start $startTime).TotalSeconds -lt $serviceTimeout)
if ($serviceStatus -ne "Running") {
Write-Host "Timeout waiting for the '$serviceName' service to start."
}
## Execute a first time login proceedure and store the used preauth key to detect future changes
if (-Not (Test-Path -Path $preAuthTestF)) {
Write-Host "Executing the tailscale login proceedure for the first time..."
$job = Start-Job $tsLogin
if ($job -ne "error") {
Wait-Job $job -timeout $jobTimeout
Write-Host
if ($job.State -eq 'Completed' -and -not $job.Error) {
Write-Host "Saving the used key to file for later comparison..."
echo $tspreauthkey > $preAuthTestF
} else {
Write-Host "Could not complete the login operation in a timely manner..."
}
}
}
$oldtspreauthkey = Get-Content -Path $preAuthTestF
echo $oldtspreauthkey
if ($tspreauthkey -ne $oldtspreauthkey) {
Write-Host "PreAuthKey change detected in Active Directory, re-running login proceedure..."
$job = Start-Job $tsLogin
if ($job -ne "error") {
Wait-Job $job -timeout $jobTimeout
Write-Host
if ($job.State -eq 'Completed' -and -not $job.Error) {
Write-Host "Saving the used key to file for later comparison..."
echo $tspreauthkey > $preAuthTestF
} else {
Write-Host "Could not complete the login operation in a timely manner..."
}
}
}
Stop-Transcript
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment