none
Programmatically (powershell) adding startup/shutdown scripts to a Group Policy

    Question

  • I'm attempting to automate some group policy tasks and am roadblocked now. I am on an active directory domain controller, attempting to create a new group policy and assign startup and showdown scripts to it. My code block below nearly works (I think). I am able to create the group policy, copy ls.ps1 to the startup and shutdown folders inside the group policy, and create the psscripts.ini file.

    When I look at this new GPO in the Group Policy Management editor the settings do not show the proper Computer Configuration. However, if I edit this new gpo, and go to add the powershell scripts through the ui, once I reach the Startup/Shutdown menu for the powershell scripts it sees my ls.ps1 script there and updates the group policy. Without making any changes the settings now show up as expected for the Computer Configuration, ls.ps1 running on startup and shutdown. How do I trigger the gpo to read the psscripts.ini or reload itself programmatically?

    I attempted to update the GPT.ini version to '1'  with the hope gpupdate would then work, but am having no luck even with gpupdate /force.

    $gpo = New-GPO -Name Testgpo
    Start-Sleep -s 5
    $guid = $gpo.id.ToString().ToUpper()
    Write-Host "Group Policy Created: $guid"
    $domain = Get-ADDomain
    $forest = $domain.forest
    
    md "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Shutdown"
    md "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Startup"
    Copy-Item .\ls.ps1 "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Shutdown"
    Copy-Item .\ls.ps1 "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Startup"
    
    $pshellscript = @"
    
    [Startup]
    0CmdLine=ls.ps1
    0Parameters=
    [Shutdown]
    0CmdLine=ls.ps1
    0Parameters=
    "@
    
    $psfilename = "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\psscripts.ini"
    $pshellscript | Out-File $psfilename -Encoding unicode
    $psfile = Get-Item $psfilename -force
    $psfile.attributes="Hidden"
    
    $gptini = @"
    [General]
    Version=1
    displayName=New Group Policy Object
    "@
    
    $gptinifilename = "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\GPT.ini"
    $gptini | Out-File $gptinifilename -Encoding utf8

    Any suggestions appreciated.

    Wednesday, February 01, 2017 6:57 PM

Answers

  • > This is where I am stuck, creating the psscripts.ini file without using the gui doesn't seem to register somewhere. When looking at the newly created GPO it says it does no Computer Configuration(in the Settings tab when looking at a GPO from Group Policy Management). If you then edit the GPO, and go to the startup/shutdown scripts it then seems to realise at this point it already has this psscripts.ini file, and populates the list with the ls.ps1 files for each respectively. I can then exit out without making changes and the Computer Configuration is now set up as expected to run the scripts.
     
    You need to modify the groupPolicyContainer object in AD - add the scripts CSE and Snapin Extension GUID to its gPCMachineExtensionNames attribute :-)
    And don't forget the version attribute and the gpt.ini file in sysvol - if both are 0, your GPO will always be considered empty.
     
    Monday, February 06, 2017 2:39 PM

All replies

  • Hi Dedeck,

    >>How do I trigger the gpo to read the psscripts.ini or reload itself programmatically?

    First thing I want to confirm is that: startup/shutdown script should stores in this location: C:\windows\System32\GroupPolicy\Machine\Scripts\Startup <just click the show files button under startup/shutdown menu>

    Second thing is : if you wanted to reload your script, there are two ways to achieve this purpose: 1> add parameter in "Script Parameters" option; 2> using something like this:

    do{
     $I=0
     #your scripts
     $I+=1
    }while($I -lt 2)

    Besides, I want to know your detailed needs so I probably could help you in another way.

    Best regards,

    Andy


    Please remember to mark the replies as answers if they help.
    If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    Friday, February 03, 2017 1:51 AM
    Moderator
  • Sorry if I was unclear here. I am running this script and creating a GPO on a domain controller, not a local GPO. So the GPO gets created in SYSVOL, there are no files in C:\windows\System32\GroupPolicy\Machine\Scripts\Startup .

    My detailed needs are: Create a Group Policy for an OU in my domain that runs a startup and shutdown script for the computers in that OU. WITHOUT using the gui, everything should be done programmatically.

    So in the script above:

    1. I create a new GPO

    2. I copy the startup/shutdown scripts(ls.ps1 in both cases here) to the new folders for the new GPO just created: "C:\Windows\SYSVOL\sysvol\my.domain\Policies\{EXAMPLE-GROUP-POLICY-GUID}\Machine\Scripts\Startup"

    3. I manually create psscripts.ini in the Machine/Scripts folder, and setup the copied scripts as the ones to be executed. (When doing all this through the gui this file gets created when you add scripts to startup/shutdown, so I am trying to mimic that action)

    This is where I am stuck, creating the psscripts.ini file without using the gui doesn't seem to register somewhere. When looking at the newly created GPO it says it does no Computer Configuration(in the Settings tab when looking at a GPO from Group Policy Management). If you then edit the GPO, and go to the startup/shutdown scripts it then seems to realise at this point it already has this psscripts.ini file, and populates the list with the ls.ps1 files for each respectively. I can then exit out without making changes and the Computer Configuration is now set up as expected to run the scripts.

    I then linked the GPO to a OU and it worked as expected running the scripts on the computers in the OU. I'm just missing 1 part so I don't need to manually use the gui for any of this.

    Friday, February 03, 2017 8:33 PM
  • > This is where I am stuck, creating the psscripts.ini file without using the gui doesn't seem to register somewhere. When looking at the newly created GPO it says it does no Computer Configuration(in the Settings tab when looking at a GPO from Group Policy Management). If you then edit the GPO, and go to the startup/shutdown scripts it then seems to realise at this point it already has this psscripts.ini file, and populates the list with the ls.ps1 files for each respectively. I can then exit out without making changes and the Computer Configuration is now set up as expected to run the scripts.
     
    You need to modify the groupPolicyContainer object in AD - add the scripts CSE and Snapin Extension GUID to its gPCMachineExtensionNames attribute :-)
    And don't forget the version attribute and the gpt.ini file in sysvol - if both are 0, your GPO will always be considered empty.
     
    Monday, February 06, 2017 2:39 PM
  • So the information provided by Martin has proven to be successful. Here is the updated working script if anyone stumbles across this in the future. It creates a new GPO on a domain controller, moves two ps1 scripts from the directory where you run this script into the GPO, and sets them to be executed on computer shutdown/startup: 

    $gpo = New-GPO -Name TestGPO -Comment "Test GPO"
    Start-Sleep -s 5
    $guid = $gpo.id.ToString().ToUpper()
    Write-Host "Group Policy Created: $guid"
    $domain = Get-ADDomain
    $forest = $domain.forest
    
    md "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Shutdown"
    md "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Startup"
    Copy-Item .\script_shutdown.ps1 "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Shutdown"
    Copy-Item .\script_startup.ps1 "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Startup"
    
    $pshellscript = @"
    
    [Startup]
    0CmdLine=script_startup.ps1
    0Parameters=
    [Shutdown]
    0CmdLine=script_shutdown.ps1
    0Parameters=
    "@
    
    $psfilename = "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\psscripts.ini"
    $pshellscript | Out-File $psfilename -Encoding unicode
    $psfile = Get-Item $psfilename -force
    $psfile.attributes="Hidden"
    
    $gptini = @"
    [General]
    Version=2
    displayName=New Group Policy Object
    "@
    
    $gptinifilename = "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\GPT.ini"
    $gptini | Out-File $gptinifilename -Encoding utf8
    
    # I don't know how this works
    # I copied these values from the GPO that was manually created and working
    $gPCMachineExtensionNames = "[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}]"
    
    
    $adgpo = ([adsisearcher]"(&(objectCategory=groupPolicyContainer)(name={$guid}))").FindAll().Item(0)
    $gpoentry = $adgpo.GetDirectoryEntry()
    $gpoentry.Properties["gPCMachineExtensionNames"].Value = $gPCMachineExtensionNames
    $gpoentry.Properties["versionNumber"].Value = "2"
    $gpoentry.CommitChanges()

    I was able to successfully execute the scripts on a workstation once linking the GPO to an OU. I have some final questions if anyone has knowledge:

    1. I'm still unclear about the gPCMachineExtensionNames values, I obtained them by creating the GPO manually and then copying them, was there a proper way to get these? Are they just values telling the client to execute with powershell?

    2. In my GPO details I have the following after creation:

    This doesn't seem to cause problems, but it is inaccurate. If I do the process I described in my earlier questions where I edit the GPO and simply view the startup script settings, this changes to '3(AD), 3(SYSVOL)' as expected. Is there a way to tell the GPO programmatic ally to reload SYSVOL? This isn't a showstopper but I figured I'd inquire.

    Thanks everyone for your help


    • Edited by Dedeck Monday, February 13, 2017 4:04 PM formatting
    Monday, February 13, 2017 3:59 PM
  • > # I don't know how this works
    > # I copied these values from the GPO that was manually created and working
    > $gPCMachineExtensionNames = "[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}]"
     
     
    German posts, but in short: The second GUID is a MMC snapin extension (to edit the setting in GPEdit), the first ist a client side extension (to process the setting on a client computer).
     
    In some rare cases there are more GUIDs involved :)
     
    Each "section" in GPedit that provides a different UI can be assumed to have its own pair of GUIDs. The safest way to grab the right values is exactly what you did: Edit an existing GPO and grab the resulting values.
     
    > In my GPO details I have the following after creation:
     
    Should vanish on its own after Sysvol replication is finished. GPMC by default connects to the PDC emulator, but creating files on Sysvol picks a rather random DC :)
     
     
    Monday, February 13, 2017 4:31 PM
  • > md "C:\Windows\SYSVOL\sysvol\$forest\Policies\{$guid}\Machine\Scripts\Shutdown"
     
    Recommendation: I would not use a local path, but rather \\$forest\sysvol\$forest
    This removes the dependency on the local path selected during DCPromo.
     
    Monday, February 13, 2017 4:33 PM