Created
July 15, 2020 14:17
-
-
Save rajbos/49f70f4e2b9765da05f0526225de2450 to your computer and use it in GitHub Desktop.
Register Windows Startup/Shutdown script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function Register-EventScript { | |
| param ( | |
| [string] $eventToRegister, # Either Startup or Shutdown | |
| [string] $pathToScript, | |
| [string] $scriptParameters | |
| ) | |
| $path = "$ENV:systemRoot\System32\GroupPolicy\Machine\Scripts\$eventToRegister" | |
| if (-not (Test-Path $path)) { | |
| # path HAS to be available for this to work | |
| New-Item -path $path -itemType Directory | |
| } | |
| # Add script to Group Policy through the Registry | |
| "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\$eventToRegister\0\0", | |
| "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\$eventToRegister\0\0" | | |
| ForEach-Object { | |
| if (-not (Test-Path $_)) { | |
| New-Item -path $_ -force | |
| } | |
| } | |
| "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\$eventToRegister\0", | |
| "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\$eventToRegister\0" | | |
| ForEach-Object { | |
| New-ItemProperty -path "$_" -name DisplayName -propertyType String -value "Local Group Policy" -force | |
| New-ItemProperty -path "$_" -name FileSysPath -propertyType String -value "$ENV:systemRoot\System32\GroupPolicy\Machine" -force | |
| New-ItemProperty -path "$_" -name GPO-ID -propertyType String -value "LocalGPO" -force | |
| New-ItemProperty -path "$_" -name GPOName -propertyType String -value "Local Group Policy" -force | |
| New-ItemProperty -path "$_" -name PSScriptOrder -propertyType DWord -value 2 -force | |
| New-ItemProperty -path "$_" -name SOM-ID -propertyType String -value "Local" -force | |
| } | |
| "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\$eventToRegister\0\0", | |
| "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\$eventToRegister\0\0" | | |
| ForEach-Object { | |
| New-ItemProperty -path "$_" -name Script -propertyType String -value $pathToScript -force | |
| New-ItemProperty -path "$_" -name Parameters -propertyType String -value $scriptParameters -force | |
| New-ItemProperty -path "$_" -name IsPowershell -propertyType DWord -value 1 -force | |
| New-ItemProperty -path "$_" -name ExecTime -propertyType QWord -value 0 -force | |
| } | |
| } | |
| # get crrentlocation so we can form the full path to the script to register | |
| $currentLocation = $PSScriptRoot | |
| # register the script twice | |
| Register-EventScript -eventToRegister "Startup" -pathToScript "$currentLocation\ScriptToRun.ps1" -scriptParameters "OnStartup" | |
| Register-EventScript -eventToRegister "Shutdown" -pathToScript "$currentLocation\ScriptToRun.ps1" -scriptParameters "OnShutdown" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| param ( | |
| [string] $message | |
| ) | |
| function Run-Script { | |
| param ( | |
| [string] $message | |
| ) | |
| # get the date in our format | |
| $date = Get-Date | |
| Get-date $date -f "yyyyMMdd HH:mm:ss" | |
| # log the date/time and the message | |
| "$($date.ToUniversalTime().ToString("yyyyMMdd HH:mm:ss")) - $message" >> "C:\Temp\Log.txt" | |
| } | |
| # call the script with the incoming parameter | |
| Run-Script -message $message |
Also Works on Windows 11 24H2.
Is posible to check if previously exists other ID and increment without removing previous one?
Here is my bit. It do it incremental
function Register-EventScript {
param (
[string] $eventToRegister, # Either Startup or Shutdown
[string] $pathToScript,
[string] $scriptParameters
)
$path = "$ENV:systemRoot\System32\GroupPolicy\Machine\Scripts\$eventToRegister"
if (-not (Test-Path $path)) {
# Path must exist for this to work
New-Item -Path $path -ItemType Directory -Force
}
# Define base registry paths
$baseRegPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\$eventToRegister",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\$eventToRegister"
)
# Find the next available index for the script
$index = 0
foreach ($basePath in $baseRegPaths) {
$existingKeys = Get-ChildItem -Path $basePath -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^\d+$' } | Select-Object -ExpandProperty PSChildName
if ($existingKeys) {
$maxIndex = ($existingKeys | ForEach-Object { [int]$_ } | Measure-Object -Maximum).Maximum
$index = [math]::Max($index, $maxIndex + 1)
}
}
# Create registry paths with the new index
$regPaths = $baseRegPaths | ForEach-Object { "$_\$index" }
$scriptRegPaths = $baseRegPaths | ForEach-Object { "$_\$index\0" }
# Create registry keys for the new index
foreach ($regPath in $regPaths) {
if (-not (Test-Path $regPath)) {
New-Item -Path $regPath -Force
}
# Set properties for the parent key
New-ItemProperty -Path $regPath -Name DisplayName -PropertyType String -Value "Local Group Policy" -Force
New-ItemProperty -Path $regPath -Name FileSysPath -PropertyType String -Value "$ENV:systemRoot\System32\GroupPolicy\Machine" -Force
New-ItemProperty -Path $regPath -Name GPO-ID -PropertyType String -Value "LocalGPO" -Force
New-ItemProperty -Path $regPath -Name GPOName -PropertyType String -Value "Local Group Policy" -Force
New-ItemProperty -Path $regPath -Name PSScriptOrder -PropertyType DWord -Value 2 -Force
New-ItemProperty -Path $regPath -Name SOM-ID -PropertyType String -Value "Local" -Force
}
# Create subkeys and set properties for the script
foreach ($scriptRegPath in $scriptRegPaths) {
if (-not (Test-Path $scriptRegPath)) {
New-Item -Path $scriptRegPath -Force
}
New-ItemProperty -Path $scriptRegPath -Name Script -PropertyType String -Value $pathToScript -Force
New-ItemProperty -Path $scriptRegPath -Name Parameters -PropertyType String -Value $scriptParameters -Force
New-ItemProperty -Path $scriptRegPath -Name IsPowershell -PropertyType DWord -Value 1 -Force
New-ItemProperty -Path $scriptRegPath -Name ExecTime -PropertyType QWord -Value 0 -Force
}
}
# get crrentlocation so we can form the full path to the script to register
$currentLocation = $PSScriptRoot
Register-EventScript -eventToRegister "Startup" -pathToScript "$currentLocation\ScriptToRun.ps1" -scriptParameters "Startup"
Register-EventScript -eventToRegister "Shutdown" -pathToScript "$currentLocation\ScriptToRun.ps1" -scriptParameters "Shutdown"
And this is for unregister:
function Unregister-EventScript {
param (
[string] $eventToUnregister # Either Startup or Shutdown
)
# Base registry paths where scripts are registered
$baseRegPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\${eventToUnregister}",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\${eventToUnregister}"
)
# Collect all registered scripts
$scripts = @()
foreach ($basePath in $baseRegPaths) {
if (Test-Path $basePath) {
Get-ChildItem -Path $basePath -ErrorAction SilentlyContinue | ForEach-Object {
$index = $_.PSChildName
$scriptPath = (Get-ItemProperty -Path "$basePath\$index\0" -ErrorAction SilentlyContinue).Script
$params = (Get-ItemProperty -Path "$basePath\$index\0" -ErrorAction SilentlyContinue).Parameters
if ($scriptPath) {
$scripts += [PSCustomObject]@{
Event = $eventToUnregister
Index = $index
ScriptPath = $scriptPath
Parameters = $params
RegBase = $basePath
}
}
}
}
}
if (-not $scripts) {
Write-Host "No scripts found for ${eventToUnregister}"
return
}
# Show scripts and ask the user which ones to remove
Write-Host "`nScripts found for event ${eventToUnregister}:`n"
$i = 0
$scripts | ForEach-Object {
Write-Host "[$i] $($_.ScriptPath) $($_.Parameters)"
$i++
}
$selection = Read-Host "Enter the number of the script to remove (comma-separated for multiple, or 'all' for all)"
if ($selection -eq "all") {
$toRemove = $scripts
}
else {
$indexes = $selection -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_ -match '^\d+$' }
$toRemove = $scripts[$indexes]
}
# Remove selected scripts
foreach ($s in $toRemove) {
$regPath = "$($s.RegBase)\$($s.Index)"
if (Test-Path $regPath) {
Remove-Item -Path $regPath -Recurse -Force
Write-Host "Removed: $($s.ScriptPath) [${eventToUnregister}]"
}
}
}
# Example usage:
Unregister-EventScript -eventToUnregister "Startup"
Unregister-EventScript -eventToUnregister "Shutdown"
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Also works on Windows 10, native, 22H2 (10.0.19045.4780).