Category Archives: Group Policy

PowerShell GPO Reporting: WSUS

In addition to my earlier creations that gives you an inventory of your GPO Deployed Printers and GPP Drive Maps, I’ve now created a similiar script that makes inventory of WSUS settings in all your GPO’s.
This can very much come in handy when having an extensive amount of GPO’s that are controlling WSUS settings (e.g. for different maintenance schedules).

See the example below of the output:
2014-02-05 07-17-52

<#
.SYNOPSIS     
Function that find certain information about all your WSUS related GPO's.
.NOTES     
           File Name: Get-GPOWsusInfo    
           Author   : Johan Dahlbom, johan[at]dahlbom.eu     
           The script are provided “AS IS” with no guarantees, no warranties, and it confer no rights. 
           Blog     : 365lab.net
#>
function Get-GPOWsusInfo {

try
{
Import-Module GroupPolicy -ErrorAction Stop
}
catch
{
throw "Module GroupPolicy not Installed"
}
        $GPO = Get-GPO -All

        foreach ($Policy in $GPO){

                $GPOID = $Policy.Id
                $GPODom = $Policy.DomainName
                $GPODisp = $Policy.DisplayName

                [xml]$xml = Get-GPOReport -Id $GPOID -ReportType xml
                $GPOSec = Get-GPPermissions -All -Guid $GPOID
                $WSUSBase = Get-GPRegistryValue -Guid $GPOID -Key HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate -ErrorAction SilentlyContinue
                $WSUSAU = Get-GPRegistryValue -Guid $GPOID -Key HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate\AU   -ErrorAction SilentlyContinue

                    if ($WsusBase) {

                        New-Object PSObject -Property @{
                           	GPOName = $GPODisp
                            GPOLinks = $xml.gpo.Linksto.SOMPath
                            GPOFilter = ($GPOSec | Where-Object {$_.Permission -eq "GpoApply"}).trustee.name
                            ScheduleDay = ($WSUSAU | Where-Object {$_.ValueName -eq "ScheduledInstallDay"}).Value.tostring().Replace("0","0 - Every Day").Replace("1","1 - Sunday").Replace("2","2 - Monday").Replace("3","3 - Tuesday").Replace("4","4 - Wednesday").Replace("5","5 - Thursday").Replace("6","6 - Friday").Replace("7","7 - Saturday")
                            Installtime =  ($WSUSAU | Where-Object {$_.ValueName -eq "ScheduledInstallTime"}).Value.tostring() + ':00'
                            AutoUpdateSetting = ($WSUSAU | Where-Object {$_.ValueName -eq "AUOptions"}).Value.tostring().Replace("2","2 - Notify for download and notify for install").Replace("3","3 - Auto download and notify for install").Replace("4","4 - Auto download and schedule the install").Replace("5","5 - Allow local admin to choose setting")
                            WSUSTargetGroup = ($WSUSBase | Where-Object {$_.ValueName -eq "TargetGroup"}).Value
                            WSUSServer = ($WSUSBase | Where-Object {$_.ValueName -eq "WUServer"}).Value
                        }
                    }

           }
}

Hope you find this useful!
When I find the time I’ll create a more complete set of GPO reporting functions with more functionality than they have today, maybe with help from Ramblingcookiemonster that has extended and created additions to the GP Preferences functions.

Until next time, Happy GPO Reporting!

/Johan

Friendly Reminder – do NOT assign passwords through Group Policy Preferences

This is an issue that have been out for quite a while, but I see it a lot when checking customers environments, so it’s always good to remind yourself about this kind of important things.

Through GPP, you have the ability to do lots of stuff, one of them is fiddling with builtin local accounts on computers and even change password on those.

A common case is applying GPP settings as below to your client computers.
2014-01-09 11-48-522014-01-09 11-49-06
Note the warning about where the password will be stored.

It actually gets worse from there… with the script which can be downloaded here, you can extract ALL passwords from ALL GPP’s you have since they are stored in XML files located on the sysvol in your domain.
OK, who have access to read those files then?
Authenticated Users, which means whoever that has an account in your domain can do this.
2014-01-09 11-50-01

Conclusion: do not change password with GPP unless you do it and remove the policy directly after the policy has successfully been applied.

In this blog post series from Microsoft PFE’s, you find a great solution to handle and store local admin passwords in a secure, yet manageble way.

/Johan

Get all GPO deployed Printers with PowerShell

As a follow up to my last post on GPP, and per request on Technet, I’ve now created Another script to make inventory of all printers in a domain deployed with GPO (both GPP and Deployed Printers). It can be a pain to use those settings some times, here you have a way to make inventory of them at least. 🙂
Just like the other one it’s based on the GroupPolicy PowerShell-Module which works from 2008R2 and up.

See below screenshots on how to run the script and what output you get. (similiar to the GPP Drive maps output)
2014-01-07 19-25-35
2014-01-07 19-26-04

If you want to export all printer information to a csv file, use below row.

.\Get-GPOPrinters.ps1 | select printerpath,gpotype,gponame,FilterGroup  | Export-Csv c:\printers.csv -NoTypeInformation

Get-GPOPrinters.ps1

<#
.SYNOPSIS     
The script finds all shared printers deployed with GPO (both deployed printers GPP.) in your domain. 
.NOTES     
           File Name: Get-GPOPrinters.ps1     
           Author   : Johan Dahlbom, johan[at]dahlbom.eu     
           The script are provided “AS IS” with no guarantees, no warranties, and it confer no rights. 
           Blog     : 365lab.net
#>
#Import the required module GroupPolicy
try
{
Import-Module GroupPolicy -ErrorAction Stop
}
catch
{
throw "Module GroupPolicy not Installed"
}
        $GPO = Get-GPO -All

        foreach ($Policy in $GPO){

                $GPOID = $Policy.Id
                $GPODom = $Policy.DomainName
                $GPODisp = $Policy.DisplayName
                $PrefPath = "\\$($GPODom)\SYSVOL\$($GPODom)\Policies\{$($GPOID)}\User\Preferences"

                    #Get GP Preferences Printers
                    $XMLPath = "$PrefPath\Printers\Printers.xml"
                    if (Test-Path "$XMLPath")
                    {
                         [xml]$PrintXML = Get-Content "$XMLPath"

                                foreach ( $Printer in $PrintXML.Printers.SharedPrinter )

                                    {New-Object PSObject -Property @{
                                        GPOName = $GPODisp
                                        PrinterPath = $printer.Properties.Path
                                        PrinterAction = $printer.Properties.action.Replace("U","Update").Replace("C","Create").Replace("D","Delete").Replace("R","Replace")
                                        PrinterDefault = $printer.Properties.default.Replace("0","False").Replace("1","True")
                                        FilterGroup = $printer.Filters.FilterGroup.Name
                                        GPOType = "Group Policy Preferences"
                                    }
                                }
                   }
                   #Get Deployed Printers
                   [xml]$xml = Get-GPOReport -Id $GPOID -ReportType xml
                   $User = $xml.DocumentElement.User.ExtensionData.extension.printerconnection
                   $Computer = $xml.DocumentElement.computer.ExtensionData.extension.printerconnection

                        foreach ($U in $User){
                            if ($U){

                                    New-Object PSObject -Property @{
                                        GPOName = $GPODisp
                                        PrinterPath = $u.Path
                                        GPOType = "GPO Deployed Printer - User"
                                    }
                            }

                        }

                        foreach ($C in $Computer){
                            if ($c){

                                    New-Object PSObject -Property @{
                                        GPOName = $GPODisp
                                        PrinterPath = $c.Path
                                        GPOType = "GPO Deployed Printer - Computer"
                                    }
                            }

                        }
           }

This was done very quick, will probably do some things a bit nicer later on. If you find any direct issues or bugs, let me know!

Enjoy!

/Johan

Getting all GPP Drive maps in a Domain with PowerShell

Group Policy Preferences are mostly great and frequently used to solve different kind of policy related problems in an it Environment.
There are a few PowerShell cmdlet for GPO’s (28 last time I checked) but only three of them are related to Group Policy Preferences.
2013-12-31 13-31-59.

Case and Solution
A customer of mine wanted to inventory their GPP Drive maps, and get information about what GPO, drive letter, drivepath, security Filtering and so on.

I know there are quite a few solutions that can do this for you, but why not use PowerShell when possible? 🙂

The script is using the GroupPolicy POSH-module which has been around since 2008R2, so this works even there.
It simply gets all Group policies in your domain, checks each policy for drive maps (by checking if Drives.xml exists) and gives you a bit of nice output. (ehh.. could be nicer, but anyway… )

See my examples below:
1. Gives you all Drive Map GPO’s plain and formats the output as a table.

2013-12-31 13-48-24
Note: The DriveAction object is not translated to a more friendly name at this time so U, stands for Update, D, for delete and so on. That is also applies on the DrivePersistent output (“Reconnect”).
Update: This is now updated so it gives you a bit of nicer output!

2. Searches for drive maps in a specific GPO.
2013-12-31 13-42-38

3. Exports the output to a csv.

.\Get-GPPDriveMaps.ps1 | Export-Csv DriveMaps.csv -NoTypeInformation

Get-GPPDriveMaps.ps1

<#
.SYNOPSIS     
           The script finds the GPP Drive Maps in your domain. 
.NOTES     
           File Name: Get-GPPDriveMaps.ps1     
           Author   : Johan Dahlbom, johan[at]dahlbom.eu     
           The script are provided “AS IS” with no guarantees, no warranties, and it confer no rights. 
#>
#Import the required module GroupPolicy
try
{
Import-Module GroupPolicy -ErrorAction Stop
}
catch
{
throw "Module GroupPolicy not Installed"
}
        $GPO = Get-GPO -All

        foreach ($Policy in $GPO){

                $GPOID = $Policy.Id
                $GPODom = $Policy.DomainName
                $GPODisp = $Policy.DisplayName

                 if (Test-Path "\\$($GPODom)\SYSVOL\$($GPODom)\Policies\{$($GPOID)}\User\Preferences\Drives\Drives.xml")
                 {
                     [xml]$DriveXML = Get-Content "\\$($GPODom)\SYSVOL\$($GPODom)\Policies\{$($GPOID)}\User\Preferences\Drives\Drives.xml"

                            foreach ( $drivemap in $DriveXML.Drives.Drive )

                                {New-Object PSObject -Property @{
                                    GPOName = $GPODisp
                                    DriveLetter = $drivemap.Properties.Letter + ":"
                                    DrivePath = $drivemap.Properties.Path
                                    DriveAction = $drivemap.Properties.action.Replace("U","Update").Replace("C","Create").Replace("D","Delete").Replace("R","Replace")
                                    DriveLabel = $drivemap.Properties.label
                                    DrivePersistent = $drivemap.Properties.persistent.Replace("0","False").Replace("1","True")
                                    DriveFilterGroup = $drivemap.Filters.FilterGroup.Name
                                }
                            }
                }
        }

The script can of course be extended with a lot more information, and make the output easier to read, but that’s a later project.

/Johan

Logon script that writes Displayname, computer model and serial number to description on computer object

Now you don’t have to look after this information anywhere else than your AD, can be very handy in many situations.
There are of course solutions that do this for you but I like have all information in one place. 🙂


To implement this you have to put the script below as a logon script for all users and delegate control so that Domain Users or any user group of your choice have write permissions to the description attribute of computer objects.

This is easiest done with the delegate control wizard that you find by right clicking to any OU.

Write-Description.vbs

On Error Resume Next

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colcomputersystem = objWMIService.ExecQuery("Select * from Win32_computersystem")
Set colBIOS = objWMIService.ExecQuery("Select * from Win32_BIOS")
For each objcomputersystem in colcomputersystem
Getcomputersystem = objcomputersystem.Model
GetComputerManufacturer = objcomputersystem.Manufacturer
Next
For each objBIOS in colBIOS
GetSerialNumber = objBIOS.SerialNumber
Next
Set objSysInfo = CreateObject("ADSystemInfo")
Set objUser = GetObject("LDAP://" & objSysInfo.UserName)
Set objComputer = GetObject("LDAP://" & objSysInfo.ComputerName)

if LCase(GetComputerManufacturer)="lenovo" then
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_ComputerSystemProduct")
For Each objItem in colItems
strModel = "Lenovo " & objItem.Version
Exit For
Next
Getcomputersystem = strModel & " (" & Getcomputersystem & ")"
end if

strMessage = objUser.CN & " / " & Getcomputersystem & " / " & GetSerialNumber
objComputer.Description = strMessage
objComputer.SetInfo