As our business continues to focus on providing white labeled Tier 3 IT support services, RMM as a service, and co-managed IT services this blog will be highlighting tips for RMM automation. Here is one of the recent scripts we added to our RMM. We often find ourselves wanting to modify the registry for all users:
Variables
It is important to not store variables in scripts especially when they are credentials for a user on the local computer, so make sure to define variables accordingly. In this script there are no variables like that, but wanted to explain some that are in the script:
- $PatternSID = this is the Regular Expression pattern for the Security ID of the users to look for (found it was different for local / domain vs. Azure)
- $ProfileList = List of SIDs and other information from the HKLM folders
- $LoadedHives = List of logged in users from HKU
- $UnloadedHives = List of not logged in users from HKU
Script Snippet
# Regex pattern for Local or Domain SIDs
$PatternSID = 'S-1-5-21-\d+-\d+\-\d+\-\d+$'
# Get Username, SID, and location of ntuser.dat for all users
$ProfileList = gp 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*' | Where-Object {$_.PSChildName -match $PatternSID} |
Select @{name="SID";expression={$_.PSChildName}},
@{name="UserHive";expression={"$($_.ProfileImagePath)\ntuser.dat"}},
@{name="Username";expression={$_.ProfileImagePath -replace '^(.*[\\\/])', ''}}
# Get all user SIDs found in HKEY_USERS (ntuder.dat files that are loaded)
$LoadedHives = gci Registry::HKEY_USERS | ? {$_.PSChildname -match $PatternSID} | Select @{name="SID";expression={$_.PSChildName}}
# Get all users that are not currently logged
$UnloadedHives = Compare-Object $ProfileList.SID $LoadedHives.SID | Select @{name="SID";expression={$_.InputObject}}, UserHive, Username
# Loop through each profile on the machine
Foreach ($item in $ProfileList) {
# Load User ntuser.dat if it's not already loaded
IF ($item.SID -in $UnloadedHives.SID) {
reg load HKU\$($Item.SID) $($Item.UserHive) | Out-Null
}
#####################################################################
# This is where you can read/modify a users portion of the registry
# This example checks for a key, adds it if missing, and creates / changes a DWORD in that key
"{0}" -f $($item.Username) | Write-Output
If (!(Test-Path registry::HKEY_USERS\$($Item.SID)\SOFTWARE\Microsoft\Windows\CurrentVersion\UserProfileEngagement)) {
New-Item -Path registry::HKEY_USERS\$($Item.SID)\SOFTWARE\Microsoft\Windows\CurrentVersion\UserProfileEngagement -Force | Out-Null
}
Set-ItemProperty registry::HKEY_USERS\$($Item.SID)\SOFTWARE\Microsoft\Windows\CurrentVersion\UserProfileEngagement -Name “ScoobeSystemSettingEnabled” -Value “0” -Type DWord
#####################################################################
# Unload ntuser.dat
IF ($item.SID -in $UnloadedHives.SID) {
### Garbage collection and closing of ntuser.dat ###
[gc]::Collect()
reg unload HKU\$($Item.SID) | Out-Null
}
}
# Regex pattern for AzureAD SIDs
$PatternSID = 'S-1-12-1-\d+-\d+\-\d+\-\d+$'
# Get Username, SID, and location of ntuser.dat for all users
$ProfileList = gp 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*' | Where-Object {$_.PSChildName -match $PatternSID} |
Select @{name="SID";expression={$_.PSChildName}},
@{name="UserHive";expression={"$($_.ProfileImagePath)\ntuser.dat"}},
@{name="Username";expression={$_.ProfileImagePath -replace '^(.*[\\\/])', ''}}
# Get all user SIDs found in HKEY_USERS (ntuder.dat files that are loaded)
$LoadedHives = gci Registry::HKEY_USERS | ? {$_.PSChildname -match $PatternSID} | Select @{name="SID";expression={$_.PSChildName}}
# Get all users that are not currently logged
$UnloadedHives = Compare-Object $ProfileList.SID $LoadedHives.SID | Select @{name="SID";expression={$_.InputObject}}, UserHive, Username
# Loop through each profile on the machine
Foreach ($item in $ProfileList) {
# Load User ntuser.dat if it's not already loaded
IF ($item.SID -in $UnloadedHives.SID) {
reg load HKU\$($Item.SID) $($Item.UserHive) | Out-Null
}
#####################################################################
# This is where you can read/modify a users portion of the registry
# This example checks for a key, adds it if missing, and creates / changes a DWORD in that key
"{0}" -f $($item.Username) | Write-Output
If (!(Test-Path registry::HKEY_USERS\$($Item.SID)\SOFTWARE\Microsoft\Windows\CurrentVersion\UserProfileEngagement)) {
New-Item -Path registry::HKEY_USERS\$($Item.SID)\SOFTWARE\Microsoft\Windows\CurrentVersion\UserProfileEngagement -Force | Out-Null
}
Set-ItemProperty registry::HKEY_USERS\$($Item.SID)\SOFTWARE\Microsoft\Windows\CurrentVersion\UserProfileEngagement -Name “ScoobeSystemSettingEnabled” -Value “0” -Type DWord
#####################################################################
# Unload ntuser.dat
IF ($item.SID -in $UnloadedHives.SID) {
### Garbage collection and closing of ntuser.dat ###
[gc]::Collect()
reg unload HKU\$($Item.SID) | Out-Null
}
}
Checking whether each item already exists helps the RMM to get the proper exit code and not show the script as failed when run.
If your company is a MSP or wants to become one and automation just seems out of reach, then contact us to run your RMM for you.