├── .gitignore ├── LGPO ├── LGPO.psd1 ├── LICENSE.txt ├── CHANGELOG.MD └── LGPO.psm1 ├── LICENSE.txt ├── Tests ├── LGPO-Clear.test.ps1 ├── LGPO-EnforceRemoval.test.ps1 └── LGPO-Set.test.ps1 ├── README.md └── Install-LGPO.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | Publish-LGPO.ps1 2 | ExampleData.ps1 3 | .vscode -------------------------------------------------------------------------------- /LGPO/LGPO.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellCrack/LGPOPSmodule/HEAD/LGPO/LGPO.psd1 -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2020 Powershellcrack 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /LGPO/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2020 Powershellcrack 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Tests/LGPO-Clear.test.ps1: -------------------------------------------------------------------------------- 1 | 2 | #======================================================= 3 | # MAIN 4 | #======================================================= 5 | Import-Module LGPO 6 | 7 | # Set Outlook's Cached Exchange Mode behavior 8 | Write-Host ("Removing user policy for Outlook's Cached Exchange Mode behavior") 9 | Remove-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' 10 | Remove-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name SyncWindowSetting 11 | Remove-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name CalendarSyncWindowSetting 12 | Remove-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name CalendarSyncWindowSettingMonths 13 | 14 | # Set the Office Update UI behavior. 15 | Write-Host ("Removing system policy from Office Update UI behavior") 16 | Remove-LocalPolicySetting -RegPath 'HKLM:\SOFTWARE\Policies\Microsoft\office\16.0\common\officeupdate' -Name HideUpdateNotifications 17 | Remove-LocalPolicySetting -RegPath 'HKLM:\SOFTWARE\Policies\Microsoft\office\16.0\common\officeupdate' -Name HideEnableDisableUpdates 18 | 19 | #Cleanup and Complete 20 | Write-Host ('Completed policy configuration') 21 | 22 | #Get GP report 23 | $ReportFile = ("gpresult_" + $env:ComputerName + ".html") 24 | $InstallArguments = "/H $env:Temp\$ReportFile /F" 25 | Remove-Item $env:Temp -Force -Recurse -ErrorAction SilentlyContinue | Out-Null 26 | Write-Host ('Running Command: Start-Process -FilePath "GPRESULT" -ArgumentList "{0}" -Wait -Passthru' -f $InstallArguments) 27 | $Result = Start-Process -FilePath GPRESULT -ArgumentList $InstallArguments -RedirectStandardError "$env:temp\gpresult_error.txt" -RedirectStandardOutput "$env:temp\gpresult_stdout.txt" -Wait -Passthru -NoNewWindow 28 | 29 | #Launch file in edge 30 | If($Result.ExitCode -eq 0){ 31 | start shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge "$env:Temp\$ReportFile" 32 | } 33 | Else{ 34 | $errormsg = Get-Content "$env:temp\gpresult_error.txt" -Raw -ErrorAction SilentlyContinue 35 | Write-Host ('Failed to create file [{0}], error code: {1}, {2}' -f "$env:Temp\$ReportFile",$Result.ExitCode,$errormsg) -ForegroundColor Red 36 | } 37 | -------------------------------------------------------------------------------- /Tests/LGPO-EnforceRemoval.test.ps1: -------------------------------------------------------------------------------- 1 | 2 | #======================================================= 3 | # MAIN 4 | #======================================================= 5 | #Import-Module LGPO 6 | 7 | # Set Outlook's Cached Exchange Mode behavior 8 | Write-Host ("Removing user policy for Outlook's Cached Exchange Mode behavior") 9 | Remove-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name Enable -EnForce 10 | Remove-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name SyncWindowSetting -EnForce 11 | Remove-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name CalendarSyncWindowSetting -EnForce 12 | Remove-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name CalendarSyncWindowSettingMonths -EnForce 13 | 14 | # Set the Office Update UI behavior. 15 | Write-Host ("Removing system policy from Office Update UI behavior") 16 | Remove-LocalPolicySetting -RegPath 'HKLM:\SOFTWARE\Policies\Microsoft\office\16.0\common\officeupdate' -Name HideUpdateNotifications -EnForce 17 | Remove-LocalPolicySetting -RegPath 'HKLM:\SOFTWARE\Policies\Microsoft\office\16.0\common\officeupdate' -Name HideEnableDisableUpdates -EnForce 18 | 19 | #Cleanup and Complete 20 | Write-Host ('Completed policy configuration') 21 | 22 | #Get GP report 23 | $ReportFile = ("gpresult_" + $env:ComputerName + ".html") 24 | $InstallArguments = "/H $env:Temp\$ReportFile /F" 25 | Remove-Item $env:Temp -Force -Recurse -ErrorAction SilentlyContinue | Out-Null 26 | Write-Host ('Running Command: Start-Process -FilePath "GPRESULT" -ArgumentList "{0}" -Wait -Passthru' -f $InstallArguments) 27 | $Result = Start-Process -FilePath GPRESULT -ArgumentList $InstallArguments -RedirectStandardError "$env:temp\gpresult_error.txt" -RedirectStandardOutput "$env:temp\gpresult_stdout.txt" -Wait -Passthru -NoNewWindow 28 | 29 | #Launch file in edge 30 | If($Result.ExitCode -eq 0){ 31 | start shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge "$env:Temp\$ReportFile" 32 | } 33 | Else{ 34 | $errormsg = Get-Content "$env:temp\gpresult_error.txt" -Raw -ErrorAction SilentlyContinue 35 | Write-Host ('Failed to create file [{0}], error code: {1}, {2}' -f "$env:Temp\$ReportFile",$Result.ExitCode,$errormsg) -ForegroundColor Red 36 | } 37 | -------------------------------------------------------------------------------- /Tests/LGPO-Set.test.ps1: -------------------------------------------------------------------------------- 1 | 2 | #======================================================= 3 | # MAIN 4 | #======================================================= 5 | Import-Module LGPO 6 | 7 | # Set Outlook's Cached Exchange Mode behavior 8 | Write-Host ("Set user policy for Outlook's Cached Exchange Mode behavior") 9 | Set-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name Enable -Type DWord -Value 1 10 | Set-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name SyncWindowSetting -Type DWord -Value 1 11 | Set-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name CalendarSyncWindowSetting -Type DWord -Value 1 12 | Set-LocalPolicyUserSetting -RegPath 'HKCU:\software\policies\microsoft\office\16.0\outlook\cached mode' -Name CalendarSyncWindowSettingMonths -Type DWord -Value 1 13 | 14 | # Set the Office Update UI behavior. 15 | Write-Host ("Set the Office Update UI behavior") 16 | Set-LocalPolicySetting -RegPath 'HKLM:\SOFTWARE\Policies\Microsoft\office\16.0\common\officeupdate' -Name HideUpdateNotifications -Type DWord -Value 1 17 | Set-LocalPolicySetting -RegPath 'HKLM:\SOFTWARE\Policies\Microsoft\office\16.0\common\officeupdate' -Name HideEnableDisableUpdates -Type DWord -Value 1 18 | 19 | #Cleanup and Complete 20 | Write-Host ('Completed Office 365 install') 21 | 22 | #Get GP report 23 | $ReportFile = ("gpresult_" + $env:ComputerName + ".html") 24 | $InstallArguments = "/H $env:Temp\$ReportFile /F" 25 | Remove-Item $env:Temp -Force -Recurse -ErrorAction SilentlyContinue | Out-Null 26 | Write-Host ('Running Command: Start-Process -FilePath "GPRESULT" -ArgumentList "{0}" -Wait -Passthru' -f $InstallArguments) 27 | $Result = Start-Process -FilePath GPRESULT -ArgumentList $InstallArguments -RedirectStandardError "$env:temp\gpresult_error.txt" -RedirectStandardOutput "$env:temp\gpresult_stdout.txt" -Wait -Passthru -NoNewWindow 28 | 29 | #Launch file in edge 30 | If($Result.ExitCode -eq 0){ 31 | start shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge "$env:Temp\$ReportFile" 32 | } 33 | Else{ 34 | $errormsg = Get-Content "$env:temp\gpresult_error.txt" -Raw -ErrorAction SilentlyContinue 35 | Write-Host ('Failed to create file [{0}], error code: {1}, {2}' -f "$env:Temp\$ReportFile",$Result.ExitCode,$errormsg) -ForegroundColor Red 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LGPO PowerShell module 2 | 3 | A powershell module that applies registry keys using the [Microsoft LGPO Toolkit](https://www.microsoft.com/en-us/download/details.aspx?id=55319). 4 | 5 | ## Prerequisites 6 | 7 | The module requires the LGPO.exe binary to be located in `C:\ProgramData\LGPO\` 8 | The LGPO binaries from Microsoft Security Compliance Toolkit 1.0 will be needed. You can get it from here 'https://www.microsoft.com/en-us/download/details.aspx?id=55319' 9 | 10 | ## Cmdlets 11 | - Get-LocalPolicySystemSettings - Retrieves all system policies 12 | - Set-LocalPolicySetting - Attempts to apply local system policy from a registry key 13 | - Update-LocalPolicySettings - Attempts to update local system policy from a file or data 14 | - Remove-LocalPolicySetting - Attempts to remove local system policy 15 | - Get-LocalPolicyUserSettings - Retrieves all user policies 16 | - Set-LocalPolicyUserSetting - Attempts to apply local user policy (Defaults to all users) 17 | - Remove-LocalPolicyUserSetting - Attempts to remove local user policy (Defaults to all users) 18 | - Clear-LocalPolicySetting - Erases all policies from system (Defaults to all polices) 19 | 20 | ## Install 21 | 22 | - Option 1: Run the provided **Install-LGPO.ps1** 23 | 24 | - Option 2: Manually download LGPO bits from 'https://www.microsoft.com/en-us/download/details.aspx?id=55319', copy LGPO.exe to _C:\ProgramData\LGPO_, then install module using the following commands: 25 | 26 | ```powershell 27 | Install-Module LGPO -Force 28 | Import-Module LGPO 29 | ``` 30 | 31 | ## Examples 32 | 33 | ```powershell 34 | # Gets current policies of system as object 35 | Get-LocalPolicySystemSettings 36 | 37 | # Gets current policies of users as object 38 | Get-LocalPolicyUserSettings 39 | 40 | # Sets policy name to system 41 | Set-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -Type DWord -Value 0 42 | 43 | # Remove system policy by name (sets to not configured) 44 | Remove-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' 45 | 46 | # Remove system policy by name but ensure it can be set back (set to not configured but also enforces the key from being recreated) 47 | Remove-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -Enforce 48 | 49 | # Sets policy name to users 50 | Set-LocalPolicyUserSetting -RegPath 'HCKU:\SOFTWARE\Policies\Microsoft\Windows\Explorer' -Name 'DisableNotificationCenter' -Type DWord -Value 1 51 | 52 | # Remove policy name for users with verbose output 53 | Remove-LocalPolicyUserSetting -RegPath 'HCKU:\SOFTWARE\Policies\Microsoft\Windows\Explorer' -Name 'DisableNotificationCenter' -Verbose 54 | 55 | # Update (replace) policy from lpo generated txt file 56 | Update-LocalPolicySettings -Policy Computer -LgpoFile C:\Lgpo.txt 57 | 58 | # Filter out policies with * and rebuild 59 | (Get-LocalPolicySystemSettings -Filter '$_.Name -ne "*"') | Update-LocalPolicySettings -Policy Computer 60 | 61 | # Clear all policies with confirmation 62 | Clear-LocalPolicySetting 63 | 64 | # Clear computer policies without confirmation 65 | Clear-LocalPolicySetting -Policy Computer -Confirm:$False 66 | 67 | ``` 68 | 69 | ## Validate 70 | 71 | Run _gpresult /H report.html_ to see the local policies that are set. 72 | 73 | - If keys set by LGPO do not exist as an Administrative template, they will be set in Extra Registry Settings 74 | 75 | - You can also use _gpedit.msc_ to view settings set in Administrative template only 76 | -------------------------------------------------------------------------------- /LGPO/CHANGELOG.MD: -------------------------------------------------------------------------------- 1 | # Change log for LGPO module 2 | 3 | ## 1.0.3.9 April 22, 2023 4 | 5 | - Fixed Machine and Computer check in two cmdlets. Thanks @simonlrostron 6 | - Fixed LGPO installer. Space after file name causing hang. Thanks [@jonblankenship] (https://github.com/jonblankenship) 7 | - Fixed Posh code lint problems. 8 | 9 | ## 1.0.3.8 September 1, 2022 10 | 11 | - Fixed enforce cmdlet Set-LocalPolicySetting; was set to $force 12 | - Added gpupdate to each cmdlet when calling Enforce 13 | 14 | ## 1.0.3.7 August 29, 2022 15 | 16 | - Fixed enforce Boolean value; made alias for Force for compatibility 17 | - Added pipeline for Key Name (Path and value must be same) 18 | 19 | ## 1.0.3.6 August 29, 2022 20 | 21 | - Fixed name not found for Set-LocalUserPolicySetting; Apply to wasn't writing correct path and name 22 | - Removed test sample data from module. 23 | 24 | ## 1.0.3.5 August 29, 2022 25 | 26 | - Fixed issue where running Set-LocalPolicyUserSetting with HKLM in path still applies to user. Should error with message 27 | - Changed some write-error to throw to ensure terminating; updated string to create new line for download link 28 | - Updated Get-LocalPolicySettings to look for lgpo path as default instead of forced 29 | - Grammatical updates. Thanks [@meichthys](https://github.com/meichthys) 30 | 31 | ## 1.0.3.4 June 05, 2022 32 | 33 | - updated position parameter from 0 to 1; mistake on listed as first parameter 34 | - updated module tags to reflect usage and search in gallery 35 | 36 | ## 1.0.3.3 June 03, 2022 37 | 38 | - Fixed force registry parameter for Set-LocalPolicySetting; missing colon for registry hive path on (eg.HKLM:) 39 | - Fixed pathing issue for LGPO registry keys; missing variable creation in if statement during SID check 40 | - Added Clear-LocalPolicySettings; always to clear all machine or use policies 41 | 42 | ## 1.0.3.2 June 02, 2022 43 | 44 | - Changed NoNewWindow to WindowStyle Hidden; hides LGPO popup 45 | - Fixed user policy cmdlet; unable to use force because of key pathing issues 46 | 47 | ## 1.0.3.1 May 26, 2022 48 | 49 | - Fixed Remove-LocalPolicySetting cmdlet; changed force parameter to Enforce 50 | - Change error output with Write-Error; cleaned up output 51 | - Added Machine to policy parameter to support calls to policy for local system 52 | - Fixed Remove-LocalPolicyUserSetting cmdlet; ensured if no name is specified it removed all values for path 53 | 54 | ## 1.0.3.0 May 14, 2022 55 | 56 | - Changed cmdlet to LocalPolicyUserSetting; follows module names and mitigates existing module conflicts 57 | - Changed all argument lists to array; support dynamic changes such as verbose output 58 | - Added get cmdlets; provides export of system and user policies 59 | - Changed function of Remove cmdlets; defaults to remove settings without enforcement. 60 | 61 | ## 1.0.2.5 May 13, 2022 62 | 63 | - Fixed Remove local settings for all values parameter 64 | - Added debugging to cmdlets; leave working files in temp directory. 65 | - renamed working files to reflect cmdlet running; provides better troubleshooting 66 | - Changed Set and remove to force Name parameter; also fixed default parameters calls 67 | 68 | ## 1.0.2.4 May 12, 2022 69 | 70 | - Fixed ExpandString for LGPO. 71 | - Added delete all for LGPO 72 | - Removed Qword from type option, not used in LGPO. 73 | 74 | ## 1.0.2.2 Mar 08, 2022 75 | 76 | - Updated psd1; added root module and functions to export; foxes exported commands 77 | - Updated versioning to meet 4 integer requirements 78 | - Fixed pms1 to psm1 to call right file 79 | - Changed user cmdlets to \-LocalPolicyUserSetting; standardized policy cmdlets 80 | 81 | ## 1.0.1 Feb 26, 2022 82 | 83 | - Renamed modules to be more accurate. 84 | - Preset LGPO binary path to C:\Programdata\LGPO; can be modified if needed 85 | - Changed $args to $lgpoargs; ensure it doesn't conflict with built in variable 86 | 87 | ## 1.0.0 April 29,2020 88 | 89 | - Initial upload; Never tested. 90 | -------------------------------------------------------------------------------- /Install-LGPO.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .LINK 3 | https://www.microsoft.com/en-us/download/details.aspx?id=55319 4 | #> 5 | Param( 6 | [ValidateSet('Internet','Blob','SMBShare')] 7 | [string]$SourceType = 'Internet', 8 | [string]$BlobURI, 9 | [string]$BlobSaSKey, 10 | [string]$SharePath, 11 | [string]$InternetURI = 'https://download.microsoft.com/download/8/5/C/85C25433-A1B0-4FFA-9429-7E023E7DA8D8/LGPO.zip', 12 | [switch]$UseProxy, 13 | [string]$proxyURI 14 | ) 15 | #======================================================= 16 | # CONSTANT VARIABLES 17 | #======================================================= 18 | $ErrorActionPreference = "Stop" 19 | $Localpath = "$Env:ALLUSERSPROFILE\LGPO" 20 | $Installer = 'LGPO.zip' 21 | ##*============================================= 22 | ##* Runtime Function - REQUIRED 23 | ##*============================================= 24 | 25 | #region FUNCTION: Check if running in ISE 26 | Function Test-IsISE { 27 | # trycatch accounts for: 28 | # Set-StrictMode -Version latest 29 | try { 30 | return ($null -ne $psISE); 31 | } 32 | catch { 33 | return $false; 34 | } 35 | } 36 | #endregion 37 | 38 | #region FUNCTION: Check if running in Visual Studio Code 39 | Function Test-VSCode{ 40 | if($env:TERM_PROGRAM -eq 'vscode') { 41 | return $true; 42 | } 43 | Else{ 44 | return $false; 45 | } 46 | } 47 | #endregion 48 | 49 | #region FUNCTION: Find script path for either ISE or console 50 | Function Get-ScriptPath { 51 | <# 52 | .SYNOPSIS 53 | Finds the current script path even in ISE or VSC 54 | .LINK 55 | Test-VSCode 56 | Test-IsISE 57 | #> 58 | param( 59 | [switch]$Parent 60 | ) 61 | 62 | Begin{} 63 | Process{ 64 | Try{ 65 | if ($PSScriptRoot -eq "") 66 | { 67 | if (Test-IsISE) 68 | { 69 | $ScriptPath = $psISE.CurrentFile.FullPath 70 | } 71 | elseif(Test-VSCode){ 72 | $context = $psEditor.GetEditorContext() 73 | $ScriptPath = $context.CurrentFile.Path 74 | }Else{ 75 | $ScriptPath = (Get-location).Path 76 | } 77 | } 78 | else 79 | { 80 | $ScriptPath = $PSCommandPath 81 | } 82 | } 83 | Catch{ 84 | $ScriptPath = '.' 85 | } 86 | } 87 | End{ 88 | 89 | If($Parent){ 90 | Split-Path $ScriptPath -Parent 91 | }Else{ 92 | $ScriptPath 93 | } 94 | } 95 | 96 | } 97 | #endregion 98 | 99 | Function Write-LogEntry{ 100 | <# 101 | .SYNOPSIS 102 | Creates a log file 103 | 104 | .DESCRIPTION 105 | Creates a log file format for cmtrace log reader 106 | 107 | .NOTES 108 | Allows to view log using cmtrace while being written to 109 | 110 | .PARAMETER Message 111 | Write message to log file 112 | 113 | .PARAMETER Source 114 | Defaults to the script running or another function that calls this function. 115 | Used to specify a different source if specified 116 | 117 | .PARAMETER Severity 118 | Ranges 1-5. CMtrace will highlight severity 2 as yellow and 3 as red. 119 | If Passthru parameter used will change host output: 120 | 0 = Green 121 | 1 = Gray 122 | 2 = Yellow 123 | 3 = Red 124 | 4 = Verbose Output 125 | 5 = Debug output 126 | 127 | .PARAMETER OutputLogFile 128 | Defaults to $Global:LogFilePath. Specify location of log file. 129 | 130 | .PARAMETER Passthru 131 | Output message to host as well. Great when replacing Write-Host with Write-LogEntry 132 | 133 | .EXAMPLE 134 | #build global log fullpath 135 | $Global:LogFilePath = "$env:Windir\Logs\$($scriptName)_$(Get-Date -Format 'yyyy-MM-dd_Thh-mm-ss-tt').log" 136 | Write-LogEntry -Message 'this is a new message' -Severity 1 -Passthru 137 | 138 | .EXAMPLE 139 | Function Test-output{ 140 | ${CmdletName} = $MyInvocation.InvocationName 141 | Write-LogEntry -Message ('this is a new message from [{0}]' -f $MyInvocation.InvocationName) -Source ${CmdletName} -Severity 0 -Passthru 142 | } 143 | Test-output 144 | 145 | OUTPUT is in green: 146 | [21:07:50.476-300] [Test-output] :: this is a new message from [Test-output] 147 | 148 | .EXAMPLE 149 | Create entry in log with warning message and output to host in yellow 150 | Write-LogEntry -Message 'this is a log entry from an error' -Severity 2 -Passthru 151 | 152 | .EXAMPLE 153 | Create entry in log with error and output to host in red 154 | Write-LogEntry -Message 'this is a log entry from an error' -Severity 3 -Passthru 155 | 156 | #> 157 | [CmdletBinding()] 158 | param( 159 | [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true)] 160 | [ValidateNotNullOrEmpty()] 161 | [string]$Message, 162 | 163 | [Parameter(Mandatory=$false,Position=1)] 164 | [string]$Source, 165 | 166 | [parameter(Mandatory=$false,Position=2)] 167 | [ValidateSet(0,1,2,3,4,5)] 168 | [int16]$Severity, 169 | 170 | [parameter(Mandatory=$false, HelpMessage="Name of the log file that the entry will written to.")] 171 | [ValidateNotNullOrEmpty()] 172 | [string]$OutputLogFile = $Global:LogFilePath, 173 | 174 | [parameter(Mandatory=$false)] 175 | [switch]$Passthru 176 | ) 177 | 178 | #get BIAS time 179 | [string]$LogTime = (Get-Date -Format 'HH:mm:ss.fff').ToString() 180 | [string]$LogDate = (Get-Date -Format 'MM-dd-yyyy').ToString() 181 | [int32]$script:LogTimeZoneBias = [timezone]::CurrentTimeZone.GetUtcOffset([datetime]::Now).TotalMinutes 182 | [string]$LogTimePlusBias = $LogTime + $script:LogTimeZoneBias 183 | 184 | # Get the file name of the source script 185 | If($Source){ 186 | [string]$ScriptSource = $Source 187 | } 188 | Else{ 189 | Try { 190 | If($MyInvocation.InvocationName){ 191 | [string]$ScriptSource = $MyInvocation.InvocationName 192 | } 193 | ElseIf ($script:MyInvocation.Value.ScriptName) { 194 | [string]$ScriptSource = Split-Path -Path $script:MyInvocation.Value.ScriptName -Leaf -ErrorAction 'Stop' 195 | } 196 | Else { 197 | [string]$ScriptSource = Split-Path -Path $script:MyInvocation.MyCommand.Definition -Leaf -ErrorAction 'Stop' 198 | } 199 | } 200 | Catch { 201 | [string]$ScriptSource = '' 202 | } 203 | } 204 | 205 | #if the severity and preference level not set to silentlycontinue, then log the message 206 | $LogMsg = $true 207 | If( $Severity -eq 4 ){$Message='VERBOSE: ' + $Message;If(!$VerboseEnabled){$LogMsg = $false} } 208 | If( $Severity -eq 5 ){$Message='DEBUG: ' + $Message;If(!$DebugEnabled){$LogMsg = $false} } 209 | #If( ($Severity -eq 4) -and ($VerbosePreference -eq 'SilentlyContinue') ){$LogMsg = $false$Message='VERBOSE: ' + $Message} 210 | #If( ($Severity -eq 5) -and ($DebugPreference -eq 'SilentlyContinue') ){$LogMsg = $false;$Message='DEBUG: ' + $Message} 211 | 212 | #generate CMTrace log format 213 | $LogFormat = "" + "" 214 | 215 | # Add value to log file 216 | If($LogMsg) 217 | { 218 | try { 219 | Out-File -InputObject $LogFormat -Append -NoClobber -Encoding Default -FilePath $OutputLogFile -ErrorAction Stop 220 | } 221 | catch { 222 | Write-Host ("[{0}] [{1}] :: Unable to append log entry to [{1}], error: {2}" -f $LogTimePlusBias,$ScriptSource,$OutputLogFile,$_.Exception.ErrorMessage) -ForegroundColor Red 223 | } 224 | } 225 | 226 | #output the message to host 227 | If($Passthru) 228 | { 229 | If($Source){ 230 | $OutputMsg = ("[{0}] [{1}] :: {2}" -f $LogTimePlusBias,$Source,$Message) 231 | } 232 | Else{ 233 | $OutputMsg = ("[{0}] [{1}] :: {2}" -f $LogTimePlusBias,$ScriptSource,$Message) 234 | } 235 | 236 | Switch($Severity){ 237 | 0 {Write-Host $OutputMsg -ForegroundColor Green} 238 | 1 {Write-Host $OutputMsg -ForegroundColor Gray} 239 | 2 {Write-Host $OutputMsg -ForegroundColor Yellow} 240 | 3 {Write-Host $OutputMsg -ForegroundColor Red} 241 | 4 {Write-Verbose $OutputMsg} 242 | 5 {Write-Debug $OutputMsg} 243 | default {Write-Host $OutputMsg} 244 | } 245 | } 246 | } 247 | 248 | ##*======================================================================== 249 | ##* VARIABLE DECLARATION 250 | ##*======================================================================== 251 | #region VARIABLES: Building paths & values 252 | # Use function to get paths because Powershell ISE & other editors have differnt results 253 | [string]$scriptPath = Get-ScriptPath 254 | [string]$scriptName = [IO.Path]::GetFileNameWithoutExtension($scriptPath) 255 | 256 | #specify path of log 257 | $Global:LogFilePath = "$env:Windir\Logs\$($scriptName)_$(Get-Date -Format 'yyyy-MM-dd_Thh-mm-ss-tt').log" 258 | 259 | If($UseProxy){ 260 | [system.net.webrequest]::defaultwebproxy = new-object system.net.webproxy($proxyURI) 261 | [system.net.webrequest]::defaultwebproxy.credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials 262 | [system.net.webrequest]::defaultwebproxy.BypassProxyOnLocal = $true 263 | }Else{ 264 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 265 | } 266 | 267 | #======================================================= 268 | # MAIN 269 | #======================================================= 270 | Try{ 271 | #Test/Create LGPO Directory 272 | if((Test-Path $Localpath) -eq $false) { 273 | Write-LogEntry -Message ('Creating LGPO directory [{0}]' -f $Localpath) -Passthru 274 | New-Item -Path $Localpath -ItemType Directory -Force -ErrorAction SilentlyContinue 275 | } 276 | } 277 | Catch{ 278 | Write-LogEntry -Message ('Unable to create directory [{0}]. {1}' -f $Localpath, $_.Exception.message) -Severity 3 279 | Break 280 | } 281 | 282 | # Download LGPO 283 | Try{ 284 | If( ($SourceType -eq 'Blob') -and $BlobURI -and $SaSKey){ 285 | <# TEST 286 | $BlobUri='https://avdimageresources.blob.core.usgovcloudapi.net/apps/LGPO.zip' 287 | $SasKey = '?sv=2020-08-04&ss=bfqt&srt=sc&sp=rwdlacuptfx&se=2022-06-02T09:31:43Z&st=2022-06-02T01:31:43Z&sip=192.168.21.5&spr=https&sig=oyjNnYQZbhDONw%2BzgtKN63Pcrehwl%2BMRDS6yJKTvv7o%3D' 288 | #> 289 | #Download via URI using SAS 290 | Write-LogEntry -Message ('Downloading LGPO from Blob [{0}]' -f "$BlobUri") -Passthru 291 | (New-Object System.Net.WebClient).DownloadFile("$BlobUri$SasKey", "$Localpath\$Installer") 292 | } 293 | ElseIf(($SourceType -eq 'SMBShare') -and $SharePath){ 294 | Write-LogEntry -Message ('Downloading LGPO from share [{0}]' -f "$SharePath") -Passthru 295 | Copy-Item $SharePath -Destination "$Localpath\$Installer" -Force 296 | } 297 | Else{ 298 | Write-LogEntry -Message ('Downloading LGPO from URL [{0}]' -f $InternetURI) -Passthru 299 | Invoke-WebRequest -Uri $InternetURI -OutFile "$Localpath\$Installer" 300 | } 301 | } 302 | Catch{ 303 | Write-LogEntry -Message ('Unable to download LGPO. {0}' -f $_.Exception.message) -Severity 3 304 | Break 305 | } 306 | 307 | # Extract LGPO Files 308 | Write-LogEntry -Message ('Unzipping LGPO file [{0}]' -f "$Localpath\$Installer") -Passthru 309 | Expand-Archive -LiteralPath "$Localpath\$Installer" -DestinationPath $Localpath -Force -Verbose 310 | 311 | #prepare Directory 312 | $LGPOFile = Get-ChildItem $Localpath -Recurse -Filter LGPO.exe 313 | $LGPOFile | Move-Item -Destination $Localpath -Force 314 | Remove-Item "$Localpath\$Installer" -Force -ErrorAction SilentlyContinue 315 | 316 | try{ 317 | Write-LogEntry -Message ('Installing NuGet package dependency') -Passthru 318 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -ErrorAction Stop 319 | }Catch{ 320 | Write-LogEntry -Message ('Unable to install nuget package. {0}' -f $_.Exception.message) -Severity 3 321 | Break 322 | } 323 | 324 | try{ 325 | Write-LogEntry -Message ('Installing LGPO module') -Passthru 326 | Install-Module LGPO -Force -ErrorAction Stop 327 | }Catch{ 328 | Write-LogEntry -Message ('Unable to install LGPO module. {0}' -f $_.Exception.message) -Severity 3 329 | Break 330 | } 331 | 332 | 333 | Write-LogEntry -Message ('Completed LGPO install') -Passthru 334 | -------------------------------------------------------------------------------- /LGPO/LGPO.psm1: -------------------------------------------------------------------------------- 1 | ### ----------------------------------- 2 | ### Get-LocalPolicySetting Cmdlet 3 | ### ----------------------------------- 4 | Function Get-LocalPolicySettings { 5 | <# 6 | .SYNOPSIS 7 | Retrieves Local policies 8 | 9 | .DESCRIPTION 10 | Uses LGPO tool to parse local policies for either machine or user and export as object 11 | 12 | .NOTES 13 | Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319 14 | Create a Directory in C:\ProgramData\LGPO 15 | Unzip LGPO.exe to that folder 16 | 17 | .PARAMETER Policy 18 | Required. Specify Computer or User 19 | 20 | .PARAMETER LGPOBinaryPath 21 | Use this to specify alternate location 22 | Defaults to "C:\ProgramData\LGPO\LGPO.exe". Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319. 23 | 24 | .PARAMETER Filter 25 | Filter on export 26 | 27 | .EXAMPLE 28 | Get-LocalPolicySettings -Policy Computer -LGPOBinaryPath "C:\ProgramData\LGPO\LGPO.exe" 29 | 30 | .EXAMPLE 31 | Get-LocalPolicySettings -Policy Computer -LGPOBinaryPath "C:\ProgramData\LGPO\LGPO.exe" -Filter '$_.Key -like "*microsoft*"' 32 | 33 | .EXAMPLE 34 | Get-LocalPolicySettings -Policy Computer -LGPOBinaryPath "C:\ProgramData\LGPO\LGPO.exe" -Filter '$_.Name -eq "*"' 35 | 36 | .EXAMPLE 37 | Get-LocalPolicySettings -Policy Computer -LGPOBinaryPath "C:\ProgramData\LGPO\LGPO.exe" -Verbose 38 | 39 | .EXAMPLE 40 | Get-LocalPolicySettings -Policy Computer -LGPOBinaryPath "C:\ProgramData\LGPO\LGPO.exe" -Debug 41 | Working files will be left in temp folder for debugging 42 | 43 | .EXAMPLE 44 | Get-LocalPolicySettings -Policy Computer -LGPOBinaryPath c:\lgpo\lgpo.exe 45 | 46 | .LINK 47 | Get-LocalPolicySystemSettings 48 | Get-LocalPolicyUserSettings 49 | #> 50 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] 51 | Param ( 52 | [Parameter(Mandatory=$true,Position=1)] 53 | [ValidateSet('Machine','Computer','User')] 54 | $Policy, 55 | 56 | [Parameter(Mandatory=$false)] 57 | [string]$Filter, 58 | 59 | [Parameter(Mandatory=$false)] 60 | [ValidateScript({Test-path $_ -PathType Leaf})] 61 | $LGPOBinaryPath = "$env:ALLUSERSPROFILE\LGPO\LGPO.exe" 62 | ) 63 | Begin 64 | { 65 | ## Get the name of this function 66 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 67 | 68 | if (-not $PSBoundParameters.ContainsKey('Verbose')) { 69 | $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') 70 | } 71 | 72 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 73 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 74 | } 75 | 76 | if (-not $PSBoundParameters.ContainsKey('Debug')) { 77 | $DebugPreference = $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') 78 | } 79 | } 80 | Process{ 81 | #check if path exists 82 | If(Test-Path $LGPOBinaryPath) 83 | { 84 | #Build argumentlist 85 | $lgpoargs = @() 86 | $lgpoargs += '/parse' 87 | If($Policy -in @('Computer', 'Machine')){ 88 | $lgpoargs += '/m' 89 | $PolicyPath = 'Machine' 90 | }Else{ 91 | $lgpoargs += '/u' 92 | $PolicyPath = 'User' 93 | } 94 | $LgpoFileName = ('LGPO-Get-' + $env:COMPUTERNAME + '-' + $Policy + '-Policies') 95 | $lgpoargs += "$env:Windir\System32\GroupPolicy\$PolicyPath\Registry.pol" 96 | 97 | #convert argument array to string for verbose output 98 | $lgpoargstr = ($lgpoargs -join ' ') 99 | 100 | Write-Verbose ("{0} : Start-Process {1} -ArgumentList '{2}' -RedirectStandardError '{3}' -RedirectStandardOutput '{4}' -Wait -WindowStyle Hidden -PassThru" -f ${CmdletName},$LGPOBinaryPath,$lgpoargstr,"$env:Temp\$LgpoFileName.stderr","$env:Temp\$LgpoFileName.stdout") 101 | #run LGPO command 102 | Try{ 103 | $result = Start-Process $LGPOBinaryPath -ArgumentList $lgpoargs -RedirectStandardError "$env:Temp\$LgpoFileName.stderr" -RedirectStandardOutput "$env:Temp\$LgpoFileName.stdout" -Wait -WindowStyle Hidden -PassThru -ErrorAction Stop 104 | Write-Verbose ("{0} : LGPO ran successfully." -f ${CmdletName}) 105 | } 106 | Catch{ 107 | Write-Error ("LGPO failed to run. {1}" -f ${CmdletName},$result.ExitCode) 108 | } 109 | 110 | #Get only the important content of lgpo export 111 | $LgpoContent = Get-Content "$env:Temp\$LgpoFileName.stdout" 112 | $LgpoContentClean = ($LgpoContent |Select-String -Pattern '^;' -NotMatch |Select-String -Pattern '\w+|\*') -split '\n' 113 | $LineCount = ($LgpoContentClean | Measure-Object -Line).Lines 114 | 115 | #loop through content to build object 116 | $r = 0 117 | $line = 0 118 | $LgpoPolArray = @() 119 | for ($line = 0; $line -lt $LineCount; $line++) 120 | { 121 | #$r = $i 122 | If($r -eq 0){ 123 | #build object to start 124 | $LgpoPol = '' | Select-Object Hive,Key,Name,Type,Value 125 | $LgpoPol.Hive = $LgpoContentClean[$line] 126 | } 127 | If($r -eq 1){$LgpoPol.Key = $LgpoContentClean[$line]} 128 | If($r -eq 2){$LgpoPol.Name = $LgpoContentClean[$line]} 129 | If($r -eq 3){ 130 | $LgpoPol.Type = $LgpoContentClean[$line].split(':')[0] 131 | $LgpoPol.Value = $LgpoContentClean[$line].split(':')[1] 132 | #reset the count after 3 lines 133 | $r = 0 134 | #collect data before reset 135 | $LgpoPolArray += $LgpoPol 136 | 137 | }Else{ 138 | $r++ 139 | } 140 | } 141 | } 142 | Else{ 143 | Write-Error ("Local Policy cannot be retrieved; LGPO binaries not found in path [{1}].`nDownload binaries from 'https://www.microsoft.com/en-us/download/details.aspx?id=55319' " -f ${CmdletName},$LGPOBinaryPath) 144 | } 145 | 146 | } 147 | End{ 148 | #cleanup LGPO temp files if not debugging 149 | If( (Test-Path "$env:Temp\$LgpoFileName.stdout" -PathType Leaf) -and !$DebugPreference ){ 150 | Remove-Item "$env:Temp\$LgpoFileName.stderr" -ErrorAction SilentlyContinue -Force | Out-Null 151 | Remove-Item "$env:Temp\$LgpoFileName.stdout" -ErrorAction SilentlyContinue -Force | Out-Null 152 | } 153 | 154 | If($Filter){ 155 | $fltr = [ScriptBlock]::Create($Filter) 156 | $LgpoPolArray | Where-Object $fltr 157 | } 158 | Else{ 159 | return $LgpoPolArray 160 | } 161 | } 162 | } 163 | 164 | ### ---------------------------------- 165 | ### Update-LocalPolicySettings Cmdlet 166 | ### ---------------------------------- 167 | Function Update-LocalPolicySettings{ 168 | <# 169 | .SYNOPSIS 170 | Updates Local policies 171 | 172 | .DESCRIPTION 173 | Uses LGPO tool to update local policies for either machine or user from data or file 174 | 175 | .NOTES 176 | Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319 177 | Create a Directory in C:\ProgramData\LGPO 178 | Unzip LGPO.exe to that folder 179 | 180 | .PARAMETER Policy 181 | Required. Specify Computer or User 182 | 183 | .PARAMETER LGPOBinaryPath 184 | Use this to specify alternate location 185 | Defaults to "C:\ProgramData\LGPO\LGPO.exe". Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319. 186 | 187 | .PARAMETER LgpoData 188 | Required. PSObject with properties Hive, Keys, Name, Type, Value 189 | 190 | .PARAMETER LgpoFile 191 | Required. File path to text file formatted for LGPO import 192 | 193 | .PARAMETER Filter 194 | Filter on export. Only available when using LgpoData parameter 195 | 196 | .EXAMPLE 197 | Update-LocalPolicySettings -Policy Computer -LGPOBinaryPath "C:\Temp\LGPO\LGPO.exe" -LgpoData (Get-LocalPolicySystemSettings) 198 | 199 | .EXAMPLE 200 | Update-LocalPolicySettings -Policy User -LgpoFile C:\policyexport.txt 201 | 202 | .EXAMPLE 203 | Update-LocalPolicySettings -Policy Computer -LgpoData (Get-LocalPolicySystemSettings -Filter '$_.Key -like "*microsoft*"') 204 | 205 | .EXAMPLE 206 | Update-LocalPolicySettings -Policy Computer -LgpoData (Get-LocalPolicySystemSettings -Filter '$_.Name -ne "*"') -Verbose 207 | 208 | .EXAMPLE 209 | (Get-LocalPolicySystemSettings -Filter '$_.Name -ne "*"') | Update-LocalPolicySettings -Policy Computer 210 | 211 | .EXAMPLE 212 | Update-LocalPolicySettings -Policy Computer -LGPOBinaryPath "C:\ProgramData\LGPO\LGPO.exe" -LgpoData (Get-LocalPolicySystemSettings -Filter '$_.Name -ne "*"') -Debug 213 | Working files will be left in temp folder for debugging 214 | 215 | #> 216 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium',DefaultParameterSetName='Data')] 217 | Param ( 218 | [Parameter(Mandatory=$true,Position=1)] 219 | [ValidateSet('Machine','Computer','User')] 220 | $Policy, 221 | 222 | [Parameter(Mandatory=$true,Position=2,ParameterSetName='Data',ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 223 | $LgpoData, 224 | 225 | [Parameter(Mandatory=$true,Position=2,ParameterSetName='File')] 226 | [ValidateScript({Test-path $_ -PathType Leaf})] 227 | $LgpoFile, 228 | 229 | [Parameter(Mandatory=$false,ParameterSetName='Data')] 230 | [string]$Filter, 231 | 232 | [Parameter(Mandatory=$false)] 233 | [ValidateScript({Test-path $_ -PathType Leaf})] 234 | $LGPOBinaryPath = "$env:ALLUSERSPROFILE\LGPO\LGPO.exe" 235 | ) 236 | Begin 237 | { 238 | ## Get the name of this function 239 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 240 | 241 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 242 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 243 | } 244 | 245 | if (-not $PSBoundParameters.ContainsKey('Verbose')) { 246 | $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') 247 | } 248 | 249 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 250 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 251 | } 252 | 253 | if (-not $PSBoundParameters.ContainsKey('Debug')) { 254 | $DebugPreference = $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') 255 | } 256 | 257 | If ($PSCmdlet.ParameterSetName -eq "File") { 258 | $LgpoFilePath = $LgpoFile 259 | } 260 | 261 | If ($PSCmdlet.ParameterSetName -eq "Data") { 262 | # build a unique output file 263 | $LgpoFileName = ('LGPO-Update-' + $env:COMPUTERNAME + '-' + $Policy + '-Policies') 264 | 265 | #$lgpoout = $null 266 | $lgpoout = "; ----------------------------------------------------------------------`r`n" 267 | $lgpoout += "; BUILDING POLICY`r`n" 268 | $lgpoout += "`r`n" 269 | } 270 | } 271 | Process{ 272 | 273 | If ($PSCmdlet.ParameterSetName -eq "Data") { 274 | If($Filter){ 275 | $fltr = [ScriptBlock]::Create($Filter) 276 | $LgpoData = $LgpoData | Where-Object $fltr 277 | } 278 | 279 | Foreach($Item in $LgpoData){ 280 | $lgpoout += "$($Item.Hive)`r`n" 281 | $lgpoout += "$($Item.Key)`r`n" 282 | $lgpoout += "$($Item.Name)`r`n" 283 | If($Item.Value){ 284 | $lgpoout += "$($Item.Type):$($Item.Value)`r`n" 285 | }Else{ 286 | $lgpoout += "$($Item.Type)`r`n" 287 | } 288 | 289 | $lgpoout += "`r`n" 290 | } 291 | } 292 | } 293 | End{ 294 | If ($PSCmdlet.ParameterSetName -eq "Data") { 295 | $lgpoout += "; BUILDING COMPLETED.`r`n" 296 | $lgpoout += "; ----------------------------------------------------------------------`r`n" 297 | $lgpoout | Out-File "$env:Temp\$LgpoFileName.lgpo" -Force -WhatIf:$false 298 | } 299 | 300 | $LgpoFilePath = "$env:Temp\$LgpoFileName.lgpo" 301 | 302 | #check if path exists 303 | If(Test-Path $LGPOBinaryPath) 304 | { 305 | If( $Policy -in @('Computer','Machine') ){ 306 | $PolicyPath = 'Machine' 307 | }Else{ 308 | $PolicyPath = 'User' 309 | } 310 | # Build agrument list 311 | # should look like this: /r path\lgpo.txt /w path\registry.pol [/v] 312 | $lgpoargs = @() 313 | $lgpoargs += '/r' 314 | $lgpoargs += $LgpoFilePath 315 | $lgpoargs += '/w' 316 | $lgpoargs += "$env:Windir\System32\GroupPolicy\$PolicyPath\Registry.pol" 317 | If($VerbosePreference){$lgpoargs += '/v'} 318 | 319 | #convert argument array to string for verbose output 320 | $lgpoargstr = ($lgpoargs -join ' ') 321 | 322 | #run LGPO command 323 | If($WhatIfPreference) 324 | { 325 | Write-Output ("What if: Performing the operation ""{0}"" on target ""{1}"" with argument ""LGPO {2}""." -f ${CmdletName},$Policy,$lgpoargstr) 326 | } 327 | Else{ 328 | #apply policy 329 | Try{ 330 | Write-Verbose ("{0} : RUNNING COMMAND: Start-Process {1} -ArgumentList '{2}' -RedirectStandardError '{3}' -RedirectStandardOutput '{4}' -Wait -WindowStyle Hidden -PassThru" -f ${CmdletName},$LGPOBinaryPath,$lgpoargstr,"$env:Temp\$LgpoFileName.stderr","$env:Temp\$LgpoFileName.stdout") 331 | $result = Start-Process $LGPOBinaryPath -ArgumentList $lgpoargs -RedirectStandardError "$env:Temp\$LgpoFileName.stderr" -RedirectStandardOutput "$env:Temp\$LgpoFileName.stdout" -Wait -WindowStyle Hidden -PassThru -ErrorAction Stop 332 | Write-Verbose ("{0} : LGPO ran successfully." -f ${CmdletName}) 333 | } 334 | Catch{ 335 | Write-Error ("LGPO failed to run. {1}" -f ${CmdletName},$result.ExitCode) 336 | } 337 | Finally{ 338 | #cleanup LGPO temp files if not debugging 339 | If( (Test-Path "$env:Temp\$LgpoFileName.lgpo" -PathType Leaf) -and !$DebugPreference ){ 340 | Remove-Item "$env:Temp\$LgpoFileName.lgpo" -ErrorAction SilentlyContinue -Force | Out-Null 341 | Remove-Item "$env:Temp\$LgpoFileName.stderr" -ErrorAction SilentlyContinue -Force | Out-Null 342 | Remove-Item "$env:Temp\$LgpoFileName.stdout" -ErrorAction SilentlyContinue -Force | Out-Null 343 | } 344 | Else{ 345 | Write-Verbose ("View file for debugging: {1}" -f ${CmdletName},$LgpoFilePath) 346 | } 347 | } 348 | } 349 | } 350 | Else{ 351 | Throw ("Local Policy was not updated; LGPO binaries not found in path [{1}].`nDownload binaries from 'https://www.microsoft.com/en-us/download/details.aspx?id=55319' " -f ${CmdletName},$LGPOBinaryPath) 352 | } 353 | } 354 | } 355 | 356 | ### ------------------------------------- 357 | ### Get-LocalPolicySystemSettings Cmdlet 358 | ### ------------------------------------- 359 | Function Get-LocalPolicySystemSettings{ 360 | <# 361 | .SYNOPSIS 362 | Retrieves Local system policies 363 | 364 | .DESCRIPTION 365 | Uses LGPO tool to parse local system policy and export as object 366 | 367 | .NOTES 368 | Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319 369 | Create a Directory in C:\ProgramData\LGPO 370 | Unzip LGPO.exe to that folder 371 | 372 | .PARAMETER Filter 373 | Filter on export 374 | 375 | .PARAMETER LGPOBinaryPath 376 | Use this to specify alternate location 377 | Defaults to "C:\ProgramData\LGPO\LGPO.exe". Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319. 378 | 379 | .EXAMPLE 380 | Get-LocalPolicySystemSettings 381 | 382 | .EXAMPLE 383 | Get-LocalPolicySystemSettings -Filter '$_.Key -like "*microsoft*"' 384 | 385 | .EXAMPLE 386 | Get-LocalPolicySystemSettings -Filter '$_.Name -eq "*"' 387 | 388 | .EXAMPLE 389 | Get-LocalPolicySystemSettings -Verbose 390 | 391 | .EXAMPLE 392 | Get-LocalPolicySystemSettings -Debug 393 | Working files will be left in temp folder for debugging 394 | 395 | .EXAMPLE 396 | Get-LocalPolicySystemSettings -LGPOBinaryPath c:\lgpo\lgpo.exe 397 | 398 | .LINK 399 | Get-LocalPolicySettings 400 | #> 401 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] 402 | Param ( 403 | [Parameter(Mandatory=$false)] 404 | [string]$Filter, 405 | 406 | [Parameter(Mandatory=$false)] 407 | [ValidateScript({Test-path $_ -PathType Leaf})] 408 | $LGPOBinaryPath 409 | ) 410 | Begin 411 | { 412 | ## Get the name of this function 413 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 414 | 415 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 416 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 417 | } 418 | } 419 | Process{ 420 | #build splat table 421 | $LGPOSplat = @{Policy='Machine'} 422 | 423 | #Add Filter to splat table 424 | If($Filter){$LGPOSplat += @{Filter=$Filter}} 425 | 426 | #Add LGPO to splat table 427 | If($LGPOBinaryPath){$LGPOSplat += @{LGPOBinaryPath=$LGPOBinaryPath}} 428 | 429 | #convert spat hashtable to string for whatif output 430 | $LGPOSplatString = $LGPOSplat.GetEnumerator() | ForEach-Object {('/' + $_.Key + ' ' + $_.Value) -join ' '} | Select-Object -Last 1 431 | 432 | If($WhatIfPreference) 433 | { 434 | Write-Output ("What if: Performing the operation ""{0}"" on target ""{1}"" with argument ""{2}""." -f ${CmdletName},$LGPOSplat.Policy,$LGPOSplatString) 435 | } 436 | Else 437 | { 438 | Get-LocalPolicySettings @LGPOSplat 439 | } 440 | } 441 | } 442 | 443 | 444 | ### ----------------------------------- 445 | ### Set-LocalPolicySetting Cmdlet 446 | ### ----------------------------------- 447 | Function Set-LocalPolicySetting { 448 | <# 449 | .SYNOPSIS 450 | Converts registry key into GPO 451 | 452 | .DESCRIPTION 453 | Uses LGPO tool to convert registry key into Local policy 454 | 455 | .NOTES 456 | Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319 457 | Create a Directory in C:\ProgramData\LGPO 458 | Unzip LGPO.exe to that folder 459 | 460 | .PARAMETER RegPath 461 | Required. Specify path to registry item 462 | 463 | .PARAMETER Name 464 | Required. Specify Name of registry key to set. 465 | 466 | .PARAMETER Type 467 | Default to 'DWord'. Specify type of registry item 468 | 469 | .PARAMETER Value 470 | Specify value or Key name 471 | 472 | .PARAMETER Enforce 473 | If LGPO failed, this will set the registry item anyway 474 | 475 | .PARAMETER LGPOBinaryPath 476 | Use this to specify alternate location 477 | Defaults to "C:\ProgramData\LGPO\LGPO.exe". Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319. 478 | 479 | .EXAMPLE 480 | Set-LocalPolicySetting -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' -Name 'TaskbarMn' -Type DWord -Value 0 481 | 482 | .EXAMPLE 483 | Set-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -Type DWord -Value 0 484 | 485 | .EXAMPLE 486 | Set-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -Type DWord -Value 0 -Verbose 487 | 488 | .EXAMPLE 489 | Set-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -Type DWord -Value 0 -Debug 490 | Working files will be left in temp folder for debugging 491 | 492 | .EXAMPLE 493 | Set-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -Type DWord -Value 0 -LGPOBinaryPath c:\lgpo\lgpo.exe 494 | #> 495 | 496 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] 497 | Param ( 498 | [Parameter(Mandatory=$true,Position=1)] 499 | [Alias("Path")] 500 | [string]$RegPath, 501 | 502 | [Parameter(Mandatory=$true,Position=2,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 503 | [Alias("v")] 504 | [string]$Name, 505 | 506 | [Parameter(Mandatory=$false,Position=3)] 507 | [ValidateSet('None','String','Binary','DWord','ExpandString','MultiString','QWord')] 508 | [Alias("PropertyType","t")] 509 | $Type = 'DWord', 510 | 511 | [Parameter(Mandatory=$True,Position=4)] 512 | [Alias("d")] 513 | $Value, 514 | 515 | [Parameter(Mandatory=$false)] 516 | [Alias("f",'Force')] 517 | [switch]$Enforce, 518 | 519 | [Parameter(Mandatory=$false)] 520 | [ValidateScript({Test-path $_ -PathType Leaf})] 521 | $LGPOBinaryPath = "$env:ALLUSERSPROFILE\LGPO\LGPO.exe" 522 | 523 | ) 524 | Begin 525 | { 526 | ## Get the name of this function 527 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 528 | 529 | if (-not $PSBoundParameters.ContainsKey('Verbose')) { 530 | $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') 531 | } 532 | 533 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 534 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 535 | } 536 | 537 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 538 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 539 | } 540 | 541 | if (-not $PSBoundParameters.ContainsKey('Debug')) { 542 | $DebugPreference = $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') 543 | } 544 | 545 | if (-not $PSBoundParameters.ContainsKey('Enforce')) { 546 | $Enforce = $false 547 | } 548 | } 549 | Process 550 | { 551 | #Attempt to get the key hive from registry path 552 | $RegKeyHive = ($RegPath).Split('\')[0].TrimEnd(':') 553 | 554 | #Convert RegKeyHive to LGPO compatible variables 555 | Switch ($RegKeyHive){ 556 | HKEY_LOCAL_MACHINE {$LGPOHive = 'Computer';$RegHive = 'HKLM:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 557 | MACHINE {$LGPOHive = 'Computer';$RegHive = 'HKLM:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 558 | HKLM {$LGPOHive = 'Computer';$RegHive = 'HKLM:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 559 | HKEY_CURRENT_USER {$LGPOHive = 'User';$RegHive = 'HKCU:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 560 | HKEY_USERS {$LGPOHive = 'User';$RegHive = 'Registry::HKEY_USERS';$RegKeyPath = ($RegPath).Split('\',2)[1]} 561 | Registry::HKEY_USERS {$LGPOHive = 'User';$RegHive = 'Registry::HKEY_USERS';$RegKeyPath = ($RegPath).Split('\',2)[1]} 562 | HKCU {$LGPOHive = 'User';$RegHive = 'HKCU:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 563 | HKU {$LGPOHive = 'User';$RegHive = 'Registry::HKEY_USERS';$RegKeyPath = ($RegPath).Split('\',2)[1]} 564 | USER {$LGPOHive = 'User';$RegHive = 'HKCU:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 565 | default {$LGPOHive = 'Computer';$RegHive = 'HKLM:';$RegKeyPath = $RegPath} 566 | } 567 | 568 | $RegKeyName = $Name 569 | 570 | #The -split operator supports specifying the maximum number of sub-strings to return. 571 | #Some values may have additional commas in them that we don't want to split (eg. LegalNoticeText) 572 | [String]$Value = $Value -split ',',2 573 | 574 | #convert registry type to LGPO type 575 | Switch($Type){ 576 | 'None' {$LGPORegType = 'NONE'} 577 | 'String' {$LGPORegType = 'SZ';} 578 | 'ExpandString' {$LGPORegType = 'EXSZ';} 579 | 'Binary' {$LGPORegType = 'BINARY'; $value = (Convert-ToHexString $value)} 580 | 'DWord' {$LGPORegType = 'DWORD'} 581 | 'QWord' {$LGPORegType = 'DWORD_BIG_ENDIAN'} 582 | 'MultiString' {$LGPORegType = 'MULTISZ'} 583 | default {$LGPORegType = 'DWORD';$Type = 'DWord'} 584 | } 585 | 586 | Write-Verbose ("{0} : Parsing registry [Hive = '{1}', Path = '{2}', Name = '{3}', Value = '{4}', Type = '{5}']" -f ${CmdletName},$RegHive,$RegKeyPath,$RegKeyName,$Value,$LGPORegType) 587 | 588 | #Remove the Username or SID from Registry key path for LGPO to process properly 589 | $LGPORegKeyPath = $RegKeyPath 590 | If($LGPOHive -eq 'User'){ 591 | $UserID = $RegKeyPath.Split('\')[0] 592 | If($UserID -match "DEFAULT|S-1-5-21-(\d+-?){4}$"){ 593 | $LGPORegKeyPath = $RegKeyPath.Replace($UserID+"\","") 594 | } 595 | } 596 | 597 | #check if path exists 598 | If(Test-Path $LGPOBinaryPath) 599 | { 600 | # build a unique output file 601 | $LgpoFileName = ('LGPO-Set-{0}-{1}-{2}' -f $RegKeyHive,$LGPORegKeyPath,$RegKeyName) -replace 'Registry::','' -replace '[\W_]','-' 602 | 603 | #$lgpoout = $null 604 | $lgpoout = "; ----------------------------------------------------------------------`r`n" 605 | $lgpoout += "; PROCESSING POLICY`r`n" 606 | $lgpoout += "; Source file:`r`n" 607 | $lgpoout += "`r`n" 608 | $lgpoout += "$LGPOHive`r`n" 609 | $lgpoout += "$LGPORegKeyPath`r`n" 610 | $lgpoout += "$RegKeyName`r`n" 611 | $lgpoout += "$($LGPORegType):$Value`r`n" 612 | $lgpoout += "`r`n" 613 | 614 | #complete LGPO file 615 | Write-Verbose ("{0} : Generating LGPO configuration file [{1}]" -f ${CmdletName},"$env:Temp\$LgpoFileName.lgpo") 616 | $lgpoout | Out-File "$env:Temp\$LgpoFileName.lgpo" -Force 617 | 618 | # Build agrument list 619 | # should look like this: /q /t path\lgpo.txt [/v] 620 | $lgpoargs = @() 621 | $lgpoargs += '/q' 622 | $lgpoargs += '/t' 623 | $lgpoargs += "$env:Temp\$LgpoFileName.lgpo" 624 | If($VerbosePreference){$lgpoargs += '/v'} 625 | 626 | #convert argument array to string for verbose output 627 | $lgpoargstr = ($lgpoargs -join ' ') 628 | 629 | If($WhatIfPreference) 630 | { 631 | Write-Output ("What if: Performing the operation ""{0}"" on target ""{1}"" with argument ""{2} {3}""." -f ${CmdletName},$LGPOHive,$LGPOBinaryPath,$lgpoargstr) 632 | } 633 | Else 634 | { 635 | Write-Verbose ("{0} : RUNNING COMMAND: Start-Process {1} -ArgumentList '{2}' -RedirectStandardError '{3}' -RedirectStandardOutput '{4}' -Wait -WindowStyle Hidden -PassThru" -f ${CmdletName},$LGPOBinaryPath,$lgpoargstr,"$env:Temp\$LgpoFileName.stderr","$env:Temp\$LgpoFileName.stdout") 636 | Try{ 637 | $result = Start-Process $LGPOBinaryPath -ArgumentList $lgpoargs -RedirectStandardError "$env:Temp\$LgpoFileName.stderr" -RedirectStandardOutput "$env:Temp\$LgpoFileName.stdout" -Wait -WindowStyle Hidden -PassThru -ErrorAction Stop 638 | Write-Verbose ("{0} : LGPO ran successfully." -f ${CmdletName}) 639 | } 640 | Catch{ 641 | Write-Error ("LGPO failed to run. {1}" -f ${CmdletName},$result.ExitCode) 642 | } 643 | } 644 | 645 | } 646 | Else{ 647 | Write-Error ("Local Policy was not set; LGPO binaries not found in path [{1}].`nDownload binaries from 'https://www.microsoft.com/en-us/download/details.aspx?id=55319' " -f ${CmdletName},$LGPOBinaryPath) 648 | } 649 | 650 | If($EnForce -eq $true) 651 | { 652 | #rebuild full path with hive 653 | $RegPath = ($RegHive +'\'+ $RegKeyPath) 654 | 655 | Write-Verbose ("{0} : Force enabled. Hard coding registry key..." -f ${CmdletName}) 656 | #verify the registry value has been set 657 | $CurrentPos = $null 658 | #loop through each key path to build the correct path 659 | #TEST $Node = $RegPath.split('\')[0] 660 | Foreach($Node in $RegPath.split('\')) 661 | { 662 | $CurrentPos += $Node + '\' 663 | If(-Not(Test-Path $CurrentPos -PathType Container)){ 664 | Write-Verbose ("{0} : Building key path [{1}]" -f ${CmdletName},$CurrentPos) 665 | New-Item $CurrentPos -ErrorAction SilentlyContinue -WhatIf:$WhatIfPreference | Out-Null 666 | } 667 | } 668 | 669 | Try{ 670 | Write-Verbose ("{0} : Setting key name [{2}] at path [{1}] with value [{3}]" -f ${CmdletName},$RegPath,$RegKeyName,$Value) 671 | Set-ItemProperty -Path $RegPath -Name $RegKeyName -Value $Value -Force -WhatIf:$WhatIfPreference -ErrorAction Stop 672 | } 673 | Catch{ 674 | Write-Error ("Unable to set registry key [{2}={3}] in path [{1}]. {4}" -f ${CmdletName},$RegPath,$RegKeyName,$Value,$_.Exception.Message) 675 | } 676 | } 677 | } 678 | End { 679 | If($EnForce -eq $true) 680 | { 681 | $GPArgument = "/Target:Computer /Force" 682 | Write-Verbose ("{0} : RUNNING COMMAND: Start-Process -FilePath `"gpupdate`" -ArgumentList `"$GPArgument`" -Wait -PassThru -WindowStyle Hidden" -f ${CmdletName}) 683 | Start-Process -FilePath "gpupdate" -ArgumentList "$GPArgument" -Wait -WindowStyle Hidden | Out-Null 684 | } 685 | 686 | #cleanup LGPO temp files if not debugging 687 | If( (Test-Path "$env:Temp\$LgpoFileName.lgpo" -PathType Leaf) -and !$DebugPreference ){ 688 | Remove-Item "$env:Temp\$LgpoFileName.lgpo" -ErrorAction SilentlyContinue -Force | Out-Null 689 | Remove-Item "$env:Temp\$LgpoFileName.stderr" -ErrorAction SilentlyContinue -Force | Out-Null 690 | Remove-Item "$env:Temp\$LgpoFileName.stdout" -ErrorAction SilentlyContinue -Force | Out-Null 691 | } 692 | } 693 | 694 | } 695 | 696 | 697 | 698 | ### ----------------------------------- 699 | ### Remove-LocalPolicySetting Cmdlet 700 | ### ----------------------------------- 701 | Function Remove-LocalPolicySetting { 702 | <# 703 | .SYNOPSIS 704 | Removes GPO setting 705 | 706 | .DESCRIPTION 707 | Uses LGPO tool to remove local policy settings or registry key 708 | 709 | .NOTES 710 | Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319 711 | Create a Directory in C:\ProgramData\LGPO 712 | Unzip LGPO.exe to that folder 713 | 714 | .PARAMETER RegPath 715 | Required. Specify path to registry item 716 | 717 | .PARAMETER Name 718 | Specify Name of registry key to remove. If no name specified, RegPath will be split up to use leaf as name 719 | 720 | .PARAMETER AllValues 721 | Ignores name and deletes all keys within path. 722 | 723 | .PARAMETER Enforce 724 | Applies a policy to always delete value instead of removing it from policy (does not show in gpresults) 725 | 726 | .PARAMETER LGPOBinaryPath 727 | Use this to specify alternate location 728 | Defaults to "C:\ProgramData\LGPO\LGPO.exe". Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319. 729 | 730 | .EXAMPLE 731 | Remove-LocalPolicySetting -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' -Name 'TaskbarMn' 732 | 733 | .EXAMPLE 734 | Remove-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -Enforce 735 | 736 | .EXAMPLE 737 | Remove-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -Verbose 738 | 739 | .EXAMPLE 740 | Remove-LocalPolicySetting -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell' -Name 'UseActionCenterExperience' -LGPOBinaryPath c:\lgpo\lgpo.exe 741 | 742 | .LINK 743 | Get-LocalPolicySystemSettings 744 | Update-LocalPolicySettings 745 | 746 | #> 747 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium',DefaultParameterSetName='name')] 748 | Param ( 749 | [Parameter(Mandatory=$true,Position=1,ParameterSetName="name")] 750 | [Parameter(Mandatory=$true,Position=1,ParameterSetName="all")] 751 | [Alias("Path")] 752 | [string]$RegPath, 753 | 754 | [Parameter(Mandatory=$true,Position=2,ParameterSetName="name",ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 755 | [Alias("v")] 756 | [string]$Name, 757 | 758 | [Parameter(Mandatory=$true,Position=2,ParameterSetName="all")] 759 | [Alias("a")] 760 | [switch]$AllValues, 761 | 762 | [Parameter(Mandatory=$false)] 763 | [Alias("f",'Force')] 764 | [switch]$Enforce, 765 | 766 | [Parameter(Mandatory=$false,HelpMessage="Default path is 'C:\ProgramData\LGPO\LGPO.exe. If this does not exists you must specify path")] 767 | [ValidateScript({Test-path $_ -PathType Leaf})] 768 | $LGPOBinaryPath = "$env:ALLUSERSPROFILE\LGPO\LGPO.exe" 769 | ) 770 | Begin 771 | { 772 | ## Get the name of this function 773 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 774 | 775 | if (-not $PSBoundParameters.ContainsKey('Verbose')) { 776 | $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') 777 | } 778 | 779 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 780 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 781 | } 782 | 783 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 784 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 785 | } 786 | 787 | if (-not $PSBoundParameters.ContainsKey('Debug')) { 788 | $DebugPreference = $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') 789 | } 790 | #set boolean value 791 | if (-not $PSBoundParameters.ContainsKey('Enforce')) { 792 | $Enforce = $false 793 | } 794 | } 795 | Process 796 | { 797 | #Attempt to get the key hive from registry path 798 | #Attempt to get the key hive from registry path 799 | $RegKeyHive = ($RegPath).Split('\')[0].TrimEnd(':') 800 | 801 | #Convert RegKeyHive to LGPO compatible variables 802 | Switch ($RegKeyHive){ 803 | HKEY_LOCAL_MACHINE {$LGPOHive = 'Computer';$RegHive = 'HKLM:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 804 | MACHINE {$LGPOHive = 'Computer';$RegHive = 'HKLM:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 805 | HKLM {$LGPOHive = 'Computer';$RegHive = 'HKLM:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 806 | HKEY_CURRENT_USER {$LGPOHive = 'User';$RegHive = 'HKCU:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 807 | HKEY_USERS {$LGPOHive = 'User';$RegHive = 'Registry::HKEY_USERS';$RegKeyPath = ($RegPath).Split('\',2)[1]} 808 | Registry::HKEY_USERS {$LGPOHive = 'User';$RegHive = 'Registry::HKEY_USERS';$RegKeyPath = ($RegPath).Split('\',2)[1]} 809 | HKCU {$LGPOHive = 'User';$RegHive = 'HKCU:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 810 | HKU {$LGPOHive = 'User';$RegHive = 'Registry::HKEY_USERS';$RegKeyPath = ($RegPath).Split('\',2)[1]} 811 | USER {$LGPOHive = 'User';$RegHive = 'HKCU:';$RegKeyPath = ($RegPath).Split('\',2)[1]} 812 | default {$LGPOHive = 'Computer';$RegHive = 'HKLM:';$RegKeyPath = $RegPath} 813 | } 814 | 815 | #if Name not specified, grab last value from full path 816 | # build a unique output file 817 | If($AllValues){ 818 | $RegKeyName = '*' 819 | } 820 | Else{ 821 | $RegKeyName = $Name 822 | } 823 | 824 | Write-Verbose ("{0} : Parsing registry [Hive = '{1}', Path = '{2}', Name = '{3}', Value = '{4}', Type = '{5}']" -f ${CmdletName},$RegHive,$RegKeyPath,$RegKeyName,$Value,$LGPORegType) 825 | 826 | #Remove the Username or SID from Registry key path 827 | $LGPORegKeyPath = $RegKeyPath 828 | If($LGPOHive -eq 'User'){ 829 | $UserID = $RegKeyPath.Split('\')[0] 830 | If($UserID -match "DEFAULT|S-1-5-21-(\d+-?){4}$"){ 831 | $LGPORegKeyPath = $RegKeyPath.Replace($UserID+"\","") 832 | } 833 | } 834 | 835 | #check if path exists 836 | If(Test-Path $LGPOBinaryPath) 837 | { 838 | If($Enforce -eq $true){ 839 | # build a unique output file 840 | If($AllValues){ 841 | $LgpoFileName = ('LGPO-Set-{0}-{1}-All-Keys' -f $RegKeyHive,$LGPORegKeyPath) -replace 'Registry::','' -replace '[\W_]','-' 842 | } 843 | Else{ 844 | $LgpoFileName = ('LGPO-Set-{0}-{1}-{2}' -f $RegKeyHive,$LGPORegKeyPath,$RegKeyName) -replace 'Registry::','' -replace '[\W_]','-' 845 | } 846 | 847 | #$lgpoout = $null 848 | $lgpoout = "; ----------------------------------------------------------------------`r`n" 849 | $lgpoout += "; PROCESSING POLICY`r`n" 850 | $lgpoout += "; Source file:`r`n" 851 | $lgpoout += "`r`n" 852 | $lgpoout += "$LGPOHive`r`n" 853 | $lgpoout += "$LGPORegKeyPath`r`n" 854 | If($AllValues){ 855 | $lgpoout += "*`r`n" 856 | $lgpoout += "DELETEALLVALUES`r`n" 857 | }Else{ 858 | $lgpoout += "$RegKeyName`r`n" 859 | $lgpoout += "DELETE`r`n" 860 | } 861 | $lgpoout += "`r`n" 862 | 863 | #complete LGPO file 864 | Write-Verbose ("{0} : Generating LGPO configuration file [{1}]" -f ${CmdletName},"$env:Temp\$LgpoFileName.lgpo") 865 | $lgpoout | Out-File "$env:Temp\$LgpoFileName.lgpo" -Force 866 | 867 | # Build agrument list 868 | # should look like this: /q /t path\lgpo.txt [/v] 869 | $lgpoargs = @() 870 | $lgpoargs += '/q' 871 | $lgpoargs += '/t' 872 | $lgpoargs += "$env:Temp\$LgpoFileName.lgpo" 873 | If($VerbosePreference){$lgpoargs += '/v'} 874 | 875 | #convert argument array to string for verbose output 876 | $lgpoargstr = ($lgpoargs -join ' ') 877 | 878 | If($WhatIfPreference) 879 | { 880 | Write-Output ("What if: Performing the operation ""{0}"" on target ""{1}"" with argument ""{2} {3}""." -f ${CmdletName},$LGPOHive,$LGPOBinaryPath,$lgpoargstr) 881 | } 882 | Else 883 | { 884 | Write-Verbose ("{0} : Start-Process {1} -ArgumentList '{2}' -RedirectStandardError '{3}' -RedirectStandardOutput '{4}' -Wait -WindowStyle Hidden -PassThru" -f ${CmdletName},$LGPOBinaryPath,$lgpoargstr,"$env:Temp\$LgpoFileName.stderr","$env:Temp\$LgpoFileName.stdout") 885 | Try{ 886 | $result = Start-Process $LGPOBinaryPath -ArgumentList $lgpoargs -RedirectStandardError "$env:Temp\$LgpoFileName.stderr" -RedirectStandardOutput "$env:Temp\$LgpoFileName.stdout" -Wait -WindowStyle Hidden -PassThru -ErrorAction Stop 887 | Write-Verbose ("{0} : LGPO ran successfully." -f ${CmdletName}) 888 | } 889 | Catch{ 890 | Write-Error ("LGPO failed to run. {0}" -f $result.ExitCode) 891 | } 892 | } 893 | 894 | #rebuild full path with hive 895 | $RegPath = ($RegHive +'\'+ $RegKeyPath) 896 | 897 | If($AllValues){ 898 | $VerboseMsg = ("{0} : Enforce enabled. Removing all registry keys from [{1}\{2}]" -f ${CmdletName},$RegHive,$RegKeyPath) 899 | $ErrorMsg = ("{0} : Unable to remove registry keys from [{1}\{2}]. {3}" -f ${CmdletName},$RegHive,$RegKeyPath,$_.Exception.Message) 900 | } 901 | Else{ 902 | $VerboseMsg = ("{0} : Enforce enabled. Removing registry key [{3}] from [{1}\{2}]" -f ${CmdletName},$RegHive,$RegKeyPath,$RegKeyName) 903 | $ErrorMsg = ("{0} : Unable to remove registry key [{1}\{2}\{3}]. {4}" -f ${CmdletName},$RegHive,$RegKeyPath,$RegKeyName,$_.Exception.Message) 904 | } 905 | 906 | Write-Verbose $VerboseMsg 907 | #verify the registry value has been set 908 | Try{ 909 | Remove-ItemProperty -Path $RegPath -Name $RegKeyName -Force -WhatIf:$WhatIfPreference -ErrorAction SilentlyContinue 910 | } 911 | Catch{ 912 | Write-Error $ErrorMsg 913 | } 914 | } 915 | Else{ 916 | 917 | Try{ 918 | #Grab all polices but filter out the one that needs be removed. Then update the entire system policy (this set thte removed policy as not configured) 919 | If($RegKeyName -ne '*' ){ 920 | Write-Verbose ("{0} : RUNNING CMDLET: Get-LocalPolicySystemSettings -Filter ('`$_.Name -ne `"$RegKeyName`" -or `$_.Key -ne `"$RegKeyPath`"') | Update-LocalPolicySettings -Policy $LGPOHive -ErrorAction Stop" -f ${CmdletName}) 921 | Get-LocalPolicySystemSettings -Filter ('$_.Name -ne "' + $RegKeyName + '" -or $_.Key -ne "' + $RegKeyPath + '"') | Update-LocalPolicySettings -Policy $LGPOHive -ErrorAction Stop 922 | #Get-LocalPolicySystemSettings | Where {$_.Name -ne $RegKeyName -or $_.Key -ne $RegKeyPath} | Update-LocalPolicySettings -Policy $LGPOHive -ErrorAction Stop 923 | } 924 | Else{ 925 | Write-Verbose ("{0} : RUNNING CMDLET: Get-LocalPolicySystemSettings -Filter ('`$_.Key -ne `"$RegKeyPath`"') | Update-LocalPolicySettings -Policy $LGPOHive -ErrorAction Stop" -f ${CmdletName}) 926 | Get-LocalPolicySystemSettings -Filter ('$_.Key -ne "' + $RegKeyPath + '"') | Update-LocalPolicySettings -Policy $LGPOHive -ErrorAction Stop 927 | } 928 | } 929 | Catch{ 930 | Write-Error ("LGPO failed to run. {1}" -f ${CmdletName},$_.Exception.Message) 931 | } 932 | } 933 | 934 | } 935 | Else{ 936 | Write-Error ("Local Policy was not set; LGPO binaries not found in path [{1}].`nDownload binaries from 'https://www.microsoft.com/en-us/download/details.aspx?id=55319' " -f ${CmdletName},$LGPOBinaryPath) 937 | } 938 | } 939 | End { 940 | If($EnForce -eq $true) 941 | { 942 | $GPArgument = "/Target:Computer /Force" 943 | Write-Verbose ("{0} : RUNNING COMMAND: Start-Process -FilePath `"gpupdate`" -ArgumentList `"$GPArgument`" -Wait -PassThru -WindowStyle Hidden" -f ${CmdletName}) 944 | Start-Process -FilePath "gpupdate" -ArgumentList "$GPArgument" -Wait -WindowStyle Hidden | Out-Null 945 | } 946 | #cleanup LGPO temp files if not debugging 947 | If( (Test-Path "$env:Temp\$LgpoFileName.lgpo" -PathType Leaf) -and !$DebugPreference ){ 948 | Remove-Item "$env:Temp\$LgpoFileName.lgpo" -ErrorAction SilentlyContinue -Force | Out-Null 949 | Remove-Item "$env:Temp\$LgpoFileName.stderr" -ErrorAction SilentlyContinue -Force | Out-Null 950 | Remove-Item "$env:Temp\$LgpoFileName.stdout" -ErrorAction SilentlyContinue -Force | Out-Null 951 | } 952 | } 953 | 954 | } 955 | 956 | 957 | ### ----------------------------------- 958 | ### Get-LocalPolicySetting Cmdlet 959 | ### ----------------------------------- 960 | Function Get-LocalPolicyUserSettings { 961 | <# 962 | .SYNOPSIS 963 | Retrieves Local user policies 964 | 965 | .DESCRIPTION 966 | Uses LGPO tool to parse local user policy and export as object 967 | 968 | .NOTES 969 | Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319 970 | Create a Directory in C:\ProgramData\LGPO 971 | Unzip LGPO.exe to that folder 972 | 973 | .PARAMETER Filter 974 | Filter on export 975 | 976 | .PARAMETER LGPOBinaryPath 977 | Use this to specify alternate location 978 | Defaults to "C:\ProgramData\LGPO\LGPO.exe". Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319. 979 | 980 | .EXAMPLE 981 | Get-LocalPolicyUserSettings 982 | 983 | .EXAMPLE 984 | Get-LocalPolicyUserSettings -Filter '$_.Key -like "*microsoft*"' 985 | 986 | .EXAMPLE 987 | Get-LocalPolicyUserSettings -Verbose 988 | 989 | .EXAMPLE 990 | Get-LocalPolicyUserSettings -Debug 991 | Working files will be left in temp folder for debugging 992 | 993 | .EXAMPLE 994 | Get-LocalPolicyUserSettings -LGPOBinaryPath c:\lgpo\lgpo.exe 995 | 996 | .LINK 997 | Get-LocalPolicySettings 998 | #> 999 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] 1000 | Param ( 1001 | [Parameter(Mandatory=$false)] 1002 | [string]$Filter, 1003 | 1004 | [Parameter(Mandatory=$false)] 1005 | [ValidateScript({Test-path $_ -PathType Leaf})] 1006 | $LGPOBinaryPath = "$env:ALLUSERSPROFILE\LGPO\LGPO.exe" 1007 | ) 1008 | Begin 1009 | { 1010 | ## Get the name of this function 1011 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 1012 | 1013 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 1014 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 1015 | } 1016 | } 1017 | Process{ 1018 | $LGPOSplat = @{ 1019 | Policy='User' 1020 | LGPOBinaryPath=$LGPOBinaryPath 1021 | } 1022 | 1023 | If($Filter){ 1024 | $LGPOSplat += @{Filter=$Filter} 1025 | } 1026 | $LGPOSplatString = $LGPOSplat.GetEnumerator() | ForEach-Object{('/' + $_.Key + ' ' + $_.Value) -join ' '} | Select-Object -Last 1 1027 | 1028 | If($WhatIfPreference) 1029 | { 1030 | Write-Output ("What if: Performing the operation ""{0}"" on target ""{1}"" with argument ""{2}""." -f ${CmdletName},$LGPOSplat.Policy,$LGPOSplatString) 1031 | } 1032 | Else 1033 | { 1034 | Get-LocalPolicySettings @LGPOSplat 1035 | } 1036 | } 1037 | } 1038 | 1039 | ### ----------------------------------- 1040 | ### Set-LocalPolicyUserSetting Cmdlet 1041 | ### ----------------------------------- 1042 | Function Set-LocalPolicyUserSetting { 1043 | <# 1044 | .SYNOPSIS 1045 | Converts registry key into GPO for user policy 1046 | 1047 | .DESCRIPTION 1048 | Uses LGPO tool to convert registry key into Local policy 1049 | 1050 | .NOTES 1051 | Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319 1052 | Create a Directory in C:\ProgramData\LGPO 1053 | Unzip LGPO.exe to that folder 1054 | 1055 | .PARAMETER RegPath 1056 | Required. Specify path to registry item 1057 | 1058 | .PARAMETER Name 1059 | Required. Specify Name of registry key to set. 1060 | 1061 | .PARAMETER Type 1062 | Default to 'DWord'. Specify type of registry item 1063 | 1064 | .PARAMETER Value 1065 | Specify value or Key name 1066 | 1067 | .PARAMETER Enforce 1068 | If LGPO failed, this will set the registry item anyway 1069 | 1070 | .PARAMETER LGPOBinaryPath 1071 | Use this to specify alternate location 1072 | Defaults to "C:\ProgramData\LGPO\LGPO.exe". Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319. 1073 | 1074 | .EXAMPLE 1075 | Set-LocalPolicyUserSetting -RegPath 'SOFTWARE\Policies\Microsoft\Windows\Explorer' -Name 'DisableNotificationCenter' -Type DWord -Value 1 1076 | 1077 | .LINK 1078 | Set-LocalPolicySetting 1079 | #> 1080 | 1081 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] 1082 | Param ( 1083 | [Parameter(Mandatory=$true,Position=1)] 1084 | [Alias("Path")] 1085 | [string]$RegPath, 1086 | 1087 | [Parameter(Mandatory=$true,Position=2,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 1088 | [Alias("v")] 1089 | [string]$Name, 1090 | 1091 | [Parameter(Mandatory=$false,Position=3)] 1092 | [ValidateSet('None','String','Binary','DWord','ExpandString','MultiString','QWord')] 1093 | [Alias("PropertyType","t")] 1094 | [string]$Type = 'DWord', 1095 | 1096 | [Parameter(Mandatory=$false,Position=4)] 1097 | [Alias("d")] 1098 | $Value, 1099 | 1100 | [Parameter(Mandatory=$false)] 1101 | [ValidateSet('CurrentUser','AllUsers','DefaultUser')] 1102 | [Alias("Users")] 1103 | [string]$ApplyTo, 1104 | 1105 | [Parameter(Mandatory=$false)] 1106 | [Alias("f",'Force')] 1107 | [switch]$Enforce, 1108 | 1109 | [Parameter(Mandatory=$false)] 1110 | [ValidateScript({Test-path $_ -PathType Leaf})] 1111 | $LGPOBinaryPath = "$env:ALLUSERSPROFILE\LGPO\LGPO.exe" 1112 | ) 1113 | Begin 1114 | { 1115 | ## Get the name of this function 1116 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 1117 | 1118 | if (-not $PSBoundParameters.ContainsKey('Verbose')) { 1119 | $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') 1120 | } 1121 | 1122 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 1123 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 1124 | } 1125 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 1126 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 1127 | } 1128 | if (-not $PSBoundParameters.ContainsKey('Enforce')) { 1129 | $Enforce = $false 1130 | } 1131 | 1132 | # Get each user profile SID and Path to the profile 1133 | $AllProfiles = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" | Where-Object {$_.PSChildName -match "S-1-5-21-(\d+-?){4}$" } | 1134 | Select-Object @{Name="SID"; Expression={$_.PSChildName}}, @{Name="UserHive";Expression={"$($_.ProfileImagePath)\NTuser.dat"}}, @{Name="UserName";Expression={Split-Path $_.ProfileImagePath -Leaf}} 1135 | 1136 | # Add in the DEFAULT User Profile (Not be confused with .DEFAULT) 1137 | $DefaultProfile = "" | Select-Object SID, UserHive,UserName 1138 | $DefaultProfile.SID = "DEFAULT" 1139 | $DefaultProfile.Userhive = "$env:systemdrive\Users\Default\NTUSER.dat" 1140 | $DefaultProfile.UserName = "Default" 1141 | 1142 | #Add it to the UserProfile list 1143 | $UserProfiles = @() 1144 | $UserProfiles += $AllProfiles 1145 | $UserProfiles += $DefaultProfile 1146 | 1147 | #get current users sid 1148 | [string]$CurrentSID = (Get-CimInstance Win32_UserAccount | Where-Object {$_.name -eq $env:username}).SID 1149 | 1150 | Write-Verbose ("{0} : Found [{1}] user profiles" -f ${CmdletName},$UserProfiles.count) 1151 | } 1152 | Process 1153 | { 1154 | #grab the hive from the regpath 1155 | $RegKeyHive = ($RegPath).Split('\')[0].Replace('Registry::','').Replace(':','') 1156 | 1157 | #check if hive is local machine. 1158 | If($RegHive -match "HKEY_LOCAL_MACHINE|HKLM|HKCR"){ 1159 | Throw ("Registry path [{1}] is not a user path. Use ' Set-LocalPolicySetting' cmdlet instead" -f ${CmdletName},$RegKeyHive) 1160 | } 1161 | 1162 | #detect if first values has hive; otherwise assume allusers 1163 | If( -Not(Test-Path "$($RegKeyHive):" -PathType Container) ){ 1164 | $RegHive = 'HKCU' 1165 | $RegKeyPath = $RegPath 1166 | } 1167 | 1168 | #Break down registry to get path 1169 | $RegKeyPath = ($RegPath).Split('\',2)[1] 1170 | $RegKeyName = $Name 1171 | 1172 | #Grab user keys and profiles based on whom it will be applied to 1173 | Switch($ApplyTo){ 1174 | 'AllUsers' {$RegHive = 'Registry::HKEY_USERS'; $ProfileList = $UserProfiles} 1175 | 'CurrentUser' {$RegHive = 'HKCU' ; $ProfileList = ($UserProfiles | Where-Object{$_.SID -eq $CurrentSID})} 1176 | 'DefaultUser' {$RegHive = 'HKU' ; $ProfileList = $DefaultProfile} 1177 | default {$RegHive = 'Registry::HKEY_USERS'; $ProfileList = $UserProfiles} 1178 | } 1179 | Write-Verbose ("Setting Registry hive from [{0}] to [{1}]" -f $RegKeyHive,$RegHive) 1180 | 1181 | #loop through profiles as long as the hive is not the current user hive 1182 | If($RegHive -notmatch 'HKCU|HKEY_CURRENT_USER'){ 1183 | 1184 | $p = 1 1185 | # Loop through each profile on the machine 1186 | Foreach ($UserProfile in $ProfileList) { 1187 | 1188 | Try{ 1189 | $objSID = New-Object System.Security.Principal.SecurityIdentifier($UserProfile.SID) 1190 | $UserName = $objSID.Translate([System.Security.Principal.NTAccount]) 1191 | } 1192 | Catch{ 1193 | $UserName = $UserProfile.UserName 1194 | } 1195 | Write-Verbose ("{0} : Setting policy [{1}] for user: {2}" -f ${CmdletName},$RegKeyName,$UserName) 1196 | 1197 | #loadhive if not mounted 1198 | If (($HiveLoaded = Test-Path "Registry::HKEY_USERS\$($UserProfile.SID)") -eq $false) { 1199 | Start-Process -FilePath "CMD.EXE" -ArgumentList "/C REG.EXE LOAD HKU\$($UserProfile.SID) $($UserProfile.UserHive)" -Wait -WindowStyle Hidden 1200 | $HiveLoaded = $true 1201 | } 1202 | 1203 | If ($HiveLoaded -eq $true) { 1204 | Write-Verbose ("{0} : RUNNING CMDLET: Set-LocalPolicySetting -Path `"$RegHive\$($UserProfile.SID)\$RegKeyPath`" -Name $RegKeyName -Type $Type -Value $Value -LGPOBinaryPath $LGPOBinaryPath -Enforce:$Enforce -WhatIf:$WhatIfPreference" -f ${CmdletName}) 1205 | Set-LocalPolicySetting -Path "$RegHive\$($UserProfile.SID)\$RegKeyPath" -Name $RegKeyName -Type $Type -Value $Value -LGPOBinaryPath $LGPOBinaryPath -Enforce:$Enforce -WhatIf:$WhatIfPreference 1206 | } 1207 | 1208 | #remove any leftover reg process and then remove hive 1209 | If ($HiveLoaded -eq $true) { 1210 | [gc]::Collect() 1211 | Start-Sleep -Seconds 3 1212 | Start-Process -FilePath "CMD.EXE" -ArgumentList "/C REG.EXE UNLOAD HKU\$($UserProfile.SID)" -Wait -PassThru -WindowStyle Hidden | Out-Null 1213 | } 1214 | $p++ 1215 | } 1216 | } 1217 | Else{ 1218 | Write-Verbose ("{0} : RUNNING CMDLET: Set-LocalPolicySetting -Path `"$RegHive\$RegKeyPath`" -Name $RegKeyName -Type $Type -Value $Value -LGPOBinaryPath $LGPOBinaryPath -Enforce:$Enforce -WhatIf:$WhatIfPreference" -f ${CmdletName}) 1219 | Set-LocalPolicySetting -Path "$RegHive\$RegKeyPath" -Name $RegKeyName -Type $Type -Value $Value -LGPOBinaryPath $LGPOBinaryPath -Enforce:$Enforce -WhatIf:$WhatIfPreference 1220 | } 1221 | 1222 | } 1223 | End{ 1224 | If($EnForce -eq $true) 1225 | { 1226 | $GPArgument = "/Target:User /Force" 1227 | Write-Verbose ("{0} : RUNNING COMMAND: Start-Process -FilePath `"gpupdate`" -ArgumentList `"$GPArgument`" -Wait -PassThru -WindowStyle Hidden" -f ${CmdletName}) 1228 | Start-Process -FilePath "gpupdate" -ArgumentList "$GPArgument" -Wait -WindowStyle Hidden | Out-Null 1229 | } 1230 | } 1231 | } 1232 | 1233 | 1234 | 1235 | ### ----------------------------------- 1236 | ### Remove-LocalPolicyUserSetting Cmdlet 1237 | ### ----------------------------------- 1238 | Function Remove-LocalPolicyUserSetting { 1239 | <# 1240 | .SYNOPSIS 1241 | Removes GPO setting on user 1242 | 1243 | .DESCRIPTION 1244 | Uses LGPO tool to remove user policy settings or registry key 1245 | 1246 | .NOTES 1247 | Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319 1248 | Create a Directory in C:\ProgramData\LGPO 1249 | Unzip LGPO.exe to that folder 1250 | 1251 | .PARAMETER RegPath 1252 | Required. Specify path to registry item 1253 | 1254 | .PARAMETER Name 1255 | Specify Name of registry key to remove. If no name specified, RegPath will be split up to use leaf as name 1256 | 1257 | .PARAMETER ApplyTo 1258 | Defaults to AllUsers. Specify either defaultuser or CurrentUser 1259 | 1260 | .PARAMETER Enforce 1261 | If LGPO failed, this will remove the registry item anyway 1262 | 1263 | .PARAMETER LGPOBinaryPath 1264 | Use this to specify alternate location 1265 | Defaults to "C:\ProgramData\LGPO\LGPO.exe". Download LGPO from https://www.microsoft.com/en-us/download/details.aspx?id=55319. 1266 | 1267 | .EXAMPLE 1268 | Remove-LocalPolicyUserSetting -RegPath 'SOFTWARE\Policies\Microsoft\Windows\Explorer' -Name 'DisableNotificationCenter' 1269 | 1270 | .LINK 1271 | Remove-LocalPolicySetting 1272 | #> 1273 | 1274 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] 1275 | Param ( 1276 | [Parameter(Mandatory=$true,Position=1)] 1277 | [Alias("Path")] 1278 | [string]$RegPath, 1279 | 1280 | [Parameter(Mandatory=$false,Position=2,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 1281 | [Alias("v")] 1282 | [string]$Name, 1283 | 1284 | [Parameter(Mandatory=$false)] 1285 | [ValidateSet('CurrentUser','AllUsers','DefaultUser')] 1286 | [Alias("Users")] 1287 | [string]$ApplyTo = 'AllUsers', 1288 | 1289 | [Parameter(Mandatory=$false)] 1290 | [Alias("f",'Force')] 1291 | [switch]$Enforce, 1292 | 1293 | [Parameter(Mandatory=$false)] 1294 | [ValidateScript({Test-path $_ -PathType Leaf})] 1295 | $LGPOBinaryPath = "$env:ALLUSERSPROFILE\LGPO\LGPO.exe" 1296 | ) 1297 | Begin 1298 | { 1299 | ## Get the name of this function 1300 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 1301 | 1302 | if (-not $PSBoundParameters.ContainsKey('Verbose')) { 1303 | $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') 1304 | } 1305 | 1306 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 1307 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 1308 | } 1309 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 1310 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 1311 | } 1312 | #set boolean value 1313 | if (-not $PSBoundParameters.ContainsKey('Enforce')) { 1314 | $Enforce = $False 1315 | } 1316 | 1317 | # Get each user profile SID and Path to the profile 1318 | $AllProfiles = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" | Where-Object {$_.PSChildName -match "S-1-5-21-(\d+-?){4}$" } | 1319 | Select-Object @{Name="SID"; Expression={$_.PSChildName}}, @{Name="UserHive";Expression={"$($_.ProfileImagePath)\NTuser.dat"}}, @{Name="UserName";Expression={Split-Path $_.ProfileImagePath -Leaf}} 1320 | 1321 | # Add in the DEFAULT User Profile (Not be confused with .DEFAULT) 1322 | $DefaultProfile = "" | Select-Object SID, UserHive,UserName 1323 | $DefaultProfile.SID = "DEFAULT" 1324 | $DefaultProfile.Userhive = "$env:systemdrive\Users\Default\NTUSER.dat" 1325 | $DefaultProfile.UserName = "Default" 1326 | 1327 | #Add it to the UserProfile list 1328 | $UserProfiles = @() 1329 | $UserProfiles += $AllProfiles 1330 | $UserProfiles += $DefaultProfile 1331 | 1332 | #get current users sid 1333 | [string]$CurrentSID = (Get-CimInstance Win32_UserAccount | Where-Object {$_.name -eq $env:username}).SID 1334 | 1335 | Write-Verbose ("{0} : Found [{1}] user profiles" -f ${CmdletName},$UserProfiles.count) 1336 | } 1337 | Process 1338 | { 1339 | #grab the hive from the regpath 1340 | $RegKeyHive = ($RegPath).Split('\')[0].Replace('Registry::','').Replace(':','') 1341 | 1342 | #check if hive is local machine. 1343 | If($RegHive -match "HKEY_LOCAL_MACHINE|HKLM|HKCR"){ 1344 | Throw ("Registry path [{1}] is not a user path. Use ' Set-LocalPolicySetting' cmdlet instead" -f ${CmdletName},$RegKeyHive) 1345 | } 1346 | 1347 | #detect if first values has hive; otherwise assume allusers 1348 | If( -Not(Test-Path "$($RegKeyHive):" -PathType Container) ){ 1349 | $RegHive = 'HKCU' 1350 | $RegKeyPath = $RegPath 1351 | } 1352 | 1353 | #if Name not specified, grab last value from full path 1354 | If($PSBoundParameters.ContainsKey('Name')){ 1355 | $RegKeyPath = ($RegPath).Split('\',2)[1] 1356 | $RegKeyName = $Name 1357 | } 1358 | Else{ 1359 | Write-Verbose ("Spliting path [{0}]. Assuming last item is key name" -f $RegPath) 1360 | $RegKeyPath = Split-Path ($RegPath).Split('\',2)[1] -Parent 1361 | $RegKeyName = ($RegPath).Split('\')[-1] 1362 | } 1363 | 1364 | #Grab user keys and profiles based on whom it will be applied to 1365 | Switch($ApplyTo){ 1366 | 'AllUsers' {$RegHive = 'Registry::HKEY_USERS'; $ProfileList = $UserProfiles} 1367 | 'CurrentUser' {$RegHive = 'HKCU' ; $ProfileList = ($UserProfiles | Where-Object{$_.SID -eq $CurrentSID})} 1368 | 'DefaultUser' {$RegHive = 'HKU' ; $ProfileList = $DefaultProfile} 1369 | default {$RegHive = 'Registry::HKEY_USERS'; $ProfileList = $UserProfiles} 1370 | } 1371 | Write-Verbose ("Setting Registry hive from [{0}] to [{1}]" -f $RegKeyHive,$RegHive) 1372 | 1373 | #loop through profiles as long as the hive is not the current user hive 1374 | If($RegHive -notmatch 'HKCU|HKEY_CURRENT_USER'){ 1375 | 1376 | $p = 1 1377 | # Loop through each profile on the machine 1378 | Foreach ($UserProfile in $ProfileList) { 1379 | 1380 | Try{ 1381 | $objSID = New-Object System.Security.Principal.SecurityIdentifier($UserProfile.SID) 1382 | $UserName = $objSID.Translate([System.Security.Principal.NTAccount]) 1383 | } 1384 | Catch{ 1385 | $UserName = $UserProfile.UserName 1386 | } 1387 | Write-Verbose ("{0} : Removing policy [{1}] for user: {2}" -f ${CmdletName},$RegKeyName,$UserName) 1388 | 1389 | #loadhive if not mounted 1390 | If (($HiveLoaded = Test-Path "Registry::HKEY_USERS\$($UserProfile.SID)") -eq $false) { 1391 | Start-Process -FilePath "CMD.EXE" -ArgumentList "/C REG.EXE LOAD HKU\$($UserProfile.SID) $($UserProfile.UserHive)" -Wait -WindowStyle Hidden 1392 | $HiveLoaded = $true 1393 | } 1394 | 1395 | If ($HiveLoaded -eq $true) { 1396 | Write-Verbose ("{0} : RUNNING CMDLET: Remove-LocalPolicySetting -Path `"$RegHive\$($UserProfile.SID)\$RegKeyPath`" -Name $RegKeyName -LGPOBinaryPath $LGPOBinaryPath -Enforce:$Enforce -WhatIf:$WhatIfPreference" -f ${CmdletName}) 1397 | Remove-LocalPolicySetting -Path "$RegHive\$($UserProfile.SID)\$RegKeyPath" -Name $RegKeyName -LGPOBinaryPath $LGPOBinaryPath -Enforce:$Enforce -WhatIf:$WhatIfPreference 1398 | } 1399 | 1400 | #remove any leftover reg process and then remove hive 1401 | If ($HiveLoaded -eq $true) { 1402 | [gc]::Collect() 1403 | Start-Sleep -Seconds 3 1404 | Start-Process -FilePath "CMD.EXE" -ArgumentList "/C REG.EXE UNLOAD HKU\$($UserProfile.SID)" -Wait -PassThru -WindowStyle Hidden | Out-Null 1405 | } 1406 | $p++ 1407 | } 1408 | } 1409 | Else{ 1410 | Write-Verbose ("{0} : RUNNING CMDLET: Remove-LocalPolicySetting -Path `"$RegHive\$RegKeyPath`" -Name $RegKeyName -LGPOBinaryPath $LGPOBinaryPath -Enforce:$Enforce -WhatIf:$WhatIfPreference" -f ${CmdletName}) 1411 | Remove-LocalPolicySetting -Path "$RegHive\$RegKeyPath" -Name $RegKeyName -LGPOBinaryPath $LGPOBinaryPath -Enforce:$Enforce -WhatIf:$WhatIfPreference 1412 | } 1413 | 1414 | } 1415 | End { 1416 | If($EnForce -eq $true) 1417 | { 1418 | $GPArgument = "/Target:User /Force" 1419 | Write-Verbose ("{0} : RUNNING COMMAND: Start-Process -FilePath `"gpupdate`" -ArgumentList `"$GPArgument`" -Wait -PassThru -WindowStyle Hidden" -f ${CmdletName}) 1420 | Start-Process -FilePath "gpupdate" -ArgumentList "$GPArgument" -Wait -WindowStyle Hidden | Out-Null 1421 | } 1422 | } 1423 | } 1424 | 1425 | 1426 | Function Clear-LocalPolicySettings{ 1427 | [CmdletBinding( 1428 | SupportsShouldProcess, 1429 | ConfirmImpact = 'High' 1430 | )] 1431 | Param ( 1432 | [Parameter(Mandatory=$false,Position=1)] 1433 | [ValidateSet('Machine','Computer','User')] 1434 | $Policy 1435 | ) 1436 | Begin 1437 | { 1438 | ## Get the name of this function 1439 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 1440 | 1441 | if (-not $PSBoundParameters.ContainsKey('Verbose')) { 1442 | $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') 1443 | } 1444 | 1445 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 1446 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 1447 | } 1448 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 1449 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 1450 | } 1451 | 1452 | $PolicyPaths = @() 1453 | } 1454 | Process 1455 | { 1456 | If($Policy){ 1457 | switch($Policy){ 1458 | 'Machine' {$PolicyPaths += 'Machine';$GPTarget='Computer'} 1459 | 'Computer' {$PolicyPaths += 'Machine';$GPTarget='Computer'} 1460 | 'User' {$PolicyPaths += 'User';$GPTarget='User'} 1461 | } 1462 | } 1463 | Else{ 1464 | $GPTarget='All' 1465 | $PolicyPaths += 'Machine' 1466 | $PolicyPaths += 'User' 1467 | } 1468 | 1469 | if ($PSCmdlet.ShouldProcess(($PolicyPaths -join ','))){ 1470 | Foreach($PolicyPath in $PolicyPaths){ 1471 | Write-Verbose ("{0} : Removing local settings for [{1}]" -f ${CmdletName},$PolicyPath) 1472 | 1473 | Remove-Item "$env:Windir\System32\GroupPolicy\$PolicyPath\Registry.pol" -Force -WhatIf:$WhatIfPreference -ErrorAction SilentlyContinue | Out-Null 1474 | } 1475 | } 1476 | } 1477 | End{ 1478 | If($GPTarget -eq 'All'){ 1479 | $GPArgument = '/Force' 1480 | } 1481 | Else{ 1482 | $GPArgument = "/Target:$GPTarget /Force" 1483 | } 1484 | Write-Verbose ("{0} : RUNNING COMMAND: Start-Process -FilePath `"gpupdate`" -ArgumentList `"$GPArgument`" -Wait -PassThru -WindowStyle Hidden" -f ${CmdletName}) 1485 | Start-Process -FilePath "gpupdate" -ArgumentList "$GPArgument" -Wait -WindowStyle Hidden | Out-Null 1486 | } 1487 | } 1488 | 1489 | 1490 | 1491 | function Get-IniContent{ 1492 | <# 1493 | $value = $iniContent[“386Enh"][“EGA80WOA.FON"] 1494 | $iniContent[“386Enh"].Keys | %{$iniContent["386Enh"][$_]} 1495 | #> 1496 | [CmdletBinding()] 1497 | Param( 1498 | [ValidateNotNullOrEmpty()] 1499 | [Parameter(Mandatory=$True)] 1500 | [string]$FilePath 1501 | ) 1502 | Begin{ 1503 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Function started" 1504 | $ini = @{} 1505 | } 1506 | Process{ 1507 | switch -regex -file $FilePath 1508 | { 1509 | "^\[(.+)\]" # Section 1510 | { 1511 | $section = $matches[1] 1512 | $ini[$section] = @{} 1513 | $CommentCount = 0 1514 | } 1515 | "^(;.*)$" # Comment 1516 | { 1517 | $value = $matches[1] 1518 | $CommentCount = $CommentCount + 1 1519 | $name = "Comment" + $CommentCount 1520 | $ini[$section][$name] = $value 1521 | } 1522 | "(.+?)\s*=(.*)" # Key 1523 | { 1524 | $name,$value = $matches[1..2] 1525 | $ini[$section][$name] = $value 1526 | } 1527 | } 1528 | return $ini 1529 | } 1530 | End{ 1531 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Function ended" 1532 | } 1533 | } 1534 | 1535 | 1536 | 1537 | function Set-IniContent{ 1538 | [CmdletBinding()] 1539 | Param( 1540 | [Parameter(ValueFromPipeline=$True,Mandatory=$True)] 1541 | [Hashtable]$InputObject, 1542 | 1543 | [Parameter(Mandatory=$True)] 1544 | [string]$FilePath, 1545 | 1546 | [ValidateSet("Unicode","UTF7","UTF8","UTF32","ASCII","BigEndianUnicode","Default","OEM")] 1547 | [Parameter()] 1548 | [string]$Encoding = "Unicode", 1549 | 1550 | [switch]$Force, 1551 | 1552 | [switch]$Append, 1553 | 1554 | [switch]$Passthru, 1555 | 1556 | [switch]$NewLine 1557 | ) 1558 | Begin{ 1559 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Function started" 1560 | } 1561 | Process{ 1562 | if ($append) {$outfile = Get-Item $FilePath} 1563 | else {$outFile = New-Item -ItemType file -Path $Filepath -Force:$Force -ErrorAction SilentlyContinue} 1564 | if (!($outFile)) {Throw "Could not create File"} 1565 | foreach ($i in $InputObject.keys){ 1566 | if (!($($InputObject[$i].GetType().Name) -eq "Hashtable")){ 1567 | #No Sections 1568 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing key: $i" 1569 | Add-Content -Path $outFile -Value "$i=$($InputObject[$i])" -NoNewline -Encoding $Encoding 1570 | 1571 | } 1572 | else { 1573 | #Sections 1574 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing Section: [$i]" 1575 | $fullList = Get-IniContent $FilePath 1576 | $sectionFound = $fullList[$i] 1577 | 1578 | #if section [] was not found add it 1579 | If(!$sectionFound){ 1580 | #Add-Content -Path $outFile -Value "" -Encoding $Encoding 1581 | Add-Content -Path $outFile -Value "[$i]" -Encoding $Encoding 1582 | } 1583 | 1584 | Foreach ($j in ($InputObject[$i].keys | Sort-Object)){ 1585 | if ($j -match "^Comment[\d]+") { 1586 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing comment: $j" 1587 | Add-Content -Path $outFile -Value "$($InputObject[$i][$j])" -NoNewline -Encoding $Encoding 1588 | } 1589 | else { 1590 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing key: $j" 1591 | Add-Content -Path $outFile -Value "$j=$($InputObject[$i][$j])" -NoNewline -Encoding $Encoding 1592 | } 1593 | } 1594 | If($NewLine){Add-Content -Path $outFile -Value "" -Encoding $Encoding} 1595 | } 1596 | } 1597 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Finished Writing to file: $path" 1598 | If($PassThru){Return $outFile} 1599 | } 1600 | End{ 1601 | Write-Verbose "$($MyInvocation.MyCommand.Name):: Function ended" 1602 | } 1603 | } 1604 | 1605 | function Remove-IniContent{ 1606 | <# 1607 | .SYNOPSIS 1608 | Removes an entry/line/setting from an INI file. 1609 | 1610 | .DESCRIPTION 1611 | A configuration file consists of sections, led by a `[section]` header and followed by `name = value` entries. This function removes an entry in an INI file. Something like this: 1612 | 1613 | [ui] 1614 | username = Regina Spektor 1615 | 1616 | [extensions] 1617 | share = 1618 | extdiff = 1619 | 1620 | Names are not allowed to contains the equal sign, `=`. Values can contain any character. The INI file is parsed using `Split-IniContent`. [See its documentation for more examples.](Split-IniContent.html) 1621 | 1622 | If the entry doesn't exist, does nothing. 1623 | Be default, operates on the INI file case-insensitively. If your INI is case-sensitive, use the `-CaseSensitive` switch. 1624 | 1625 | .LINK 1626 | Set-IniEntry 1627 | 1628 | .LINK 1629 | Split-IniContent 1630 | 1631 | .EXAMPLE 1632 | Remove-IniEntry -Path C:\Projects\Carbon\StupidStupid.ini -Section rat -Name tails 1633 | 1634 | Removes the `tails` item in the `[rat]` section of the `C:\Projects\Carbon\StupidStupid.ini` file. 1635 | 1636 | .EXAMPLE 1637 | Remove-IniEntry -Path C:\Users\me\npmrc -Name 'prefix' -CaseSensitive 1638 | 1639 | Demonstrates how to remove an INI entry in an INI file that is case-sensitive. 1640 | #> 1641 | 1642 | [CmdletBinding(SupportsShouldProcess=$true)] 1643 | param 1644 | ( 1645 | [Parameter(Mandatory=$true)] 1646 | [string] 1647 | # The path to the INI file. 1648 | $Path, 1649 | [string] 1650 | # The name of the INI entry to remove. 1651 | $Name, 1652 | [string] 1653 | # The section of the INI where the entry should be set. 1654 | $Section, 1655 | [Switch] 1656 | # Removes INI entries in a case-sensitive manner. 1657 | $CaseSensitive 1658 | ) 1659 | 1660 | $settings = @{ } 1661 | 1662 | if( Test-Path $Path -PathType Leaf ){ 1663 | $settings = Split-IniContent -Path $Path -AsHashtable -CaseSensitive:$CaseSensitive 1664 | } 1665 | else{ 1666 | Write-Error ('INI file {0} not found.' -f $Path) 1667 | return 1668 | } 1669 | 1670 | $key = $Name 1671 | if( $Section ){ 1672 | $key = '{0}.{1}' -f $Section,$Name 1673 | } 1674 | 1675 | if( $settings.ContainsKey( $key ) ) 1676 | { 1677 | $lines = New-Object 'Collections.ArrayList' 1678 | Get-Content -Path $Path | ForEach-Object { [void] $lines.Add( $_ ) } 1679 | $null = $lines.RemoveAt( ($settings[$key].LineNumber - 1) ) 1680 | if( $PSCmdlet.ShouldProcess( $Path, ('remove INI entry {0}' -f $key) ) ) 1681 | { 1682 | if( $lines ){ 1683 | $lines | Set-Content -Path $Path 1684 | } 1685 | else{ 1686 | Clear-Content -Path $Path 1687 | } 1688 | } 1689 | } 1690 | } 1691 | 1692 | Function Set-LocalPolicyUserRightsAssignment{ 1693 | <# 1694 | https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/secedit-export 1695 | https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/user-rights-assignment 1696 | 1697 | #> 1698 | [CmdletBinding()] 1699 | Param ( 1700 | [Parameter(Mandatory=$true,Position=0)] 1701 | [ValidateSet('SeAssignPrimaryTokenPrivilege', 1702 | 'SeAuditPrivilege', 1703 | 'SeBackupPrivilege', 1704 | 'SeBatchLogonRight', 1705 | 'SeChangeNotifyPrivilege', 1706 | 'SeCreateGlobalPrivilege', 1707 | 'SeCreatePagefilePrivilege', 1708 | 'SeCreatePermanentPrivilege', 1709 | 'SeCreateSymbolicLinkPrivilege', 1710 | 'SeCreateTokenPrivilege', 1711 | 'SeDebugPrivilege', 1712 | 'SeDelegateSessionUserImpersonatePrivilege', 1713 | 'SeDenyBatchLogonRight', 1714 | 'SeDenyInteractiveLogonRight', 1715 | 'SeDenyNetworkLogonRight', 1716 | 'SeDenyRemoteInteractiveLogonRight', 1717 | 'SeDenyServiceLogonRight', 1718 | 'SeEnableDelegationPrivilege', 1719 | 'SeImpersonatePrivilege', 1720 | 'SeIncreaseBasePriorityPrivilege', 1721 | 'SeIncreaseQuotaPrivilege', 1722 | 'SeIncreaseWorkingSetPrivilege', 1723 | 'SeInteractiveLogonRight', 1724 | 'SeLoadDriverPrivilege', 1725 | 'SeLockMemoryPrivilege', 1726 | 'SeMachineAccountPrivilege', 1727 | 'SeManageVolumePrivilege', 1728 | 'SeNetworkLogonRight', 1729 | 'SeProfileSingleProcessPrivilege', 1730 | 'SeRelabelPrivilege', 1731 | 'SeRemoteInteractiveLogonRight', 1732 | 'SeRemoteShutdownPrivilege', 1733 | 'SeRestorePrivilege', 1734 | 'SeSecurityPrivilege', 1735 | 'SeServiceLogonRight', 1736 | 'SeShutdownPrivilege', 1737 | 'SeSyncAgentPrivilege', 1738 | 'SeSystemEnvironmentPrivilege', 1739 | 'SeSystemProfilePrivilege', 1740 | 'SeSystemtimePrivilege', 1741 | 'SeTakeOwnershipPrivilege', 1742 | 'SeTcbPrivilege', 1743 | 'SeTimeZonePrivilege', 1744 | 'SeTrustedCredManAccessPrivilege', 1745 | 'SeUndockPrivilege' 1746 | )] 1747 | [array]$Privilege, 1748 | 1749 | [Parameter(Mandatory=$true,Position=1)] 1750 | [array]$User, 1751 | 1752 | 1753 | 1754 | [Parameter(Mandatory=$false)] 1755 | [ValidateScript({Test-path $_ -PathType Leaf})] 1756 | $LGPOBinaryPath = "$env:ALLUSERSPROFILE\LGPO\LGPO.exe" 1757 | ) 1758 | Begin 1759 | { 1760 | ## Get the name of this function 1761 | [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name 1762 | 1763 | if (-not $PSBoundParameters.ContainsKey('Verbose')) { 1764 | $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') 1765 | } 1766 | 1767 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 1768 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 1769 | } 1770 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 1771 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 1772 | } 1773 | If(!(Test-Path $InfPath)){ 1774 | Write-Log -Message "[$InfPath] not specified or does not exist. Unable to build LGPO Template." -CustomComponent "Template" -ColorLevel 6 -NewLine -HostMsg 1775 | exit -1 1776 | }Else{ 1777 | #build array with content 1778 | $GptTmplContent = Split-IniContent -Path $InfPath 1779 | } 1780 | 1781 | #First export security policy 1782 | Try{ 1783 | $result = Start-Process secedit -ArgumentList "/export /cfg `"$env:Temp\secedit.backup.inf`"" -RedirectStandardError "$env:Temp\secedit.backup.stderr" -RedirectStandardOutput "$env:Temp\secedit.backup.stdout" -Wait -WindowStyle Hidden -PassThru -ErrorAction Stop 1784 | Write-Verbose ("{0} : Secedit backup ran successfully." -f ${CmdletName}) 1785 | } 1786 | Catch{ 1787 | Throw ("Failed to backup security settings. {0}" -f $result.ExitCode) 1788 | } 1789 | Finally{ 1790 | $CurrentSecurityPolicy = Get-content "$env:Temp\secedit.backup.inf" 1791 | } 1792 | } 1793 | 1794 | Process 1795 | { 1796 | <# SAMPLE TESTS 1797 | [array]$User = '*S-1-1-0','*S-1-5-20','*S-1-5-32-544','*S-1-5-32-545','*S-1-5-32-551' 1798 | [array]$User = 'S-1-1-1','S-1-5-20' 1799 | [array]$User = 'Everyone','NT AUTHORITY\NETWORK SERVICE' 1800 | $name = $User[0] 1801 | $name = $User[-1] 1802 | #> 1803 | $SIDSet = @() 1804 | Foreach($name in $User) 1805 | { 1806 | if ($name -match 'S-\d-(?:\d+-){1,14}\d+'){ 1807 | $SID = $name.replace('*','') 1808 | #Translate SID to User; if it doesn't translate don't add to 1809 | $objSID = New-Object System.Security.Principal.SecurityIdentifier($SID) 1810 | Try{ 1811 | $UserName = ($objSID.Translate([System.Security.Principal.NTAccount])).Value 1812 | Write-Verbose ("{0} : Translated user [{1}] to User [{2}]." -f ${CmdletName},$SID,$UserName) 1813 | } 1814 | Catch{ 1815 | Write-Verbose ("{0} : Error with SID [{1}]. {2}" -f ${CmdletName},$SID,$_.Exception.Message) 1816 | Continue 1817 | } 1818 | } 1819 | else{ 1820 | $UserName = $User 1821 | #Translate User to SID 1822 | Try{ 1823 | $SID = ((New-Object System.Security.Principal.NTAccount($name)).Translate([System.Security.Principal.SecurityIdentifier])).Value 1824 | Write-Verbose ("{0} : Translated user [{1}] to SID [{2}]." -f ${CmdletName},$UserName,$SID) 1825 | } 1826 | Catch{ 1827 | Write-Verbose ("{0} : Unable to get SID from [{1}]. {2}" -f ${CmdletName},$UserName,$_.Exception.Message) 1828 | Continue 1829 | } 1830 | } 1831 | $SID = '*' + $SID 1832 | $SIDSet += $SID 1833 | } 1834 | $NewUsers = $SIDSet -join ',' 1835 | 1836 | <# SAMPLE TESTS 1837 | [array]$Privilege = 'SeNetworkLogonRight','SeBackupPrivilege' 1838 | 1839 | $Right = $Privilege[0] 1840 | #> 1841 | #$MatchPrivilege = $Privilege -join '|' 1842 | 1843 | Foreach($Right in $Privilege) 1844 | { 1845 | $NewRights = $Right + " = " + $NewUsers 1846 | If($ExistingRights = ($CurrentSecurityPolicy | Select-String -Pattern $Right).Line) 1847 | { 1848 | $RightsToReplace = $ExistingRights 1849 | $CurrentSecurityPolicy = $CurrentSecurityPolicy.replace($RightsToReplace,$NewRights) 1850 | } 1851 | Else{ 1852 | 1853 | } 1854 | 1855 | 1856 | } 1857 | $CurrentSecurityPolicy | Set-Content "$env:Temp\secedit.updated.inf" 1858 | 1859 | <# 1860 | #generate start of file 1861 | $secedit = "[Unicode]`r`n" 1862 | $secedit += "Unicode=yes`r`n" 1863 | $secedit += "[Version]`r`n" 1864 | $secedit += "signature=`"`$CHICAGO`$`"`r`n" 1865 | $secedit += "Revision=1`r`n" 1866 | #> 1867 | 1868 | 1869 | 1870 | #get system access section 1871 | If (($GptTmplContent.Section -eq 'System Access').count -gt 0){ 1872 | Write-host "'System Access' section found in [$InfPath], building list...." -ForegroundColor Cyan 1873 | $secedit += "[System Access]`r`n" 1874 | 1875 | $AccessValueList = $GptTmplContent | Where-Object {$_.section -eq 'System Access'} 1876 | Foreach ($AccessKey in $AccessValueList){ 1877 | $AccessName = $AccessKey.Name 1878 | $AccessValue = $AccessKey.Value 1879 | If ($AccessName -eq "NewAdministratorName"){ 1880 | $AccessValue = $AccessValue -replace $AccessKey.Value, "$Global:NewAdministratorName" 1881 | } 1882 | If ($AccessName -eq "NewGuestName"){ 1883 | $AccessValue = $AccessValue -replace $AccessKey.Value, "$Global:NewGuestName" 1884 | } 1885 | $secedit += "$AccessName = $AccessValue`r`n" 1886 | #$secedit += "$PrivilegeValue" 1887 | } 1888 | } 1889 | Else{ 1890 | Write-host "'System Access' section was not found in [$InfPath], skipping..." -ForegroundColor Gray 1891 | } 1892 | 1893 | #next get Privilege Rights section 1894 | If (($GptTmplContent.Section -eq 'Privilege Rights').count -gt 0){ 1895 | Write-host "'Privilege Rights' section found in [$InfPath], building list...." -ForegroundColor Cyan 1896 | $secedit += "[Privilege Rights]`r`n" 1897 | 1898 | $PrivilegeValueList = $GptTmplContent | Where-Object {$_.section -eq 'Privilege Rights'} 1899 | Foreach ($PrivilegeKey in $PrivilegeValueList){ 1900 | $PrivilegeName = $PrivilegeKey.Name 1901 | $PrivilegeValue = $PrivilegeKey.Value 1902 | 1903 | If ($PrivilegeValue -match "ADD YOUR ENTERPRISE ADMINS|ADD YOUR DOMAIN ADMINS|S-1-5-21"){ 1904 | 1905 | If($IsMachinePartOfDomain){ 1906 | $EA_SID = Get-UserToSid -Domain $envMachineDNSDomain -User "Enterprise Admins" 1907 | $DA_SID = Get-UserToSid -Domain $envMachineDNSDomain -User "Domain Admins" 1908 | $PrivilegeValue = $PrivilegeValue -replace "ADD YOUR ENTERPRISE ADMINS",$EA_SID 1909 | $PrivilegeValue = $PrivilegeValue -replace "ADD YOUR DOMAIN ADMINS",$DA_SID 1910 | } 1911 | Else{ 1912 | $ADMIN_SID = Get-UserToSid -LocalAccount 'Administrators' 1913 | $PrivilegeValue = $PrivilegeValue -replace "ADD YOUR ENTERPRISE ADMINS",$ADMIN_SID 1914 | $PrivilegeValue = $PrivilegeValue -replace "ADD YOUR DOMAIN ADMINS",$ADMIN_SID 1915 | $PrivilegeValue = $PrivilegeValue -replace "S-1-5-21-[0-9-]+",$ADMIN_SID 1916 | } 1917 | } 1918 | #split up values, get only unique values and make it a comma deliminated list again 1919 | $temp = $PrivilegeValue -split "," 1920 | $PrivilegeValue = $($temp | Get-Unique) -join "," 1921 | 1922 | 1923 | $secedit += "$PrivilegeName = $PrivilegeValue`r`n" 1924 | #$secedit += "$PrivilegeValue" 1925 | 1926 | #Write-Log -Message "RUNNING COMMAND: SECEDIT /configure /db secedit.sdb /cfg '$workingTempPath\$($GPO.name).seceditapply.inf' /overwrite /log '$workingLogPath\$($GPO.name).seceditapply.log' /quiet" -CustomComponent "COMMAND" -ColorLevel 8 -NewLine None -HostMsg 1927 | #Start-Process SECEDIT -ArgumentList " /configure /db secedit.sdb /cfg ""$workingTempPath\$($GPO.name).seceditapply.inf"" /overwrite /quiet" -RedirectStandardOutput "$workingLogPath\$($GPO.name).secedit.stdout.log" -RedirectStandardError "$workingLogPath\$($GPO.name).secedit.stderr.log" -Wait -NoNewWindow 1928 | #$SeceditApplyResults = ECHO y| SECEDIT /configure /db secedit.sdb /cfg "$workingTempPath\$($GPO.name).seceditapply.inf" /overwrite /log "$workingLogPath\$($GPO.name).seceditapply.log" 1929 | } 1930 | } 1931 | Else{ 1932 | Write-host "'Privilege Rights' was not found in [$InfPath], skipping..." -ForegroundColor Gray 1933 | } 1934 | 1935 | 1936 | } 1937 | End { 1938 | If($secedit){ 1939 | $secedit | Out-File "$env:Temp\$OutputName" -Force 1940 | Write-host "Saved file to [$env:Temp\$OutputName]" -ForegroundColor Gray 1941 | } 1942 | } 1943 | } 1944 | 1945 | 1946 | 1947 | 1948 | $exportModuleMemberParams = @{ 1949 | Function = @( 1950 | 'Get-LocalPolicySystemSettings', 1951 | 'Set-LocalPolicySetting', 1952 | 'Update-LocalPolicySettings', 1953 | 'Remove-LocalPolicySetting', 1954 | 'Get-LocalPolicyUserSettings', 1955 | 'Set-LocalPolicyUserSetting', 1956 | 'Remove-LocalPolicyUserSetting', 1957 | 'Clear-LocalPolicySettings' 1958 | ) 1959 | } 1960 | 1961 | Export-ModuleMember @exportModuleMemberParams 1962 | --------------------------------------------------------------------------------