{"id":3343,"date":"2025-07-26T16:40:17","date_gmt":"2025-07-26T08:40:17","guid":{"rendered":"https:\/\/www.jhouseconsulting.com\/?p=3343"},"modified":"2025-08-22T21:48:37","modified_gmt":"2025-08-22T13:48:37","slug":"priming-a-non-persistent-windows-image-using-an-autologon-process-with-an-auto-logoff-timer","status":"publish","type":"post","link":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/2025\/07\/26\/priming-a-non-persistent-windows-image-using-an-autologon-process-with-an-auto-logoff-timer-3343","title":{"rendered":"Priming a Non-persistent Windows Image using an Autologon Process with an Auto Logoff Timer"},"content":{"rendered":"\n<p>Several years ago, and inspired by an <a href=\"https:\/\/jgspiers.com\/citrix-director-reduce-logon-times\/\" target=\"_blank\" rel=\"noopener\" title=\"\">article<\/a> written by <a href=\"https:\/\/www.linkedin.com\/in\/jgs10\/\" target=\"_blank\" rel=\"noopener\" title=\"\">George Spiers<\/a> to reduce login times, where &#8220;the second logon is quicker&#8221;, together with some <a href=\"https:\/\/modalyitblog.wordpress.com\/2016\/10\/03\/powershell-gui-reboot-prompt\/\" target=\"_blank\" rel=\"noopener\" title=\"\">code<\/a> from <a href=\"https:\/\/www.linkedin.com\/in\/mauricedaly\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Maurice Daly<\/a>, I created a methodology and scripts that is designed to Autologon a non-persistent Session Host (both VDI and RDS), and then log it off again before another script will <a href=\"https:\/\/www.jhouseconsulting.com\/2019\/03\/04\/controlling-the-starting-of-the-citrix-desktop-service-brokeragent-1894\" target=\"_blank\" rel=\"noopener\" title=\"\">Start the Citrix Desktop Service (BrokerAgent)<\/a>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img fetchpriority=\"high\" decoding=\"async\" width=\"382\" height=\"440\" src=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-content\/uploads\/2025\/07\/Autologon-Logoff-Timer.png\" alt=\"\" class=\"wp-image-3354\" srcset=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-content\/uploads\/2025\/07\/Autologon-Logoff-Timer.png 382w, https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-content\/uploads\/2025\/07\/Autologon-Logoff-Timer-300x346.png 300w\" sizes=\"(max-width: 382px) 100vw, 382px\" \/><\/figure>\n<\/div>\n\n\n<p>It has been working flawlessly for years. However, I was never 100% happy with it because the process was using a domain (service) account for the Autologon process. The main challenge here was trying to change the password on a regular basis to stay compliant when managing multiple images. You cannot realistically do it without an outage. And in a 24&#215;7 environment, it becomes difficult and onerous. I also felt that using a domain account can be &#8220;heavy&#8221; during a boot storm as you need to ensure you are excluding this account from profile management and policies where possible. Sometimes that is easier said than done. There is a level of risk here, as someone can easily make a change that will cause issues. The ability to roll the password and stay compliant was my biggest concern and where I got stuck for quite some time.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>I spent a lot of time whiteboarding the process flow and all the moving parts (the scripts, registry values involved, etc). I realised that the only way to address this was to have a local account with a strong secure password (stored as an LSA Secret) that changes every time you rebuild the image, or re-run the script. You never need to record or know the password, and it can be different for each image. The local account is added to the local Users group by default, as there is no need for it to be a local Administrator. If you have the \u201cAllow log on locally\u201d policy set that excludes the local Users group, you\u2019ll either need to adjust this policy or add the user to the appropriate local group that allows them to logon locally. If needed there is a variable you can set that will add the account to the local Administrators group. The only constant needs to be the name of the local account so that it works in conjunction with my <a href=\"https:\/\/www.jhouseconsulting.com\/2019\/03\/04\/controlling-the-starting-of-the-citrix-desktop-service-brokeragent-1894\" target=\"_blank\" rel=\"noopener\">Start the Citrix Desktop Service (BrokerAgent) script.<\/a><\/p>\n<p>Then I got caught out by the Winlogon DefaultDomainName registry value without even realising that since Windows Vista and Server 2008 R1 it was no longer used to set the default logon Domain for the computer. Silly me! I had a Group Policy that would apply the Domain Name to this value by a registry preference, as that was once a best practice. So this would fill the DefaultDomainName registry value, breaking the Autologon of a local account. Together with these scripts and changes I made to the <a href=\"https:\/\/www.jhouseconsulting.com\/2019\/03\/04\/controlling-the-starting-of-the-citrix-desktop-service-brokeragent-1894\" target=\"_blank\" rel=\"noopener\">Start the Citrix Desktop Service (BrokerAgent) script<\/a>, I was finally able to get the process working as needed.<\/p>\n<p>Maybe these scenarios is also why Microsoft moved this Winlogon DefaultDomainName dependency starting from Windows Vista and Server 2008 R1 to a different registry location controlled by the &#8220;<a href=\"https:\/\/learn.microsoft.com\/en-us\/troubleshoot\/windows-server\/group-policy\/change-default-logon-domain-name\" target=\"_blank\" rel=\"noopener\">Assign a default domain for logon<\/a>&#8221; group policy setting.<\/p>\n\n\n\n<p>Now that I&#8217;ve overcome these challenges, I&#8217;m happy to share the scripts and process.<\/p>\n<p>Here is a video of a Session Host starting up, auto logging on using a local account named PrimeMySystem, and then auto logging off gracefully.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe title=\"AutoLogon Logoff Timer\" width=\"1200\" height=\"900\" src=\"https:\/\/www.youtube.com\/embed\/cJGS2Z3hgiY?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>Cool, isn&#8217;t it? \ud83d\ude42<\/p>\n\n\n\n<p>This process uses two PowerShell scripts and a batch script to make it simple to deploy.<\/p>\n<ul>\n<li><a  data-e-Disable-Page-Transition=\"true\" class=\"download-link\" title=\"\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/download\/3374\/?tmstv=1776914764\" rel=\"nofollow\" id=\"download-link-3374\" data-redirect=\"false\" >\n\tAutoLogonLogoffTimer.ps1\t(945 downloads\t)\n<\/a>\n &#8211; This PowerShell script is the UI with the countdown started by the Scheduled Task when the PrimeMySystem account logs on, which then gracefully logs off the session.<\/li>\n<li><a  data-e-Disable-Page-Transition=\"true\" class=\"download-link\" title=\"\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/download\/3376\/?tmstv=1776914764\" rel=\"nofollow\" id=\"download-link-3376\" data-redirect=\"false\" >\n\tAutoLogonScheduledTask.ps1\t(853 downloads\t)\n<\/a>\n &#8211; This PowerShell script creates the local account, generates a strong secure password, sets the Autologon registry values, stores the password as an LSA Secret, copies the AutoLogonLogoffTimer.ps1 to the C:\\Scripts folder, and creates the &#8220;Session Host Autologon Logoff Task&#8221; Scheduled Task.<\/li>\n<li><a  data-e-Disable-Page-Transition=\"true\" class=\"download-link\" title=\"\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/download\/3378\/?tmstv=1776914764\" rel=\"nofollow\" id=\"download-link-3378\" data-redirect=\"false\" >\n\tAutoLogonScheduledTask.cmd\t(888 downloads\t)\n<\/a>\n &#8211; This batch script can be used to run the AutoLogonScheduledTask.ps1 script with the required parameters.<\/li>\n<\/ul>\n<p>To deploy, download all 3 scripts and place them in the same folder. Run the batch script as administrator to complete the configuration and copy the AutoLogonLogoffTimer.ps1 script into place.<\/p>\n<p>As always, my scripts are well documented to help make them easy to follow.<\/p>\n<p>Here is the full code view of the <a  data-e-Disable-Page-Transition=\"true\" class=\"download-link\" title=\"\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/download\/3378\/?tmstv=1776914764\" rel=\"nofollow\" id=\"download-link-3378\" data-redirect=\"false\" >\n\tAutoLogonScheduledTask.cmd\t(888 downloads\t)\n<\/a>\n script<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\n@Echo Off\ncls\n:: This script will deploy the AutoLogon process\n\nSetLocal\n\nSet LocalLocation=%WinDir%\\Temp\n\ncopy \/y &quot;%~dp0AutoLogonScheduledTask.ps1&quot; &quot;%LocalLocation%&quot;\ncopy \/y &quot;%~dp0AutoLogonLogoffTimer.ps1&quot; &quot;%LocalLocation%&quot;\n\nPUSHD &quot;%LocalLocation%&quot;\n\nIF \/I &quot;%1&quot;==&quot;MDTBuildAccount&quot; GOTO MDT\nIF \/I &quot;%1&quot;==&quot;&quot; GOTO LocalAccount\n\n:MDT\npowershell.exe -ExecutionPolicy Bypass -Command &quot;&amp; '&quot;%LocalLocation%\\AutoLogonScheduledTask.ps1&quot;' -MDT -RemoveLegalPrompt -WaitForNetwork -RemoveDynamicSiteName&quot;\n\nGOTO Finish\n\n:LocalAccount\npowershell.exe -ExecutionPolicy Bypass -Command &quot;&amp; '&quot;%LocalLocation%\\AutoLogonScheduledTask.ps1&quot;' -NewLocalAdmin:'PrimeMySystem' -PasswordLength:20 -SpecialCharacters:5 -RemoveLegalPrompt -RemoveDynamicSiteName&quot;\n\n:Finish\n\nPOPD\n\ndel \/q &quot;%LocalLocation%\\AutoLogonScheduledTask.ps1&quot;\ndel \/q &quot;%LocalLocation%\\AutoLogonLogoffTimer.ps1&quot;\n\nEndLocal\nExit \/b 0\n<\/pre><\/div>\n\n\n<p>Here is the full code view of the <a  data-e-Disable-Page-Transition=\"true\" class=\"download-link\" title=\"\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/download\/3376\/?tmstv=1776914764\" rel=\"nofollow\" id=\"download-link-3376\" data-redirect=\"false\" >\n\tAutoLogonScheduledTask.ps1\t(853 downloads\t)\n<\/a>\n script<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\n&lt;#\n  This script sets the Citrix VDA autologon process by creating a scheduled task to logoff the auto logged on\n  session and copy the script into place. LSA secrets is used to store the password securely.\n\n  The script was first written in May 2017 and inspired by the &quot;Autologon account...&quot; section of an article\n  written by George Spiers:\n  - https:\/\/jgspiers.com\/citrix-director-reduce-logon-times\/\n\n  To secrure the password I have used a PowerShell function, written by Andy Arismendi called Set-SecureAutoLogon,\n  to manage the LSA secrets:\n  - https:\/\/andyarismendi.blogspot.com\/2011\/10\/powershell-set-secureautologon.html\n  There are also other references to a similar process here:\n  - https:\/\/www.onevinn.com\/blog\/windows-10-secure-autologon-powershell\n  - https:\/\/github.com\/Ccmexec\/MEMCM-OSD-Scripts\/tree\/master\/Kiosk%20scripts\n\n  In April 2022 it became clear that using a Domain account became too onerous for rolling password changes between\n  multiple images due to Cyber and\/or password policies, etc. So I started to work on a process that uses a local\n  account with a strong randomly generated password that is NOT exposed (recorded) and ONLY stored as an LSA secret.\n  I ran into a few challenges when using a local account for the Autologon process mainly due to the legacy\n  DefaultDomainName value being set by a Group Policy Preference. So I parked it for a while whilst I considered the\n  best approach. I enhanced the StartCitrixDesktopService.ps1 script on 31st January 2023 allowing for the\n  DefaultDomainName value to be managed, and have only just returned to complete the local account enhancements as\n  of 16th July 2025. In order for this to work you must NOT set the DefaultDomainName by Group Policy under the\n  &quot;HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon&quot; registry key. Note that the &quot;Assign a\n  default domain for logon&quot; Group Policy setting sets the DefaultLogonDomain value under the\n  &quot;HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System&quot; registry key, which does not affect\n  the Autologon process. If you want to set the DefaultDomainName value, use the additional functionality that I\n  have added into the StartCitrixDesktopService.ps1 script.\n  Reference:\n  - https:\/\/www.jhouseconsulting.com\/2019\/03\/04\/controlling-the-starting-of-the-citrix-desktop-service-brokeragent-1894\n\n  This script uses the Get-LocalUser, New-LocalUser, Set-LocalUser, Get-LocalGroupMember and Add-LocalGroupMember\n  cmdlets, which require PowerShell 5.1 (WMF 5.1) or later for the most part, so I have included functions that\n  support older versions of PowerShell.\n\n  Syntax Examples:\n\n    - To create and set the Autologon credentials and Scheduled Task as a new local user account\n      called &quot;PrimeMySystem&quot;, including removal of the legal prompts and the DynamicSiteName.\n      AutoLogonScheduledTask.ps1 -NewLocalUser:&quot;PrimeMySystem&quot; -PasswordLength:20 -SpecialCharacters:5 -RemoveLegalPrompt -RemoveDynamicSiteName\n\n    - To set the Autologon credentials and Scheduled Task as the MDT Domain Join account, including\n      removal of the legal prompts, the DynamicSiteName, and set the always wait for the network policy.\n      AutoLogonScheduledTask.ps1 -MDT -RemoveLegalPrompt -WaitForNetwork -RemoveDynamicSiteName\n\n  Where...\n  -NewLocalUser          = New local user to create that will be used for the AutoLogon process.\n  -MakeUserAnAdmin       = Add the user to the local Administrators group. Defaults to false.\n  -PasswordLength        = Length of the randomly generated strong password. Defaults to 20.\n  -SpecialCharacters     = Number of special characters to use in the password. Defaults to 5.\n  -DomainAdminDomain     = Domain in FQDN format preferrably\n  -DomainAdmin           = Username that has permissions to move computer objects in AD.\n                           You would typically use the Domain join account here.\n  -DomainAdminPassword   = Password\n  -Decode                = Decode (Optional). This is needed if you pass the DomainAdminDomain,\n                           DomainAdmin and DomainAdminPassword variables from MDT.\n  -MDT                   = Get the DomainAdminDomain DomainAdmin DomainAdminPassword variables and\n                           automatically decrypt them. Note that the &quot;Microsoft.SMS.TSEnvironment&quot;\n                           object is only available during the Task Sequences. You cannot use this\n                           parameter to test this script outside of MDT.\n  -RemoveLegalPrompt     = Remove Legal Banner\n  -WaitForNetwork        = Enable Wait For Network\n  -RemoveDynamicSiteName = Remove the DynamicSiteName value from registry. This is important if\n                           building an image that will be deployed across multiple Active Directory\n                           Sites.\n\n  The registry values Keys for Autologon are found under the following key:\n  - HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\Current Version\\Winlogon\n  - The values are:\n    - DefaultUserName (REG_SZ) the account name used for the automatic logon.\n    - DefaultPassword (REG_SZ) the password for the account specified by the DefaultUserName. We\n      do not use this, as it is stored in plain text. Instead we store it securly as an LSA Secret.\n    - DefaultDomainName (REG_SZ) the domain name to which the account specified above is a member.\n      We leave this blank (empty) in order to use a local account.\n    - AutoAdminLogon (REG_SZ) Setting will cause the automatic logon to occur with the above\n      credentials, which includes the stored LSA Secret.\n    - AutoLogonCount (REG_DWORD) is set to the number of times you want the AutoAdminLogon to take\n      place. We don't need to set this here, as the AutoAdminLogon setting will allow the Session\n      Host to autologon, which is all we need.\n  The system will logon automatically with the specified credentials and decrement the AutoLogonCount\n  value until it reaches zero. When it reaches zero, the DefaultPassword, stored LSA Secret, and\n  AutoLogonCount values are deleted and the AutoAdminLogon value is set to 0. However, if the\n  AutoLogonCount value is missing altogether, the AutoAdminLogon value will remain set to 1 and the\n  system will continue to autologon after every reboot. This is okay for image management. But if\n  you want to use this for other purposes, setting the AutoLogonCount to 1 will achieve the same\n  outcome.\n\n  Script name: AutoLogonScheduledTask.ps1\n  Release 1.8\n  Written by Jeremy Saunders (jeremy@jhouseconsulting.com) 12th May 2017\n  Modified by Jeremy Saunders (jeremy@jhouseconsulting.com) 28th July 2025\n\n#&gt;\n#-------------------------------------------------------------\n&#x5B;cmdletbinding()]\nparam (\n    &#x5B;string]$NewLocalUser,\n    &#x5B;switch]$MakeUserAnAdmin,\n    &#x5B;int]$PasswordLength = 20,\n    &#x5B;int]$SpecialCharacters = 5,\n    &#x5B;string]$DomainAdmin,\n    &#x5B;string]$DomainAdminPassword,\n    &#x5B;System.Security.SecureString]$SecurePassword,\n    &#x5B;string]$DomainAdminDomain,\n    &#x5B;Int]$AutoLogonCount,\n    &#x5B;switch]$RemoveLegalPrompt,\n    &#x5B;switch]$WaitForNetwork,\n    &#x5B;switch]$RemoveDynamicSiteName,\n    &#x5B;switch]$Backup\n)\n\n# Set Powershell Compatibility Mode\nSet-StrictMode -Version 2.0\n\n# Enable verbose, warning and error mode\n$VerbosePreference = 'Continue'\n$WarningPreference = 'Continue'\n$ErrorPreference = 'Continue'\n\n#-------------------------------------------------------------\n\nFunction IsTaskSequence(&#x5B;switch] $verbose) {\n  # This code was taken from a discussion on the CodePlex PowerShell App Deployment Toolkit site.\n  # It was posted by mmashwani.\n  # The only issue with this function is that it writes terminating errors to the transcription log, which looks\n  # rather ugly. So this function will eventually be updated so that it checks for the existenace of the relevant\n  # snapins (Get-PSSnapin) and assemblies (&#x5B;AppDomain]::CurrentDomain.GetAssemblies()) that have been loaded.\n  # References:\n  # - https:\/\/richardspowershellblog.wordpress.com\/2007\/09\/30\/assemblies-loaded-in-powershell\/\n  # - http:\/\/learningpcs.blogspot.com.au\/2012\/06\/powershell-v2-test-if-assembly-is.html\n  Try {\n      &#x5B;__ComObject]$SMSTSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction 'SilentlyContinue' -ErrorVariable SMSTSEnvironmentErr\n  }\n  Catch {\n    # The Microsoft.SMS.TSEnvironment assembly is not present.\n  }\n  If ($SMSTSEnvironmentErr) {\n    Write-Verbose &quot;Unable to load ComObject &#x5B;Microsoft.SMS.TSEnvironment]. Therefore, script is not currently running from an MDT or SCCM Task Sequence.&quot; -verbose:$verbose\n    Return $false\n  }\n  ElseIf ($null -ne $SMSTSEnvironment) {\n    Write-Verbose &quot;Successfully loaded ComObject &#x5B;Microsoft.SMS.TSEnvironment]. Therefore, script is currently running from an MDT or SCCM Task Sequence.&quot; -verbose:$verbose\n    Return $true\n  }\n}\n\n#-------------------------------------------------------------\n$invalidChars = &#x5B;io.path]::GetInvalidFileNamechars() \n$datestampforfilename = ((Get-Date -format s).ToString() -replace &quot;&#x5B;$invalidChars]&quot;,&quot;-&quot;)\n\n# Get the current script path\n$ScriptPath = {Split-Path $MyInvocation.ScriptName}\n$ScriptPath = $(&amp;$ScriptPath)\n$ScriptName = &#x5B;System.IO.Path]::GetFilenameWithoutExtension($MyInvocation.MyCommand.Path.ToString())\n$Logfile = &quot;$ScriptName-$($datestampforfilename).txt&quot;\n$logPath = &quot;$($env:windir)\\Temp&quot;\n\nIf (IsTaskSequence) {\n  $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment \n  $logPath = $tsenv.Value(&quot;LogPath&quot;)\n}\n\n$logfile = &quot;$logPath\\$Logfile&quot;\n\ntry {\n  # The Microsoft.BDD.TaskSequencePSHost.exe (TSHOST) does not support\n  # transcription, so we wrap this in a try catch to prevent errors.\n  Start-Transcript $logFile\n}\ncatch {\n  Write-Verbose &quot;This host does not support transcription&quot;\n}\n\n#-------------------------------------------------------------\n\nFunction New-RandomPassword {\n  # This function was posted on Reddit by OPconfused: https:\/\/www.reddit.com\/r\/PowerShell\/comments\/17wz2xh\/powershell_generate_random_password\/\n  param(\n        &#x5B;Parameter(Mandatory)]\n        &#x5B;Alias('length')]\n        &#x5B;ValidateRange(0,30)]\n        &#x5B;int]$PasswordLength\n  )\n\n  $validCharacters = 48..57 + 65..90 + 97..122 + (\n      '!', '@', '#', '$', '%', '^', '&amp;', '*'\n  ) | ForEach-Object { &#x5B;char]$_ }\n\n  return (1..$PasswordLength | ForEach-Object {\n      Get-Random $validCharacters\n  }) -join ''\n}\n\nFunction GenerateStrongPassword {\n  # http:\/\/woshub.com\/generating-random-password-with-powershell\/\n  param (\n    &#x5B;parameter(Mandatory=$true)]&#x5B;int]$PasswordLength,\n    &#x5B;parameter(Mandatory=$true)]&#x5B;int]$SpecialCharacters\n  )\n  Add-Type -AssemblyName System.Web\n  $PassComplexCheck = $false\n  do {\n    $newPassword = &#x5B;System.Web.Security.Membership]::GeneratePassword($PasswordLength,$SpecialCharacters)\n    If ( ($newPassword -cmatch &quot;&#x5B;A-Z\\p{Lu}\\s]&quot;) `\n        -and ($newPassword -cmatch &quot;&#x5B;a-z\\p{Ll}\\s]&quot;) `\n        -and ($newPassword -match &quot;&#x5B;\\d]&quot;) `\n        -and ($newPassword -match &quot;&#x5B;^\\w]&quot;)\n      ) {\n      $PassComplexCheck = $True\n    }\n  } While ($PassComplexCheck -eq $false)\n  return $newPassword\n}\n\nfunction Test-RegistryValue {\n  param (\n    &#x5B;parameter(Mandatory=$true)]\n    &#x5B;ValidateNotNullOrEmpty()]$Path,\n    &#x5B;parameter(Mandatory=$true)]\n    &#x5B;ValidateNotNullOrEmpty()]$Value\n  )\n  # Create a drive to HKEY_CLASSES_ROOT &amp; HKEY_CURRENT_USER. By default these two\n  # registry geys are not available for mounting and using in PowerShell.\n  if (!(get-psdrive hkcr -ea 0)){New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT | out-null}\n  if (!(get-psdrive hku -ea 0)){New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS | out-null}\n  $ErrorActionPreference = &quot;stop&quot;\n  try {\n    If ((Get-ItemProperty -Path &quot;$Path&quot; | Select-Object -ExpandProperty &quot;$Value&quot;) -ne $null) {\n      return $true\n    } Else {\n      return $false\n    }\n  }\n  catch {\n    return $false\n  }\n  finally { $ErrorActionPreference = &quot;Continue&quot; }\n}\n\nfunction Test-RegistryPath {\n  param (\n    &#x5B;parameter(Mandatory=$true)]\n    &#x5B;ValidateNotNullOrEmpty()]$Path\n  )\n  # Create a drive to HKEY_CLASSES_ROOT &amp; HKEY_CURRENT_USER. By default these two\n  # registry geys are not available for mounting and using in PowerShell.\n  if (!(get-psdrive hkcr -ea 0)){New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT | out-null}\n  if (!(get-psdrive hku -ea 0)){New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS | out-null}\n  $ErrorActionPreference = &quot;stop&quot;\n  try {\n    Get-Item -Path &quot;$Path&quot; | Out-Null\n    return $true\n  }\n  catch {\n    return $false\n  }\n  finally { $ErrorActionPreference = &quot;Continue&quot; }\n}\n\nfunction createLocalUser {\n  # This function was written for backward PowerShell compatibility.\n  # - It creates a new users and adds it to the default &quot;Users&quot; group.\n  # - It only supports passing a clear text password (no SecureString compatibility).\n  # - UserFlags is a bitmask. The 0x10000 flag corresponds to &quot;Password never expires&quot;.\n  # - AccountExpirationDate is not supported by the WinNT ADSI Provider.\n  param (\n    &#x5B;string]$Username,\n    &#x5B;string]$Password,\n    &#x5B;string]$Description,\n    &#x5B;switch]$PasswordNeverExpires\n  )\n  try {\n    # Check if user already exists\n    $existingUser = &#x5B;ADSI]&quot;WinNT:\/\/$env:COMPUTERNAME\/$Username,user&quot;\n    if ($existingUser.Name -eq $Username) {\n      $existingUser.SetPassword($Password)\n      $existingUser.SetInfo()\n      # Set 'password never expires' if requested\n      if ($PasswordNeverExpires) {\n        #DONT_EXPIRE_PASSWORD 0x10000 65536\n        $existingUser.UserFlags = 65536\n        $existingUser.SetInfo()\n      }\n      return $True\n    }\n  } catch {\n    # User does not exist, continue\n  }\n  try {\n    # Create new user\n    $computer = &#x5B;ADSI]&quot;WinNT:\/\/$env:COMPUTERNAME&quot;\n    $user = $computer.Create(&quot;User&quot;, $Username)\n    $user.SetPassword($Password)\n    $user.SetInfo()\n    $user.Description = $Description\n    $user.SetInfo()\n    # Set 'password never expires' if requested\n    if ($PasswordNeverExpires) {\n      #DONT_EXPIRE_PASSWORD 0x10000 65536\n      $user.UserFlags = 65536\n      $user.SetInfo()\n    }\n    # Add user to 'Users' group\n    $group = &#x5B;ADSI]&quot;WinNT:\/\/$env:COMPUTERNAME\/Users,group&quot;\n    $group.Add(&quot;WinNT:\/\/$env:COMPUTERNAME\/$Username,user&quot;)\n    return $True\n  } catch {\n    return $False\n  }\n}\n\nfunction addUser2Group\n{   \n    # This function was written by Ethol Palmer and posted to stackoverflow:\n    # - https:\/\/stackoverflow.com\/questions\/13929960\/add-user-to-local-group\/14262326#14262326\n    Param(\n        &#x5B;string]$user,\n        &#x5B;string]$group\n    )\n\n    $cname = gc env:computername\n    $objUser = &#x5B;ADSI](&quot;WinNT:\/\/$user&quot;)\n    $objGroup = &#x5B;ADSI](&quot;WinNT:\/\/$cname\/$group,group&quot;)\n    $members = $objGroup.Invoke('Members')\n    $found = $false\n\n    foreach($m in $members)\n    {\n        if($m.GetType().InvokeMember('Name', 'GetProperty', $null, $m, $null) -eq $user)\n        {\n            $found = $true\n        }\n    }\n\n    if(-not $found)\n    {\n        $objGroup.PSBase.Invoke('Add',$objUser.PSBase.Path)\n    }\n\n    $members = $objGroup.PSBase.Invoke('Members')\n    $found = $false\n    foreach($m in $members)\n    {\n        if($m.GetType().InvokeMember('Name', 'GetProperty', $null, $m, $null) -eq $user)\n        {\n            $found = $true\n        }\n    }\n\n    return $found\n}\n\n#-------------------------------------------------------------\n\n$ExitCode = 0\n$GoodToProceed = $False\n\n\nIf (&#x5B;string]::IsNullOrEmpty($NewLocalUser)) {\n  If ($MDT) {\n    If (IsTaskSequence) {\n      Write-Verbose &quot;Reading Task Sequence variables&quot; -verbose\n      $Decode = $True\n      $DomainAdminDomain = $tsenv.Value(&quot;UserDomain&quot;)\n      $DomainAdmin = $tsenv.Value(&quot;UserID&quot;)\n      $DomainAdminPassword = $tsenv.Value(&quot;UserPassword&quot;)\n    } Else {\n      Write-Verbose &quot;This script is not running from a task sequence&quot; -verbose\n    }\n  }\n  If (!&#x5B;string]::IsNullOrEmpty($DomainAdminDomain) -AND !&#x5B;string]::IsNullOrEmpty($DomainAdmin) -AND (!&#x5B;string]::IsNullOrEmpty($DomainAdminPassword) -OR !&#x5B;string]::IsNullOrEmpty($SecurePassword))) {\n    $GoodToProceed = $True\n    If ($Decode) {\n      # Decode the base64 encoded blob using UTF-8\n      $DomainAdminDomain = &#x5B;System.Text.Encoding]::UTF8.GetString(&#x5B;System.Convert]::FromBase64String($DomainAdminDomain))\n      $DomainAdmin = &#x5B;System.Text.Encoding]::UTF8.GetString(&#x5B;System.Convert]::FromBase64String($DomainAdmin))\n      $DomainAdminPassword = &#x5B;System.Text.Encoding]::UTF8.GetString(&#x5B;System.Convert]::FromBase64String($DomainAdminPassword))\n    }\n    If (!&#x5B;string]::IsNullOrEmpty($DomainAdminPassword)) {\n      $DomainAdminPasswordSecureString = ConvertTo-SecureString -String $DomainAdminPassword -AsPlainText -Force\n    } Else {\n      $DomainAdminPasswordSecureString = $SecurePassword\n    }\n    $DefaultUserName = $DomainAdmin\n    $DefaultDomainName = $DomainAdminDomain\n    $PasswordSecureString = $DomainAdminPasswordSecureString\n    $SecurityPrincipal = &quot;$DefaultDomainName\\$DefaultUserName&quot;\n  }\n}\n\nIf (!&#x5B;string]::IsNullOrEmpty($NewLocalUser)) {\n  $GoodToProceed = $True\n\n  #$StrongPassword = New-RandomPassword -PasswordLength:$PasswordLength\n  $StrongPassword = GenerateStrongPassword -PasswordLength:$PasswordLength -SpecialCharacters:$SpecialCharacters\n  $StrongPasswordAsSecureString = ConvertTo-SecureString &quot;$StrongPassword&quot; -AsPlainText -Force\n\n  $CreateLocalUser = $True\n\n  # I have included the createLocalUser function if you are running a PowerShell version less than 5.1.\n  If (($PSVersionTable.PSVersion.Major -eq 5 -AND $PSVersionTable.PSVersion.Minor -ge 1) -OR $PSVersionTable.PSVersion.Major -gt 5) {\n    $ErrorActionPreference = &quot;stop&quot;\n    Try {\n      Get-LocalUser -Name &quot;$NewLocalUser&quot; | out-null\n      $CreateLocalUser = $False\n    }\n    Catch {\n      # Local Admin not found\n    }\n    $ErrorActionPreference = &quot;Continue&quot;\n    If ($CreateLocalUser) {\n      write-verbose &quot;Creating the `&quot;$NewLocalUser`&quot; account with a randomly generated strong password&quot; -verbose\n      New-LocalUser &quot;$NewLocalUser&quot; -Password $StrongPasswordAsSecureString -FullName &quot;$NewLocalUser&quot; -Description &quot;$NewLocalUser Account&quot; -PasswordNeverExpires -AccountNeverExpires | out-null\n    } Else {\n      write-verbose &quot;The `&quot;$NewLocalUser`&quot; account already exists&quot; -verbose\n      write-verbose &quot;Setting its password to a randomly generated strong password&quot; -verbose\n      Set-LocalUser -Name &quot;$NewLocalUser&quot; -Password $StrongPasswordAsSecureString\n    }\n  } Else {\n    write-verbose &quot;Creating the `&quot;$NewLocalUser`&quot; account with a randomly generated strong password&quot; -verbose\n    createLocalUser -Username &quot;$NewLocalUser&quot; -Password $StrongPassword -Description &quot;$NewLocalUser Account&quot; -PasswordNeverExpires | out-null\n  }\n\n  # I have included the addUser2Group function if you are running a PowerShell version less than 5.1.\n  $LocalGroupName = &quot;Users&quot;\n  If ($MakeUserAnAdmin) {\n    $LocalGroupName = &quot;Administrators&quot;\n  }\n  If (($PSVersionTable.PSVersion.Major -eq 5 -AND $PSVersionTable.PSVersion.Minor -ge 1) -OR $PSVersionTable.PSVersion.Major -gt 5) {\n    $isInGroup = (Get-LocalGroupMember -Group &quot;$LocalGroupName&quot;).Name -contains &quot;$env:COMPUTERNAME\\$NewLocalUser&quot;\n    If ($isInGroup -eq $False) {\n      write-verbose &quot;Adding the `&quot;$NewLocalUser`&quot; account to the local `&quot;$LocalGroupName`&quot; group&quot; -verbose\n      Add-LocalGroupMember -Group &quot;$LocalGroupName&quot; -Member &quot;$NewLocalUser&quot;\n    } Else {\n      write-verbose &quot;The `&quot;$NewLocalUser`&quot; account is already a member of the local `&quot;$LocalGroupName`&quot; group&quot; -verbose\n    }\n  } Else {\n    write-verbose &quot;Adding the `&quot;$NewLocalUser`&quot; account to the local `&quot;$LocalGroupName`&quot; group&quot; -verbose\n    addUser2Group -user &quot;$NewLocalUser&quot; -group &quot;$LocalGroupName&quot; | out-null\n  }\n\n  $DefaultUserName = &quot;$NewLocalUser&quot;\n  $DefaultDomainName = &quot;&quot;\n  $PasswordSecureString = $StrongPasswordAsSecureString\n  #$SecurityPrincipal = &quot;$ENV:COMPUTERNAME\\$DefaultUserName&quot;\n  $SecurityPrincipal = &quot;$DefaultUserName&quot;\n}\n\nIf ($GoodToProceed) {\n\n  &#x5B;string] $WinlogonPath = &quot;HKLM:\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon&quot;\n  &#x5B;string] $WinlogonPolicyPath = &quot;HKLM:\\Software\\Policies\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon&quot;\n  &#x5B;string] $WinlogonBannerPolicyPath = &quot;HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System&quot;\n  &#x5B;string] $NetlogonParametersPath = &quot;HKLM:\\System\\CurrentControlSet\\Services\\Netlogon\\parameters&quot;\n\n  &#x5B;string] $Enable = 1\n  &#x5B;string] $Disable = 0\n\n  #region C# Code to P-invoke LSA LsaStorePrivateData function.\n  Add-Type @&quot;\n    using System;\n    using System.Collections.Generic;\n    using System.Text;\n    using System.Runtime.InteropServices;\n \n    namespace ComputerSystem\n    {\n       public class LSAutil\n       {\n           &#x5B;StructLayout(LayoutKind.Sequential)]\n           private struct LSA_UNICODE_STRING\n           {\n               public UInt16 Length;\n               public UInt16 MaximumLength;\n               public IntPtr Buffer;\n           }\n \n           &#x5B;StructLayout(LayoutKind.Sequential)]\n           private struct LSA_OBJECT_ATTRIBUTES\n           {\n               public int Length;\n               public IntPtr RootDirectory;\n               public LSA_UNICODE_STRING ObjectName;\n               public uint Attributes;\n               public IntPtr SecurityDescriptor;\n               public IntPtr SecurityQualityOfService;\n           }\n \n           private enum LSA_AccessPolicy : long\n           {\n               POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,\n               POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,\n               POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,\n               POLICY_TRUST_ADMIN = 0x00000008L,\n               POLICY_CREATE_ACCOUNT = 0x00000010L,\n               POLICY_CREATE_SECRET = 0x00000020L,\n               POLICY_CREATE_PRIVILEGE = 0x00000040L,\n               POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,\n               POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,\n               POLICY_AUDIT_LOG_ADMIN = 0x00000200L,\n               POLICY_SERVER_ADMIN = 0x00000400L,\n               POLICY_LOOKUP_NAMES = 0x00000800L,\n               POLICY_NOTIFICATION = 0x00001000L\n           }\n \n           &#x5B;DllImport(&quot;advapi32.dll&quot;, SetLastError = true, PreserveSig = true)]\n           private static extern uint LsaRetrievePrivateData(\n                       IntPtr PolicyHandle,\n                       ref LSA_UNICODE_STRING KeyName,\n                       out IntPtr PrivateData\n           );\n \n           &#x5B;DllImport(&quot;advapi32.dll&quot;, SetLastError = true, PreserveSig = true)]\n           private static extern uint LsaStorePrivateData(\n                   IntPtr policyHandle,\n                   ref LSA_UNICODE_STRING KeyName,\n                   ref LSA_UNICODE_STRING PrivateData\n           );\n \n           &#x5B;DllImport(&quot;advapi32.dll&quot;, SetLastError = true, PreserveSig = true)]\n           private static extern uint LsaOpenPolicy(\n               ref LSA_UNICODE_STRING SystemName,\n               ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,\n               uint DesiredAccess,\n               out IntPtr PolicyHandle\n           );\n \n           &#x5B;DllImport(&quot;advapi32.dll&quot;, SetLastError = true, PreserveSig = true)]\n           private static extern uint LsaNtStatusToWinError(\n               uint status\n           );\n \n           &#x5B;DllImport(&quot;advapi32.dll&quot;, SetLastError = true, PreserveSig = true)]\n           private static extern uint LsaClose(\n               IntPtr policyHandle\n           );\n \n           &#x5B;DllImport(&quot;advapi32.dll&quot;, SetLastError = true, PreserveSig = true)]\n           private static extern uint LsaFreeMemory(\n               IntPtr buffer\n           );\n \n           private LSA_OBJECT_ATTRIBUTES objectAttributes;\n           private LSA_UNICODE_STRING localsystem;\n           private LSA_UNICODE_STRING secretName;\n \n           public LSAutil(string key)\n           {\n               if (key.Length == 0)\n               {\n                   throw new Exception(&quot;Key lenght zero&quot;);\n               }\n \n               objectAttributes = new LSA_OBJECT_ATTRIBUTES();\n               objectAttributes.Length = 0;\n               objectAttributes.RootDirectory = IntPtr.Zero;\n               objectAttributes.Attributes = 0;\n               objectAttributes.SecurityDescriptor = IntPtr.Zero;\n               objectAttributes.SecurityQualityOfService = IntPtr.Zero;\n \n               localsystem = new LSA_UNICODE_STRING();\n               localsystem.Buffer = IntPtr.Zero;\n               localsystem.Length = 0;\n               localsystem.MaximumLength = 0;\n \n               secretName = new LSA_UNICODE_STRING();\n               secretName.Buffer = Marshal.StringToHGlobalUni(key);\n               secretName.Length = (UInt16)(key.Length * UnicodeEncoding.CharSize);\n               secretName.MaximumLength = (UInt16)((key.Length + 1) * UnicodeEncoding.CharSize);\n           }\n \n           private IntPtr GetLsaPolicy(LSA_AccessPolicy access)\n           {\n               IntPtr LsaPolicyHandle;\n \n               uint ntsResult = LsaOpenPolicy(ref this.localsystem, ref this.objectAttributes, (uint)access, out LsaPolicyHandle);\n \n               uint winErrorCode = LsaNtStatusToWinError(ntsResult);\n               if (winErrorCode != 0)\n               {\n                   throw new Exception(&quot;LsaOpenPolicy failed: &quot; + winErrorCode);\n               }\n \n               return LsaPolicyHandle;\n           }\n \n           private static void ReleaseLsaPolicy(IntPtr LsaPolicyHandle)\n           {\n               uint ntsResult = LsaClose(LsaPolicyHandle);\n               uint winErrorCode = LsaNtStatusToWinError(ntsResult);\n               if (winErrorCode != 0)\n               {\n                   throw new Exception(&quot;LsaClose failed: &quot; + winErrorCode);\n               }\n           }\n \n           public void SetSecret(string value)\n           {\n               LSA_UNICODE_STRING lusSecretData = new LSA_UNICODE_STRING();\n \n               if (value.Length &gt; 0)\n               {\n                   \/\/Create data and key\n                   lusSecretData.Buffer = Marshal.StringToHGlobalUni(value);\n                   lusSecretData.Length = (UInt16)(value.Length * UnicodeEncoding.CharSize);\n                   lusSecretData.MaximumLength = (UInt16)((value.Length + 1) * UnicodeEncoding.CharSize);\n               }\n               else\n               {\n                   \/\/Delete data and key\n                   lusSecretData.Buffer = IntPtr.Zero;\n                   lusSecretData.Length = 0;\n                   lusSecretData.MaximumLength = 0;\n               }\n \n               IntPtr LsaPolicyHandle = GetLsaPolicy(LSA_AccessPolicy.POLICY_CREATE_SECRET);\n               uint result = LsaStorePrivateData(LsaPolicyHandle, ref secretName, ref lusSecretData);\n               ReleaseLsaPolicy(LsaPolicyHandle);\n \n               uint winErrorCode = LsaNtStatusToWinError(result);\n               if (winErrorCode != 0)\n               {\n                   throw new Exception(&quot;StorePrivateData failed: &quot; + winErrorCode);\n               }\n           }\n       }\n   }\n&quot;@\n  #endregion\n\n  try {\n    $ErrorActionPreference = &quot;Stop&quot;\n    $decryptedPass = &#x5B;Runtime.InteropServices.Marshal]::PtrToStringAuto(\n                     &#x5B;Runtime.InteropServices.Marshal]::SecureStringToBSTR($PasswordSecureString))\n    $ErrorActionPreference = &quot;Continue&quot;\n    If ($Backup) {\n      try {\n        $WinlogonPathProps = Get-ItemProperty -Path $WinlogonPath\n\n        write-verbose &quot;Backing up settings from: $($WinlogonPath)&quot; -verbose\n        write-verbose &quot;- AutoAdminLogon: $($WinlogonPathProps.AutoAdminLogon)&quot; -verbose\n        If ($WinlogonPathProps -match &quot;^ForceAutoLogon$&quot;) {\n          write-verbose &quot;- ForceAutoLogon: $($WinlogonPathProps.ForceAutoLogon)&quot; -verbose\n        }\n        write-verbose &quot;- DefaultUserName: $($WinlogonPathProps.DefaultUserName)&quot; -verbose\n        write-verbose &quot;- DefaultDomainName: $($WinlogonPathProps.DefaultDomainName)&quot; -verbose\n        If ($WinlogonPathProps -match &quot;^DefaultPassword$&quot;) {\n          write-verbose &quot;- DefaultPassword: $($WinlogonPathProps.DefaultPassword)&quot; -verbose\n        }\n        If ($WinlogonPathProps -match &quot;^AutoLogonCount$&quot;) {\n          write-verbose &quot;- AutoLogonCount: $($WinlogonPathProps.AutoLogonCount)&quot; -verbose\n        }\n\n        # The winlogon logon banner settings.\n        write-verbose &quot;- LegalNoticeCaption: $($WinlogonPathProps.LegalNoticeCaption)&quot; -verbose\n        write-verbose &quot;- LegalNoticeText: $($WinlogonPathProps.LegalNoticeText)&quot; -verbose\n\n        # The system policy logon banner settings.\n        $WinlogonBannerPolicyPathProps = Get-ItemProperty -Path $WinlogonBannerPolicyPath\n        write-verbose &quot;Backing up settings from: $($WinlogonBannerPolicyPath)&quot; -verbose\n        write-verbose &quot;- legalnoticecaption: $($WinlogonBannerPolicyPathProps.legalnoticecaption)&quot; -verbose\n        write-verbose &quot;- legalnoticetext: $($WinlogonBannerPolicyPathProps.legalnoticetext)&quot; -verbose\n      }\n      catch {\n       #$_.Exception.Message\n      }\n    }\n         \n    # Store the password securely.\n    $ErrorActionPreference = &quot;Stop&quot;\n    write-verbose &quot;Storing the password securely as an LSA Secret.&quot; -verbose\n    $lsaUtil = New-Object ComputerSystem.LSAutil -ArgumentList &quot;DefaultPassword&quot;\n    $lsaUtil.SetSecret($decryptedPass)\n    $ErrorActionPreference = &quot;Continue&quot;\n\n    # Store the autologon registry settings.\n    write-verbose &quot;Setting the AutoAdminLogon registry value.&quot; -verbose\n    Set-ItemProperty -Path $WinlogonPath -Name AutoAdminLogon -Value $Enable -Type STRING -Force\n    write-verbose &quot;Setting the DefaultUserName registry value.&quot; -verbose\n    Set-ItemProperty -Path $WinlogonPath -Name DefaultUserName -Value $DefaultUserName -Type STRING -Force\n    write-verbose &quot;Setting the DefaultDomainName registry value.&quot; -verbose\n    Set-ItemProperty -Path $WinlogonPath -Name DefaultDomainName -Value $DefaultDomainName -Type STRING -Force\n \n    if ($AutoLogonCount) {\n      write-verbose &quot;Setting the AutoLogonCount registry value.&quot; -verbose\n      Set-ItemProperty -Path $WinlogonPath -Name AutoLogonCount -Value $AutoLogonCount -Type DWORD -Force\n    } else {\n      write-verbose &quot;Removing the AutoLogonCount registry value.&quot; -verbose\n      Remove-ItemProperty -Path $WinlogonPath -Name AutoLogonCount -ErrorAction SilentlyContinue\n    }\n \n    # Remove an existing DefaultPassword value which will break the secure-autologon\n    write-verbose &quot;Removing the DefaultPassword registry value.&quot; -verbose\n    Remove-ItemProperty -Path $WinlogonPath -Name DefaultPassword -ErrorAction SilentlyContinue\n\n    if ($RemoveDynamicSiteName) {\n      # Remove the DynamicSiteName registry value\n      write-verbose &quot;Removing the DynamicSiteName registry value.&quot; -verbose\n      If (Test-RegistryValue -Path &quot;$NetlogonParametersPath&quot; -Value &quot;DynamicSiteName&quot;) {\n        Remove-ItemProperty -Path $NetlogonParametersPath -Name DynamicSiteName -Force\n      }\n    }\n\n    if ($WaitForNetwork) {\n      # Always wait for the network at computer startup and logon. The autologon could fail if\n      # the network isn't ready.\n      write-verbose &quot;Setting the Always wait for the network at computer startup and logon (SyncForegroundPolicy) registry value.&quot; -verbose\n      If (!(Test-RegistryPath -Path &quot;$WinlogonPolicyPath&quot;)) {\n        New-Item -Path &quot;$WinlogonPolicyPath&quot; -Force | Out-Null\n      }\n      Set-ItemProperty -Path $WinlogonPolicyPath -Name SyncForegroundPolicy -Value 1 -Type DWORD -Force\n    }\n\n    if ($RemoveLegalPrompt) {\n      write-verbose &quot;Removing the LegalNoticeCaption and LegalNoticeText registry values&quot; -verbose\n      Set-ItemProperty -Path $WinlogonPath -Name LegalNoticeCaption -Value $null -Force\n      Set-ItemProperty -Path $WinlogonPath -Name LegalNoticeText -Value $null -Force\n\n      If (Test-RegistryPath -Path &quot;$WinlogonPolicyPath&quot;) {\n        Set-ItemProperty -Path $WinlogonBannerPolicyPath -Name legalnoticecaption -Value $null -Force\n        Set-ItemProperty -Path $WinlogonBannerPolicyPath -Name legalnoticetext -Value $null -Force\n      }\n    }\n\n    write-verbose &quot;Successfully set autologon&quot; -verbose\n\n  } catch {\n    #$_.Exception.Message\n    $ExitCode = 1\n  }\n\n  # Copy the auto logoff script into place\n\n  $Scripts = &quot;$env:SystemDrive\\Scripts&quot;\n  If (-not(Test-Path -Path &quot;$Scripts&quot;)) {\n    New-Item -Path &quot;$Scripts&quot; -ItemType Directory | Out-Null\n  }\n\n  # Push the current location onto a location stack and then change the current location to the location specified\n  Push-Location &quot;$ScriptPath&quot;\n\n  If (Test-Path -path &quot;$ScriptPath\\AutoLogonLogoffTimer.ps1&quot;) {\n    write-verbose &quot;Copying the AutoLogonLogoffTimer.ps1 script into place.&quot; -verbose\n    copy-item -path &quot;.\\AutoLogonLogoffTimer.ps1&quot; -Destination &quot;$Scripts\\&quot; -Recurse -Force -Verbose\n  } Else {\n    write-warning &quot;The AutoLogonLogoffTimer.ps1 script is missing!&quot; -verbose\n  }\n\n  # Change the current location back to the location most recently pushed onto the stack\n  Pop-Location\n\n  # Create the Scheduled Task\n  write-verbose &quot;Creating the Scheduled Task.&quot; -verbose\n\n  # The name of the scheduled task\n  $taskName = &quot;Session Host Autologon Logoff Task&quot;\n\n  # The task description\n  $taskDescription = &quot;This task is created to logoff the autologon session after a Session Host has been restarted&quot;\n\n  # We can delay the logoff task by x seconds if needed to give the autologon process a chance to complete\n  $AddDelayTrigger = $True\n  $DelayedStartInSeconds = 30\n\n  # The Task Action command\n  #$TaskCommand = &quot;${env:SystemRoot}\\system32\\WindowsPowerShell\\v1.0\\powershell.exe&quot;\n  $TaskCommand = @(Get-Command powershell.exe)&#x5B;0].Definition\n\n  # The script to be executed\n  $TaskScript = &quot;$Scripts\\AutoLogonLogoffTimer.ps1&quot;\n\n  # The Task Action command argument\n  #$TaskArguments = '-Executionpolicy bypass -WindowStyle Minimized -Command &quot;&amp; ' + &quot; '&quot; + $TaskScript + &quot;'&quot;\n  $TaskArguments = '-Executionpolicy bypass -WindowStyle Minimized -Command &quot;&amp; ' + &quot; '&quot; + $TaskScript + &quot;'&quot; + '&quot;'\n\n  $taskSecurityPrincipal = $SecurityPrincipal\n\n  # Create the TaskService object.\n  Try {\n    &#x5B;Object] $service = new-object -com(&quot;Schedule.Service&quot;)\n    If (!($service.Connected)){\n      Try {\n        $service.Connect()\n        # Get a folder to create a task definition in\n        # This is actually the %SystemRoot%\\System32\\Tasks folder.\n        $rootFolder = $service.GetFolder(&quot;\\&quot;)\n\n        # Delete the task if already present\n        $ScheduledTasks = $rootFolder.GetTasks(0)\n        $Task = $ScheduledTasks | Where-Object{$_.Name -eq &quot;$TaskName&quot;}\n        If ($Task -ne $Null){\n          Try {\n            $rootFolder.DeleteTask($Task.Name,0)\n            # 'Success'\n          }\n          Catch &#x5B;System.Exception]{\n            # 'Exception Returned'\n          }\n        } Else {\n          # &quot;Task Not Found&quot;\n        }\n\n        # Create the new task\n        $taskDefinition = $service.NewTask(0)\n\n        $taskPrincipal = $taskDefinition.Principal\n        # InteractiveToken\n        $taskPrincipal.LogonType = 3\n        # Must be a valid user account\n        $taskPrincipal.UserID = $taskSecurityPrincipal\n        $taskPrincipal.RunLevel = 0\n\n        # Create a registration trigger with a trigger type of (9) LogonTrigger\n        $triggers = $taskDefinition.Triggers\n        $trigger = $triggers.Create(9)\n        $trigger.ExecutionTimeLimit = &quot;PT30M&quot;\n        If ($AddDelayTrigger) {\n          # The delay time in seconds before the task runs once it's been triggered\n          $trigger.Delay = &quot;PT${DelayedStartInSeconds}S&quot;\n        }\n\n        # Begin the task only when the autologon user logs on\n        $trigger.UserID = $taskSecurityPrincipal\n        $trigger.Enabled = $true\n\n        # Create the action for the task to execute.\n        $Action = $taskDefinition.Actions.Create(0)\n        $Action.Path = $TaskCommand\n        $Action.Arguments = $TaskArguments\n        $Action.WorkingDirectory = &quot;&quot;\n\n        # Register (create) the task.\n        $Settings = $taskDefinition.Settings\n        # Set the Task Compatibility to V2 (Windows 7\/2008R2)\n        $Settings.Compatibility = 3\n        # The default task priority 7 (below normal), so we set this back to normal\n        $Settings.Priority = 6\n        $Settings.AllowDemandStart = $true\n        $Settings.StopIfGoingOnBatteries = $false\n        $Settings.DisallowStartIfOnBatteries = $false\n\n        $regInfo = $taskDefinition.RegistrationInfo\n        $regInfo.Description = $taskDescription\n        $regInfo.Author = $Env:Username\n\n        # Note that the task is created as an XML file under the %SystemRoot%\\System32\\Tasks folder\n        # 6 == Task Create or Update\n        # 3 == LogonTypeInteractive\n        $rootFolder.RegisterTaskDefinition($taskName, $taskDefinition, 6, '', '', 3) | Out-Null\n        write-verbose &quot;- Scheduled Task Created Successfully&quot; -verbose\n      }\n      Catch &#x5B;System.Exception]{\n        write-warning &quot;- Scheduled Task Creation Failed&quot; -verbose\n        $ExitCode = 1\n      }\n    }\n  }\n  Catch &#x5B;System.Exception]{\n    write-warning &quot;- Scheduled Task Creation Failed&quot; -verbose\n    $ExitCode = 1\n  }\n\n} Else {\n  write-warning &quot;Missing credentials.&quot; -verbose\n  $ExitCode = 1\n}\n\ntry {\n  # The Microsoft.BDD.TaskSequencePSHost.exe (TSHOST) does not support\n  # transcription, so we wrap this in a try catch to prevent errors.\n  Stop-Transcript\n}\ncatch {\n  Write-Verbose &quot;This host does not support transcription&quot;\n}\nExit $ExitCode\n<\/pre><\/div>\n\n\n<p>Here is the full code view of the <a  data-e-Disable-Page-Transition=\"true\" class=\"download-link\" title=\"\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/download\/3374\/?tmstv=1776914764\" rel=\"nofollow\" id=\"download-link-3374\" data-redirect=\"false\" >\n\tAutoLogonLogoffTimer.ps1\t(945 downloads\t)\n<\/a>\n script<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\n&lt;#\n  This script provides a countdown timer with progress bar in a nice UI that\n  will automatically logoff the session when the countdown reaches 0.\n\n  It was primarily written to help manage the post reboot process of Citrix\n  VDA Session Hosts. When a Citrix VDA restarts as part of scheduled reboots,\n  for example, or when non-persistent desktops reboot to reset, the first\n  logon is generally always the longest. So we use an autologon account to\n  prime the VDA when it restarts. This script will logoff the auto logged on\n  session when the countdown reaches 0.\n\n  I have found it more reliable to use shutdown.exe instead of logoff.exe so\n  that we can forcibly logoff the session as logoff.exe sometimes gets stuck\n  due to running processes.\n\n  So use...\n    shutdown.exe \/l \/f\n      where...\n        \/l = logoff\n        \/f = force\n\n  Note that the &quot;Last Run Result&quot; of the scheduled task will be 0x40010004\n  because we forcefully logoff the session which kills the process (this\n  script) causing it to exit with a code of 0x40010004.\n\n  Based on a script written by Maurice Daly on 04\/10\/2016\n  - https:\/\/modalyitblog.wordpress.com\/2016\/10\/03\/powershell-gui-reboot-prompt\/\n\n  Script name: AutoLogonLogoffTimer.ps1\n  Release 1.2\n  Modified by Jeremy Saunders (jeremy@jhouseconsulting.com) 20th June 2017\n\n#&gt;\n#-------------------------------------------------------------\n&#x5B;cmdletbinding()]\nparam (\n       &#x5B;int]$Seconds=15\n      )\n\n# Set Powershell Compatibility Mode\nSet-StrictMode -Version 2.0\n\n# Enable verbose, warning and error mode\n$VerbosePreference = 'Continue'\n$WarningPreference = 'Continue'\n$ErrorPreference = 'Continue'\n\n#-------------------------------------------------------------\n\n# Hide the PowerShell console window without hiding the other child windows that it spawns\n# - http:\/\/powershell.cz\/2013\/04\/04\/hide-and-show-console-window-from-gui\/\n$Code = @&quot;\n&#x5B;DllImport(&quot;Kernel32.dll&quot;)]\npublic static extern IntPtr GetConsoleWindow();\n&#x5B;DllImport(&quot;user32.dll&quot;)]\npublic static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);\n&quot;@\n# Create new types as per the definition above. \nAdd-Type -Namespace Console -Name Window -MemberDefinition $code -PassThru | out-null\nFunction Show-Console {\n  $consolePtr = &#x5B;Console.Window]::GetConsoleWindow()\n  #5 show\n  &#x5B;Console.Window]::ShowWindow($consolePtr, 5)\n}\nFunction Hide-Console {\n  $consolePtr = &#x5B;Console.Window]::GetConsoleWindow()\n  #0 hide\n  &#x5B;Console.Window]::ShowWindow($consolePtr, 0)\n}\nHide-Console | out-null\n\n#-------------------------------------------------------------\n\n#----------------------------------------------\n#region Import Assemblies\n#----------------------------------------------\n&#x5B;void]&#x5B;Reflection.Assembly]::Load('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')\n&#x5B;void]&#x5B;Reflection.Assembly]::Load('System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')\n&#x5B;void]&#x5B;Reflection.Assembly]::Load('System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')\n#endregion Import Assemblies\n\nfunction Main {\n&lt;#\n    .SYNOPSIS\n        The Main function starts the project application.\n    \n    .PARAMETER Seconds\n        $Seconds is the number of seconds for the countdown timer.\n    \n    .NOTES\n        Use this function to initialize your script and to call GUI forms.\n\t\t\n    .NOTES\n        To get the console output in the Packager (Forms Engine) use: \n\t\t$ConsoleOutput (Type: System.Collections.ArrayList)\n#&gt;\n\tParam (&#x5B;int]$Seconds)\n\t\t\n\t#--------------------------------------------------------------------------\n\t#TODO: Add initialization script here (Load modules and check requirements)\n\t\n\t\n\t#--------------------------------------------------------------------------\n\t\n\tif((Call-MainForm_psf($Seconds)) -eq 'OK')\n\t{\n\t\t\n\t}\n\t\n\t$global:ExitCode = 0 #Set the exit code for the Packager\n}\n\nfunction Call-MainForm_psf\n{\n\tParam (&#x5B;int]$Seconds)\n\n\t#----------------------------------------------\n\t#region Import the Assemblies\n\t#----------------------------------------------\n\t&#x5B;void]&#x5B;reflection.assembly]::Load('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')\n\t&#x5B;void]&#x5B;reflection.assembly]::Load('System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')\n\t&#x5B;void]&#x5B;reflection.assembly]::Load('System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')\n\t#endregion Import Assemblies\n\n\t#----------------------------------------------\n\t#region Generated Form Objects\n\t#----------------------------------------------\n\t&#x5B;System.Windows.Forms.Application]::EnableVisualStyles()\n\t$MainForm = New-Object 'System.Windows.Forms.Form'\n\t$panel2 = New-Object 'System.Windows.Forms.Panel'\n\t$ButtonCancel = New-Object 'System.Windows.Forms.Button'\n\t$ButtonLogoffNow = New-Object 'System.Windows.Forms.Button'\n\t$panel1 = New-Object 'System.Windows.Forms.Panel'\n\t$labelITSystemsMaintenance = New-Object 'System.Windows.Forms.Label'\n\t$labelSecondsLeftToLogoff = New-Object 'System.Windows.Forms.Label'\n\t$labelTime = New-Object 'System.Windows.Forms.Label'\n\t$labelDescription = New-Object 'System.Windows.Forms.Label'\n\t$timerUpdate = New-Object 'System.Windows.Forms.Timer'\n\t$InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState'\n\t$progressBar1 = New-Object 'System.Windows.Forms.ProgressBar'\n\t#endregion Generated Form Objects\n\n\t#----------------------------------------------\n\t# User Generated Script\n\t#----------------------------------------------\n\t$TotalTime = $Seconds #in seconds\n\t\n\t$MainForm_Load={\n\t\t#TODO: Initialize Form Controls here\n\t\t$labelTime.Text = &quot;{0:D2}&quot; -f $TotalTime #$TotalTime\n\t\t#Add TotalTime to current time\n\t\t$script:StartTime = (Get-Date).AddSeconds($TotalTime)\n\t\t#Start the timer and progress bar\n\t\t$timerUpdate.Start()\n\t\t$progressBar1.PerformStep()\n\t}\n\t\n\t\n\t$timerUpdate_Tick={\n\t\t# Define countdown timer\n\t\t&#x5B;TimeSpan]$span = $script:StartTime - (Get-Date)\n\t\t#Update the display\n\t\t$labelTime.Text = &quot;{0:N0}&quot; -f $span.TotalSeconds\n\t\t$timerUpdate.Start()\n\t\tif ($span.TotalSeconds -le 0)\n\t\t{\n\t\t\t$timerUpdate.Stop()\n\t\t\tshutdown.exe \/l \/f\n\t\t}\n\t\t$progressBar1.PerformStep()\n\t}\n\t\n\t$ButtonLogoffNow_Click = {\n\t\t# Logoff the computer immediately\n\t\tshutdown.exe \/l \/f\n\t}\n\t\n\t$ButtonCancel_Click={\n\t\t$MainForm.Add_Closing({$_.Cancel = $false}) # Re-enable closing the form\n\t\t$MainForm.Close()\n\t}\n\t\n\t$labelITSystemsMaintenance_Click={\n\t\t#TODO: Place custom script here\n\t\t\n\t}\n\t\n\t$panel2_Paint=&#x5B;System.Windows.Forms.PaintEventHandler]{\n\t#Event Argument: $_ = &#x5B;System.Windows.Forms.PaintEventArgs]\n\t\t#TODO: Place custom script here\n\t\t\n\t}\n\t\n\t$labelTime_Click={\n\t\t#TODO: Place custom script here\n\t\t\n\t}\n\t\t# --End User Generated Script--\n\t#----------------------------------------------\n\t#region Generated Events\n\t#----------------------------------------------\n\t\n\t$Form_StateCorrection_Load=\n\t{\n\t\t#Correct the initial state of the form to prevent the .Net maximized form issue\n\t\t$MainForm.WindowState = $InitialFormWindowState\n\t}\n\t\n\t$Form_StoreValues_Closing=\n\t{\n\t\t#Store the control values\n\t}\n\n\t\n\t$Form_Cleanup_FormClosed=\n\t{\n\t\t#Remove all event handlers from the controls\n\t\ttry\n\t\t{\n\t\t\t$ButtonCancel.remove_Click($buttonCancel_Click)\n\t\t\t$ButtonLogoffNow.remove_Click($ButtonLogoffNow_Click)\n\t\t\t$panel2.remove_Paint($panel2_Paint)\n\t\t\t$labelITSystemsMaintenance.remove_Click($labelITSystemsMaintenance_Click)\n\t\t\t$labelTime.remove_Click($labelTime_Click)\n\t\t\t$MainForm.remove_Load($MainForm_Load)\n\t\t\t$timerUpdate.remove_Tick($timerUpdate_Tick)\n\t\t\t$MainForm.remove_Load($Form_StateCorrection_Load)\n\t\t\t$MainForm.remove_Closing($Form_StoreValues_Closing)\n\t\t\t$MainForm.remove_FormClosed($Form_Cleanup_FormClosed)\n\t\t}\n\t\tcatch &#x5B;Exception]\n\t\t{ }\n\t}\n\t#endregion Generated Events\n\n\t#----------------------------------------------\n\t#region Generated Form Code\n\t#----------------------------------------------\n\t$MainForm.SuspendLayout()\n\t$panel2.SuspendLayout()\n\t$panel1.SuspendLayout()\n\t#\n\t# MainForm\n\t#\n\t$MainForm.Controls.Add($panel2)\n\t$MainForm.Controls.Add($panel1)\n\t$MainForm.Controls.Add($labelSecondsLeftToLogoff)\n\t$MainForm.Controls.Add($labelTime)\n\t$MainForm.Controls.Add($labelDescription)\n\t$MainForm.Controls.Add($progressBar1)\n\t$MainForm.AutoScaleDimensions = '6, 13'\n\t$MainForm.AutoScaleMode = 'Font'\n\t$MainForm.BackColor = 'White'\n\t$MainForm.ClientSize = '373, 400'\n\t$MainForm.MaximizeBox = $False\n\t$MainForm.MinimizeBox = $False\n\t$MainForm.Add_Closing({$_.Cancel = $true}) # Disable closing the form using the X button\n\t$MainForm.WindowState = 'Normal'\n\t$MainForm.Name = 'MainForm'\n\t$MainForm.ShowIcon = $False\n\t$MainForm.ShowInTaskbar = $False\n\t$MainForm.StartPosition = 'CenterScreen'\n\t$MainForm.Text = 'Citrix VDA Autologon Process'\n\t$MainForm.TopMost = $True\n\t$MainForm.add_Load($MainForm_Load)\n\t#\n\t# panel2\n\t#\n\t$panel2.Controls.Add($ButtonCancel)\n\t$panel2.Controls.Add($ButtonLogoffNow)\n\t$panel2.BackColor = 'ScrollBar'\n\t$panel2.Location = '0, 326'\n\t$panel2.Name = 'panel2'\n\t$panel2.Size = '378, 80'\n\t$panel2.TabIndex = 9\n\t$panel2.add_Paint($panel2_Paint)\n\t#\n\t# ButtonCancel\n\t#\n\t$ButtonCancel.Location = '250, 17'\n\t$ButtonCancel.Name = 'ButtonCancel'\n\t$ButtonCancel.Size = '77, 45'\n\t$ButtonCancel.TabIndex = 7\n\t$ButtonCancel.Text = 'Cancel'\n\t$ButtonCancel.UseVisualStyleBackColor = $True\n\t$ButtonCancel.add_Click($buttonCancel_Click)\n\t#\n\t# ButtonLogoffNow\n\t#\n\t$ButtonLogoffNow.Font = 'Microsoft Sans Serif, 8.25pt, style=Bold'\n\t$ButtonLogoffNow.ForeColor = 'DarkRed'\n\t$ButtonLogoffNow.Location = '42, 17'\n\t$ButtonLogoffNow.Name = 'ButtonLogoffNow'\n\t$ButtonLogoffNow.Size = '91, 45'\n\t$ButtonLogoffNow.TabIndex = 0\n\t$ButtonLogoffNow.Text = 'Logoff Now'\n\t$ButtonLogoffNow.UseVisualStyleBackColor = $True\n\t$ButtonLogoffNow.add_Click($ButtonLogoffNow_Click)\n\t#\n\t# panel1\n\t#\n\t$panel1.Controls.Add($labelITSystemsMaintenance)\n\t$panel1.BackColor = '0, 114, 198'\n\t$panel1.Location = '0, 0'\n\t$panel1.Name = 'panel1'\n\t$panel1.Size = '375, 67'\n\t$panel1.TabIndex = 8\n\t#\n\t# labelITSystemsMaintenance\n\t#\n\t$labelITSystemsMaintenance.Font = 'Microsoft Sans Serif, 14.25pt'\n\t$labelITSystemsMaintenance.ForeColor = 'White'\n\t$labelITSystemsMaintenance.Location = '11, 18'\n\t$labelITSystemsMaintenance.Name = 'labelITSystemsMaintenance'\n\t$labelITSystemsMaintenance.Size = '310, 23'\n\t$labelITSystemsMaintenance.TabIndex = 1\n\t$labelITSystemsMaintenance.Text = 'Citrix VDA Autologon Logoff Timer'\n\t$labelITSystemsMaintenance.TextAlign = 'MiddleLeft'\n\t$labelITSystemsMaintenance.add_Click($labelITSystemsMaintenance_Click)\n\t#\n\t# labelSecondsLeftToLogoff\n\t#\n\t$labelSecondsLeftToLogoff.AutoSize = $True\n\t$labelSecondsLeftToLogoff.Font = 'Microsoft Sans Serif, 9pt, style=Bold'\n\t$labelSecondsLeftToLogoff.Location = '87, 283'\n\t$labelSecondsLeftToLogoff.Name = 'labelSecondsLeftToLogoff'\n\t$labelSecondsLeftToLogoff.Size = '155, 15'\n\t$labelSecondsLeftToLogoff.TabIndex = 5\n\t$labelSecondsLeftToLogoff.Text = 'Seconds left to logoff :'\n\t#\n\t# labelTime\n\t#\n\t$labelTime.AutoSize = $True\n\t$labelTime.Font = 'Microsoft Sans Serif, 9pt, style=Bold'\n\t$labelTime.ForeColor = '192, 0, 0'\n\t$labelTime.Location = '237, 283'\n\t$labelTime.Name = 'labelTime'\n\t$labelTime.Size = '43, 15'\n\t$labelTime.TabIndex = 3\n\t$labelTime.Text = '00:60'\n\t$labelTime.TextAlign = 'MiddleCenter'\n\t$labelTime.add_Click($labelTime_Click)\n\t#\n\t# labelDescription\n\t#\n\t$labelDescription.Font = 'Microsoft Sans Serif, 9pt'\n\t$labelDescription.Location = '12, 76'\n\t$labelDescription.Name = 'labelDescription'\n\t$labelDescription.Size = '350, 204'\n\t$labelDescription.TabIndex = 2\n\t$labelDescription.Text = 'When a Citrix VDA restarts as either part of scheduled reboots, or when non-persistent desktops reboot to reset, the first logon is generally always the longest. So we use an autologon account to prime the VDA when it restarts. This script is designed to logoff the auto logged on session when the countdown reaches 0.\n\nIf using Power Management with non-persistent desktops, you must ensure this script runs before the Citrix Desktop Service (BrokerAgent) service starts, or you will end up in a reboot loop.\n\nIf you do not wish to logoff at this time, please click on the cancel button below.'\n\t#\n\t# progressBar1\n\t#\n\t$progressBar1.Location = '12, 306'\n\t$progressBar1.Size = '350, 15'\n\t$progressBar1.Name = 'progressBar1'\n\t$progressBar1.Minimum = 0\n\t$progressBar1.Maximum = $TotalTime\n\t$progressBar1.Step = 1\n\t$progressBar1.Value = 0\n\t$progressBar1.Style = 'continuous'\n\t#\n\t# timerUpdate\n\t#\n\t$timerUpdate.Interval = 1000 # 1 second\n\t$timerUpdate.add_Tick($timerUpdate_Tick)\n\t$panel1.ResumeLayout()\n\t$panel2.ResumeLayout()\n\t$MainForm.ResumeLayout()\n\t#endregion Generated Form Code\n\n\t#----------------------------------------------\n\n\t#Save the initial state of the form\n\t$InitialFormWindowState = $MainForm.WindowState\n\t#Init the OnLoad event to correct the initial state of the form\n\t$MainForm.add_Load($Form_StateCorrection_Load)\n\t#Clean up the control events\n\t$MainForm.add_FormClosed($Form_Cleanup_FormClosed)\n\t#Store the control values when form is closing\n\t$MainForm.add_Closing($Form_StoreValues_Closing)\n\t#Show the Form\n\treturn $MainForm.ShowDialog()\n\n}\n\n#Start the application\nMain ($Seconds)\n<\/pre><\/div>\n\n\n<p>Enjoy!<\/p>\n\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>Several years ago, and inspired by an article written by George Spiers to reduce login times, where &#8220;the second logon is quicker&#8221;, together with some code from Maurice Daly, I created a methodology and scripts that is designed to Autologon a non-persistent Session Host (both VDI and RDS), and then log it off again before &#8230; <a title=\"Priming a Non-persistent Windows Image using an Autologon Process with an Auto Logoff Timer\" class=\"read-more\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/2025\/07\/26\/priming-a-non-persistent-windows-image-using-an-autologon-process-with-an-auto-logoff-timer-3343\" aria-label=\"Read more about Priming a Non-persistent Windows Image using an Autologon Process with an Auto Logoff Timer\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[39,554,14,626,823,729,659,5,91,38,242],"tags":[887,877],"class_list":["post-3343","post","type-post","status-publish","format-standard","hentry","category-application-virtualization","category-best-practice","category-citrix","category-cvad","category-daas","category-desktop-virtualisation","category-powershell","category-scripting","category-vdi","category-xenapp","category-xendesktop","tag-allow-log-on-locally","tag-the-second-logon-is-quicker"],"aioseo_notices":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/3343","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/comments?post=3343"}],"version-history":[{"count":5,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/3343\/revisions"}],"predecessor-version":[{"id":3475,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/3343\/revisions\/3475"}],"wp:attachment":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/media?parent=3343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/categories?post=3343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/tags?post=3343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}