Documenting GPPref drive and printer mappings

GPPrefs are great – but in true MS fashion – they are very much a bolt-on from when they were acquired many years ago – and the ability to script reading values (let alone creation) is somewhere limited due to this.

This dude made a fantastic script to document GPPref drive mappings here

Getting all GPP Drive maps in a Domain with PowerShell

You should be able to go to the link above for the original script, i have a slightly updated version below, which outputs the content to a CSV instead of to screen.

<#
.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
}
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”)
{
$DriveXML = Get-Content “\\$($GPODom)\SYSVOL\$($GPODom)\Policies\{$($GPOID)}\User\Preferences\Drives\Drives.xml”

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

$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

Add-Content -Value “$GPOName,$DriveLetter,$DrivePath,$DriveAction,$DriveLabel,$DrivePersistent,$DriveFilterGroup” -Path C:\Temp\GPODriveMaps.csv
}
}
}

 

In addition, i used this script as a base to make one that will document printer mappings from GPPrefs

<#
.SYNOPSIS
The script finds the GPP Printer Maps in your domain.
.NOTES
File Name: Get-GPPPrinterMaps.ps1
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\Printers\Printers.xml”)
{

$PrinterXML = Get-Content “\\$($GPODom)\SYSVOL\$($GPODom)\Policies\{$($GPOID)}\User\Preferences\Printers\Printers.xml”

foreach ( $PrinterMap in $PrinterXML.Printers.SharedPrinter) {

$GPOName = $GPODisp
$PrinterName = $PrinterMap.name
$PrinterPath = $PrinterMap.Properties.path
$PrinterAction = $PrinterMap.Properties.action.Replace(“U”,”Update”).Replace(“C”,”Create”).Replace(“D”,”Delete”).Replace(“R”,”Replace”)
$PrinterDefault = $PrinterMap.Properties.default.Replace(“0″,”False”).Replace(“1″,”True”)
$PrinterFilterGroup = $PrinterMap.Filters.FilterGroup.name

Add-Content -Value “$GPOName,$PrinterName,$PrinterPath,$PrinterAction,$PrinterDefault,$PrinterFilterGroup” -Path C:\Temp\GPOPrinterMaps.csv
}
}
}

Storing credentials for Powershell scripts – Encrypted Strings or Credential Manager

If you’ve been reading through some of our other blog posts, you’ll have noticed that we generally like to automate things using Powershell – which quite often requires storing credentials somehow. Preferably not in plain text.

In our existing scripts on this blog, the process has generally involved generating an encryption key, using that key to convert a password to an encrypted string, then storing both in individual files. While that method works fine and has some nice benefits, there’s another alternative that’s worth knowing about: storing credentials in Windows Credential Manager.

I’ll put the code for both methods further down, but first I’d like to list the main differences between the two methods:

Encrypted string in file

  • Portable between users and computers
  • Can be used in WinPE or wherever Powershell is available
  • Only as secure as the NTFS permissions on the files storing the key and encrypted password (someone with read access can use powershell to reveal the password if they know what the files are for)
  • Utilises a bit of ‘security by obfuscation’ – depending on how you name the files, no one is going to know what they’re for, and malware/viruses definitely aren’t going to realise the files are encrypted credentials that could be easily reverse-engineered.
  • When used with Task Scheduler, the scheduled task can be run as any user/local system

Windows Credential Manager

  • Only portable between computers if using roaming profiles; isn’t portable between users
  • Can only be used in a full-windows environment that has Windows Credential Manager (ie: not in WinPE)
  • Is as secure as the Windows account attached to the credential store (assuming a complex password, pretty secure)
  • If the Windows account becomes compromised somehow (you leave the PC unlocked, malware/virus, etc), it’s a relatively simple process to pull any account details you’ve stored in Windows Credential Manager via Powershell.
  • When used with Task Scheduler, the scheduled task has to be running as the Windows account attached to the credentials store

So, how do you do each of these?

#-----------Encrypting a password to a file-----------#
#File Locations
$KeyFile = "C:\Temp\KeyFile.key"
$PasswordFile = "C:\Temp\PWFile.pw"

#Create the encryption key and dump it to a file
$Key = New-Object Byte[] 16
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
$Key | out-file $KeyFile

#Use the encryption key to encrypt the password and dump the encrypted password to a file
$Password = Read-Host -assecurestring "Password: "
$Password | ConvertFrom-SecureString -key $Key | Out-File $PasswordFile

#-----------Retrieving an encrypted password from a file-----------#
#File Locations
$KeyFile = "C:\Temp\KeyFile.key"
$PasswordFile = "C:\Temp\PWFile.pw"

#Grab the key, decrypt the password and store it in a credentials object
$key = Get-Content $KeyFile
$MyCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "<Username>", (Get-Content $PasswordFile | ConvertTo-SecureString -Key $key)
#-----------Storing credentials in Windows Credential Manager-----------# 
#Install Packages/Modules if required
If(!(Get-PackageProvider -Name 'NuGet')){Install-PackageProvider -Name NuGet -Force}
If(!(Get-Module -ListAvailable -Name 'CredentialManager')){Install-Module CredentialManager -Force}else{Import-Module CredentialManager}

#Create new credentials - store against LocalMachine (so can be used by other sessions of the current user)
New-StoredCredential -Target "PS_Azure" -Persist 'LocalMachine' -Credentials $(Get-Credential) | Out-Null

#-----------Retrieving credentials from Windows Credential Manager-----------#
#Retreive the credentials
$Credentials = Get-StoredCredential -Target 'PS_Azure'