Tag Archives: Automation

Find old share names in files on Apps share

A client was talking about how he couldn’t quit sharing a certain share in his Citrix environment. There were to many connections still to that share. So I suggested that I could help him by making a script that looks for certain values in .ini, .log, .cmd, .bat, .cfg, .config etc files. You can adjust this to your own preference.

I did a check of the drive mapping G:\. Please note that a lot of log files contain Logging: which matches G:. That is why I did a match on G:\. In Powershell the ‘\’ character  is an expression followed by a special character which in this case will be \. That is why you need a double slash.

$Locatie = "\\ShareName" 
$Exportfile = ".\Exportfile.csv"
$List = gci $Locatie -Recurse | Where {$_.Extension -match ".ini" -or $_.Extension -match ".cfg" -or $_.Extension -match ".config" -or $_.Extension -match ".inc" -or $_.Extension -match ".bat" -or $_.Extension -match ".cmd" -or $_.Extension -match ".log" -or $_.Extension -match ".txt"}
Foreach ($item in $list){$Content = Get-Content $item.fullname
$Pad = $item.fullname
If ($Content -match "G:\\"){Add-Content -Value  "Er is een verwijzing naar G:\ gevonden in: $Pad" -Path $Exportfile}
If ($Content -match "G:/"){Add-Content -Value  "Er is een verwijzing naar G:/ gevonden in: $Pad" -Path $Exportfile}
If ($Content -match "ServerName1"){Add-Content -Value  "Er is een verwijzing naar ServerName1 gevonden in: $Pad" -Path $Exportfile}
If ($Content -match "ServerName2"){Add-Content -Value  "Er is een verwijzing naar ServerName2 gevonden in: $Pad" -Path $Exportfile}
If ($Content -match "ServerName3"){Add-Content -Value  "Er is een verwijzing naar ServerName3 gevonden in: $Pad" -Path $Exportfile}
If ($Content -match "ServerName4"){Add-Content -Value  "Er is een verwijzing naar ServerName4 gevonden in: $Pad" -Path $Exportfile}
If ($Content -match "ServerName5"){Add-Content -Value  "Er is een verwijzing naar ServerName5 gevonden in: $Pad" -Path $Exportfile}
If ($Content -match "ServerName6"){Add-Content -Value  "Er is een verwijzing naar ServerName6 gevonden in: $Pad" -Path $Exportfile}}

App-v 5 and Citrix Provisioning

An administrator here came to me and asked me about how to Powershell around a problem with the App-V 5.0 Client Cache directory. The implementation configured is that App-V uses a folder on the D disk. This disk is dedicated. It is not on the distributed Vdisk. When the server reboots the cache becomes corrupted and the App-V service does not start. A sync is necessary in order to start the App-V 5.0 service. I made a script that clears a few reg values, deletes the App-v Client Connection Groups, App-V Client Packages, the AppV folder in Programdata and the entire folder on the D disk.

I handed over the script to the administrator and asked him to create a scheduled task that run at system startup. The reason for  running the script this way, is that creating a GPO that run a Powershell script will not statisfy the required security context. The SYSTEM account doesn’t have enought permissions to complete the script. PSRemoting will not work either. When running the script on another server with the Invoke-Command -Scriptblock {} fails. This is probably due to a bug in App-V. The account has enough rights and UAC is disabled. Yet all attempts fail. Please review the script before implementing

 

<#Script Variables#>
$ServiceName = "AppVClient"
$ProgramDataAppV = "C:\ProgramData\Microsoft\AppV"
$AppVData = "D:\App-V 5.0"

<#Regvalues#>
$Regvalues=@()
$Regvalues +=@{Regvalue="HKLM:\SOFTWARE\Microsoft\AppV\Client\PackageGroups"}
$Regvalues +=@{Regvalue="HKLM:\SOFTWARE\Microsoft\AppV\Client\Packages"}
$Regvalues +=@{Regvalue="HKLM:\SOFTWARE\Microsoft\AppV\Client\Streaming\Packages"}

#Service stoppen om Program Data te verwijderen.
$State = Get-Service $ServiceName
If ($State.status -NotMatch "Stopped"){Stop-Service $ServiceName
Start-Sleep -s 5}
Remove-Item $ProgramDataAppV -force -recurse

#Verwijderen van de Registersleutels
Foreach ($item in $Regvalues){If ((Test-Path $item.Regvalue) -ne $True){Remove-item $item.regvalue -force -Recurse}}

#Service Starten om initiele synch uit te voeren zodat de D schijf wordt vrijgegeven.
$State = Get-Service $ServiceName
If ($State.status -Match "Stopped"){Start-Service $ServiceName
Start-Sleep -s 5}
Get-AppvPublishingServer | Sync-AppvPublishingServer

#Service Stoppen om Packages en AppvClientConnectionGroup te verwijderen.
$State = Get-Service $ServiceName
If ($State.status -NotMatch "Stopped"){
Write-Host Stoppen
Stop-Service $ServiceName
Start-Sleep -s 5}
Get-AppvClientConnectionGroup -all | Remove-AppvClientConnectionGroup
Get-AppvClientPackage -all | Remove-AppvClientPackage
Start-Sleep -s 10

#Service stoppen om App-v folder op de D schijf te verwijderen.
If ($State.status -NotMatch "Stopped"){Stop-Service $ServiceName
Start-Sleep -s 5}
Remove-Item $AppVData -Force -Recurse
Start-Sleep -s 10

#Check of de folder ook daadwerkelijk verwijderd is.
If ((Test-Path $AppVData) -eq $True){

#Proberen de D schijf leeg te krijgen door eerst te synchen
Get-AppvPublishingServer | Sync-AppvPublishingServer
Start-Sleep -s 5
$State = Get-Service $ServiceName
If ($State.status -NotMatch "Stopped"){Stop-Service $ServiceName
Start-Sleep -s 5}
Get-AppvClientConnectionGroup -all | Remove-AppvClientConnectionGroup
Get-AppvClientPackage -all | Remove-AppvClientPackage
Start-Sleep -s 10
Remove-Item $AppVData -Force -Recurse

#Laatste check op de D schijf om te kijken of de folder nu daadwerkelijk weg is.
If ((Test-Path $AppVData) -eq $True){
$Outinfo = "De App-V Data op de D Schijf is na twee pogingen niet succesvol verwijderd. Bekijk het logboek."
Add-Content -Value $Outinfo -Path "C:\ScriptFout.txt"
$Outinfo = Get-Date
Add-Content -Value $Outinfo -Path "C:\ScriptFout.txt"
}}

#Laatste Sync uitvoeren
Get-AppvPublishingServer | Sync-AppvPublishingServer

Renaming files and moving it to a different location

An OCE printer can only scan files to a FTP location with one name. There are no unique attributes that the Multifuctional printer can add to a file. This results in files being overwritten if not renamed immediately after being transferred. I’ve written a little script that is run every 5 seconds via Task Scheduler. This script renames files in a  unique format and then moves the file to some place else.

$Folder = "C:\Inetpub\FTProot\"
$Destination = "\\Ergensopdebozewereld"
$Applytime = (Get-Date).AddSeconds(-20)
$Content = @(gci $Folder | where {$_.LastWriteTime -lt $Applytime -and $_.PSIsContainer -eq $False})
Foreach ($item in $Content){$TEMP = $Item.LastWriteTime
$Time = Get-Date $TEMP -Format yyyyMMdd_HHmmss
$Name = $item.name.replace(".tif","")
Rename-Item -Path $Item.fullname -NewName "$Name_$Time.tif"
$Item = GI "$Folder\$Name_$Time.tif"
Move-Item -Path $Item -Destination $Destination -Force}

Manage websites from local server

$list =@(Get-WmiObject -Namespace "root/Webadministration" -Query 'Select * from Site')
Foreach ($item in $list){write-host $item.name}

IIS6 compatiblity uses a different namespace root/MicrosoftIISv2

All you need to do is get cred en authenticate to a different server using either -ComputerName $Hostname or  -Authentication “6”.

Next you can create a remote job using the earlier cached credentials and create a script with the listed names like this:

Import-Module WebAdministration
Stop-Website "$name" 
$State = Get-website |Where {$_.Name -eq "$Name"} | Select State
If ($State -notmatch "Stopped"){Stop-Website $Name }

Of course you can also you the schtasks /create command (in Powershell) to add a job that deletes itself or enable-psremoting.

An entire different approach would be to connect using the servermanager via Powershell. You can load the servermanager and connect to a server. The advantage would be that one server is responsible. You do need access to that server. Some high secure environments block this kind of traffic. You can load any dll for IIS Web Administration

[System.Reflection.Assembly]::LoadFrom( "C:\windows\system32\inetsrv\Microsoft.Web.Administration.dll" )
$computer = "COMPUTERNAME"
$ServerManager = [Microsoft.Web.Administration.ServerManager]::OpenRemote($computer.ToLower())
[int]$ID="1"
Foreach ($item in $ServerManager.sites){
Write-host "$ID $item"
$ID++
}

while ($ID -gt $Servermanager.sites.count){
     $ID = read-host "Voer de site die u wilt stoppen"
      $ID--}


$ServerManager.Sites.Item($ID).stop()

Windows 8 and Windows 8.1 install dotnet Frameworks 3.5

To install dotnet framework 3.5 you’ll will have to do a couple of things. First of all you need to disable a task as soons as you have completed setup. Well this is actually optional. It is necessary to do this step if you want to deploy that image to other PC’s. Windows 8(.1) deletes install media to save disk space. Run the following command immediately after setup completed:

schtasks.exe /change /disable /tn "\Microsoft\Windows\AppxDeploymentclient\Pre-Staged App CleanUp"

To install the DotNet Framework 3.5 feature in Windows 8(.1) run the following command. Where D: is the installtion media

DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:d:\sources\sxs

All of the above of course in an elevated Powershell window

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

Volgnummer bijhouden in een CSV file

Import-module 'ActiveDirectory'
 $getadusers = @()
 $filter = @()
 $samaccountnamelijst = @()
 $Header = 'Samaccountname'
 $CSV = '.\Gemeentenet.csv'
 $Extension = $null
 $import = @()
 Add-Content -Value $Header -Path $CSV
 $getadusers = Get-aduser -filter *
 foreach ($entry in $getadusers){if ($entry -ne $null){$samaccountnamelijst += $entry.samaccountname}}
 foreach ($sam in $samaccountnamelijst){Add-Content -Value $sam -Path $CSV}
 $Deelnemerlijst = @()
 $allusers = import-csv $csv
 foreach ($Deelnemeruser in $allusers){if ($Deelnemeruser -match $deelnemer){$Deelnemerlijst += $Deelnemeruser}}
 $Deelnemerlijst | export-csv .\$Deelnemer.csv

$entry = $null
$username = 'othext'
 $CSV = '.\Gemeentenet.csv'
 $import = @()
 $filter = @()
 $import = import-csv $csv
 foreach ($entry in $import){if ($entry -match $username){$filter += $entry.samaccountname}}
 $filter = $filter -split "@{samaccountname=" |sort
 $filter = $filter -split "$username" | sort
 $filter = $filter -split "}" | Sort -Descending
 $nummer = [int]$filter[0]
 $nummer++

Add-content -Value $volledigesamaccountname -path $csv