Category Archives: Configuratie

Configuratie van Microsoft omgevingen

Get all installed hot fixes and software

An adminstrator wanted to know if a certain KB from Microsoft had been installed. He wanted to know a command that does the job. In a world with DOS you can simply run:

systeminfo

However he also wanted to see if a Xenapp Hotfix had been installed. This of course can’t be done with the command above. So I wrote some code that exports the uninstall information from the local server. The code export x64 and x86 software. If the server is not 64 bit you’ll get errors. That said you’ll probably don’t have Powershell v3 installed on such server.

$List1 = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
$List1 += Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*
$List1 = $List1 | Select DisplayName, DisplayVersion, Publisher, InstallDate

App-v 4.6 large cache detection and alert script

App-v 4.6 generates sometime a large sftfs.fsd file. Users are experiencing performance issues when the file exceeds 15 GB. To fix this problem administrators remove the file by rebooting the Xenapp in safe mode. No user should be logged in of course. The Citrix servers therefore need to be empty. My colleagues ran a VB script that did the job of detecting but nothing else. I have made a script in Powershell that does the same but also set the server in ProhibitLogOns logon mode. The implement this script the server must have the Xenapp SDK installed. The server which runs the script need to have relay rights on the SMTP server. You’ll also need to have a Xenapp Server with PSRemoting enabled or the server itself should be member of the Xenapp farm.

#Load Modules and Snapins
Import-Module ActiveDirectory
Add-PSSnapin Citrix*
#Opens array for servers that apply on the conditions specified below
$ProhibitLogonServers =@()
$SMTP = "SMTPSERVER"
#Get all Xenapp server based on OU
$list = Get-ADComputer -Filter * -SearchBase "OU=Citrix Servers,OU=Servers,DC=Domain,DC=LOCAL"
Foreach ($Computer in $List){$Server = $Computer.DNSHostName 
$Result = GI "\\$Server\d$\AppVClientcache\Global\SoftGrid Client\sftfs.fsd"
If ($result.length -ne 0){$Outinfo = $Server+";"+$Result.length+" Bytes"
AC -Value $Outinfo -Path ".\log.csv"
#The conditions are met if the file is greater and engels 15 GB
If (($Result.length / 1073741824 ) -ge 15){$ProhibitLogonServers += $Computer}}}

#Mail message if no server are found                                                                                                                                                                            
If ($ProhibitLogonServers.length -eq 0){
$Mail = "Er is geen server gevonden die voldoet aan de voorwaarden om op ProhibitLogons te worden gezet" + "`n`n" + "Met Vriendelijke groet," +  "`n" + "Ochtend Controle Script"
Send-MailMessage -From "SendingAddress" -Subject "Prohibitlogons Report" -To "DestinationAddress" -Body $mail -SmtpServer $SMTP}

#Mail message one server is found
If ($ProhibitLogonServers.count -eq 1){
$Mail = "Er is een server gevonden die voldoet aan de voorwaarden om op ProhibitLogons te worden gezet. De server heeft als naam:" + "`n`n" + "$ProhibitlogonServers.Name" +"`n`n"+ "Met vriendelijke groet," + "`n`n" + "Ochtendcontrole Script"
Send-MailMessage -From "SendingAddress" -Subject "Prohibitlogons Report" -To "DestinationAddress" -Body $mail -SmtpServer $SMTP}

#Mail message if more than one server is found
If ($ProhibitLogonServers.count -gt 1){
$Mail = "Er zijn servers gevonden die voldoen aan de voorwaarden om op ProhibitLogons te worden gezet. De servers hebben de naam:" + "`n`n"
foreach ($server in $prohibitlogonservers){$Mail = $Mail + $Server.Name + "`r`n"}
$Mail = $Mail  + "`n" + "Met vriendelijke groet," + "`n`n" + "Ochtend Controle Script"
Send-MailMessage -From "SendingAddress" -Subject "Prohibitlogons Report" -To "DestinationAddress" -Body $mail -SmtpServer $SMTP}

#Opens array to check if the server has been set to prohibit logons. If servers are found a retry will be executed
$FailedServers = @()
If ($Prohibitlogonservers -ne $null){
Foreach ($Server in $Prohibitlogonservers){Set-XAServerLogOnMode -ServerName $Server.Name -LogOnMode Prohibitlogons -ComputerName CitrixServer}
Foreach ($Server in $Prohibitlogonservers){If ((Get-XAServer -ServerName $Server.Name -ComputerName CitrixServer).LogonMode -notmatch "ProhibitLogonOns"){$FailedServers += $Server}}}

#If a server is rebooting during the process you do want to make sure that server is set to Prohibit Logons. 
Start-sleep -s 900

#Retry setting the server to prohibit logons
If ($Failedservers.count -ne 0){
Foreach ($Server in $FailedServers){Set-XAServerLogOnMode -ServerName $Server.Name -LogOnMode Prohibitlogons -ComputerName CitrixServer}
$Failedservers = @()
Foreach ($Server in $FailedServers){If ((Get-XAServer -ServerName $Server.Name -ComputerName CitrixServer).LogonMode -notmatch "ProhibitLogonOns"){$FailedServers += $Server}}}

#Mail message if servers aren't set to prohibit logons
If ($Failedservers.count -ne 0){$Mail = "Er zijn servers niet succesvol op prohibitlogons gezet. Deze servers zijn:" + "`n`n"
foreach ($server in $Failedservers){$Mail = $Mail + $Server.Name + "`r`n"}
$Mail = $Mail  + "`n" +'Zet deze server(s) handmatig op ProhibitLogons' + "`n`n" + "Met vriendelijke groet," + "`n`n" + "Ochtend Controle Script"
Send-MailMessage -From "SendingAddress" -Subject "Prohibitlogons Failed" -To "DestinationAddress" -Body $mail -SmtpServer $SMTP}

 

Export all TNSNames files from all servers in the domain.

A colleague asked me if it was possible to export all servers that have an Oracle directory. I made a script that collects all server from Active Directory. Next I test if the C:\Oracle Directory Exists. That is arrayed. Next I search the directories of tnsnames. Excluding the .sample files of course.

Import-Module ActiveDirectory
$ADComputers = Get-ADComputer -Filter * -Properties * | Where {$_.OperatingSystem -match "Server"}
$Computers =@()
ForEach ($ADComputer in $ADComputers){$ADComputer = $ADComputer.DNSHostName
If((Test-Path "\\$ADComputer\C$\Oracle") -eq $True){$Computers += $ADComputer}}

ForEach ($Computer in $Computers){$Folders =@( gci "\\$Computer\c$\Oracle\" -recurse)
ForEach ($Item in $Folders){if ($item -match "TNSNames.ora" -and $item.fullname -notmatch "sample"){Add-content -Value $item.fullname -Path ".\Export.csv"}}}

Office 2010,2013 activation problem

For a customer I prepared an image. This image contained  a 32 bit version of Office 2010. I needed to enter a key for the installation. At that point I did not had access to their  volume licensing. I wanted to complete the image as soon as possible. That is why I entered a MSDN key. I was unaware at that point that this would cause many problems. First of all the deployed image at that point didn’t accept MAK keys. When I entered the MAK key I received an error that the key was incorrect. After an hour of troubleshooting I downloaded the VL version of Office 2010. I clicked on install. After install Office 2010 accepted my key. However it didn’t activate. I had to call Microsoft Activiation Center in order to activate the key. I asked them why automatic activation did not work. They said that I had to contact MSDN Activation Support. I put the two together and knew that this was caused by the MSDN key that somewhere was activated. I looked for an activation key in the registry somewhere. After deleting some keys I could activate. The keys are:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\14.0\Registration

And if you installed the 32 bit Office 2010:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Office\14.0\Registration

Do this before you install Office 2010 VL.

Synology VPN L2TP IPSEC

You can install a VPN Server on a Disk Station or Rack Station Synology NAS. When you configure a PPTP setting you can connect from any device without much configuration. However when you want a more secure solution you can choose for L2TP. When you open the correct ports on your router and Synology firewall you can connect from any iOS, Mac OS X, Android and even Windows Phone device. However Windows assumes that you always connect with a direct internet line (so without NAT) to a Internet Server (so without NAT). There is not other configuration. Now in my case I’m mostly behind a NAT device and my Synology most definitely is behind a NAT router. So you have to change some settings in the register and reboot before this works. Microsoft has made a KB for it. In this KB they refer only Vista and Server 2008 as being applicable. But Windows 7, 8, 8.1 , Server 2008 R2, Server 2012 and Server 2012 R2 are also affected. If you configure Windows as specified in the KB you can successfully connect to your Synology.

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

Remove old definitions

Symantec Endpoint Protection has a tendency to preserve definitions that are no longer needed. I’ve written a powershell script in three variations.

First is a powershell script that deletes any folders in the Virusdef above the count of 3. So if there are 4 folders with definitions it will delete the oldest.

$Servers =@( Import-CSV ".\Server.csv")
Foreach ($Server in $Servers){$Folders =@( gci "\\$Server\C$\Program Files\Common Files\Symantec Shared\VirusDefs" | Where {$_.PsIsContainer -and $_.Name -notmatch "Binhub" -and $_.Name -notmatch "Texthub"} | Sort CreationTime -Descending | Select -Skip 3})
ForEach ($Folder in $Folders){Remove-Item $Folder -Force -Recurse}

Second is a powershell script that deletes any folder in de Virusdef folder older than 2 days ago. Of course only definition folders not the other two folders.

$Datum = (Get-Date).AddDays(-2)
$Servers = @(Import-CSV ".\Server.csv")
Foreach ($Server in $Servers){gci -Path "\\$Server\C$\Program Files\Common Files\Symantec Shared\VirusDefs" | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $Datum -and $_.Name -notmatch "Binhub" -and $_.Name -notmatch "Texthub" } | Remove-Item -Force}

The last script is a combination of the above. It will any folder older than two days ago skipping the first. If a server hasn’t updated its definition it will not delete the active  definition.

$Datum = (Get-Date).AddDays(-2)
$Servers = @(Import-CSV ".\Server.csv")
Foreach ($Server in $Servers){gci -Path "\\$Server\C$\Program Files\Common Files\Symantec Shared\VirusDefs" -Recurse -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $Datum } | Sort CreationTime -Descending | Select -Skip 1| Remove-Item -Force}

All Script require a script.csv file with servers. Just a header with Server. Neighter do you need any delimiters. Just a list with servers

You can replace import-csv with get-content as needed.

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

Updates bijwerken via batch

Bij gebrek aan een WSUS server kunnen updates worden uitgerold via een batch script. De .Net Frameworks updates en updates als Malicious Software Removal Tools of andere Windows installer packages kunnen middels onderstaand script uitgevoerd worden:

@ECHO OFF


Set DataDir=E:InstallHotfixes

:: Put Terminal server in install mode
CHANGE USER /INSTALL
ECHO.


CD /d %DataDir%
FOR /f %%i in ('dir *.exe /b') DO %%i /quiet /norestart


:: Put Terminal server back in execute mode
ECHO.
CHANGE USER /EXECUTE

:: Just wait a few secs before exiting this script, or Altiris will report error 1 after exiting this script.
:: May be caused by previous statement and directly exiting the script, therefore this delay.
:: Use the ping command for a delay.


PING localhost >nul

Voor updates die geen echte installer hebben kan het volgende script worden uitgevoerd:
@ECHO OFF

Set DataDir=E:InstallHotfixes08

:: Put Terminal server in install mode
CHANGE USER /INSTALL
ECHO.

CD /d %DataDir%
FOR /f %%i in ('dir *.exe /b') DO %%i /z /u

:: Put Terminal server back in execute mode
ECHO.
CHANGE USER /EXECUTE

:: Just wait a few secs before exiting this script, or Altiris will report error 1 after exiting this script.
:: May be caused by previous statement and directly exiting the script, therefore this delay.
:: Use the ping command for a delay.

PING localhost >nul

Deze scripts zijn handig voor Terminal server. Als je niet ingelogd bent op een Terminal server kan je de install mode achterwegen laten.