PrintHA.DSC.psm1
enum Ensure { Absent Present } enum FileMirrorState { Same SourceNewer DestinationNewer SourceMissing DestinationMissing SourceMissingDestinationMissing } enum PrinterAction { None Create Remove } <# This resource manages the presence of the XML configuration file (specific for each computer) copied from a specified source folder. #> [DscResource()] class cFileMirror { # The source folder containing XML configuration files [DscProperty(Mandatory)] [String]$SourceFolder # The fully qualified name of the target file [DscProperty(Key)] [String] $DestinationPath [DscProperty(Mandatory)] [Ensure] $Ensure [String]$SourcePath [void]Set() { Write-verbose '[Set] Entering' # Compose the source file name in runtime $this.SourcePath = $this.SourceFolder + '\' + $env:COMPUTERNAME + '.xml' # Get the current config file status [FileMirrorState]$State = $this.GetConfigStatus() if($this.Ensure -eq [Ensure]::Present) { switch($State) { {([FileMirrorState]::Same, [FileMirrorState]::SourceMissingDestinationMissing) -contains $_} {break} 'SourceMissing' { Write-verbose '[Set] Removing Destination' Remove-Item "$($this.DestinationPath)" -Force -ErrorAction 'SilentlyContinue' break } default { Write-verbose '[Set] Updating Destination' Copy-Item "$($this.SourcePath)" "$($this.DestinationPath)" -Force } } } else { switch($State) { {([FileMirrorState]::DestinationMissing, [FileMirrorState]::SourceMissingDestinationMissing) -contains $_} {break} default { Write-Verbose '[Set] Removing Destination' Remove-Item "$($this.DestinationPath)" -Force -ErrorAction 'SilentlyContinue' } } } Write-Verbose '[Set] Returning' } [cFileMirror]Get() { Write-verbose '[Get] Entering' Write-verbose '[Get] Returning' return $this } [bool]Test() { Write-verbose '[Test] Entering' # Compose the source file name in runtime $this.SourcePath = $this.SourceFolder + '\' + $env:COMPUTERNAME + '.xml' [bool]$retVal = $false # Get the current config file status [FileMirrorState]$State=$this.GetConfigStatus() if($this.Ensure -eq [Ensure]::Present) { switch($State) { {([FileMirrorState]::Same, [FileMirrorState]::SourceMissingDestinationMissing) -contains $_} { $retVal = $true; break} } } else { switch($State) { {([FileMirrorState]::DestinationMissing, [FileMirrorState]::SourceMissingDestinationMissing) -contains $_} { $retVal = $true; break} } } Write-verbose "[Test] Returning: $retVal" return $retVal } <# Returns the current status of the configuration file as the result of comparison of time stamps of the source and the destination file. #> [FileMirrorState]GetConfigStatus() { Write-Verbose "[GetConfigStatus] Source: $($this.SourcePath)" if(Test-Path "$($this.SourcePath)") { #file exists in source Write-Verbose '[GetConfigStatus] Source exists' $srcFile=Get-Item "$($this.SourcePath)" if(Test-Path "$($this.DestinationPath)") { #destination file exists - overwrite if newer Write-verbose '[GetConfigStatus] Destination exists' $dstFile=Get-Item "$($this.DestinationPath)" if($srcFile.LastWriteTime -gt $dstFile.LastWriteTime) { Write-verbose '[GetConfigStatus] Source newer' return [FileMirrorState]::SourceNewer } if($srcFile.LastWriteTime -eq $dstFile.LastWriteTime) { Write-verbose '[GetConfigStatus] Destination same' return [FileMirrorState]::Same } Write-verbose '[GetConfigStatus] Destination newer' return [FileMirrorState]::DestinationNewer } else { #destination file does not exist - copy from source Write-Verbose '[GetConfigStatus] Destination does not exist' return [FileMirrorState]::DestinationMissing } } else { Write-verbose '[GetConfigStatus] Source does not exist' if(Test-Path "$($this.DestinationPath)") { Write-verbose '[GetConfigStatus] Destination exists' return [FileMirrorState]::SourceMissing } Write-verbose '[GetConfigStatus] Destination does not exist' return [FileMirrorState]::SourceMissingDestinationMissing } } } <# This resource manages print drivers installed on the local computer according to the corresponding configuration DB (XML file). #> [DscResource()] class cPrintDriverUpdater { # The root folder where the drivers database (XML file) is stored [DscProperty(Key)] [String]$DriversRoot # An optional suffix representing the version of the drivers DB [DscProperty()] [String]$DBVersion [DscProperty(Mandatory)] [Ensure] $Ensure # The registry key where the status is stored [DscProperty()] [string]$RegConfigRoot="HKLM:\SOFTWARE\GreyCorbel\DSC\PrintHA" # The fully qualified path to an optional registry file [DscProperty()] [String]$RegFilePath # The switch controlling whether the $RegFilePath file is to be imported before installing the driver. [DscProperty()] [bool]$ApplyRegChangesBeforeDriverUpdate = $false # The Name of the global driver list [string]$DBNameRoot="DriverDatabase" [string]$DBName [void]Set() { Write-verbose '[Set] Entering' if(-not (Test-Path "$($this.RegConfigRoot)")) { New-Item -Path "$($this.RegConfigRoot)" -ItemType Directory -Force | Out-Null } if(-not [string]::IsNullOrEmpty($this.DBVersion)) { $this.DBName = $this.DBNameRoot + '_' + $this.DBVersion + ".xml" } else { $this.DBName=$this.DBNameRoot + ".xml"; } # Apply registry changes before driver update if ((-not [System.String]::IsNullOrEmpty($this.RegFilePath)) -and ($this.ApplyRegChangesBeforeDriverUpdate)) { Write-Verbose ('[Set] Applying registry file: ' + $this.RegFilePath) Update-Registry -Ensure $this.Ensure -RegFilePath $this.RegFilePath } if($this.Ensure -eq [Ensure]::Present) { if(Test-Path "$($this.DriversRoot)\$env:COMPUTERNAME`.xml") { (Update-PnPDrivers -DriversRoot $this.DriversRoot -DriversDB "$env:COMPUTERNAME`.xml") | Write-Verbose Set-ItemProperty -Path "$($this.RegConfigRoot)" -Name LastUpdated_Machine -Value ([System.IO.File]::GetLastWriteTimeUtc("$($this.DriversRoot)\$env:COMPUTERNAME`.xml")).ToFileTimeUtc() } else { (Update-PnPDrivers -DriversRoot $this.DriversRoot -DriversDB $this.DBName) | Write-Verbose Set-ItemProperty -Path "$($this.RegConfigRoot)" -Name LastUpdated_Global -Value ([System.IO.File]::GetLastWriteTimeUtc("$($this.DriversRoot)\$($this.DBName)")).ToFileTimeUtc() } } else { Write-verbose '[Set] Removing all drivers' Get-PnPDriver | Remove-PnPDriver | Out-Null # Reset cached data Set-ItemProperty -Path "$($this.RegConfigRoot)" -Name LastUpdated_Global -Value 0 Set-ItemProperty -Path "$($this.RegConfigRoot)" -Name LastUpdated_Machine -Value 0 } # Apply registry changes after driver update if ((-not [System.String]::IsNullOrEmpty($this.RegFilePath)) -and (-not $this.ApplyRegChangesBeforeDriverUpdate)) { Write-Verbose ('[Set] Applying registry file: ' + $this.RegFilePath) Update-Registry -Ensure $this.Ensure -RegFilePath $this.RegFilePath } Write-Verbose '[Set] Returning' } [cPrintDriverUpdater]Get() { Write-Verbose '[Get] Entering' Write-Verbose '[Get] Returning' return $this } [bool]Test() { Write-Verbose '[Test] Entering' [bool]$retVal=$false if($this.Ensure -eq [Ensure]::Present) { $retVal = -not ($this.GetConfigExpirationStatus()) } # Test registry if ($retVal) { $updater = New-Object -TypeName cRegistryUpdater $updater.Ensure = $this.Ensure if (-not [System.String]::IsNullOrEmpty($this.RegFilePath)) { $updater.RegFilePath = $this.RegFilePath $retVal = $updater.Test() } if ($retVal) { $dDatabaseName = Get-DriverDatabaseName -DBNameRoot $this.DBNameRoot -DriversRoot $this.DriversRoot -DBVersion $this.DBVersion [XML]$xml = Get-Content -Path $dDatabaseName -Force foreach ($driver in $xml.PrintDrivers.driver) { if ($driver.regFilePath) { $updater.RegFilePath = $driver.regFilePath $retVal = $updater.Test() if (-not $retVal) { break } } } } } #Absent always returns false Write-Verbose "[Test] Returning: $retVal" return $retVal } [bool]GetConfigExpirationStatus() { [bool]$retVal=$false [datetime]$LastUpdatedCached=[datetime]::MinValue [datetime]$LastUpdatedReal=[datetime]::MaxValue Write-Verbose '[GetConfigExpirationStatus] Entering' if(-not [string]::IsNullOrEmpty($this.DBVersion)) { $this.DBName = $this.DBNameRoot + '_' + $this.DBVersion + ".xml" } else { $this.DBName=$this.DBNameRoot + ".xml" } if(Test-Path "$($this.DriversRoot)\$env:COMPUTERNAME`.xml") { Write-Verbose '[GetConfigExpirationStatus] Machine config exists' $data=Get-ItemProperty -Path "$($this.RegConfigRoot)" -Name LastUpdated_Machine -ErrorAction SilentlyContinue if($data -ne $null) { $LastUpdatedCached=[DateTime]::FromFileTimeUtc($data.LastUpdated_Machine) } $LastUpdatedReal=[System.IO.File]::GetLastWriteTimeUtc("$($this.DriversRoot)\$env:COMPUTERNAME`.xml") } else { Write-Verbose "[GetConfigExpirationStatus] Machine config does not exist, using global: $($this.DriversRoot)\$($this.DBName)" $data=Get-ItemProperty -Path "$($this.RegConfigRoot)" -Name LastUpdated_Global -ErrorAction SilentlyContinue if($data -ne $null) { $LastUpdatedCached=[DateTime]::FromFileTimeUtc($data.LastUpdated_Global) } $LastUpdatedReal=[System.IO.File]::GetLastWriteTimeUtc("$($this.DriversRoot)\$($this.DBName)") } $retVal = ($LastUpdatedReal -gt $LastUpdatedCached) Write-Verbose "[GetConfigExpirationStatus] Cached LastUpdate: $LastUpdatedCached" Write-Verbose "[GetConfigExpirationStatus] DB LastUpdate: $LastUpdatedReal" Write-Verbose "[GetConfigExpirationStatus] Returning: $retVal" return $retVal } } # Gets full name of driver database (XML) function Get-DriverDatabaseName { param( [Parameter(Mandatory=$true)][String]$DBNameRoot, [Parameter(Mandatory=$true)][String]$DriversRoot, [Parameter(Mandatory=$false)][String]$DBVersion ) if(-not [string]::IsNullOrEmpty($DBVersion)) { $dbName = $DBNameRoot + '_' + $DBVersion + ".xml" } else { $dbName = $DBNameRoot + ".xml" } if(Test-Path "$DriversRoot\$env:COMPUTERNAME.xml") { return "$DriversRoot\$env:COMPUTERNAME.xml" } else { return "$DriversRoot\$dbName" } } # Updates registry through cRegistryUpdater resource class function Update-Registry { param( [Parameter(Mandatory)][Ensure]$Ensure, [Parameter(Mandatory)][String]$RegFilePath ) process { Write-Verbose '[Update-Registry] Entering' $updater = New-Object -TypeName cRegistryUpdater $updater.Ensure = $Ensure $updater.RegFilePath = $RegFilePath $updater.Set() Write-Verbose '[Update-Registry] Returning' } } ##### PnP API ######## Function Install-PnPDriver([String[]]$InfPath) { Format-PnPUtilOutput(pnputil -a "$InfPath") } Function Get-PnPDriver { Format-PnPUtilOutput(pnputil -e) } Function Remove-PnPDriver { Param( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [Object[]]$PnPDriver ) Process { if($PnPDriver -eq $null) {return} foreach($DriverDef in $PnpDriver) { if($DriverDef."Published Name" -ne $null) { $PublishedName=$DriverDef."Published Name" } else { $PublishedName=$DriverDef } Format-PnPUtilOutput(pnputil -d $PublishedName) } } } ##### Internals ######## Function Update-PnPDrivers { Param ( [String]$DriversRoot, [String]$DriversDB ) Process { $data=[xml](Get-Content "$DriversRoot\$DriversDB") foreach($driver in $data.PrintDrivers.driver) { Install-PnPDriver("$DriversRoot\$($driver.InfPath)") #Apply registry changes if ($driver.regFilePath) { Write-Verbose ('[Update-PnPDrivers] Applying registry file: ' + $driver.regFilePath) Update-Registry -Ensure ([Ensure]::Present) -RegFilePath $driver.regFilePath } } } } Function Format-PnPUtilOutput([String[]]$rawData) { $currentObj=new-object PSCustomObject foreach($line in $rawData) { $idx=$line.IndexOf(" : ") if($idx -eq -1) { continue } $key=$line.Substring(0,$idx) $val=$line.Substring($idx+3, $line.Length-$idx-3).Trim() if($currentObj.$key -ne $null) { $currentObj $currentObj=new-object PSCustomObject } Add-Member -InputObject $currentObj -MemberType NoteProperty -Name $key -Value $val } $currentObj } ##### Print WMI ######## Function Get-PrinterWMI { Param ( [Parameter(Mandatory=$false)] [String]$Name, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { Write-verbose "[Get] Entering Get-PrinterWMI Function" if ($Name) { $result = Get-WmiObject -Namespace Root\cimv2 -class Win32_Printer -ComputerName $ComputerName | Where-Object -Property name -EQ -Value $Name } Return $Result } } Function Get-PrintConfigurationWMI { Param ( [Parameter(Mandatory=$false)] [String]$Name, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { Write-verbose "[Get] Entering Get-PrintConfigurationWMI Function" if ($Name) { $result = Get-WmiObject -Namespace Root\cimv2 -class Win32_PrinterConfiguration -ComputerName $ComputerName | Where-Object -Property name -EQ -Value $Name } Return $Result } } Function Get-PrinterPortWMI { Param ( [Parameter(Mandatory=$false)] [String]$Name, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { $result = Get-WmiObject -Namespace Root\cimv2 -class Win32_TcpIpPrinterPort -ComputerName $ComputerName | Where-Object -Property name -imatch -Value "$Name" Return $Result } } Function Get-PrinterDriverWMI { Param ( [Parameter(Mandatory=$false)] [String]$Name, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { $Result = Get-WmiObject -Namespace Root\cimv2 -class Win32_PrinterDriver -ComputerName $ComputerName | Where-Object -Property name -imatch -Value "$Name" Return $Result } } Function add-PrinterPortWMI { Param ( [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$true)] [String]$PrinterHostAddress, [Parameter(Mandatory=$false)] [String]$PortNumber = "9100", [Parameter(Mandatory=$false)] [INT]$Protocol = 1, [Parameter(Mandatory=$False)] $SnmpEnabled = $False, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { $port = [wmiclass]"\\$ComputerName\Root\cimv2:Win32_TcpIpPrinterPort" $port.psbase.scope.options.EnablePrivileges = $true $newPort = $port.CreateInstance() $newport.name = $Name $newport.Protocol = $Protocol if ($PrinterHostAddress -ne $null) { $newport.HostAddress = $PrinterHostAddress } $newport.PortNumber = $PortNumber $newport.SnmpEnabled = $SnmpEnabled $newport.Put() $Result = Get-WmiObject -Namespace Root\cimv2 -class Win32_TcpIpPrinterPort -ComputerName $ComputerName | Where-Object -Property name -EQ -Value $Name Return $Result } } Function add-PrinterDriverWMI { Param ( [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { $printdriver = [wmiclass]"\\$ComputerName\Root\cimv2:Win32_PrinterDriver" $driver = $printdriver.CreateInstance() $driver.Name= $Name $printdriver.AddPrinterDriver($driver) $printdriver.Put() $Result = Get-WmiObject -Namespace Root\cimv2 -class Win32_PrinterDriver -ComputerName $ComputerName | Where-Object -Property name -like -Value "$Name*" | Where-Object -Property SupportedPlatform -EQ -Value $platform Return $Result } } Function add-PrinterWMI { Param ( [Parameter(Mandatory=$True)] [String]$DriverName, [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$true)] [String]$PortName, [Parameter(Mandatory=$false)] [String]$Location, [Parameter(Mandatory=$false)] [String]$Comment, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { $wmi = ([WMIClass]"\\$ComputerName\Root\cimv2:Win32_Printer") $Printer = $wmi.CreateInstance() $Printer.DriverName = $DriverName $Printer.PortName = $PortName if ($Location -ne $null) { $Printer.Location = $Location } if ($Comment -ne $null) { $Printer.Comment = $Comment } $Printer.Name = $Name #$Printer.Caption = $Name $Printer.DeviceID = $Name $Printer.Put() $Result = Get-WmiObject -Namespace Root\cimv2 -class Win32_Printer -ComputerName $ComputerName | Where-Object -Property name -EQ -Value $Name Return $Result } } Function Remove-PrinterWMI { Param ( [Parameter(Mandatory=$false)] [String]$Name, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { $result = Get-WmiObject -Namespace Root\cimv2 -class Win32_Printer -ComputerName $ComputerName | Where-Object -Property name -CMatch -Value $Name Try { $result | Remove-WmiObject } Catch { Return $Error[0] } Return $Result } } Function Remove-PrinterPortWMI { Param ( [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { $result = Get-WmiObject -Namespace Root\cimv2 -class Win32_TcpIpPrinterPort -ComputerName $ComputerName | Where-Object -Property name -EQ -Value $Name $result | Remove-WmiObject Return $Result } } Function Remove-PrinterDriverWMI { Param ( [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { if ($Name -in ((Get-PrinterWMI).DriverName)) { $UsedBy = get-printerwmi | Where-Object -Name DriverName -eq -Value $name $Message = "Cannot delete. Driver is used by printer " + $UsedBy.name Return $Message } $Result = Get-WmiObject -Namespace Root\cimv2 -class Win32_PrinterDriver -ComputerName $ComputerName | Where-Object -Property name -like -Value "$Name,*" Return $Result } } Function Set-PrinterWMI { Param ( [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$false)] [String]$Shared, [Parameter(Mandatory=$false)] [String]$ShareName, [Parameter(Mandatory=$false)] [String]$Published, [Parameter(Mandatory=$false)] [String]$Comment, [Parameter(Mandatory=$false)] [string]$Location, [Parameter(Mandatory=$false)] [String]$ComputerName = $env:COMPUTERNAME ) Process { $Printer = Get-WmiObject -Namespace Root\cimv2 -class Win32_Printer -ComputerName $ComputerName | Where-Object -Property name -EQ -Value $Name # Share/Unshare Printer Switch ($Shared) { $True { if (!$ShareName) { $ShareName = $Printer.name } $Printer.shared = $true $Printer.ShareName = $ShareName } $False { $Printer.shared = $false } Default{} } $Printer.put() # Publised/Not Published in Active Directory Switch ($Published) { $True { $Printer.Published=$true } $False { $Printer.Published=$false } Default{} } $Printer.put() # Comment Printer if ($Comment) { $Printer.Comment = $Comment } $Printer.put() #Printer Location if ($Location) { $Printer.Location = $Location } $Printer.put() $Result = Get-WmiObject -Namespace Root\cimv2 -class Win32_Printer -ComputerName $ComputerName | Where-Object -Property name -EQ -Value $Name Return $Result } } Function Set-PrintConfigurationWMI { Param ( [Parameter(Mandatory=$true)] [String]$Name, [Parameter(Mandatory=$false)] [bool]$Color, [Parameter(Mandatory=$false)] [bool]$Collation, [Parameter(Mandatory=$false)] [String]$PaperSize, [Parameter(Mandatory=$false)] [String]$DuplexingMode, [Parameter(Mandatory=$false)] [String]$PageOrientation ) Process { Write-verbose "[Set] Entering Set-PrintConfigurationWMI Function" $Dirty = 0 Add-Type -AssemblyName System.Printing $permAdminServer = ([System.Printing.PrintSystemDesiredAccess] "AdministrateServer") $permAdminPrinter = ([System.Printing.PrintSystemDesiredAccess] "AdministratePrinter") $ps = New-Object System.Printing.PrintServer $permAdminServer $queue = $ps.GetPrintQueues() | Where-Object -Property name -EQ -Value $Name $QueuePrintCapabilities = $queue.GetPrintCapabilities() $queue2 = New-Object System.Printing.PrintQueue $ps,$queue.Name,$permAdminPrinter if ($Color -ne $null) { Switch ($Color) { $True { $queue2.DefaultPrintTicket.OutputColor = "Color" $queue2.UserPrintTicket.OutputColor = "Color" $Dirty ++ } $False { $queue2.DefaultPrintTicket.OutputColor = "Monochrome" $queue2.UserPrintTicket.OutputColor = "Monochrome" $Dirty ++ } Default { Write-Host "Color parameter value unsupported!" } } } if ($Dirty -gt 0) { $queue2.Commit() $Dirty = 0 } if ($Collation -ne $null) { Switch ($Collation) { $True { $queue2.DefaultPrintTicket.Collation = "Collated" $queue2.UserPrintTicket.Collation = "Collated" $Dirty ++ } $False { $queue2.DefaultPrintTicket.Collation = "UnCollated" $queue2.UserPrintTicket.Collation = "UnCollated" $Dirty ++ } Default { Write-Host "Collation parameter value unsupported!" } } } if ($Dirty -gt 0) { $queue2.Commit() $Dirty = 0 } if ($PaperSize) { if ($PaperSize -notin ($QueuePrintCapabilities.PageMediaSizeCapability.PageMediaSizeName)) { Write-Host "PaperSize parameter value unsupported!" -ForegroundColor Yellow $QueuePrintCapabilities.PageMediaSizeCapability | Sort-Object | write-host -ForegroundColor Yellow Break } $property = New-Object System.Printing.PageMediaSize([System.Printing.PageMediaSizeName]::$PaperSize) $queue2.DefaultPrintTicket.PageMediaSize = $property $queue2.UserPrintTicket.PageMediaSize = $property $Dirty ++ if ($Dirty -gt 0) { $queue2.Commit() $Dirty = 0 } } if ($DuplexingMode) { if ($DuplexingMode -notin ($QueuePrintCapabilities.DuplexingCapability)) { Write-Host "DuplexingMode parameter value unsupported!" -ForegroundColor Yellow $QueuePrintCapabilities.DuplexingCapability | write-host -ForegroundColor Yellow } $queue2.DefaultPrintTicket.Duplexing = $DuplexingMode $queue2.UserPrintTicket.Duplexing = $DuplexingMode $Dirty ++ if ($Dirty -gt 0) { $queue2.Commit() $Dirty = 0 } } if ($PageOrientation) { if ($PageOrientation -notin ($QueuePrintCapabilities.PageOrientationCapability)) { Write-Host "PageOrientation parameter value unsupported!" -ForegroundColor Yellow $QueuePrintCapabilities.PageOrientationCapability | write-host -ForegroundColor Yellow } $queue2.DefaultPrintTicket.PageOrientation = $PageOrientation $queue2.UserPrintTicket.PageOrientation = $PageOrientation $Dirty ++ if ($Dirty -gt 0) { $queue2.Commit() $Dirty = 0 } } } } # Checks whether PrintManagement PS module is available (Windows Server 2012 or newer) function Get-PrintManagementAvailable { $pm = Get-Module -Name PrintManagement if ($pm -eq $null) { $pm = Get-Module -ListAvailable|Where-Object -Property Name -EQ -Value PrintManagement } return ($pm -ne $null) } function Get-PrinterDACLWMI { param( [Parameter(Mandatory=$true)]$printerName ) Write-Verbose '[Get-PrinterDACLWMI]Entering' $printer = Get-WmiObject -Class Win32_Printer -Filter ('name = ''' + $printerName + '''') -ErrorAction SilentlyContinue if ($printer -eq $null) { Write-Verbose ('[Set-PrinterDACLWMI]Printer not found: ' + $printerName) return '' } $sd = $printer.GetSecurityDescriptor().Descriptor $result = ([WMIClass]'Win32_SecurityDescriptorHelper').Win32SDToSDDL($sd) if ($result.ReturnValue -ne 0) { Write-Verbose ('[Set-PrinterDACLWMI]Translation of security descriptor to SDDL failed with this exit code: ' + $result.ReturnValue) return '' } return $result.SDDL } # Parses DACL from JSON string and updates security descriptor of the printer function Set-PrinterDACL { param( [Parameter(Mandatory=$true)][String]$printerName, [Parameter(Mandatory=$true)][String]$jsonDACL, [Parameter(Mandatory=$false)][bool]$noDefaultAdminPermissions = $false ) Write-Verbose '[SetPrinterDACL]Entering' # Use PrintManagement PS module when available if (Get-PrintManagementAvailable) { $p = Get-Printer -Name $printerName -Full -ErrorAction SilentlyContinue if ($p -eq $null) { Write-Verbose ('[SetPrinterDACL]Unable to get printer object: ' + $printerName) return $false } $origSDDL = $p.PermissionSDDL $origDACL = [System.Text.RegularExpressions.Regex]::Matches($origSDDL,'D:\w*\([\w\W]+\)') $newDACL = Get-SDDLfromJsonDACL -noDefaultAdminPermissions $noDefaultAdminPermissions -jsonDACL $jsonDACL $sddl = $origSDDL.Replace($origDACL,$newDACL) try { Write-Verbose ('[SetPrinterDACL]Setting printer security descriptor in SDDL format: ' + $sddl) Set-Printer -Name $printerName -PermissionSDDL $sddl } catch { Write-Verbose '[SetPrinterDACL]Setting printer security descriptor failed' return $false } } # Use WMI to get/set DACL else { $origSDDL = Get-PrinterDACLWMI -printerName $printerName if ([System.String]::IsNullOrEmpty($origSDDL)) { Write-Verbose '[SetPrinterDACL]Reading current SDDL failed' return $false } $origDACL = [System.Text.RegularExpressions.Regex]::Matches($origSDDL,'D:\w*\([\w\W]+\)') $newDACL = Get-SDDLfromJsonDACL -noDefaultAdminPermissions $noDefaultAdminPermissions -jsonDACL $jsonDACL $sddl = $origSDDL.Replace($origDACL,$newDACL) Write-Verbose ('[SetPrinterDACL]Setting printer security descriptor in SDDL format: ' + $sddl) if (-not (Set-PrinterDACLWMI -printerName $printerName -desiredSDDL $sddl)) { Write-Verbose '[SetPrinterDACL]Setting printer security descriptor failed' return $false } } Write-Verbose '[SetPrinterDACL]Returning' return $true } # Updates DACL of the printer by using WMI classes (Windows Server 2008 / R2) function Set-PrinterDACLWMI { param( [Parameter(Mandatory=$true)]$printerName, [Parameter(Mandatory=$true)]$desiredSDDL ) Write-Verbose '[Set-PrinterDACLWMI]Entering' # Parse SDDL and build new DACL $rawSD = New-Object System.Security.AccessControl.RawSecurityDescriptor($desiredSDDL) -ErrorAction SilentlyContinue if ($rawSD -eq $null) { Write-Verbose ('[Set-PrinterDACLWMI]Unable to parse SDDL: ' + $desiredSDDL) return $false } $newDACL = @() foreach ($ace in $rawSD.DiscretionaryAcl) { $newAce = ([WMIClass] "Win32_Ace").CreateInstance() $trustee = ([WMIClass] "Win32_Trustee").CreateInstance() $sid = $ace.SecurityIdentifier [byte[]] $sidArray = ,0 * $sid.BinaryLength $sid.GetBinaryForm($SIDArray,0) $trustee.SID = $sidArray $newAce.Trustee = $trustee $newAce.AccessMask = $ace.AccessMask $newAce.AceType = $ace.AceType $newAce.AceFlags = $ace.AceFlags $newDACL += $newAce } # Replace DACL in the original security descriptor $printer = Get-WmiObject -Class Win32_Printer -Filter ('name = ''' + $printerName + '''') -ErrorAction SilentlyContinue if ($printer -eq $null) { Write-Verbose ('[Set-PrinterDACLWMI]Printer not found: ' + $printerName) return $false } $sd = $printer.GetSecurityDescriptor().Descriptor $sd.DACL = $newDACL $sd.ControlFlags = 0x0004 $printer.psbase.Scope.Options.EnablePrivileges = $true $result = $printer.SetSecurityDescriptor($sd) switch ($result.ReturnValue) { 0 { Write-Verbose '[Set-PrinterDACLWMI]DACL successfully set' } 2 { Write-Verbose '[Set-PrinterDACLWMI]Setting DACL failed. The user does not have access to the requested information.'; return $false } 8 { Write-Verbose '[Set-PrinterDACLWMI]Setting DACL failed. Unknown failure.'; return $false } 9 { Write-Verbose '[Set-PrinterDACLWMI]Setting DACL failed. The user does not have adequate privileges to execute the method.'; return $false } 21 {Write-Verbose '[Set-PrinterDACLWMI]Setting DACL failed. A parameter specified in the method call is not valid.'; return $false } default { Write-Verbose '[Set-PrinterDACLWMI]Setting DACL failed.'; return $false } } return $true } # Parses DACL in JSON format and returns SDDL string function Get-SDDLfromJsonDACL { param( [Parameter(Mandatory=$true)][String]$jsonDACL, [Parameter(Mandatory=$false)][bool]$noDefaultAdminPermissions=$false ) Write-Verbose '[Get-SDDLfromJsonDACL]Entering' $dacl = ConvertFrom-Json -InputObject $jsonDACL $disAcl = New-Object System.Security.AccessControl.DiscretionaryAcl($true,$false,0) foreach ($ace in $dacl) { $validAce = $true [System.Security.Principal.SecurityIdentifier]$sid = $null [System.Security.AccessControl.AceType]$accessType = 0 [Int32]$accessMask = 0 [System.Security.AccessControl.InheritanceFlags]$inheritanceFlags = [System.Security.AccessControl.InheritanceFlags]::None [System.Security.AccessControl.PropagationFlags]$propagationFlags = [System.Security.AccessControl.PropagationFlags]::None # Parse SID if ($ace.SecurityIdentifier) { $sid = New-Object System.Security.Principal.SecurityIdentifier($ace.SecurityIdentifier) } elseif ($ace.PrincipalName) { Write-Verbose ('[Get-SDDLfromJsonDACL]Converting PrincipalName to SID: ' + $ace.PrincipalName) try { $nt = New-Object System.Security.Principal.NTAccount($ace.PrincipalName) $sid = $nt.Translate([System.Security.Principal.SecurityIdentifier]) } catch { Write-Verbose '[Get-SDDLfromJsonDACL]Converting PrincipalName to SID failed.' $validAce = $false } } else { Write-Verbose '[Get-SDDLfromJsonDACL]Missing SecurityIdentifier or PrincipalName key.' $validAce = $false } # Parse qualifier if ($ace.AccessType) { switch ($ace.AccessType.ToUpper()) { 'ALLOW' { $accessType = [System.Security.AccessControl.AccessControlType]::Allow } 'DENY' { $accessType = [System.Security.AccessControl.AccessControlType]::Deny } default { Write-Verbose ('[Get-SDDLAceList]Invalid AccessType value: ' + $ace.AccessType); $validAce = $false } } } else { Write-Verbose '[Get-SDDLfromJsonDACL]Missing AccessType key.' $validAce = $false } if (-not [System.String]::IsNullOrEmpty($ace.AccessPermissions)) { switch ($ace.AccessPermissions.ToUpper()) { 'PRINT' { $permissions = 'SWRC' } 'MANAGE DOCUMENTS' { $permissions = 'RPWPSDRCWDWO' } 'MANAGE PRINTER' { $permissions = 'LCSWSDRCWDWO' } default { $permissions = $ace.AccessPermissions } } try { $sd = New-Object System.Security.AccessControl.RawSecurityDescriptor(('D:(A;;'+$permissions+';;;SY)')) $accessMask = $sd.DiscretionaryAcl[0].AccessMask } catch { Write-Verbose ('[Get-SDDLfromJsonDACL]Invalid AccessPermissions value: ' + $ace.AccessPermissions) $validAce = $false } } else { Write-Verbose '[Get-SDDLfromJsonDACL]Missing AccessPermissions key.' $validAce = $false } if (-not [System.String]::IsNullOrEmpty($ace.AceFlags)) { try { $sd = New-Object System.Security.AccessControl.RawSecurityDescriptor(('D:(A;'+$ace.AceFlags+';GA;;;SY)')) $inheritanceFlags = $sd.DiscretionaryAcl[0].InheritanceFlags $propagationFlags = $sd.DiscretionaryAcl[0].PropagationFlags } catch { Write-Verbose ('[Get-SDDLfromJsonDACL]Invalid AceFlags value: ' + $ace.AceFlags) $validAce = $false } } if ($validAce) { Write-Verbose ('[Get-SDDLfromJsonDACL]Adding ACE: ' + $accessType.ToString() + ';' + $sid.Value + ';' + $accessMask.ToString() + ';' + $inheritanceFlags.ToString() + ';' + $propagationFlags.ToString()) $disAcl.AddAccess($accessType,$sid,$accessMask,$inheritanceFlags,$propagationFlags) } } Write-Verbose ('[Get-SDDLfromJsonDACL]Count of parsed ACEs: ' + $disAcl.Count.ToString()) $ownerSID = [System.Security.Principal.NTAccount]::new('SYSTEM').Translate([System.Security.Principal.SecurityIdentifier]) $groupSID = [System.Security.Principal.NTAccount]::new('Everyone').Translate([System.Security.Principal.SecurityIdentifier]) $commonSD = New-Object System.Security.AccessControl.CommonSecurityDescriptor($true,$false,[System.Security.AccessControl.ControlFlags]::None,$ownerSID,$groupSID,$null,$disAcl) $sddl = $commonSD.GetSddlForm([System.Security.AccessControl.AccessControlSections]::Access) # Append default admin permissions if not explicitly specified if (-not $noDefaultAdminPermissions) { # Built-in administrators if ([System.Text.RegularExpressions.Regex]::IsMatch($sddl,'\(*;BA\)') -eq $false) { $sddl += '(A;;LCSWSDRCWDWO;;;BA)' } # Local administrator if ([System.Text.RegularExpressions.Regex]::IsMatch($sddl,'\(*;LA\)') -eq $false) { $sddl += '(A;;LCSWSDRCWDWO;;;LA)' } # System account if ([System.Text.RegularExpressions.Regex]::IsMatch($sddl,'\(*;SY\)') -eq $false) { $sddl += '(A;;LCSWSDRCWDWO;;;SY)' } } Write-Verbose '[Get-SDDLfromJsonDACL]Returning' return $sddl } <# This resoure manages print queues installed on the local computer. It enables to install/remove a print queue and configure its basic properties. #> [DscResource()] class cPrinter { # The name of the print queue [DscProperty(Key)] [String]$Name [DscProperty(Mandatory)] [Ensure] $Ensure # The printer port managed through Win32_TcpIpPrinterPort WMI class. [DscProperty(Mandatory)] [string]$IPAddress # The name of the print driver. [DscProperty(Mandatory)] [string]$DriverName # The print server farm name (needs to be contained in the OptionalNames value in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters) [DscProperty(Mandatory)] [string]$FarmName # If this property has a value then the print queue is shared under this name. [DscProperty()] [string]$ShareName # The location of the printer. [DscProperty()] [string]$Location # An additional comment displayed with the printer. [DscProperty()] [string]$Comment # Boolean value controlling that the print queue is not to be removed when the server is removed from the farm. [DscProperty()] [bool]$KeepWhenLeavingFarm # [DscProperty()] [bool]$Published # Boolean value controlling whether color printing is enabled or not [DscProperty()] [bool]$Color # String in JSON format specifying the DACL [DscProperty()] [String]$DaclInJSONFormat # Controls whether the resource adds default permissions to administrators or not [DscProperty()] [bool]$NoDefaultAdminPermissions=$false [void] Set() { Write-verbose '[Set] Entering' $farms = $this.GetLocalFarms() $this.FixProps() $Printer=Get-PrinterWMI -Name $this.Name -ErrorAction SilentlyContinue $PrintConfiguration=Get-PrintConfigurationWMI -Name $this.Name -ErrorAction SilentlyContinue $ColorConfiguration = $null [PrinterAction]$Action=[PrinterAction]::None if($this.Ensure -eq [Ensure]::Present) { [bool]$ShallCreatePrinter=$false if(($Farms -contains $this.FarmName) -and ($Printer -eq $null)) { $Action=[PrinterAction]::Create } if(($Farms -notcontains $this.FarmName) -and ($Printer -ne $null) -and (-not $this.KeepWhenLeavingFarm)) { $Action=[PrinterAction]::Remove } } else #Absent { if(($Farms -contains $this.FarmName) -and ($Printer -ne $null)) { $Action=[PrinterAction]::Remove } } switch($Action) { 'Create' { if((Get-PrinterPortWMI -Name $this.IPAddress -ErrorAction SilentlyContinue) -eq $null) { Write-Verbose '[Set] Port does not exist' Add-PrinterPortWMI -Name $this.IPAddress -PrinterHostAddress $this.IPAddress } if((Get-PrinterDriverWMI -Name $this.DriverName -ErrorAction SilentlyContinue)-eq $null) { Write-Verbose '[Set] Driver does not exist' Add-PrinterDriverWMI -Name $this.DriverName } Add-PrinterWMI -DriverName $this.DriverName -Name $this.Name -PortName $this.IPAddress -Location $this.Location -Comment $this.Comment if(-not [string]::IsNullOrEmpty($this.ShareName)) { #create shared printer Write-Verbose "[Set] Creating shared printer with name $($this.Name) and shared name $($this.ShareName)" Set-printerWMI -Name $this.Name -Shared $true -ShareName $this.ShareName -Published $this.Published } if(-not [string]::IsNullOrEmpty($this.Color)) { #set Color output mode for printing defaults Write-Verbose "[Set] Setting Color Mode for printing defaults $($this.Name) to $($this.Color)" Set-PrintConfigurationWMI -Name $this.Name -Color $this.Color } # Discreationary Access Control List (DACL) if(-not [String]::IsNullOrEmpty($this.DaclInJSONFormat)) { Set-PrinterDACL -printerName $this.Name -jsonDACL $this.DaclInJSONFormat -noDefaultAdminPermissions $this.NoDefaultAdminPermissions } break; } 'Remove' { Write-Verbose '[Set] Printer should not exist -> removing' if($Printer -ne $null) { Write-Verbose '[Set] Printer should not exist -> removing' Remove-PrinterWMI -Name $this.Name } if((Get-PrinterPortWMI -Name $this.IPAddress -ErrorAction SilentlyContinue) -ne $null) { Write-Verbose '[Set] Printer should not exist -> removing port as well' Remove-PrinterPortWMI -Name $this.IPAddress } #we do not remove printer driver unless this was the last printer using it #if((Get-PrinterWMI | ?{$_.DriverName -eq $this.DriverName}) -eq $null) #{ # Write-Verbose "[Set]Last printer using driver $($this.DriverName) -> removing driver" # Remove-PrinterDriverWMI -Name $this.DriverName #} break; } default { #keep status quo - just update properties if needed if($Printer -ne $null) { if((-not $Printer.Shared) -and (-not [string]::IsNullOrWhiteSpace($this.ShareName))) { Write-Verbose "[Set] Sharing the printer with share name $($this.ShareName)" Set-PrinterWMI -Name $this.Name -Shared $true -ShareName $this.ShareName } if($Printer.Shared -and [string]::IsNullOrWhiteSpace($this.ShareName)) { Write-Verbose "[Set] UnSharing the printer " Set-PrinterWMI -Name $this.Name -Shared $false } if(-not [string]::IsNullOrWhiteSpace($this.Comment) -and ($Printer.Comment -ne $this.Comment)) { Write-Verbose "[Set] Setting the printer description" Set-PrinterWMI -Name $this.Name -Comment $this.Comment } if(-not [string]::IsNullOrWhiteSpace($this.Location) -and ($printer.Location -ne $this.Location)) { Write-Verbose "[Set] Setting the printer location" Set-PrinterWMI -Name $this.Name -Location $this.Location } if($Printer.Published -ne $this.Published) { Write-Verbose "[Set] Setting the printer publishing status" Set-PrinterWMI -Name $this.Name -Published $this.Published } Switch ($PrintConfiguration.Color) { "1" {$ColorConfiguration = $false} "2" {$ColorConfiguration = $true} default {Write-Verbose "[Set] No match on Switch"} } if($ColorConfiguration -ne $this.Color) { Write-Verbose "[Set] Setting the printer output color mode" Set-PrintConfigurationWMI -Name $this.Name -Color $this.Color } # Discreationary Access Control List (DACL) if(-not [String]::IsNullOrEmpty($this.DaclInJSONFormat)) { Set-PrinterDACL -printerName $this.Name -jsonDACL $this.DaclInJSONFormat -noDefaultAdminPermissions $this.NoDefaultAdminPermissions } } break; } } Write-verbose '[Set] Returning' } [cPrinter]Get() { Write-verbose '[Get] Entering' $Printer=Get-PrinterWMI -Name $this.Name -ErrorAction SilentlyContinue # $PrintConfiguration=Get-PrintConfigurationWMI -Name $this.Name -ErrorAction SilentlyContinue if($Printer -eq $null) { Write-Verbose '[Get] Printer does not exist' $this.Ensure='Absent' } else { Write-Verbose '[Get] Printer exists' $this.Ensure='Present' } return $this } [bool]Test() { Write-verbose '[Test] Entering' $farms = $this.GetLocalFarms() $this.FixProps() [bool]$retVal=$false $Printer=Get-PrinterWMI -Name $this.Name -ErrorAction SilentlyContinue $PrintConfiguration=Get-PrintConfigurationWMI -Name $Printer.Name -ErrorAction SilentlyContinue New-Variable -Name ColorConfiguration if($this.Ensure -eq [Ensure]::Present) { if(($Printer -ne $null) -and ($farms -contains $this.FarmName)) #printer is there and server is member of the farm { $retVal=$true Write-Verbose "[Test] Present: Present AND InFarm" } if(($printer -eq $null) -and ($farms -notcontains $this.FarmName)) #server is not there and server is not member of the farm { $retVal=$true Write-Verbose "[Test] Present: NOT Present AND NOT InFarm" } if(($printer -ne $null) -and ($farms -notcontains $this.FarmName) -and ($this.KeepWhenLeavingFarm)) { $retVal=$true Write-Verbose "[Test] Present: Present and NOT InFarm AND KeepeWhenLeavingFarm" } if($retVal) { if($Printer -ne $null) { if($Printer.Location -ne $this.Location) { $retVal=$false Write-Verbose "[Test] Present: PropTest: Location does not match" } if($Printer.Comment -ne $this.Comment) { $retVal=$false Write-Verbose "[Test] Present: PropTest: Comment does not match" } if($printer.Shared) { if($printer.ShareName -ne $this.shareName) { $retVal=$false Write-Verbose "[Test] Present: PropTest: ShareName does not match" } if([string]::IsNullOrWhiteSpace($this.ShareName)) { $retVal=$false Write-Verbose "[Test] Present: PropTest: We are shared but should not be" } } if((-not $printer.Shared) -and (-not [string]::IsNullOrWhiteSpace($this.ShareName))) { $retVal=$false Write-Verbose "[Test] Present: PropTest: We are not shared but should be" } if($Printer.Published -ne $this.Published) { $retVal=$false Write-Verbose "[Test] Present: PropTest: Published does not match" } if($PrintConfiguration -ne $null) { Switch ($PrintConfiguration.Color) { "1" {$ColorConfiguration = $false} "2" {$ColorConfiguration = $true} default {Write-Verbose "[Test] Present: No Match on Switch"} } if ($ColorConfiguration -ne $this.Color) { Write-Verbose "[Test] Present: PropTest: Output Color does not match" $retVal=$false } } } } } else #Absent { if($Printer -eq $null) { $retVal = $true Write-Verbose "[Test] Absent: NOT Present" } } # Compare security descriptors if ($retVal -and ($this.Ensure -eq [Ensure]::Present) -and (-not [System.String]::IsNullOrEmpty($this.DaclInJSONFormat))) { Write-Verbose '[Test] Comparing DACL' $newSDDL = Get-SDDLfromJsonDACL -jsonDACL $this.DaclInJSONFormat -noDefaultAdminPermissions $this.NoDefaultAdminPermissions $oriSDDL = '' if (Get-PrintManagementAvailable) { $p = Get-Printer -Name $this.Name -Full -ErrorAction SilentlyContinue if ($p) { $oriSDDL = $p.PermissionSDDL } } else { $oriSDDL = Get-PrinterDACLWMI -printerName $this.Name } Write-Verbose ('[Test] Present DACL: ' + $oriSDDL) Write-Verbose ('[Test] Desired DACL: ' + $newSDDL) $retVal = ([System.String]::Compare($newSDDL,$oriSDDL,$true) -eq 0) } Write-verbose "[Test] Returning: $retVal" return $retVal } [string[]]GetLocalFarms() { [Microsoft.Win32.RegistryKey]$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("System\CurrentControlSet\Services\LanManServer\Parameters", $true) $farms = $key.GetValue("OptionalNames") #if value does not exist, use empty array if($farms -eq $null) {$farms=@()} return $farms } [void]FixProps() { if($this.Comment -eq [string]::Empty) { $this.Comment=$null } if($this.Location -eq [string]::Empty) { $this.Location=$null } if($this.ShareName -eq [string]::Empty) { $this.ShareName=$null } } } <# This resource enables to manage registry keys and values by means of importing a .reg file. #> [DscResource()] class cRegistryUpdater { # The fully qualified path to the .reg file [DscProperty(Key)] [string]$RegFilePath [DscProperty(Mandatory)] [Ensure] $Ensure [System.Array]$regKeys [cRegistryUpdater]Get() { Write-verbose '[Get] Entering' Write-verbose '[Get] Returning' return $this } [void]Set() { Write-Verbose '[Set] Entering' # Import registry file if ($this.Ensure -eq [Ensure]::Present) { $regFile = Get-Item -Path $this.RegFilePath -Force -ErrorAction SilentlyContinue if ($regFile) { $regFile = $regFile.FullName Write-Verbose ('[Set] Importing file: ' + $regFile) Start-Process -FilePath reg.exe -ArgumentList 'import',$regFile -NoNewWindow -Wait -ErrorAction SilentlyContinue } else { Write-Verbose ('[Set] Registry file not found: ' + $this.RegFilePath) } } # Delete all keys read from registry file else { if ($this.LoadRegFile($this.RegFilePath)) { foreach ($k in $this.regKeys) { $key = Get-Item -Path ('Registry::' + $k.Key) -Force -ErrorAction SilentlyContinue if ($key) { Write-Verbose ('[Set] Deleting key: ' + $k.Key) Remove-Item -Path $key.PSPath -Recurse -Force -ErrorAction SilentlyContinue } else { Write-Verbose ('[Set] Key does not exist: ' + $k.Key) } } } else { Write-Verbose ('[Set] Reading registry file failed: ' + $this.RegFilePath) } } Write-Verbose '[Set] Returning' } [bool]Test() { [bool]$retVal = $false # Registry file loaded if ($this.LoadRegFile($this.RegFilePath)) { if ($this.Ensure -eq [Ensure]::Present) { $retVal = $this.TestRegPresent() } else { $retVal = $this.TestRegAbsent() } return $retVal } # Loading registry file failed else { return $retVal #FALSE } } # Validates registry entries: [Ensure]::Present [bool]TestRegPresent() { Write-Verbose '[TestRegPresent] Entering' foreach ($k in $this.regKeys) { $key = Get-Item -Path ('Registry::' + $k.Key) -Force -ErrorAction SilentlyContinue if (($k.Operator -eq '') -and ($key -eq $null)) { Write-Verbose ('[TestRegPresent] Key not found: ' + $k.Key) return $false } if (($k.Operator -eq '-') -and ($key -ne $null)) { Write-Verbose ('[TestRegPresent] Key exists: ' + $k.Key) return $false } } Write-Verbose '[TestRegPresent] Returning' return $true } # Validates registry entries: [Ensure]::Absent [bool]TestRegAbsent() { Write-Verbose '[TestRegAbsent] Entering' foreach ($k in $this.regKeys) { $key = Get-Item -Path ('Registry::' + $k.Key) -Force -ErrorAction SilentlyContinue if ($key -ne $null) { Write-Verbose ('[TestRegAbsent] Key exists: ' + $k.Key) return $false } } Write-Verbose '[TestRegAbsent] Returning' return $true } # Loads registry file and imports keys [bool]LoadRegFile([String]$regFile) { $this.regKeys = @() Write-Verbose "[LoadRegFile] Checking registry file: $regFile" $f = Get-Item -Path $regFile -ErrorAction SilentlyContinue if ($f -eq $null) { return $false } $i = 0 $curKey = '' foreach ($row in (Get-Content -Path $regFile -Force -Encoding Unicode -ErrorAction SilentlyContinue)) { if ([System.Text.RegularExpressions.Regex]::IsMatch($row,'^\[\-?HK[\w|\W]+\]$')) { $curKey = [System.Text.RegularExpressions.Regex]::Match($row,'(?<=^\[\-?)HK[\w|\W]+(?=\]$)').Value if ($curKey -ne "") { $key = @{ Key = $curKey; Operator = [System.Text.RegularExpressions.Regex]::Match($row,'(?<=\[)\-').Value } $this.regKeys += $key $i++ Write-Verbose "[LoadRegFile] Read key (#$i): $curKey" } } } Write-Verbose '[LoadRegFile] Returning' return $true } } |