source/Remove-KioskSettings.ps1 (249 lines of code) (raw):

[CmdletBinding()] param ( # Reinstall Kiosk Settings. If called from Installation Script this will be chosen. [Parameter()] [switch]$Reinstall ) #region Set Variables $script:FullName = $MyInvocation.MyCommand.Path $script:Dir = Split-Path $script:FullName $Script:File = [string]$myInvocation.MyCommand.Name [String]$Script:LogDir = Join-Path -Path $env:SystemRoot -ChildPath "Logs" $date = Get-Date -UFormat "%Y-%m-%d %H-%M-%S" $Script:LogName = [io.path]::GetFileNameWithoutExtension($Script:File) + "-$date.log" $GPODir = "$Script:Dir\gposettings" $ToolsDir = "$Script:Dir\Tools" $DirConfigurationScripts = "$Script:Dir\Scripts\Configuration" $KioskDir = "$env:SystemDrive\KioskSettings" $ProvisioningPackagesDir = "$KioskDir\ProvisioningPackages" $RegKeysRestoreFile = "$KioskDir\RegKeyRestore.csv" $AppLockerRestoreFile = "$KioskDir\ApplockerPolicy.xml" # Event Log Information $EventLog = 'AVD Client Kiosk' $EventSource = 'Configuration Removal Script' #endregion Set Variables #region Restart Script in 64-bit powershell if necessary If ($ENV:PROCESSOR_ARCHITEW6432 -eq "AMD64") { $scriptArguments = $null Try { foreach($k in $PSBoundParameters.keys) { switch($PSBoundParameters[$k].GetType().Name) { "SwitchParameter" {if($PSBoundParameters[$k].IsPresent) { $scriptArguments += "-$k " } } "String" { $scriptArguments += "-$k `"$($PSBoundParameters[$k])`" " } "Int32" { $scriptArguments += "-$k $($PSBoundParameters[$k]) " } "Boolean" { $scriptArguments += "-$k `$$($PSBoundParameters[$k]) " } "Version" { $scriptArguments += "-$k `"$($PSBoundParameters[$k])`" " } } } If ($null -ne $scriptArguments) { $RunScript = Start-Process -FilePath "$env:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe" -ArgumentList "-File `"$PSCommandPath`" $scriptArguments" -PassThru -Wait -NoNewWindow } Else { $RunScript = Start-Process -FilePath "$env:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe" -ArgumentList "-File `"$PSCommandPath`"" -PassThru -Wait -NoNewWindow } } Catch { Throw "Failed to start 64-bit PowerShell" } Exit $RunScript.ExitCode } #endregion Restart Script in 64-bit powershell if necessary #region Functions Function Write-Log { [CmdletBinding()] param ( [Parameter()] [string] $EventLog = $EventLog, [Parameter()] [string] $EventSource = $EventSource, [Parameter()] [string] [ValidateSet('Information','Warning','Error')] $EntryType = 'Information', [Parameter()] [Int] $EventID, [Parameter()] [string] $Message ) If ($EntryType -eq 'Error') { Write-Error $Message } Elseif ($EntryType -eq 'Warning') { Write-Warning -Message $Message } Else { Write-Output $Message } Write-EventLog -LogName $EventLog -Source $EventSource -EntryType $EntryType -EventId $EventId -Message $Message -ErrorAction SilentlyContinue } #endregion Functions #region Initialization and Logging New-EventLog -LogName $EventLog -Source $EventSource -ErrorAction SilentlyContinue If (-not (Test-Path $Script:LogDir)) { $null = New-Item -Path $Script:LogDir -ItemType Directory -Force } Start-Transcript -Path "$Script:LogDir\$Script:LogName" -Force Write-Log -EntryType Information -EventId 5 -Message "Executing '$Script:FullName'." #endregion Initialization and Logging #region Main Script # Removing Embedded Shells Configuration . "$DirConfigurationScripts\AssignedAccessWmiBridgeHelpers.ps1" If (Get-ShellLauncherConfiguration) { Write-Log -EventId 6 -EntryType Information -Message "Removing Shell Launcher settings via WMI Bridge." Clear-ShellLauncherConfiguration } If (Get-MultiAppKioskConfiguration) { Write-Log -EventId 6 -EntryType Information -Message "Removing Multi-App Kiosk Configuration via WMI Bridge." Clear-MultiAppKioskConfiguration } # Removing Non-Administrators Local GPO. $DirNonAdminsGPO = "$env:SystemRoot\System32\GroupPolicyUsers\S-1-5-32-545" If (Test-Path -Path $DirNonAdminsGPO) { Write-Log -EventId 7 -EntryType Information -Message "Deleting Non-Administrators local group policy object and forcing GPUpdate." Remove-Item -Path $DirNonAdminsGPO -Recurse -Force -ErrorAction SilentlyContinue If (!(Test-Path -Path $DirNonAdminsGPO)) { Write-Log -EventId 8 -EntryType Information -Message "Non-Administrators Local GPO removed successfully." Start-Process -FilePath "gpupdate.exe" -ArgumentList "/Force" -Wait -ErrorAction SilentlyContinue } Else { Write-Log -EventId 9 -EntryType Error -Message "Non-Administrators Local GPO folder was not removed successfully." Exit 2 } } If (Test-Path -Path $KioskDir) { # Removing changes to default user hive by reading the restore file and resetting all configured registry values to their previous values. If (Test-Path -Path $RegKeysRestoreFile) { $RegKeys = Import-Csv -Path $RegKeysRestoreFile Write-Log -EventId 10 -EntryType Information -Message "Restoring registry keys to default." Write-Log -EventId 11 -EntryType Information -Message "Loading Default User Hive and updated registry values." Start-Process -FilePath "REG.exe" -ArgumentList "LOAD", "HKLM\Default", "$env:SystemDrive\Users\default\ntuser.dat" -Wait ForEach ($entry in $RegKeys) { #reset from previous values $Key = $null $Value = $null $Type = $null $Data = $null #set values $Key = $Entry.Key $Value = $Entry.Value $Type = $Entry.Type $Data = $Entry.Data If ($Key -like 'HKCU\*') { $Key = $Key.Replace("HKCU\","HKLM\Default\") } If ($null -ne $Data -and $Data -ne '') { # Restore the value to the original Start-Process -FilePath "REG.exe" -ArgumentList "ADD `"$Key`" /v $Value /t $Type /d `"$Data`" /f" -wait } Else { # Delete the value since it didn't exist. Start-Process -FilePath "REG.exe" -ArgumentList "DELETE `"$Key`" /v $Value /f" -wait -ErrorAction SilentlyContinue } } Write-Log -EventId 12 -EntryType Information -Message "Unloading Default User Hive." $HiveUnloadResult = Start-Process -FilePath "REG.exe" -ArgumentList "UNLOAD", "HKLM\Default" -Wait -PassThru -NoNewWindow $ExitCode = $HiveUnloadResult.ExitCode If ($ExitCode -ne 0) { # sometimes the registry doesn't unload properly so we have to perform powershell garbage collection first. [GC]::Collect() [GC]::WaitForPendingFinalizers() Start-Sleep -Seconds 5 $HiveUnloadResult = Start-Process -FilePath "REG.exe" -ArgumentList "UNLOAD", "HKLM\Default" -Wait $ExitCode = $HiveUnloadResult.ExitCode } If ($ExitCode -eq 0) { Write-Log -EventId 13 -EntryType Information -Message "Hive unloaded successfully." } Else { Write-Log -EventId 14 -EntryType Error -Message "Hive unloaded with exit code '$ExitCode'." } } # Remove Applocker Configuration by clearing Applocker Policy. If (Test-Path -Path $AppLockerRestoreFile) { Write-Log -EventID 15 -EntryType Information -Message "Restoring AppLocker Policy to Default." Set-AppLockerPolicy -XmlPolicy $AppLockerRestoreFile Set-Service -Name AppIDSvc -StartupType Manual -ErrorAction SilentlyContinue Stop-Service -Name AppIDSvc -Force If ((Get-Service -Name AppIDSvc).Status -eq 'Running') { Stop-Service -Name AppIDSvc -Force -ErrorAction SilentlyContinue } } # Remove Provisioning Packages by finding the package files in the kiosksettings directory and removing them from the OS. If (Test-Path -Path $ProvisioningPackagesDir) { Write-Log -EventID 16 -EntryType Information -Message "Removing any provisioning packages previously applied by this configuration." $ProvisioningPackages = Get-ChildItem -Path $ProvisioningPackagesDir -Filter '*.ppkg' ForEach ($Package in $ProvisioningPackages) { $PackageId = (Get-ProvisioningPackage -AllInstalledPackages | Where-Object {$_.PackageName -eq "$($package.BaseName)"}).PackageId If ($PackageId) { Remove-ProvisioningPackage -PackageId $PackageId } } } # Restore User Logos If (Test-Path -Path "$kioskDir\UserLogos") { Write-Log -EntryType Information -EventId 17 -Message "Restoring User Logo Files" Get-ChildItem -Path "$KioskDir\UserLogos" | Copy-Item -Destination "$env:ProgramData\Microsoft\User Account Pictures" -Force $null = cmd /c "$ToolsDir\lgpo.exe" /t "$GPODir\Remove-computer-userlogos.txt" '2>&1' } # Remove Kiosk Settings Directory Write-Log -EventId 18 -EntryType Information -Message "Removing '$KioskDir' Directory" Remove-Item -Path $KioskDir -Recurse -Force } # Remove Scheduled Tasks Write-Log -EventId 19 -EntryType Information -Message "Removing Scheduled Tasks." Get-ScheduledTask | Where-Object {$_.TaskName -like '(AVD Client)*'} | Unregister-ScheduledTask -Confirm:$false # Remove Custom Start Menu Shortcut Write-Log -EventId 20 -EntryType Information -Message "Removing Custom AVD Client Shortcuts." $DirsShortcuts = "$env:ProgramData\Microsoft\Windows\Start Menu\Programs", "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Startup", "$env:SystemDrive\Users\Public\Desktop" $linkAVD = "Azure Virtual Desktop.lnk" ForEach ($DirShortcut in $DirsShortcuts) { $pathLinkAVD = Join-Path $DirShortcut -ChildPath $linkAVD If (Test-Path -Path $pathLinkAVD) { Remove-Item -Path $pathLinkAVD -Force } } # Remove Custom Start Menu Get-ChildItem -Path "$env:SystemDrive\Users\Default\AppData\Local\Microsoft\Windows\Shell" -Filter 'LayoutModification.*' | Remove-Item -Force # Remove Version Registry Entry Write-Log -EventId 21 -EntryType Information -Message "Removing Kiosk Registry Key to track install version." If (Test-Path -Path 'HKLM:\Software\Kiosk') { Remove-Item -Path 'HKLM:\Software\Kiosk' -Recurse -Force } # Remove Keyboard Filter If ((Get-WindowsOptionalFeature -Online -FeatureName Client-KeyboardFilter).state -eq 'Enabled') { Write-Log -EventId 22 -EntryType Information -Message "Removing Keyboard Filter and configuration." & "$DirConfigurationScripts\Disable-KeyboardFilter.ps1" If (!$Reinstall) { Disable-WindowsOptionalFeature -Online -FeatureName Client-KeyboardFilter -NoRestart } } If (Get-LocalUser | Where-Object {$_.Name -eq 'KioskUser0'}) { # Delete Kiosk User Profile if it exists. First Logoff Kiosk User. try { ## Find all sessions matching the specified username $sessions = quser | Where-Object {$_ -match 'kioskuser0'} If ($sessions) { ## Parse the session IDs from the output $sessionIds = ($sessions -split ' +')[2] Write-Log -EventId 23 -EntryType Information -Message "Found $(@($sessionIds).Count) user login(s) on computer." ## Loop through each session ID and pass each to the logoff command $sessionIds | ForEach-Object { Write-Log -EventId 24 -EntryType Information -Message "Logging off session id [$($_)]..." logoff $_ } } } catch { if ($_.Exception.Message -match 'No user exists') { Write-Host "The user is not logged in." } else { throw $_.Exception.Message } } Write-Log -EventId 25 -EntryType Information -Message "Deleting User Profile" Get-CimInstance -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq 'KioskUser0' } | Remove-CimInstance -ErrorAction SilentlyContinue Write-Log -EventId 26 -EntryType Information -Message "Removing 'KioskUser0' User Account." Remove-LocalUser -Name 'KioskUser0' } Write-Log -EventId 27 -EntryType Information -Message "**** Custom Kiosk Mode removed successfully ****" Stop-Transcript