Category Archives: Powershell

Add Printer Script Unique Print Drivers

For an automated installation it was necessary to have an up to date list of the printer drivers. As print manufactorers occassionally add a dozen printer drivers into one setup we wanted to have a script that connects to all on duty print servers. I used the function Add-PrinterDriver for this cause. In the RES Automation Manager script there was some code necessary to first add a feature if it wasn’t present:

Import-Module ServerManager
$RSATADPowerShell = Get-WindowsFeature -Name "RSAT-AD-PowerShell"
If ($RSATADPowerShell.Installed -match "False"){
Add-WindowsFeature RSAT-AD-PowerShell}

Then I added the function in another script:

Import-Module ActiveDirectory
#Functie Add-PrinterDriver
function Add-PrinterDriver { 
 [CmdletBinding()] 
         Param( 
              [Parameter(Mandatory=$true)] 
              [string] $PrintServer, 
              [switch] $Clean 
             ) 

#Collecting all shared printer objects from the specified print server 
$allprinters = @(Get-WmiObject win32_printer -ComputerName $PrintServer -Filter 'shared=true') 
#Defining all unique printer drivers from the specified print server 
$drivers = @($allprinters | Select-Object drivername -Unique) 
#Defining a collection containing the first printer object using a unique printer driver 
$printers = @() 
foreach ($item in $drivers){ 
$printers += @($allprinters | Where-Object {$_.drivername -eq $item.drivername})[0] 
} 

#Collecting locally installed drivers 
$localdrivers = @() 
foreach ($driver in (Get-WmiObject Win32_PrinterDriver)){ 
$localdrivers += @(($driver.name -split ",")[0]) 
} 

#Initializing the CurrentPrinter variable for use with Write-Progress 
$CurrentPrinter = 1 

#Looping through the printer objects collection, installing those who are not already installed on the local computer 
foreach ($printer in $printers) { 

Write-Progress -Activity "Installing printers..." -Status "Current printer: $($printer.name)" -Id 1 -PercentComplete (($CurrentPrinter/$printers.count) * 100) 

#Create hash-table for output object 
$outputobject = @{} 
$outputobject.drivername = $printer.drivername 

$locallyinstalled = $localdrivers | Where-Object {$_ -eq $printer.drivername} 
if (-not $locallyinstalled) { 
Write-Verbose "$($printer.drivername) is not installed locally" 
$AddPrinterConnection = Invoke-WmiMethod -Path Win32_Printer -Name AddPrinterConnection -ArgumentList ([string]::Concat('\', $printer.__SERVER, '', $printer.ShareName)) -EnableAllPrivileges 
$outputobject.returncode = $AddPrinterConnection.ReturnValue 
} 
else 
{ 
Write-Verbose "$($printer.drivername) is already installed locally" 
$outputobject.returncode = "Already installed" 
} 

#Create a new object for each driver, based on the outputobject hash-table 
New-Object -TypeName PSObject -Property $outputobject 

$CurrentPrinter ++ 

} 

#Deletes all printer connections for the current user 
if ($clean) { 
$printers = Get-WmiObject Win32_Printer -EnableAllPrivileges -Filter network=true 
if ($printers) { 
foreach ($printer in $printers) { 
$printer.Delete() 
} 
} 
} 
}

$OS = (Get-WmiObject Win32_OperatingSystem).Caption.replace("Microsoft ","").Replace("Standard ","Standard").Replace("Enterprise ","Enterprise").Replace("Datacenter ","Datacenter")
$ADPrintservers = Get-ADComputer -Filter * -Property * |Where {$_.name -like "PR*"} | select DNSHostName,OperatingSystem
$Pingable =@()
foreach ($computer in $ADPrintservers){
if (Test-Connection $Computer.DNSHostName -quiet) { $Pingable += $Computer}}
foreach ($Computer in $Pingable){
If ($OS -contains $Computer.OperatingSystem){
Add-PrinterDriver -Printserver $Computer.DNSHostName}}

The script above enumerates all servers starting with PR*. Next this script test whether the server is pingable or not. You could enter credentials if you disabled pinging to the Test-Connection command. Next it validates if the server has the same OS as the print server. Some print servers are around for the 32 bit environment. You can also add a filter for that. At the end it deletes the space that is somehow added to the replace part of OS variable.  The bare function is like this:

function Add-PrinterDriver { 
 [CmdletBinding()] 
         Param( 
              [Parameter(Mandatory=$true)] 
              [string] $PrintServer, 
              [switch] $Clean 
             ) 

#Collecting all shared printer objects from the specified print server 
$allprinters = @(Get-WmiObject win32_printer -ComputerName $PrintServer -Filter 'shared=true') 
#Defining all unique printer drivers from the specified print server 
$drivers = @($allprinters | Select-Object drivername -Unique) 
#Defining a collection containing the first printer object using a unique printer driver 
$printers = @() 
foreach ($item in $drivers){ 
$printers += @($allprinters | Where-Object {$_.drivername -eq $item.drivername})[0] 
} 

#Collecting locally installed drivers 
$localdrivers = @() 
foreach ($driver in (Get-WmiObject Win32_PrinterDriver)){ 
$localdrivers += @(($driver.name -split ",")[0]) 
} 

#Initializing the CurrentPrinter variable for use with Write-Progress 
$CurrentPrinter = 1 

#Looping through the printer objects collection, installing those who are not already installed on the local computer 
foreach ($printer in $printers) { 

Write-Progress -Activity "Installing printers..." -Status "Current printer: $($printer.name)" -Id 1 -PercentComplete (($CurrentPrinter/$printers.count) * 100) 

#Create hash-table for output object 
$outputobject = @{} 
$outputobject.drivername = $printer.drivername 

$locallyinstalled = $localdrivers | Where-Object {$_ -eq $printer.drivername} 
if (-not $locallyinstalled) { 
Write-Verbose "$($printer.drivername) is not installed locally" 
$AddPrinterConnection = Invoke-WmiMethod -Path Win32_Printer -Name AddPrinterConnection -ArgumentList ([string]::Concat('\', $printer.__SERVER, '', $printer.ShareName)) -EnableAllPrivileges 
$outputobject.returncode = $AddPrinterConnection.ReturnValue 
} 
else 
{ 
Write-Verbose "$($printer.drivername) is already installed locally" 
$outputobject.returncode = "Already installed" 
} 

#Create a new object for each driver, based on the outputobject hash-table 
New-Object -TypeName PSObject -Property $outputobject 

$CurrentPrinter ++ 

} 

#Deletes all printer connections for the current user 
if ($clean) { 
$printers = Get-WmiObject Win32_Printer -EnableAllPrivileges -Filter network=true 
if ($printers) { 
foreach ($printer in $printers) { 
$printer.Delete() 
} 
} 
} 
}

This function lets powershell connect to the printserver. It does a query on all shared printers. Then it sorts the results to unique values. At last it connects to that printer which causes the driver to be installed. There is a group policy necessary for this to work. The following policy settings are mandatory:

PointAndPrintRestrictions

 

This is a computer policy located at Computer Configuration –> Windows Settings –> Printers –> Point and Print Restrictions

Random Password Generator

Generates strong passwords

PS1:

$length = 9
For ($a=48;$a –le 122;$a++) {$ascii+=,[char][byte]$a }
Function GET-Temppassword() {

Param(

[int]$length=10,

[string[]]$sourcedata

)

For ($loop=1; $loop –le $length; $loop++) {

            $TempPassword+=($sourcedata | GET-RANDOM)

            }

return $TempPassword

}

For ($a=48;$a –le 122;$a++) {$ascii+=,[char][byte]$a }

GET-Temppassword –length $Length –sourcedata $ascii

Optional Function:

Function GET-Temppassword() {

Param(

[int]$length=10,

[string[]]$sourcedata

)

For ($loop=1; $loop –le $length; $loop++) {

            $TempPassword+=($sourcedata | GET-RANDOM)

            }

return $TempPassword

}

ZIP:

 

Setting User logon hours

To set the user logon hours to 24×7 run the following script:

PS1:

Import-Module ActiveDirectory
$gebruikerslijst = Get-aduser -Filter * -Properties DistinguishedName

Foreach ($gebruiker in $gebruikerslijst){
$user = [ADSI]"LDAP://$gebruiker"
[byte[]]$hours = @(255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255)
$user.logonhours.value = $hours
$user.setinfo() 
}

Each byte represents 8 hours. The first byte start at 1 am at sunday untill 9 am at sunday. This next is byte is from 9 am untill 17 pm at sunday and so forth. Each byte represents of course 8 bit. Each bit is an hour. So to deny access on the first hour one should use 254.

ZIP:

Logonhours

IP-address converter

In een Synology kan men IP-adressen blokkeren op basis van een lijst. Deze lijst moet alleen ip-adressen bevatten. Er kunnen geen subnets of iets dergelijk opgegeven worden. Met een Powershell script zijn deze ip-adressen om te zetten. Ga voor een lijst naar deze site. Selecteer een land, bijvoorbeeld China. Selecteer de Netmask variant en gooi deze in een CSV. Importeer vervolgens de Output in de automatisch blokkeren lijst. Dit gaat via het configuratie scherm –> Beveiliging –> Automatisch blokkeren –> Blokkeren –> Importeer lijst

 

PS1:

<#
.SYNOPSIS
Imports function for Get-IPrange. Imports CSV. Export List of IP-addresses. Expect XML file with content. Expects CSV file with Subnets

.NOTES
File Name : IPrangeconverter.ps1
Author    : Steven van den Berg (Bexit)
Date      : 9:00 Vrijdag 14 januari 2014
Requires  : PowerShell v3.0
Tag       : PowerShell, Get-IPrange

#>

#Function
function Get-IPrange 
{ 
<#  
  .SYNOPSIS   
    Get the IP addresses in a range  
  .EXAMPLE  
   Get-IPrange -start 192.168.8.2 -end 192.168.8.20  
  .EXAMPLE  
   Get-IPrange -ip 192.168.8.2 -mask 255.255.255.0  
  .EXAMPLE  
   Get-IPrange -ip 192.168.8.3 -cidr 24  
#>  

param  
(  
  [string]$start,  
  [string]$end,  
  [string]$ip,  
  [string]$mask,  
  [int]$cidr  
)  

function IP-toINT64 () {  
  param ($ip)  

  $octets = $ip.split(".")  
  return [int64]([int64]$octets[0]*16777216 +[int64]$octets[1]*65536 +[int64]$octets[2]*256 +[int64]$octets[3])  
}  

function INT64-toIP() {  
  param ([int64]$int)  

  return (([math]::truncate($int/16777216)).tostring()+"."+([math]::truncate(($int%16777216)/65536)).tostring()+"."+([math]::truncate(($int%65536)/256)).tostring()+"."+([math]::truncate($int%256)).tostring() ) 
}  

if ($ip) {$ipaddr = [Net.IPAddress]::Parse($ip)}  
if ($cidr) {$maskaddr = [Net.IPAddress]::Parse((INT64-toIP -int ([convert]::ToInt64(("1"*$cidr+"0"*(32-$cidr)),2)))) }  
if ($mask) {$maskaddr = [Net.IPAddress]::Parse($mask)}  
if ($ip) {$networkaddr = new-object net.ipaddress ($maskaddr.address -band $ipaddr.address)}  
if ($ip) {$broadcastaddr = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $maskaddr.address -bor $networkaddr.address))}  

if ($ip) {  
  $startaddr = IP-toINT64 -ip $networkaddr.ipaddresstostring  
  $endaddr = IP-toINT64 -ip $broadcastaddr.ipaddresstostring  
} else {  
  $startaddr = IP-toINT64 -ip $start  
  $endaddr = IP-toINT64 -ip $end  
}  

for ($i = $startaddr; $i -le $endaddr; $i++)  
{  
  INT64-toIP -int $i  
} 

}

#XML
Clear
#Import XML Config File
$xmlConfigfile = ".IPAddressConverter.xml"

	While (((Test-Path $xmlConfigfile) -eq $false) -or ($NoXML)){
		[System.Windows.Forms.MessageBox]::Show("ERROR: $xmlConfigfile not found!")
	write-host De XML file kan niet gevonden worden -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}
	exit
	}
If (-not ($CSV -and $Outfile)) {
		$xml = get-content $xmlConfigfile
		If (-not $CSV) {$CSV = $xml.Config.Settings.CSV}
		If (-not $Header) {$Header = $xml.Config.Settings.Header}
		If (-not $Outfile) {$Outfile = $xml.Config.Settings.Outfile}
		}

# The method of reading a .CSV file below ensures that a single line csv is also handled correct
	While (((Test-Path $CSV) -eq $false) -or ($NoCSV)){
		[System.Windows.Forms.MessageBox]::Show("ERROR: $xmlConfigfile not found!")
	write-host De CSV file kan niet gevonden worden -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}
	exit
	}

$list = @(import-csv -Delimiter '/' $CSV)
write-host ".CSV file contains" $list.count " lines." -F Yellow -B DarkCyan
$list[0]

if ($error.count -ne 0)

{
	write-host "An error occurred during the operation. Details follow:"
	$error[0].categoryInfo
	$error[0].invocationinfo
	write-host "=========================================================="
	write-host "Quit due to an error" -Fore Red
	Exit
}
else
{
	#"Successfully opened .CSV file..."
}

#Loop through .CSV file
foreach($entry in $list)

{
	# Reset the variable to make sure that they are clean before processing a user.
	$IP=$entry.IP
	$Mask=$entry.Mask

$list = Get-IPrange -ip $IP -mask $Mask
Add-Content -Value $list -Path $OutFile
}

XML:

<Config> 
  <Settings>
	<CSV>.IPAddressConverter.csv</CSV>
	<Outfile>.Output.csv</Outfile>
  </Settings>
</Config>

CSV:

IP/MASK
1.1.1.1/255.255.255.0

 

Functie (Optioneel):

function Get-IPrange 
{ 
<#  
  .SYNOPSIS   
    Get the IP addresses in a range  
  .EXAMPLE  
   Get-IPrange -start 192.168.8.2 -end 192.168.8.20  
  .EXAMPLE  
   Get-IPrange -ip 192.168.8.2 -mask 255.255.255.0  
  .EXAMPLE  
   Get-IPrange -ip 192.168.8.3 -cidr 24  
#>  

param  
(  
  [string]$start,  
  [string]$end,  
  [string]$ip,  
  [string]$mask,  
  [int]$cidr  
)  

function IP-toINT64 () {  
  param ($ip)  

  $octets = $ip.split(".")  
  return [int64]([int64]$octets[0]*16777216 +[int64]$octets[1]*65536 +[int64]$octets[2]*256 +[int64]$octets[3])  
}  

function INT64-toIP() {  
  param ([int64]$int)  

  return (([math]::truncate($int/16777216)).tostring()+"."+([math]::truncate(($int%16777216)/65536)).tostring()+"."+([math]::truncate(($int%65536)/256)).tostring()+"."+([math]::truncate($int%256)).tostring() ) 
}  

if ($ip) {$ipaddr = [Net.IPAddress]::Parse($ip)}  
if ($cidr) {$maskaddr = [Net.IPAddress]::Parse((INT64-toIP -int ([convert]::ToInt64(("1"*$cidr+"0"*(32-$cidr)),2)))) }  
if ($mask) {$maskaddr = [Net.IPAddress]::Parse($mask)}  
if ($ip) {$networkaddr = new-object net.ipaddress ($maskaddr.address -band $ipaddr.address)}  
if ($ip) {$broadcastaddr = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $maskaddr.address -bor $networkaddr.address))}  

if ($ip) {  
  $startaddr = IP-toINT64 -ip $networkaddr.ipaddresstostring  
  $endaddr = IP-toINT64 -ip $broadcastaddr.ipaddresstostring  
} else {  
  $startaddr = IP-toINT64 -ip $start  
  $endaddr = IP-toINT64 -ip $end  
}  

for ($i = $startaddr; $i -le $endaddr; $i++)  
{  
  INT64-toIP -int $i  
} 

}

ZIP:

IPAddressConverter

 

 

Empty ADGroup

Script reads old group name and new group name from CSV file.  The processes data from XML and PS1 file. It exports the previous rights to a CSV file in the subdir CSVfiles. Needs XML and CSV files.

PS1:

$xmlConfigfile = ".EmptyADgroup.xml"

	While (((Test-Path $xmlConfigfile) -eq $false) -or ($NoXML)){
		[System.Windows.Forms.MessageBox]::Show("ERROR: $xmlConfigfile not found!")
	write-host De XML file kan niet gevonden worden -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}
	exit
	}

	If (-not ($CSV -and $Header -and $Migrated -and $Domain -and $OUlocal1 - $OUlocal2 -and $OUGlobal1 -and $OUGlobal2)) {
		$xml = get-content $xmlConfigfile
		If (-not $CSV) {$CSV = $xml.Config.Settings.CSV}
		If (-not $Header) {$Header = $xml.Config.Settings.Header}
		If (-not $Migrated) {$Migrated = $xml.Config.Settings.Migrated}
		}

Import-Module ActiveDirectory

		While (((Test-Path $CSV) -eq $false) -or ($NoCSV)){
		[System.Windows.Forms.MessageBox]::Show("ERROR: $xmlConfigfile not found!")
	write-host De CSV file kan niet gevonden worden -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}
	exit
	}

$list = @(import-csv -Delimiter ';' $CSV)
write-host ".CSV file contains" $list.count " lines." -F Yellow -B DarkCyan
$list[0]

if ($error.count -ne 0)

{
	write-host "An error occurred during the operation. Details follow:"
	$error[0].categoryInfo
	$error[0].invocationinfo
	write-host "=========================================================="
	write-host "Quit due to an error" -Fore Red
	Exit
}
else
{
	#"Successfully opened .CSV file..."
}

#Loop through .CSV file
foreach($entry in $list)

{
	# Reset the variable to make sure that they are clean before processing a user.
	$Oldgroup=$entry.OldGroup
	$NewGroup=$entry.NewGroup

	if ($Oldgroup -ne $null){$CSVExportFile = ($Oldgroup+".csv")}

		While (((Test-Path ".CSVFiles$CSVExportFile") -ne $false) -or ($NoCSVExportFile)){
		[System.Windows.Forms.MessageBox]::Show("ERROR: $CSVExportFile already exists!")
	write-host Het CSV bestande $CSVExportFile bestaat al -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}
	exit
	}
	write-host "Er wordt een export gemaakt van de groep $Oldgroup" -b DarkCyan -f Yellow
	$lijst = get-adgroupmember	 $Oldgroup -recursive

	Add-content -Value $Header -Path ".CSVFiles$CSVExportFile"

	foreach ($item in $lijst){
	$Outinfo = $Oldgroup + ";" + $item.samaccountname
	Add-content -Value $Outinfo -Path ".CSVFiles$CSVExportFile"}

			While (((Test-Path ".CSVFiles$CSVExportFile") -eq $false) -or ($NoCSVExportFile)){
		[System.Windows.Forms.MessageBox]::Show("ERROR: $CSVExportFile not found!")
	write-host Het CSV bestand $CSVExportFile is niet weggeschreven -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}
	exit
	}
	write-host "De export is gemaakt van de groep $Oldgroup op locatie .CSVFiles$CSVExportFile" -b DarkCyan -f Yellow
	write-host "De users in de groep $Oldgroup worden nu uit de groep gehaald" -b DarkCyan -f Yellow
	foreach ($item in $lijst){

	Remove-ADGroupMember $oldgroup -Members $item.samaccountname -Confirm:$false
	}

	$lijst = get-adgroupmember $Oldgroup -recursive
	if ($lijst -ne $null) {write-host "Niet alle users zijn uit de groep $oldgroup gehaald" -b Black -f Red}
	if ($lijst -eq $null) {write-host "Alle users zijn uit de groep $oldgroup gehaald" -b DarkCyan -f Yellow}
	if ($lijst -eq $null) {$Description = get-adgroup "ALC_APL_mibores" -Properties * | ForEach-Object {$_.Description}}
	$AddDescription = "$Migrated $Newgroup |"
	$Description = [string]$description
	$Description = ($AddDescription+$description)
	if ($lijst -eq $null) {Set-ADGroup $Oldgroup -Description $Description}

	}

XML:

<Config> 
  <Settings>
	<CSV>.EmptyADgroup.csv</CSV>
	<Header>Group;sAMaccountname</Header>
	<Migrated>Deze Groep is gemigreerd naar de groep</Migrated>
  </Settings>
</Config>

CSV:

Oldgroup;Newgroup
Oldgroup;Newgroup

ZIP:

EmptyADgroup

 

Get Inherited Permission

Script reads DFS Location from host. Script reads ADuser from host. Script checks whether DFS location and User specified are correct. Then checks how the user have access to the folder and what NTFS rights the user has.

PS1:

#Load Active Directory modules
Import-Module ActiveDirectory 
Clear-host
$Locatie = Read-Host "Voer de DFS Locatie in in UNC Format bijvoorbeeld:\gemeentenet.localdfsdeelnemerfolder"
While ((Test-Path $Locatie) -ne $true){
write-host "De opgegeven locatie bestaat niet. Voor opnieuw in" -b Black -f Red
$Locatie = Read-Host "Voer de DFS Locatie in in UNC Format bijvoorbeeld:\gemeentenet.localdfsdeelnemerfolder"
While ((Test-Path $Locatie) -ne $true){
	[System.Windows.Forms.MessageBox]::Show("ERROR: $locatie bestaat niet. Het script is beeindigd!")
	write-host De $locatie bestaat niet. Voer het script opnieuw uit! -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}}}
$User = Read-Host "Voer de User in in sAMaccountname Format bijvoorbeeld:othsbe02"
$testresult = get-aduser $User
If ($testresult -eq $null){
write-host "De opgegeven User bestaat niet. Voor opnieuw in" -b Black -f Red
$User = Read-Host "Voer de User in in sAMaccountname Format bijvoorbeeld:othsbe02"
$testresult = get-aduser $User
if ($testresult -eq $null){
	[System.Windows.Forms.MessageBox]::Show("ERROR: $User bestaat niet. Het script is beëindigd!")
	write-host De $User bestaat niet. Voer het script opnieuw uit! -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}}}
$Folders = @()
$Folders = get-item $locatie  | where {$_.psiscontainer -eq $true}
$outfile = ".temp.csv"
$Header = "Folder Path;IdentityReference;AccessControlType;IsInherited;InheritanceFlags;PropagationFlags;Filesystemrights"
Add-Content -Value $Header -Path $OutFile 
foreach ($Folder in $Folders){
	$ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access  }
	Foreach ($ACL in $ACLs){
	$OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference  + ";" + $ACL.AccessControlType + ";" + $ACL.IsInherited + ";" + $ACL.InheritanceFlags + ";" + $ACL.PropagationFlags + ";" + $ACL.FileSystemRights
	Add-Content -Value $OutInfo -Path $OutFile	
	}}

	$CSVImport = import-csv $outfile -delimiter ";"	
	$list1 = @()
	foreach ($item in $CSVImport){
	$identity = $item.Identityreference.replace("GEMEENTENET","")
	if ($item -match "BUILTIN" -and $item -match "Users"){$identity = $item.Identityreference
	$temp1 = Get-ADGroupmember -identity "Domain Users" -recursive |ForEach-Object {$_.sAMaccountname}}

	if ($item -notmatch "Builtin" -and $item -notmatch "NT AUTHORITY" -and $item -notmatch "CREATOR"){
	$temp1 = Get-ADGroupmember $identity -recursive |ForEach-Object {$_.sAMaccountname} }

	if ($item -match "BUILTINAdministrators"){$identity = $item.Identityreference.replace("BUILTIN","")
	$temp1 = Get-ADGroupmember $identity -recursive |ForEach-Object {$_.sAMaccountname} }
	foreach ($line in $temp1){$list1 += $line + ";" + $identity + ";" + $item.FileSystemRights}
	$result = $list1 |? {$user -contains $_}}

$print = $list1 -match $user
$print | sort -unique
remove-item $outfile

ZIP: