Skip to content

Instantly share code, notes, and snippets.

@RobinBeismann
Created November 16, 2022 22:03
Show Gist options
  • Save RobinBeismann/32f5dc3f3a609f9801ed3a62dfb148e7 to your computer and use it in GitHub Desktop.
Save RobinBeismann/32f5dc3f3a609f9801ed3a62dfb148e7 to your computer and use it in GitHub Desktop.
#
# This tool reads the Attributes ATTRPREFIX-Autologon-Domain, ATTRPREFIX-Autologon-Enabled, ATTRPREFIX-Autologon-Password, ATTRPREFIX-Autologon-Username and uses Sysinternals Autologin to configure it on the client
# Logging is done to the Application Event Log
#
#region Static Variables
# Logging Settings
$script:LoggingOptions = "EventLog", "Host"
$script:LogSource = "Invoke-AutoLogonConfig"
$script:LogDebugMessages = $false
$script:LogName = "Application"
# Registry Properties to check
$regProperties = "AutoAdminLogon", "DefaultUserName", "DefaultDomainName", "AutoLogonSID"
$regKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
# User Membership Cache
$cacheKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Company-Name\SecureAutoLogon"
$cacheProperty = "CachedMembership"
$cacheUsernameProperty = "CachedUser"
#endregion
#region Pathing
# Get current Script Directory
$currentDirectory = [System.AppDomain]::CurrentDomain.BaseDirectory.TrimEnd('\')
if ($currentDirectory -eq $PSHOME.TrimEnd('\'))
{
$currentDirectory = $PSScriptRoot
}
if(!$currentDirectory -or $currentDirectory -eq ""){
$currentDirectory = Split-Path $script:MyInvocation.MyCommand.Path
}
$global:serviceUIPath = "$currentDirectory\bin\ServiceUIx64.exe"
$global:toastPath = "$currentDirectory\bin\Toast.exe"
$global:aAutologonBinary = "$currentDirectory\bin\Autologon64.exe"
#endregion
#region Functions
Function Write-Log {
<#
.SYNOPSIS
Write messages to a log file in CMTrace.exe compatible format or Legacy text file format.
.DESCRIPTION
Write messages to a log file in CMTrace.exe compatible format or Legacy text file format and optionally display in the console.
.PARAMETER Message
The message to write to the log file or output to the console.
.PARAMETER Severity
Defines message type. When writing to console or CMTrace.exe log format, it allows highlighting of message type.
Options: 1 = Information (default), 2 = Warning (highlighted in yellow), 3 = Error (highlighted in red)
.PARAMETER Source
The source of the message being logged. Also used as the event log source.
.PARAMETER ScriptSection
The heading for the portion of the script that is being executed. Default is: $script:installPhase.
.PARAMETER LogType
Choose whether to write a CMTrace.exe compatible log file or a Legacy text log file.
.PARAMETER LoggingOptions
Choose where to log 'Console', 'File', 'EventLog' or 'None'. You can choose multiple options.
.PARAMETER LogFileDirectory
Set the directory where the log file will be saved.
.PARAMETER LogFileName
Set the name of the log file.
.PARAMETER MaxLogFileSizeMB
Maximum file size limit for log file in megabytes (MB). Default is 10 MB.
.PARAMETER LogName
Set the name of the event log.
.PARAMETER EventID
Set the event id for the event log entry.
.PARAMETER WriteHost
Write the log message to the console.
.PARAMETER ContinueOnError
Suppress writing log message to console on failure to write message to log file. Default is: $true.
.PARAMETER PassThru
Return the message that was passed to the function
.PARAMETER VerboseMessage
Specifies that the message is a debug message. Verbose messages only get logged if -LogDebugMessage is set to $true.
.PARAMETER DebugMessage
Specifies that the message is a debug message. Debug messages only get logged if -LogDebugMessage is set to $true.
.PARAMETER LogDebugMessage
Debug messages only get logged if this parameter is set to $true in the config XML file.
.EXAMPLE
Write-Log -Message "Installing patch MS15-031" -Source 'Add-Patch' -LogType 'CMTrace'
.EXAMPLE
Write-Log -Message "Script is running on Windows 8" -Source 'Test-ValidOS' -LogType 'Legacy'
.NOTES
Slightly modified version of the PSADT logging cmdlet. I did not write the original cmdlet, please do not credit me for it.
.LINK
https://psappdeploytoolkit.com
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[AllowEmptyCollection()]
[Alias('Text')]
[string[]]$Message,
[Parameter(Mandatory = $false, Position = 1)]
[ValidateRange(1, 3)]
[int16]$Severity = 1,
[Parameter(Mandatory = $false, Position = 2)]
[ValidateNotNullorEmpty()]
[string]$Source = $script:LogSource,
[Parameter(Mandatory = $false, Position = 3)]
[ValidateNotNullorEmpty()]
[string]$ScriptSection = $script:RunPhase,
[Parameter(Mandatory = $false, Position = 4)]
[ValidateSet('CMTrace', 'Legacy')]
[string]$LogType = 'CMTrace',
[Parameter(Mandatory = $false, Position = 5)]
[ValidateSet('Host', 'File', 'EventLog', 'None')]
[string[]]$LoggingOptions = $script:LoggingOptions,
[Parameter(Mandatory = $false, Position = 6)]
[ValidateNotNullorEmpty()]
[string]$LogFileDirectory = $(Join-Path -Path $Env:WinDir -ChildPath $('\Logs\' + $script:LogName)),
[Parameter(Mandatory = $false, Position = 7)]
[ValidateNotNullorEmpty()]
[string]$LogFileName = $($script:LogSource + '.log'),
[Parameter(Mandatory = $false, Position = 8)]
[ValidateNotNullorEmpty()]
[int]$MaxLogFileSizeMB = '4',
[Parameter(Mandatory = $false, Position = 9)]
[ValidateNotNullorEmpty()]
[string]$LogName = $script:LogName,
[Parameter(Mandatory = $false, Position = 10)]
[ValidateNotNullorEmpty()]
[int32]$EventID = 1,
[Parameter(Mandatory = $false, Position = 11)]
[ValidateNotNullorEmpty()]
[boolean]$ContinueOnError = $true,
[Parameter(Mandatory = $false, Position = 12)]
[switch]$PassThru = $false,
[Parameter(Mandatory = $false, Position = 13)]
[switch]$VerboseMessage = $false,
[Parameter(Mandatory = $false, Position = 14)]
[switch]$DebugMessage = $false,
[Parameter(Mandatory = $false, Position = 15)]
[boolean]$LogDebugMessage = $script:LogDebugMessages
)
Begin {
## Get the name of this function
[string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
## Logging Variables
# Log file date/time
[string]$LogTime = (Get-Date -Format 'HH:mm:ss.fff').ToString()
[string]$LogDate = (Get-Date -Format 'MM-dd-yyyy').ToString()
If (-not (Test-Path -LiteralPath 'variable:LogTimeZoneBias')) { [int32]$script:LogTimeZoneBias = [timezone]::CurrentTimeZone.GetUtcOffset([datetime]::Now).TotalMinutes }
[string]$LogTimePlusBias = $LogTime + '-' + $script:LogTimeZoneBias
# Initialize variables
[boolean]$WriteHost = $false
[boolean]$WriteFile = $false
[boolean]$WriteEvent = $false
[boolean]$DisableLogging = $false
[boolean]$ExitLoggingFunction = $false
If (('Host' -in $LoggingOptions) -and (-not ($VerboseMessage -or $DebugMessage))) { $WriteHost = $true }
If ('File' -in $LoggingOptions) { $WriteFile = $true }
If ('EventLog' -in $LoggingOptions) { $WriteEvent = $true }
If ('None' -in $LoggingOptions) { $DisableLogging = $true }
# Check if the script section is defined
[boolean]$ScriptSectionDefined = [boolean](-not [string]::IsNullOrEmpty($ScriptSection))
# Check if the source is defined
[boolean]$SourceDefined = [boolean](-not [string]::IsNullOrEmpty($Source))
# Check if the event log and event source exit
[boolean]$LogNameNotExists = (-not [System.Diagnostics.EventLog]::Exists($LogName))
[boolean]$LogSourceNotExists = (-not [System.Diagnostics.EventLog]::SourceExists($Source))
## Create script block for generating CMTrace.exe compatible log entry
[scriptblock]$CMTraceLogString = {
Param (
[string]$lMessage,
[string]$lSource,
[int16]$lSeverity
)
"<![LOG[$lMessage]LOG]!>" + "<time=`"$LogTimePlusBias`" " + "date=`"$LogDate`" " + "component=`"$lSource`" " + "context=`"$([Security.Principal.WindowsIdentity]::GetCurrent().Name)`" " + "type=`"$lSeverity`" " + "thread=`"$PID`" " + "file=`"$Source`">"
}
## Create script block for writing log entry to the console
[scriptblock]$WriteLogLineToHost = {
Param (
[string]$lTextLogLine,
[int16]$lSeverity
)
If ($WriteHost) {
# Only output using color options if running in a host which supports colors.
If ($Host.UI.RawUI.ForegroundColor) {
Switch ($lSeverity) {
3 { Write-Host -Object $lTextLogLine -ForegroundColor 'Red' -BackgroundColor 'Black' }
2 { Write-Host -Object $lTextLogLine -ForegroundColor 'Yellow' -BackgroundColor 'Black' }
1 { Write-Host -Object $lTextLogLine }
}
}
# If executing "powershell.exe -File <filename>.ps1 > log.txt", then all the Write-Host calls are converted to Write-Output calls so that they are included in the text log.
Else {
Write-Output -InputObject $lTextLogLine
}
}
}
## Create script block for writing log entry to the console as verbose or debug message
[scriptblock]$WriteLogLineToHostAdvanced = {
Param (
[string]$lTextLogLine
)
# Only output using color options if running in a host which supports colors.
If ($Host.UI.RawUI.ForegroundColor) {
If ($VerboseMessage) {
Write-Verbose -Message $lTextLogLine
}
Else {
Write-Debug -Message $lTextLogLine
}
}
# If executing "powershell.exe -File <filename>.ps1 > log.txt", then all the Write-Host calls are converted to Write-Output calls so that they are included in the text log.
Else {
Write-Output -InputObject $lTextLogLine
}
}
## Create script block for event writing log entry
[scriptblock]$WriteToEventLog = {
If ($WriteEvent) {
$EventType = Switch ($Severity) {
3 { 'Error' }
2 { 'Warning' }
1 { 'Information' }
}
If ($LogNameNotExists -and (-not $LogSourceNotExists)) {
Try {
# Delete event source if the log does not exist
$null = [System.Diagnostics.EventLog]::DeleteEventSource($Source)
$LogSourceNotExists = $true
}
Catch {
[boolean]$ExitLoggingFunction = $true
# If error deleting event source, write message to console
If (-not $ContinueOnError) {
Write-Host -Object "[$LogDate $LogTime] [${CmdletName}] $ScriptSection :: Failed to create the event log source [$Source]. `n: $_" -ForegroundColor 'Red'
}
}
}
If ($LogNameNotExists -or $LogSourceNotExists) {
Try {
# Create event log
$null = New-EventLog -LogName $LogName -Source $Source -ErrorAction 'Stop'
}
Catch {
[boolean]$ExitLoggingFunction = $true
# If error creating event log, write message to console
If (-not $ContinueOnError) {
Write-Host -Object "[$LogDate $LogTime] [${CmdletName}] $ScriptSection :: Failed to create the event log [$LogName`:$Source]. `n: $_" -ForegroundColor 'Red'
}
}
}
Try {
# Write to event log
Write-EventLog -LogName $LogName -Source $Source -EventId $EventID -EntryType $EventType -Category '0' -Message $ConsoleLogLine -ErrorAction 'Stop'
}
Catch {
[boolean]$ExitLoggingFunction = $true
# If error creating directory, write message to console
If (-not $ContinueOnError) {
Write-Host -Object "[$LogDate $LogTime] [${CmdletName}] $ScriptSection :: Failed to write to event log [$LogName`:$Source]. `n: $_" -ForegroundColor 'Red'
}
}
}
}
## Exit function if it is a debug message and logging debug messages is not enabled in the config XML file
If (($DebugMessage -or $VerboseMessage) -and (-not $LogDebugMessage)) { [boolean]$ExitLoggingFunction = $true; Return }
## Exit function if logging to file is disabled and logging to console host is disabled
If (($DisableLogging) -and (-not $WriteHost)) { [boolean]$ExitLoggingFunction = $true; Return }
## Exit Begin block if logging is disabled
If ($DisableLogging) { Return }
## Create the directory where the log file will be saved
If (-not (Test-Path -LiteralPath $LogFileDirectory -PathType 'Container')) {
Try {
$null = New-Item -Path $LogFileDirectory -Type 'Directory' -Force -ErrorAction 'Stop'
}
Catch {
[boolean]$ExitLoggingFunction = $true
# If error creating directory, write message to console
If (-not $ContinueOnError) {
Write-Host -Object "[$LogDate $LogTime] [${CmdletName}] $ScriptSection :: Failed to create the log directory [$LogFileDirectory]. `n: $_" -ForegroundColor 'Red'
}
Return
}
}
## Assemble the fully qualified path to the log file
[string]$LogFilePath = Join-Path -Path $LogFileDirectory -ChildPath $LogFileName
}
Process {
ForEach ($Msg in $Message) {
## If the message is not $null or empty, create the log entry for the different logging methods
[string]$CMTraceMsg = ''
[string]$ConsoleLogLine = ''
[string]$LegacyTextLogLine = ''
If ($Msg) {
# Create the CMTrace log message
If ($ScriptSectionDefined) { [string]$CMTraceMsg = "[$ScriptSection] :: $Msg" }
# Create a Console and Legacy "text" log entry
[string]$LegacyMsg = "[$LogDate $LogTime]"
If ($ScriptSectionDefined) { [string]$LegacyMsg += " [$ScriptSection]" }
If ($Source) {
[string]$ConsoleLogLine = "$LegacyMsg [$Source] :: $Msg"
Switch ($Severity) {
3 { [string]$LegacyTextLogLine = "$LegacyMsg [$Source] [Error] :: $Msg" }
2 { [string]$LegacyTextLogLine = "$LegacyMsg [$Source] [Warning] :: $Msg" }
1 { [string]$LegacyTextLogLine = "$LegacyMsg [$Source] [Info] :: $Msg" }
}
}
Else {
[string]$ConsoleLogLine = "$LegacyMsg :: $Msg"
Switch ($Severity) {
3 { [string]$LegacyTextLogLine = "$LegacyMsg [Error] :: $Msg" }
2 { [string]$LegacyTextLogLine = "$LegacyMsg [Warning] :: $Msg" }
1 { [string]$LegacyTextLogLine = "$LegacyMsg [Info] :: $Msg" }
}
}
}
## Execute script block to write the log entry to the console as verbose or debug message
& $WriteLogLineToHostAdvanced -lTextLogLine $ConsoleLogLine -lSeverity $Severity
## Exit function if logging is disabled
If ($ExitLoggingFunction) { Return }
## Execute script block to create the CMTrace.exe compatible log entry
[string]$CMTraceLogLine = & $CMTraceLogString -lMessage $CMTraceMsg -lSource $Source -lSeverity $lSeverity
## Choose which log type to write to file
If ($LogType -ieq 'CMTrace') {
[string]$LogLine = $CMTraceLogLine
}
Else {
[string]$LogLine = $LegacyTextLogLine
}
## Write the log entry to the log file and event log if logging is not currently disabled
If (-not $DisableLogging) {
if($WriteFile){
## Write to file log
Try {
$LogLine | Out-File -FilePath $LogFilePath -Append -NoClobber -Force -Encoding 'UTF8' -ErrorAction 'Stop'
}
Catch {
If (-not $ContinueOnError) {
Write-Host -Object "[$LogDate $LogTime] [$ScriptSection] [${CmdletName}] :: Failed to write message [$Msg] to the log file [$LogFilePath]. `n: $_" -ForegroundColor 'Red'
}
}
}
if($WriteEvent){
## Write to event log
Try {
& $WriteToEventLog -lMessage $ConsoleLogLine -lName $LogName -lSource $Source -lSeverity $Severity
}
Catch {
If (-not $ContinueOnError) {
Write-Host -Object "[$LogDate $LogTime] [$ScriptSection] [${CmdletName}] :: Failed to write message [$Msg] to the log file [$LogFilePath]. `n: $_" -ForegroundColor 'Red'
}
}
}
}
## Execute script block to write the log entry to the console if $WriteHost is $true and $LogLogDebugMessage is not $true
& $WriteLogLineToHost -lTextLogLine $ConsoleLogLine -lSeverity $Severity
}
}
End {
## Archive log file if size is greater than $MaxLogFileSizeMB and $MaxLogFileSizeMB > 0
Try {
If ((-not $ExitLoggingFunction) -and (-not $DisableLogging)) {
[IO.FileInfo]$LogFile = Get-ChildItem -LiteralPath $LogFilePath -ErrorAction 'Stop'
[decimal]$LogFileSizeMB = $LogFile.Length / 1MB
If (($LogFileSizeMB -gt $MaxLogFileSizeMB) -and ($MaxLogFileSizeMB -gt 0)) {
## Change the file extension to "lo_"
[string]$ArchivedOutLogFile = [IO.Path]::ChangeExtension($LogFilePath, 'lo_')
[hashtable]$ArchiveLogParams = @{ ScriptSection = $ScriptSection; Source = ${CmdletName}; Severity = 2; LogFileDirectory = $LogFileDirectory; LogFileName = $LogFileName; LogType = $LogType; MaxLogFileSizeMB = 0; WriteHost = $WriteHost; ContinueOnError = $ContinueOnError; PassThru = $false }
## Log message about archiving the log file
$ArchiveLogMessage = "Maximum log file size [$MaxLogFileSizeMB MB] reached. Rename log file to [$ArchivedOutLogFile]."
Write-Log -Message $ArchiveLogMessage @ArchiveLogParams -ScriptSection ${CmdletName}
## Archive existing log file from <filename>.log to <filename>.lo_. Overwrites any existing <filename>.lo_ file. This is the same method SCCM uses for log files.
Move-Item -LiteralPath $LogFilePath -Destination $ArchivedOutLogFile -Force -ErrorAction 'Stop'
## Start new log file and Log message about archiving the old log file
$NewLogMessage = "Previous log file was renamed to [$ArchivedOutLogFile] because maximum log file size of [$MaxLogFileSizeMB MB] was reached."
Write-Log -Message $NewLogMessage @ArchiveLogParams -ScriptSection ${CmdletName}
}
}
}
Catch {
## If renaming of file fails, script will continue writing to log file even if size goes over the max file size
}
Finally {
If ($PassThru) { Write-Output -InputObject $Message }
}
}
}
function Send-ToastNotification($Title,$Message){
$lArgs = $global:toastPath,
'-ToastTitle',
"\`"$Title\`"",
'-ToastText',
"\`"$Message\`""
Start-Process -FilePath $global:serviceUIPath -ArgumentList $lArgs
}
#endregion
#region Manage Folder
$passhashDir = "$currentDirectory\secure"
$passhashFile = "$passhashdir\hash"
# Create Path if it does not exist
$path = $passhashDir
if(!(Test-Path -Path $path -ErrorAction SilentlyContinue)){
Write-Log -Source "AutologonConfig" -Message "Creating `"$path`".."
$null = New-Item -Path $path -ItemType Directory -Force
}
# Initial value
$ACLUpdated = $false
# Read ACLs
$ACL = Get-Acl -Path $path
$orgAcl = Get-Acl -Path $path
# Check inheritance
if(!$acl.AreAccessRulesProtected){
Write-Log -Source "AutologonConfig" -Message "Breaking ACL Inheritance on `"$path`".."
$ACL.SetAccessRuleProtection($true,$false)
$ACLUpdated = $true
}
# Permission Table
$Permissions = @{
"S-1-5-32-544" = [System.Security.AccessControl.FileSystemRights]::FullControl
"S-1-5-18" = [System.Security.AccessControl.FileSystemRights]::FullControl
}
# Add ACLs
$Permissions.GetEnumerator() | ForEach-Object {
$SIDIdentity = New-Object -TypeName System.Security.Principal.SecurityIdentifier($_.Name)
$Ar = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule($SIDIdentity, $_.Value,'ContainerInherit,ObjectInherit', 'None', 'Allow')
$ACL.SetAccessRule($Ar)
}
#Compare if we have differences
Compare-Object -ReferenceObject @($orgAcl.Access) -DifferenceObject @($acl.Access) -Property IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags, PropagationFlags | ForEach-Object {
if($_.SideIndicator -eq "<="){
Write-Log -Source "AutologonConfig" -Message "Removing ACL: `"$($_.AccessControlType): $($_.FileSystemRights)`" for $($_.IdentityReference) with Inheritance $($_.InheritanceFlags) and Propgation $($_.PropagationFlags)"
}else{
Write-Log -Source "AutologonConfig" -Message "Adding ACL: `"$($_.AccessControlType): $($_.FileSystemRights)`" for $($_.IdentityReference) with Inheritance $($_.InheritanceFlags) and Propgation $($_.PropagationFlags)"
}
$ACLUpdated = $true
}
# Write ACLs if they were updates
if($ACLUpdated){
Write-Log -Source "AutologonConfig" -Message "Updating ACLs on `"$path`".."
Set-Acl -Path $path -AclObject $acl
}else{
Write-Log -Source "AutologonConfig" -Message "ACLs on `"$path`" are fine."
}
#endregion
# Get the current values via ADSI Searcher
try{
Write-Log -Source "AutologonConfig" -Message "Reading Autologon Settings from Active Directory.." -LoggingOptions Host
$ADSI = [adsisearcher]"objectcategory=computer"
$ADSI.Filter = "sAMAccountName=$($env:computername + "$")"
$null = $ADSI.PropertiesToLoad.Add("ATTRPREFIX-Autologon-Domain")
$null = $ADSI.PropertiesToLoad.Add("ATTRPREFIX-Autologon-Enabled")
$null = $ADSI.PropertiesToLoad.Add("ATTRPREFIX-Autologon-Password")
$null = $ADSI.PropertiesToLoad.Add("ATTRPREFIX-Autologon-Username")
$computer = $ADSI.FindOne()
Write-Log -Source "AutologonConfig" -Message "Successfully read autologon Settings from Active Directory.." -LoggingOptions Host
}catch{
Write-Log -Source "AutologonConfig" -Message "Failed to retrieve autologon Settings from Active Directory, error: $_" -Severity 3 -EventID 2
exit 1;
}
try{
# Check if Autologon is enabled
if(
($aEnabled = $computer.Properties['ATTRPREFIX-Autologon-Enabled']) -and
($aEnabled -eq $true)
){
[string]$aUsername = $computer.Properties['ATTRPREFIX-Autologon-Username']
[string]$aPassword = $computer.Properties['ATTRPREFIX-Autologon-Password']
[string]$aDomain = $computer.Properties['ATTRPREFIX-Autologon-Domain']
$cacheOutdated = $false
# Cache our AD Memberships
if($aUsername){
$ADSI.Filter = "sAMAccountName=$aUsername"
$null = $ADSI.PropertiesToLoad.Add("memberOf")
$user = $ADSI.FindOne()
[array]$ADMembership = $user.Properties.memberof | Sort-Object
$ADMembershipJson = ConvertTo-Json -InputObject $ADMembership -Compress
}
# Check if our cache key exists
if(!(Test-Path -Path "Registry::$cacheKey" -ErrorAction SilentlyContinue)){
Write-Log -Source "AutologonConfig" -Message "Creating Registry Key `"$cacheKey`"" -LoggingOptions Host
$null = New-Item -Path "Registry::$cacheKey" -Force
}
# Retrieve our cache key
$cache = Get-ItemProperty -Path "Registry::$cacheKey"
# Check if we got a cache
if(
!$cache -or
!$cache.$cacheProperty -or
!$cache.$cacheUsernameProperty
){
Write-Log -Source "AutologonConfig" -Message "Group Cache is empty so this configuration comes from a previous SecureAutoLogon Version, marking it for creation.." -LoggingOptions Host
$cacheOutdated = $true
# Check if our cache is uptodate
}elseif(
(
$cache -and
$cache.$cacheProperty -and
$cache.$cacheUsernameProperty
) -and
(
($cache.$cacheUsernameProperty -ne $aUsername) -or
($cache.$cacheProperty -ne $ADMembershipJson)
)
){
Write-Log -Source "AutologonConfig" -Message "Group Cache is outdated, marking it for re-apply.." -LoggingOptions Host
$cacheOutdated = $true
}
# Check if all required values are set
if(
$aUsername -and
$aPassword -and
$aDomain -and
($aStream = [IO.MemoryStream]::new([byte[]][char[]]([string]$aPassword))) -and
($aPasswordHash = Get-FileHash -InputStream $aStream -Algorithm SHA256) -and
($aDomain.Length -gt 0) -and
($aPassword.Length -gt 0) -and
($aUsername.Length -gt 0)
){
$winlogon = Get-Item -Path "Registry::$regKey"
$UserMessage = $null
$logMessage = $null
if(
# Validate AutoAdminLogon Account
!('AutoAdminLogon' -in $winlogon.Property) -or
!($winlogon.GetValue('AutoAdminLogon') -eq 1)
){
$UserMessage = "Autologon has been configured, please reboot to apply."
$logMessage = "Successfully configured Autologon (Reason: User update) for `"$env:computername`" with user `"$aUsername`" and domain `"$aDomain`""
}elseif(
# Validate DefaultDomainName Account
!('DefaultDomainName' -in $winlogon.Property) -or
!($winlogon.GetValue('DefaultDomainName') -eq $aDomain)
){
$UserMessage = "Autologon has been configured, please reboot to apply."
$logMessage = "Successfully configured Autologon (Reason: User Domain update) for `"$env:computername`" with user `"$aUsername`" and domain `"$aDomain`""
}elseif(
# Validate DefaultUserName Account
!('DefaultUserName' -in $winlogon.Property) -or
!($winlogon.GetValue('DefaultUserName') -eq $aUsername)
){
$UserMessage = "Autologon has been configured, please reboot to apply."
$logMessage = "Successfully configured Autologon (Reason: User Name update) for `"$env:computername`" with user `"$aUsername`" and domain `"$aDomain`""
}elseif(
# Validate our password hash
!(Test-Path -Path $passhashFile -ErrorAction SilentlyContinue) -or
!([string]($aPasswordHash.Hash) -eq (Get-Content -Path $passhashFile -Encoding 'UTF8' -Raw))
){
$UserMessage = "Autologon has been configured, please reboot to apply."
$logMessage = "Successfully configured Autologon (Reason: User Password update) for `"$env:computername`" with user `"$aUsername`" and domain `"$aDomain`""
}elseif(
# Validate user membership cache
$cacheOutdated
){
$logMessage = "Successfully configured Autologon (Reason: User Membership update) for `"$env:computername`" with user `"$aUsername`" and domain `"$aDomain`""
if($cache.$cacheProperty){
$cachedGroups = ConvertFrom-Json -InputObject $cache.$cacheProperty
Compare-Object -ReferenceObject $cachedGroups -DifferenceObject $ADMembership | ForEach-Object {
if($_.SideIndicator -eq "<="){
$logMessage += "`nRemoved AD Group: `"$($_.InputObject)`""
}else{
$logMessage += "`nAdded AD Group: `"$($_.InputObject)`""
}
$ACLUpdated = $true
}
}
}
if(
$logMessage
){
Write-Log -Source "AutologonConfig" -Message "Configuring Autologon for `"$env:computername`" with user `"$aUsername`" and domain `"$aDomain`"" -LoggingOptions Host
# Invoke Autologon from SysInternals
Start-Process -FilePath $global:aAutologonBinary -ArgumentList $aUsername,$aDomain,$aPassword,"/accepteula" -ErrorAction Stop
# Write Password Hash
Set-Content -Path $passhashFile -Value $aPasswordHash.Hash -Confirm:$false -Force -Encoding 'UTF8' -NoNewLine
# Send Toast Notification
if($UserMessage){
Send-ToastNotification -Title "AutoLogon" -Message $UserMessage
}
Write-Log -Source "AutologonConfig" -Message $logMessage
# Update Cache
Set-ItemProperty -Path "Registry::$cacheKey" -Name $cacheUsernameProperty -Value $aUsername
Set-ItemProperty -Path "Registry::$cacheKey" -Name $cacheProperty -Value $ADMembershipJson
}else{
Write-Log -Source "AutologonConfig" -Message "Autologon already configured correctly." -EventID 2
}
}else{
Write-Log -Source "AutologonConfig" -Message "Not all autologon settings are configured, exiting.." -EventID 2
}
}else{
Write-Log -Source "AutologonConfig" -Message "Autologon is not enabled for this machine, checking if it is currently configured.."
# Check if we still have an auto logon configuration, if so, remove
if(
($winlogon = Get-Item -Path "Registry::$regKey") -and
(
$regProperties | Where-Object { $_ -in $winlogon.Property }
)
){
Write-Log -Source "AutologonConfig" -Message "Autologon is not enabled for this machine but configured, removing local configuration.." -LoggingOptions Host
Send-ToastNotification -Title "AutoLogon" -Message "Autologon Configuration has been removed, please reboot to apply."
# Loop through all potential registry keys and remove them
$regProperties | Where-Object { $_ -in $winlogon.Property } | ForEach-Object {
Write-Log -Source "AutologonConfig" -Message "Removing `"$regKey\$_`" .." -LoggingOptions Host
Remove-ItemProperty -Path "Registry::$regKey" -Name $_ -ErrorAction Stop
}
Write-Log -Source "AutologonConfig" -Message "Successfully removed local autologon configuration."
}else{
Write-Log -Source "AutologonConfig" -Message "Autologon is not configured on this machine, exiting.." -EventID 2
}
exit 0;
}
}catch{
Write-Log -Source "AutologonConfig" -Message "Failed to process autologon settings., error: $_" -Severity 3 -EventID 2
exit 1;
}
[cmdletbinding()]
Param (
[string]
$ToastSender = "PowerShell",
[string]
$ToastTitle = "No Title",
[string]
[parameter(ValueFromPipeline)]
$ToastText = "No Text"
)
Add-Type -AssemblyName System.Windows.Forms
$global:balmsg = New-Object System.Windows.Forms.NotifyIcon
$path = (Get-Process -id $pid).Path
$balmsg.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
$balmsg.BalloonTipText = $ToastText
$balmsg.BalloonTipTitle = $ToastTitle
$balmsg.Visible = $true
$balmsg.ShowBalloonTip(20000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment