Created
November 16, 2022 22:03
-
-
Save RobinBeismann/32f5dc3f3a609f9801ed3a62dfb148e7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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