{"id":2282,"date":"2014-01-05T00:01:00","date_gmt":"2014-01-05T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2014\/01\/05\/use-powershell-to-import-group-policy-objects\/"},"modified":"2014-01-05T00:01:00","modified_gmt":"2014-01-05T00:01:00","slug":"use-powershell-to-import-group-policy-objects","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-import-group-policy-objects\/","title":{"rendered":"Use PowerShell to Import Group Policy Objects"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft PFE, Ian Farr talks about using Windows PowerShell to import Group Policy Objects.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Yesterday, guest blogger, Ian Farr talked about backing up Group Policy Objects&nbsp; (GPOs) in his post <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/using-powershell-to-back-up-group-policy-objects\/\" target=\"_blank\">Using PowerShell to Back Up Group Policy Objects<\/a>. He continues his GPO series today&hellip;<\/p>\n<h2>The challenge<\/h2>\n<p>Welcome back! Part 1 looked at my script, <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Comprehensive-Group-Policy-5f9d3ea6\">Comprehensive Group Policy Backup Script<\/a>. Part 2 is about a Group Policy import script. Previously done, you say? True, but I have yet to find a script that mirrors all of the following configuration items to a test domain:<\/p>\n<ul>\n<li>Group Policy settings<\/li>\n<li>Delegation<\/li>\n<li>Security filtering<\/li>\n<li>Scope-of-management (SOM)<\/li>\n<li>Block inheritance<\/li>\n<li>Enforced<\/li>\n<li>Link enabled<\/li>\n<li>Link order<\/li>\n<li>WMI filters<\/li>\n<\/ul>\n<p>Until now. This script can also process a <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/cc739066(v=WS.10).aspx\" target=\"_blank\">Migration Table<\/a>. Let&rsquo;s discuss it&hellip;<\/p>\n<h2>The import<\/h2>\n<p>The import script flow is determined by the backup script&rsquo;s output. What do we have? A folder with the normal <b>Backup-GPO<\/b> cmdlet results. In the same folder, there&rsquo;s an XML file that has the details of any WMI filters from the source domain. The <b>Export-Clixml<\/b> cmdlet created this file. We need to import it with the <b>Import-Clixml<\/b> cmdlet:<\/p>\n<p style=\"margin-left:30px\">$WmiFilters = Import-Clixml -Path $WmiXML<\/p>\n<p><b>$WmiFIlters<\/b> has the configuration information for each WMI filter from the source domain.<\/p>\n<p>We also have another XML file, GpoDetails.xml, with information for reconstructing GPO settings that were not captured by <b>Backup-GPO<\/b>. This is imported too:<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp; $CustomGpoInfo = Import-Clixml -Path $CustomGpoXML<\/p>\n<p>In <b>$CustomGpoInfo<\/b>, there&rsquo;s an object for each backed-up GPO. Each object has the following properties:<\/p>\n<ul>\n<li><b>BackupGuid<\/b> : A unique GUID identifying the backed-up GPO.<\/li>\n<li><b>Name<\/b>: The GPO name.<\/li>\n<li><b>GpoGuid<\/b>: The GUID of the GPO in Active Directory.<\/li>\n<li><b>SOMs<\/b>: Details of where the GPO is linked to (SOM) and link configuration.<\/li>\n<li><b>DomainDN<\/b> : the distinguished name of the source domain.<\/li>\n<\/ul>\n<p>For example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8015.wes-1-5-14-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8015.wes-1-5-14-1.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Let&rsquo;s look at the <b>SOMs<\/b> property in detail. Scope-of-management refers to a site, domain, or organizational unite where a GPO is linked. Each <b>SOM<\/b> object in the <b>SOMs<\/b> array has that information and more:<\/p>\n<p style=\"margin-left:30px\">&ldquo;$SomDN:$SomInheritance:$LinkEnabled:$LinkOrder:$LinkEnforced&quot;<\/p>\n<p>For example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3051.wes-1-5-14-2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3051.wes-1-5-14-2.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>There are five pieces of information for each entry. Each piece is separated by a colon. Here&rsquo;s what they represent:<\/p>\n<ul>\n<li><b>$SomDN<\/b>: The distinguished name of the SOM.<\/li>\n<li><b>$SomInheritance<\/b>:&nbsp; Whether Block Inheritance is enabled on the SOM (True or False).<\/li>\n<li><b>$LinkEnabled<\/b>: Whether the GPO link is enabled or disabled (True or False).<\/li>\n<li><b>$LinkOrder<\/b>: The precedence of the GPO link (order number).<\/li>\n<li><b>$LinkEnforced<\/b>: Whether the GPO link is enforced (True or False).<\/li>\n<\/ul>\n<p>The backup folder might also contain a migration table to translate domain-specific information from one domain to another. This should be manually updated after the <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Comprehensive-Group-Policy-5f9d3ea6\" target=\"_blank\">Backup_GPOs<\/a> script has completed.<\/p>\n<p>To process the backup output, the import script needs five sections:<\/p>\n<ol>\n<li>Import WMI filters<\/li>\n<li>Import backed-up GPOs<\/li>\n<li>Link WMI filters<\/li>\n<li>Create GPO links<\/li>\n<li>Configure GPO links<\/li>\n<\/ol>\n<h2>Logging on<\/h2>\n<p>The script also records key actions. A script log shows script activity and aids troubleshooting. For years, I&rsquo;ve logged script output in a format that can be parsed by the SMS Trace application (part of the <a href=\"http:\/\/www.microsoft.com\/en-us\/download\/details.aspx?id=18153\" target=\"_blank\">Systems Management Server 2003 Toolkit 2<\/a>, which is now superseded by CM Trace). This allows me to match events to script components, highlight key information, filter, search, and even look up error codes.<\/p>\n<p>Here are some sample log entries:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8688.wes-1-5-14-3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8688.wes-1-5-14-3.png\" alt=\"Image of log\" title=\"Image of log\" \/><\/a><\/p>\n<p>You can download the entire function from the Script Center Repository: <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Log-ScriptEvent-Function-ea238b85\" target=\"_blank\">Log-ScriptEvent Function<\/a>.<\/p>\n<p>Now, let&rsquo;s look at the script sections in detail&hellip;<\/p>\n<h3>Import WMI filters<\/h3>\n<p>If the <b>WmiFilter<\/b> script switch is specified, this section is executed. A loop processes each filter in the <b>$WmiFilters<\/b> array. The <b>DomainDN<\/b> portion of the current filter&rsquo;s <b>DistinguishedName<\/b> property is updated to reflect the target domain, and then saved to a variable (<b>$SourceDomainDN<\/b> and <b>$TargetDomainDN<\/b> have been defined earlier in the script).<\/p>\n<p style=\"margin-left:30px\">ForEach ($WMI in $WmiFilters) {<\/p>\n<p style=\"margin-left:30px\">$TargetWmiDN = $WMI.DistinguishedName &ndash;Replace $SourceDomainDN, $TargetDomainDN<\/p>\n<p>For example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8764.wes-1-5-14-4.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8764.wes-1-5-14-4.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Is updated to:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5277.wes-1-5-14-5.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5277.wes-1-5-14-5.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>This variable is then supplied to <b>Get-ADObject<\/b> to test whether the filter already exists in the target domain.<\/p>\n<p style=\"margin-left:30px\">TargetWMI = Get-ADObject -Identity $TargetWmiDN<\/p>\n<p>If the filter does exist, properties from the backup are added to a hash table with the <b>[Ordered] type<\/b> declaration. <b>[Ordered]<\/b> ensures that the properties stay in the defined order.<\/p>\n<p style=\"margin-left:30px\">$Properties = [Ordered]@{<\/p>\n<p style=\"margin-left:30px\">&quot;msWMI-Author&quot; = $WMI.&quot;msWMI-Author&quot;<\/p>\n<p style=\"margin-left:30px\">&quot;msWMI-ChangeDate&quot; = &quot;$(Get-Date -Format yyyyMMddhhmmss).706000-000&quot;<\/p>\n<p style=\"margin-left:30px\">&quot;msWMI-ID&quot; = $WMI.&quot;msWMI-ID&quot;&nbsp;<\/p>\n<p style=\"margin-left:30px\">&quot;msWMI-Name&quot; = $WMI.&quot;msWMI-Name&quot;<\/p>\n<p style=\"margin-left:30px\">&quot;msWMI-Parm1&quot; = $WMI.&quot;msWMI-Parm1&quot;<\/p>\n<p style=\"margin-left:30px\">&quot;msWMI-Parm2&quot; = $WMI.&quot;msWMI-Parm2&quot;<\/p>\n<p style=\"margin-left:30px\">}&nbsp;&nbsp; #End of $Properties<\/p>\n<p>The <b>Set-ADObject<\/b> cmdlet is then used to update the filter with <b>$Properties<\/b> passed to the <b>Replace<\/b> parameter:<\/p>\n<p style=\"margin-left:30px\">$UpdateWmiFilter = Set-ADObject -Identity $TargetWmiDN -Replace $Properties<\/p>\n<p>If the filter doesn&rsquo;t exist, the hash table of properties is given an additional attribute: <b>&ldquo;msWMI-CreationDate&rdquo;<\/b>:<\/p>\n<p style=\"margin-left:30px\">&quot;msWMI-CreationDate&quot; = &quot;$(Get-Date -Format yyyyMMddhhmmss).706000-000&quot;<\/p>\n<p>The <b>New-ADObject<\/b> cmdlet is then called:<\/p>\n<p style=\"margin-left:30px\">$NewWmiFilter = New-ADObject -Name $WMI.&quot;msWMI-ID&quot; -Type $WMI.ObjectClass `<\/p>\n<p style=\"margin-left:30px\">-Path &quot;CN=SOM,CN=WMIPolicy,CN=System,$TargetDomainDN&quot; `<\/p>\n<p style=\"margin-left:30px\">-OtherAttributes $Properties<\/p>\n<p>Here&rsquo;s an explanation of its parameters.<\/p>\n<ul>\n<li><b>Name<\/b>: The AD name attribute of the new object.<\/li>\n<li><b>Type<\/b>: The object class, for example, <b>msWMI-Som<\/b>.<\/li>\n<li><b>Path<\/b>: Where to create the object in Active Directory (note the use of <b>$TargetDomainDN<\/b> in the string).<\/li>\n<li><b>OtherAttributes<\/b>: Accepts a hash table of object attributes that are not covered by a cmdlet parameter.<\/li>\n<\/ul>\n<p>When every WMI filter is imported, the parent loop is closed.<\/p>\n<h3>Import backed-up GPOs<\/h3>\n<p>A parent loop processes each object in the <b>$CustomGpoInfo<\/b> array:<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForEach ($CustomGpo in $CustomGpoInfo) {<\/p>\n<p>The <b>Import-GPO<\/b> cmdlet is executed:<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp; $ImportedGpo = Import-GPO -BackupId $CustomGpo.BackupGuid<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -Path $BackupFolder<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -CreateIfNeeded<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -Domain $DomainFQDN<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -TargetName $CustomGpo.Name<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -MigrationTable $MigrationFile<\/p>\n<p>The parameters:<\/p>\n<ul>\n<li><b>BackupID<\/b>: The backup GUID property of the current object.<\/li>\n<li><b>Path<\/b>: The backup folder (a script parameter).<\/li>\n<li><b>CreateIfNeeded<\/b>: Creates a GPO if one doesn&rsquo;t exist.<\/li>\n<li><b>Domain<\/b>: The domain into which the GPO is to be imported (a script parameter).<\/li>\n<li><b>TargetName<\/b>: The name of the imported GPO, the name property of the current object.<\/li>\n<li><b>MigrationTable<\/b>: Included if the <b>MigTable<\/b> switch is specified at script execution. The migration table in the backup folder is referenced.<\/li>\n<\/ul>\n<p>A backed-up GPO object is imported into the target domain. What about those additional GPO configuration settings?<b><\/b><\/p>\n<h3>Link WMI filters<\/h3>\n<p>Before the next GPO is processed, this section is executed only if the <b>WmiFilter<\/b> script switch is activated. If the current custom GPO object has a WMI filter property, the corresponding filter in the target domain is linked to the newly imported GPO.<\/p>\n<p>Use the <b>WmiFilter<\/b> property of the current custom GPO to construct the path to the WMI filter in the target domain:<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $TargetWmiDN = &quot;CN=$($CustomGpo.WmiFilter),CN=SOM,CN=WMIPolicy,CN=System,$TargetDomainDN&quot;<\/p>\n<p>Test that the filter is present and include the <b>msWMI-Name<\/b> value in the properties that are returned:<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $TargetWMI = Get-ADObject -Identity $TargetWmiDN -Property &quot;msWMI-Name&quot;<\/p>\n<p>If the filter is present, use the <b>Id<\/b> property of the imported GPO to construct the path to the corresponding Group Policy container in the target domain:<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $TargetGpoDN = &quot;CN={$($ImportedGpo.Id)},CN=Policies,CN=System,$TargetDomainDN&quot;<\/p>\n<p>What&rsquo;s a Group Policy container? A GPO is made up of two components. The first is the Group Policy container, which includes settings that are stored in Active Directory (there&rsquo;s an attribute for the linked WMI filter). The second is a Group Policy template, which has settings that are stored in the System Volume (SYSVOL). (This provides a file system share that is replicated to all domain controllers).<\/p>\n<p>To finish, use the path to the Group Policy container to update the WMI filter attribute <b>gPCWQLFilter<\/b> on the Group Policy container object:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $UpdateGpoFilter = Set-ADObject $TargetGpoDN -Replace @{gPCWQLFilter = &quot;[$TargetDomainFQDN;$($TargetWMI.Name);0]&quot;}<\/p>\n<p>The <b>Replace<\/b> parameter accepts a hash table of attributes. In this instance, the value that is associated with the <b>gPCWQLFilter<\/b> attribute has an interesting format constructed by using the FQDN of the target domain and the name of the target WMI filter (the <b>msWMI-Name<\/b> value). Here&rsquo;s an example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4786.wes-1-5-14-6.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4786.wes-1-5-14-6.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<h3>Create GPO links<\/h3>\n<p>The information in this section is executed only if the <b>SomInfo<\/b> script switch is activated. If the current custom GPO object has a populated <b>SOMs<\/b> property, each <b>SOM<\/b> entry from the array is evaluated in a child loop. The aim is to link the imported GPO to corresponding <b>SOMs<\/b> in the target domain.<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SOMs = $CustomGpo | Select-Object -ExpandProperty SOMs<\/p>\n<p>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForEach ($SOM in $SOMs) {<\/p>\n<p>To obtain the original SOM distinguished name, the <b>$SOM<\/b> string is split by using the &ldquo;<b>:<\/b>&rdquo; delimiter, and the first element of the array is assigned to a variable:<\/p>\n<p style=\"margin-left:30px\">$SomDN = ($SOM &ndash;Split &quot;:&quot;)[0]<\/p>\n<p>For example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8623.wes-1-5-14-7.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8623.wes-1-5-14-7.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>The <b>DomainDN<\/b> of the string is then replaced with the distinguished name of the target domain:<\/p>\n<p style=\"margin-left:30px\">$SomDN = $SomDN &ndash;Replace $CustomGpo.DomainDN, $DomainDN<\/p>\n<p>For example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6165.wes-1-5-14-8.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6165.wes-1-5-14-8.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Next, check that the updated <b>SOMDN<\/b> exists by using the <b>Get-ADObject<\/b> cmdlet:<\/p>\n<p style=\"margin-left:30px\">$TargetSom = Get-ADObject -Identity $SomDn<\/p>\n<p style=\"margin-left:30px\"><b>Note<\/b>&nbsp;&nbsp;It is assumed that a matching path already exists in the target test domain.<\/p>\n<p>If the distinguished name doesn&rsquo;t exist, an error is logged, and we move to the next <b>SOM<\/b>. If the distinguished name exists, create a new link to it by using the <b>New-GPLink<\/b> cmdlet:<\/p>\n<p style=\"margin-left:30px\">$SomLink = New-GPLink -Guid $ImportedGpo.Id -Domain $DomainFQDN -Target $SomDN<\/p>\n<p>Remember <b>$ImportedGPO<\/b>? It contains the result of the <b>Import-GPO<\/b> cmdlet. Its <b>Id<\/b> property is the GPO GUID of the imported policy in the target domain.<\/p>\n<p>Onward&#8230;<\/p>\n<p>Each <b>SOM<\/b> is processed and the <b>SOM<\/b> child loop is exited. The current custom GPO from the <b>$CustomGpoInfo<\/b> array is updated. The GPO GUID of the newly imported policy is added as a property called <b>NewGpoGuid<\/b>:<\/p>\n<p style=\"margin-left:30px\">$CustomGpo | Add-Member -MemberType NoteProperty -Name NewGpoGuid -Value $ImportedGpo.Id<\/p>\n<p>For example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7217.wes-1-5-14-9.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7217.wes-1-5-14-9.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>The process is repeated for each custom GPO object. The parent loop is then exited.<\/p>\n<h3>Configure GPO links<\/h3>\n<p>Time to process the block inheritance, link enabled, link order, and link enforced details. As in the <i>Import Backed-Up GPOs<\/i> section, a parent loop processes each object in the <b>$CustomGpoInfo<\/b> array. The <b>SOMs<\/b> property is expanded, and a child loop processes each entry.<\/p>\n<p>Again, the <b>$SomDN<\/b> value is obtained by splitting the <b>$SOM<\/b> string. This time, though, we&rsquo;re also interested in the other elements, for example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-1-5-14-10.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-1-5-14-10.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>The <b>Set-GPLink<\/b> cmdlet doesn&rsquo;t understand Boolean values, so these have to be converted to <b>Yes<\/b> or <b>No<\/b>. Here&rsquo;s how the <b>$LinkEnabled<\/b> value is processed. The <b>$SOM<\/b> string is split at the &ldquo;<b>:<\/b>&rdquo;, and the second index of the array is tested for <b>$True<\/b> or <b>$False<\/b>:<\/p>\n<p style=\"margin-left:30px\">Switch ($SOM.Split(&quot;:&quot;)[2]) {<\/p>\n<p style=\"margin-left:30px\">$True {<\/p>\n<p style=\"margin-left:30px\">#Set the GP link enabled variable to Yes<\/p>\n<p style=\"margin-left:30px\">$LinkEnabled = &quot;Yes&quot;<\/p>\n<p style=\"margin-left:30px\">}&nbsp;&nbsp; #End of $True<\/p>\n<p style=\"margin-left:30px\">$False {<\/p>\n<p style=\"margin-left:30px\">#Set the GP link enabled variable to No<\/p>\n<p style=\"margin-left:30px\">$LinkEnabled = &quot;No&quot;<\/p>\n<p style=\"margin-left:30px\">}&nbsp;&nbsp; #End of $False<\/p>\n<p style=\"margin-left:30px\">}&nbsp;&nbsp; #End of Switch ($SOM.Split(&quot;:&quot;)[2])<\/p>\n<p style=\"margin-left:30px\"><b>Note<\/b>&nbsp;&nbsp;The <b>Switch<\/b> statement is very powerful. It accepts wildcard characters, regular expressions, or the content of a file as input. It can even loop. Have a look at Get-Help about_Switch.<\/p>\n<p>The <b>$LinkEnforced<\/b> value is obtained by using the same <b>Switch<\/b> statement. This time, the fourth index of the array is used. <b>$LinkOrder<\/b> is grabbed from the third index.<\/p>\n<p>Here&rsquo;s what the <b>Set-GPLink<\/b> syntax looks like:<\/p>\n<p style=\"margin-left:30px\">$SomLink = Set-GPLink -Guid $CustomGpo.NewGpoGuid<\/p>\n<p style=\"margin-left:30px\">&nbsp; -Domain $DomainFQDN<\/p>\n<p style=\"margin-left:30px\">&nbsp; -Target $SomDN<\/p>\n<p style=\"margin-left:30px\">&nbsp; -LinkEnabled $LinkEnabled<\/p>\n<p style=\"margin-left:30px\">&nbsp; -Order $LinkOrder<\/p>\n<p style=\"margin-left:30px\">&nbsp; -Enforced $LinkEnforced<\/p>\n<p>The value that is fed to the <b>Guid<\/b> parameter is the <b>NewGpoGuid<\/b> property that was recently added to the current custom GPO object. After executing <b>Set-GPLink<\/b>, almost all of the additional data is restored.<\/p>\n<p>Here&rsquo;s the last piece of the puzzle. The <b>Set-GPInheritance<\/b> cmlet is only called to configure block inheritance when the corresponding value is <b>True<\/b>:<\/p>\n<p style=\"margin-left:30px\">If ($SomInheritance -eq $True) {<\/p>\n<p style=\"margin-left:30px\">#Set block inheritance<\/p>\n<p style=\"margin-left:30px\">$SetInheritance = Set-GPInheritance -Target $SomDn -IsBlocked Yes<\/p>\n<p style=\"margin-left:30px\"><b>Note<\/b>&nbsp;&nbsp;In PFE, we don&rsquo;t recommend the use of the enforced or the block inheritance options because they can complicate troubleshooting. If the script enables either of these options, a warning will be logged (highlighted in yellow in the following example):<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-1-5-14-11.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-1-5-14-11.png\" alt=\"Image of error message\" title=\"Image of error message\" \/><\/a><\/p>\n<p>Then, on to the next <b>SOM<\/b> entry until all link details are processed. Then, on to the next GPO import until all backed-up GPOs are processed.<\/p>\n<p>Now inspect the script log. It will be in the directory from which the import script was executed. Target any red. Finally, fire up the GPMC for the test domain&hellip;Cool, eh?<\/p>\n<p>Well, I enjoyed that and I hope you did too. Have fun!<\/p>\n<p>You can download the entire script from the Script Center Repository: <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Comprehensive-Group-Policy-212562cb\" target=\"_blank\">Comprehensive Group Policy Import Script<\/a>.<\/p>\n<p>~Ian<\/p>\n<p>Thank you, Ian. Join me tomorrow as the Scripting Wife reveals the top five Hey, Scripting Guy! Blog posts of 2013. It is cool stuff&mdash;you will not want to miss it.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft PFE, Ian Farr talks about using Windows PowerShell to import Group Policy Objects. Microsoft Scripting Guy, Ed Wilson, is here. Yesterday, guest blogger, Ian Farr talked about backing up Group Policy Objects&nbsp; (GPOs) in his post Using PowerShell to Back Up Group Policy Objects. He continues his GPO series today&hellip; The challenge Welcome [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[152,56,472,3,61,45],"class_list":["post-2282","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-group-policy","tag-guest-blogger","tag-ian-farr","tag-scripting-guy","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft PFE, Ian Farr talks about using Windows PowerShell to import Group Policy Objects. Microsoft Scripting Guy, Ed Wilson, is here. Yesterday, guest blogger, Ian Farr talked about backing up Group Policy Objects&nbsp; (GPOs) in his post Using PowerShell to Back Up Group Policy Objects. He continues his GPO series today&hellip; The challenge Welcome [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/2282","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=2282"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/2282\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=2282"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=2282"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=2282"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}