chocolatey / chocolatey-licensed-issues

Issues for Licensed Editions of Chocolatey
19 stars 13 forks source link

Self-Service - Set HKCU values when self-service is running #22

Open ferventcoder opened 7 years ago

ferventcoder commented 7 years ago

Provide a means of being able to set HKCU values even when the background agent is performing the task.

┆Issue is synchronized with this GitLab issue by Unito

alexp205 commented 7 years ago

This workaround uses Active Setup (which is configured through keys in HKLM) and HKU to alter keys/values in HKCU for all users. Of course, if changes to only the current user's HKCU are desired, then only that part of the code needs to be used.

Here are the details for some of the parameters used in the snippet below: value name - "Name" in the key's values window corresponding value - "Data" in the key's values window value type - "Type" in the key's values window UID - this must be a UUID, preferably a GUID but anything works as long as it is unique within the Active Setup subkeys version - the is a series of 4 number separated by commas, Active Setup uses this to determine when to overwrite the command run

#Active Setup - affects all users on login
$HKCUPath = "HKCU:\path\to\HKCU\key"
$HKCUData = "if (!(Test-Path `'$HKCUPath`')) {New-Item -Path `'$HKCUPath`' -Force}; Set-ItemProperty -Path `'$HKCUPath`' -Name [insert value name here] -Value [insert corresponding value here] -Type [insert value type here]"
$ActiveSetupPath = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\[insert UID here]"
Set-ItemProperty -Path $ActiveSetupPath -Name "StubPath" -Value "powershell.exe -executionpolicy unrestricted -command ""$HKCUData"""
Set-ItemProperty -Path $ActiveSetupPath -Name "Version" -Value [insert version numbers here]

#HKU - immediately affects current user (workaround for HKCU)
$hivelist = "HKLM:\SYSTEM\CurrentControlSet\Control\hivelist"
Get-Item $hivelist | Select-Object -ExpandProperty property | ForEach-Object {
    $hivelistData = (Get-ItemProperty -Path $hivelist -Name $_).$_
    if ($hivelistData -like "*$env:chocolateyUserContext*") {
        if ($hivelistData -like "*NTUSER.DAT*") {
            $hivelistUser = $_
        }
    }
}
if ($hivelistUser -match '\\([^\\]+)$') {
    $HKUIndex = $matches[1]
}
New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS
$HKUPath = "HKU:\$HKUIndex\path\to\HKCU\key"
Set-ItemProperty -Path $HKUPath -Name [insert value name here] -Value [insert corresponding value here] -Type [insert value type here]

Take care that the path in the HKUPath line (i.e. $HKUPath = "HKU:\$HKUIndex\path\to\HKCU\key") is the same path as $HKCU with HKU:\$HKUIndex substituted for HKCU:. Also note that I left out the creation of said keys if they do not already exist.

alexp205 commented 6 years ago

NOTE: The above code snippet does not work as intended. Initial testing led to HKCU keys that had actually been created manually and not deleted. This new code uses scripts to run the necessary commands for creating/setting HKCU keys. While bulky and inefficient, it was the only solution I was able to find in time that could run the powershell commands as the correct user.

Here are the details for some of the parameters used in the snippet below: value name - "Name" in the key's values window value - "Data" in the key's values window value type - "Type" in the key's values window UID - this must be a UUID, preferably a GUID but anything works as long as it is unique within the Active Setup subkeys version - the is a series of 4 number separated by commas, Active Setup uses this to determine when to overwrite the command run

# ---setup Active Setup scripts/commands and key for modifying HKCU keys---
$ActiveSetupPath = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\<UID>"
$cmdScriptContent = @"
powershell C:\path\to\powershell\script.ps1
"@
$cmdScriptContent | Set-Content "C:\path\to\cmd\script.cmd" -Force
$HKCUPath = "HKCU:" + $path
$psScriptContent = @"
if (!(Test-Path '$($HKCUPath)')) {
    New-Item -Path '$($HKCUPath)' -Force
}
Set-ItemProperty -Path '$($HKCUPath)' -Name <value name> -Value <value> -Type <value type>
"@
$psScriptContent | Set-Content "C:\path\to\powershell\script.ps1" -Force

# configure Active Setup
Set-ItemProperty -Path $ActiveSetupPath -Name "StubPath" -Value "C:\path\to\cmd\script.cmd" -Type String
Set-ItemProperty -Path $ActiveSetupPath -Name "Version" -Value <version> -Type String

# ---modify current user HKCU---
New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS
# get username from system, if this fails (returns empty string) then use 
# chocolateyUserContext
$username = (Get-WMIObject -class Win32_ComputerSystem).username.split('\')[1]
if ($username) {
    $userkey = $username
} else {
    $userkey = $env:chocolateyUserContext
}
# this block sets a value in the user's corresponding HKU registry hive (reflecting changes
# that would have been made to HKCU)
$hivelist = "HKLM:\SYSTEM\CurrentControlSet\Control\hivelist"
if ($userkey) {
    # each user's (including system "users") HKU hive info is listed at the $hivelist
    # location, this line parses through each one
    Get-Item $hivelist | Select-Object -ExpandProperty property | ForEach-Object {
        $hivelistData = (Get-ItemProperty -Path $hivelist -Name $_).$_
        if ($hivelistData -like "*$userkey*") {
            if ($hivelistData -like "*NTUSER.DAT*") {
                $hivelistUser = $_
                if ($hivelistUser -match '\\([^\\]+)$') {
                    $HKUIndex = $matches[1]
                }
                $HKUPath = "HKU:\$HKUIndex" + $path
                Set-ItemProperty -Path $HKUPath -Name <value name> -Value <value> -Type <value type>
            }
        }
    }
}