Featured image of post Using PowerShell to generate and deploy Group Policies for non-domain environments

Using PowerShell to generate and deploy Group Policies for non-domain environments

So I’ve been having a hard time coming up with a title for this one. As I’ve stated in previous blogs we’re moving more and more clients to cloud only environments using Azure AD, Teams, and Onedrive as their collaboration and file sharing solution. The issue with this was that it became quite difficult to deploy GPOs. This was especially bad when wanting to use ADMX templates. We could use Intune but found that even there we had so many limitation it would not work for us.

Full disclosure; There are some third party applications that offer GPO deployment. We found most of them to be overkill for what we needed, or not very suitable for the MSP market. I mean – We already have our RMM system, and tacking on another application just did not seem right to me.

So to solve the issues with GPO deployment for Azure AD environments, or workgroup environments I’ve created a PowerShell script that allows you to deploy group policies. I’ve also created a script to monitor if the deployment ran correctly. That way you can use your RMM to see who received the new policy and who has not.

Execution Script

Before we get started on the script, you will need the following two items: LGPO.exe, which we’ll use to export and deploy the policy, and winrar which will create our setup file. We download the LGPO.exe for you (Please host this somewhere you trust.). Winrar you’ll need to install yourself.

Disclaimer/warning: Please note that the script is destructive to the currently installed local group policies. Please run the script inside of a VM or machine that does not have any local policies. It will clear all policies by destroying the actual policy files. You have been warned 🙂

So the steps are straightforward – Save the script and execute it with the parameters you need. The script will delete the current GPOs, and then open the group policy editor. Import your ADMX files, edit the settings, and close the editor. Then the script will finish up and put 2 files on your desktop – One to apply the policy, the other to remove the policy in case you no longer need it.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
<#
.SYNOPSIS
  Creates an execuble that can apply and remove a local Group Policy Object
.DESCRIPTION
 Creates an execuble that can apply and remove a specific local policy. The executable is a self-extracting winrar archive. Winrar installation is required for processing.
 The execuble will work in "MERGE" mode, meaning that settings that are duplicate will be overwritten, other settings will not be touched.

Parameters are not required, but optional. Script will fail if LGPO and Winrar are not present.

WARNING: SCRIPT IS DESTRUCTIVE TO LOCAL GROUP POLICIES. DO NOT RUN ON PRODUCTION MACHINES. Use at own risk.
.PARAMETER DownloadURL
Specificies where to download LGPO from if not installed.
.PARAMETER DownloadLocation
Specificies where to download LGPO to if not installed. Defaults to C:\Temp\LGPO
.PARAMETER WorkingPath
Specificies where to put temporary files. Defaults to C:\Temp\LGPO
.PARAMETER WinrarPath
Path where winrar is found. Defaults to C:\Program Files\WinRAR\WinRAR.exe
.PARAMETER GPOName
Decides part of the name of the file that will be placed in C:\ProgramData\
.PARAMETER GPOVersion
Decides part of the name of the file that will be placed in C:\ProgramData\
.INPUTS
none
.OUTPUTS
executable generated and stored in user desktop location
.NOTES
Version: 0.4
Author: Kelvin Tegelaar
Creation Date: 02/2020
Purpose/Change: Initial script. Beta.

#>
Param(
[string]$DownloadURL = "http://cyberdrain.com/wp-content/uploads/2020/02/LGPO.exe",
    [string]$DownloadLocation = "C:\Temp\LGPO",
[string]$WinrarPath = "C:\Program Files\WinRAR\WinRAR.exe",
    [string]$GPOName = "GPO",
[string]$GPOVersion = "1.0"
)

write-host "Checking if base folder exists in $DownloadLocation and if not, creating it." -ForegroundColor Green
try {
    $TestDownloadLocation = Test-Path $DownloadLocation
    if (!$TestDownloadLocation) {
write-host "Creating Folder to download LGPO." -ForegroundColor Green
new-item $DownloadLocation -ItemType Directory -force
    }
    $TestDownloadLocationExe = Test-Path "$DownloadLocation\LGPO.exe"
if (!$TestDownloadLocationExe) {
        write-host "Download LGPO." -ForegroundColor Green
        Invoke-WebRequest -UseBasicParsing -Uri $DownloadURL -OutFile "$DownloadLocation\LGPO.exe"
}
$TestDownloadLocationBat = Test-Path "$DownloadLocation\LGPOExecute.bat"
if (!$TestDownloadLocationBat) {
write-host "Generating configuration batch file." -ForegroundColor Green

        @"

LGPO.exe /t ComputerPolicy.txt /v > "C:\ProgramData\$GPOName $GPOVersion Computer.log"
LGPO.exe /t UserPolicy.txt /v > "C:\ProgramData\$GPOName $GPOVersion User.log"
"@ | Out-File -Encoding ascii "$DownloadLocation\LGPOExecute.bat" -Force

    }

}
catch {
write-host "The download and extraction of LGPO.EXE failed. Error: $($\_.Exception.Message)" -ForegroundColor Red
exit 1
}
write-host "Clearing all existing policies." -ForegroundColor Green
#Clears all local policies
remove-item -Recurse -Path "$($ENV:windir)\System32\GroupPolicyUsers" -Force -erroraction silentlycontinue
remove-item -Recurse -Path "$($ENV:windir)\System32\GroupPolicy" -Force -erroraction silentlycontinue
remove-item -Recurse -Path "$DownloadLocation\ComputerPolicy.txt" -Force -erroraction silentlycontinue
remove-item -Recurse -Path "$DownloadLocation\Userpolicy.txt" -Force -erroraction silentlycontinue
write-host "Running GPUpdate to clear local policy cache." -ForegroundColor Green
gpupdate /force
write-host "Starting GPEdit. Please create your policy. After closing GPEdit we will resume." -ForegroundColor Green
start-process "gpedit.msc" -Wait
write-host "Exporting policies with LGPO." -ForegroundColor Green
& "$DownloadLocation\LGPO.EXE" /parse /m "$($ENV:windir)\System32\GroupPolicy\Machine\Registry.pol" > $DownloadLocation\ComputerPolicy.txt
& "$DownloadLocation\LGPO.EXE" /parse /u "$($ENV:windir)\System32\GroupPolicy\User\Registry.pol" > $DownloadLocation\Userpolicy.txt
write-host "Sleeping for 10 seconds to give LGPO a chance to export all settings if GPO is large." -ForegroundColor Green
start-sleep 10
$UserDesktop = [Environment]::GetFolderPath("Desktop")
@"
Setup=LGPOExecute.bat
TempMode
Silent=1
"@ | out-file "$DownloadLocation\SFXConfig.conf" -Force

write-host "Creating Apply executable and placing on current user desktop." -ForegroundColor Green
& $WinrarPath -s a -ep1 -r -o+ -dh -ibck -sfx  -iadm -z"C:\temp\LGPO\SFXConfig.conf" "$UserDesktop\$GPOName $GPOVersion Apply Policy.exe" "$DownloadLocation\*"
start-sleep 3

write-host "Creating Remove executable and placing on current user desktop." -ForegroundColor Green
$ComputerPolicy = get-content "$DownloadLocation\ComputerPolicy.txt"
$UserPolicy = get-content "$DownloadLocation\UserPolicy.txt"
$ReplacementArray = @("DELETEKEYS", "DELETE", "QWORD", "SZ", "EXSZ", "MULTISZ", "BINARY", "CREATEKEY", "DELETEALLVALUES", "DWORD")
foreach ($Replacement in $ReplacementArray) {
    $ComputerPolicy = $ComputerPolicy | Foreach-Object { $_ -replace "^.*$replacement._$", "CLEAR" }
$UserPolicy = $UserPolicy | Foreach-Object { $\_ -replace "^._$replacement.*$", "CLEAR" }
}
$UserPolicy | out-file "$DownloadLocation\Userpolicy.txt"
$ComputerPolicy | out-file "$DownloadLocation\ComputerPolicy.txt"

& $winrarPath -s a -ep1 -r -o+ -dh -ibck -sfx  -iadm -z"C:\temp\LGPO\SFXConfig.conf" "$UserDesktop\$GPOName $GPOVersion Remove Policy.exe" "$DownloadLocation\*"
remove-item -Recurse -Path "$DownloadLocation\LGPOExecute.bat" -Force -erroraction silentlycontinue

Deploy the files on your desktop as-if its an application via your RMM.

Monitoring the deployment

So you can run the executable and when it runs it will create 2 log files in C:\ProgramData, one for User policies, the other for Computer policies. To monitor these, you check if the file exists and if it contains “Policy saved” in the last 3 lines.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$GPOFile = "C:\ProgramData\GPO 1.0 User.log"

$Check = Test-Path "C:\ProgramData\GPO 1.0 User.log"
if (!$Check) {
    $Healthstate = "GPO has not deployed. Log file does not exist."
}
else {
    $State = get-content $GPOFile | Select-Object -last 3
    if ($state[0] -ne "POLICY SAVED.") { $Healthstate = "GPO Log found but policy not saved." } else { $Healthstate = "Healthy" }
}

And that’s it! With this you’ll be able to deploy GPOs as if you still have your local AD domain, something we really missed in our cloud only deployments. As always, Happy PowerShelling.

All blogs are posted under AGPL3.0 unless stated otherwise
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy