Blog

Steelooper's Blog

Je eigen router / modem gebruiken met KPN Glasvezel (2015-03-18T19:50:00.000+01:00)

Author: Bas Steelooper

Nou, het werkt eindelijk allemaal..

Ik ben pas geleden overgestapt naar KPN Glasvezel en kwam tegen wat beperkingen aan (waar een normale gebruiker geen last van heeft)
Zo kon ik geen IPSec VPN tunnel meer opzetten met mijn servers, of met mijn Backup Locatie. Daarnaast ervoer ik ook een vertraging in mijn internet verkeer. Mijn snelheid was nog maar 70 mbit down en 65 mbit up. Terwijl ik toch echt voor een 100/100 verbinding betaal.

Een gedeelte van de vertraging zou komen door de dubbele NAT die plaatsvond.
Ik heb dus besloten om te kijken hoe ik dit op kon lossen. Bij Ziggo kon ik mijn modem in Bridge laten plaatsen. Maar dit bleek met de Experiabox v9 niet mogelijk. Wel is er een handleiding om dit te doen met de V8 modem. Maar die heb ik niet, en na herhaaldelijk aanvragen bij KPN en tot 6 keer een V9 toegestuurd te hebben gekregen heb ik besloten om het maar helemaal anders te doen.

Onderstaande tekening is een weergave van hoe ik het nu helemaal opgezet heb.

Ik heb wel een TV getekend in het plaatje, maar ik neem geen TV af via Ziggo. De TV kan ik ook via de Managed Switch laten lopen. Er komt dan een extra afsplitsing met een VLAN 4 naar de TV Decoders. Maar aangezien ik het niet nodig heb... Heb ik me er gemakkelijk af gemaakt.

Gebruikte hardware:

  • Fibre : Genexis modem geleverd door KPN
  • Switch: Zyxel GS1900-24E
  • Firewall: Zyxel ZyWall USG-20
  • ExperiaBox: Experiabox V9 geleverd door KPN
Gebruikte informatie: Netwerkje.com Eigen Router

KPN heeft het een en ander werkend opgeleverd, dat wil zeggen Internet doet het. Telefoon doet het (na nieuwe kabel getrokken te hebben)

Op de GS1900-24 heb ik als eerste VLANs aangemaakt. De VLAN IDs weet ik van Netwerkje.com

1 = Default
4 = IPTV
6 = DATA
7 = IP Telefonie
101 = Client LAN

Vervolgens hebben we die toegewezen aan de verschillende poorten.
Poort 2: VLAN 4,6 en 7 - Trunk - Tagged
Poort 4: VLAN 6 - Trunk - Tagged
Poort 6: VLAN 4 en 7 - Trunk - Tagged

Poort 8-24: VLAN 101 - UNtagged

Kabels aangesloten
Poort 2: Fibre modem
Poort 4: Firewall - WAN
Poort 6: Experiabox - WAN

Poorten 16-24 gevuld met de bekabeling in huis

De ExperiaBox kwam netjes online voor Telefonie, met een rode led voor Internet

Daarna kwam de uitdaging. De verbinding opbouwen. Aangezien er weinig documentatie is hoe dit te doen met de ZyWall heb ik dit uit moeten zoeken. Het bleek dat vooral de volgorde belangrijk was.

Als eerste gaan we de VLAN aanmaken waarop het internet leeft: (Configuration -> Network - Interface TAB:VLAN)

Let op dat het VLAN id op 6 staat,
dat de ZONE op WAN staat
en dat de interface op wan1 staat.

Dit resulteert in het volgende:


Vervolgens maken we een ISP Account aan: (Configuration --> Object - ISP Account)

Naam: KPN
Protocol: PPPoE
Authentication Type: Chap/PAP
Username: MACADRES Experiabox@internet
Password: kpn
Compression: On

Dan de PPP connectie aanmaken (Configuration -> Network - Interface TAB:PPP)

Interface Properties
Interface Name: KPN
Base Inteface : vlan6
Zone: WAN
---
Connectivity: Nailed-up
---
ISP-Setting
Account Profile: KPN
---
IP Address Assignment - Get Automatically

Na het opslaan van de laatste instelling zul je zien dat de verbinding meteen online is. Als dit niet het geval is klik dan op de connect button.

Ik hoop dat dit duidelijk is, en iemand er iets aan heeft in de toekomst.

Clean the exchange server logfiles (2015-03-11T10:59:00.001+01:00)

Author: Bas Steelooper

At a client I found that disks were filling up with logfiles. Most but not all logfiles were cleared automatically after 7 or 14 days but that left a few logfiles filling up the disk..


I created a scheduled task which runs every night (after the backup run) and removes all old logfiles:

It is a powershell one liner:

powershell.exe Get-ChildItem 'c:Program FilesMicrosoftExchange ServerV15Logging','C:inetpublogs' -Directory | Get-ChildItem -Include '*.log','*.blg' -Recurse | ? LastWriteTime -lt (Get-Date).AddDays(-7) | Remove-Item

 This script will remove all logfiles older than 7 days.

Outlook for Android and iOS (2015-02-02T14:04:00.002+01:00)

Author: Bas Steelooper


A lot of sites are now reporting the insecurity of the application Outlook which appeared januari 29th in the Apple AppStore. (Warning – Microsofts Outlook app for iOS breaks your company security) and (Microsoft Wants to Improve Your Mobile Email Experience with the New Outlook for iOS and Android) This is the same application (some rebranding has been done) as the Accompli app which is now purchased by Microsoft.

What is the problem with this app?
It is a good app. It looks very need, but to do what is does it needs a little something from you and it will store this information on the servers in the cloud (Now at AWS but soon Microsoft Azure)
What is this information it needs?.... That is your Username and Password.
What does it do with this information? .... It starts downloading your entire mailbox, and caches this in the cloud.
Why is this a problem? .... For a private person not so much.... You probably share all the information on Facebook, twitter etc anyway, and don't have secrets in your mail which other instances / agencies are interested in.... But for companies this might be a large issue. They usually have something setup which is referred to as a company security policy. This policy mostly states the following items:

  • Device must have a pincode or password
  • Device must be encrypted
  • In case of lost the device must be wiped
  • etc.

All these things are not possible with the new App. From an App it is NOT possible to set device settings such as encryptions and passwords. A wipe is also not possible (In some cases the mailbox is reported to be removed)....


What to do now?
Firewall
Block the application from entering your network. If possible do this on your firewall with an User-Agent filter.
Filter for the following user agents:

  • Outlook-iOS-Android
  • Outlook for iOS and Android

Exchange (Exchange 2010 and Higher)
You can also add an rule on your Exchange server which will block access to the mail environment.
New-ActiveSyncDeviceAccessRule -Characteristic DeviceModel -QueryString "Outlook for iOS and Android" -AccessLevel Block
Block or Quarantine the Outlook for iOS and Android App in Exchange Server and Office 365

Future
Microsoft is busy with this application, updating and modifying it. So it is important to keep an eye on the changes which will occur in this application.
I do think that the application has a lot of potential and is a way to go, but first some issues have to be resolved. But for now "Hands Off"

Exchange services (2015-01-20T15:46:00.000+01:00)

Author: Bas Steelooper

Today I was at a client which had an issue with their Exchange environment. They were installing updates and one of the Exchange servers was giving trouble after that.
When I logged on to the server I noticed that all services were disabled, and since I am lazy I scripted the recovery for this ;-)

I though I shared it with you. Maybe there can be a check before if the service is running or not, or if it is really disabled.. But mostly this is a quick fix for your Exchange environment.

get-service "msexcha*" | Set-Service -StartupType automatic
get-service HostControllerService | Set-Service -StartupType automatic
get-service wsbexchange | Set-Service -StartupType automatic
get-service FMS | Set-Service -StartupType automatic
get-service W3SVC | Set-Service -StartupType automatic
get-service IISADMIN | Set-Service -StartupType automatic
get-service pla | set-service -startuptype automatic
get-service RemoteRegistry | set-service -startuptype automatic
get-service SearchExchangeTracing | Set-Service -StartupType automatic
get-service "MSExchangeImap4" | set-service -StartupType manual
get-service "MSExchangeImap4BE" | set-service -StartupType manual
get-service "MSExchangePop3" | set-service -StartupType manual
get-service "MSExchangePop3BE" | set-service -StartupType manual

get-service HostControllerService | start-service
get-service FMS | start-service
get-service "msexcha*" -StartupType automatic | start-service
get-service wsbexchange | start-service
get-service W3SVC | start-service
get-service WinRM | start-service
get-service pla | start-service
get-service RemoteRegistry | start-service
get-service IISADMIN | start-service
get-service SearchExchangeTracing | start-service

How to operate a secure Synology system... (2014-08-11T15:41:00.000+02:00)

Author: Bas Steelooper

With the current hype around the outbreak of #SynoLocker, a ransomware virus which encrypts all your files and only allows decryption after paying a ransom fee ($400), it is nice to have your Synology protected as good as possible to minimize the attack vectors (ways people can compromise the security) to a minimum without loosing any end-user usability and ease.

In the different forums you find the following advices:
* Disable the default Admin Account
* Change the default ports on the services
* Use SSL
* Don't use 3rd party applications
* etc.

Below I will describe what is in my opinion a good way to protect your Synology for attacks. I will be using 3rd party applications from the SynoCommunity repository.
Starting point is an up to date Synology system and you are logged on as an Admin user (Admin or a different user with admin-rights)

Below are the links to a series of posts to secure your Synology:
1. Make sure your synology is up to date
2. Publish the applications through HAProxy
3. More to come..

Synology : Publish through HAProxy (2014-08-11T15:33:00.001+02:00)

Author: Bas Steelooper

This is the second article in a series to secure your Synology NAS.

HAProxy enables users to access programs on their NAS without opening additional ports in the firewall. Also because the applications are not accessible on the ports which they normally run on, and you need to know the exact url to use, it is hard to exploit the application if there is an bug in the software. (For instance SYNOLOCKER)
If you use the DDNS service of Synology you can use names in front of the DDNS name to connect to the services.
f.i. https://dsm.mydemonas.synology.me would redirect me to the admin interface of my NAS.

To achieve this we need to install an additional program HA-Proxy. This is available through the repository from Syno Community. The address for the repository is: http://packages.synocommunity.com

What this tutorial will assist you in is the following:
1. Add the repository
2. Prepare the NAS for the application
2.a Install a certificate
2.b enable SSH
3. Install the application and pre-requisite
3.a some problem fixing
4. conclusion.

I hope this will help you ;)



Add the repository
First open the package center:


















When in Package center select Installed and click the button Settings












Click on Add, and fill in the following information:
Name: Syno Community
Location: http://packages.synocommunity.com


On the left hand side click on community and then refresh.



A lot of packages will appear here.



Create a Certificate
Before we install HAProxy we first need to update the certificate and enable SSH.

Go to Control Panel


 Open Security


Click on the TAB Certificate


Click on Create Certificate

In this tutorial we create a self-signed certificate, if you have a valid certificate you can import it here,  or you can create a certificate request which you can send to a certificate authority.

Fill-in your information

At common name fill in the DNS name you want to use. The DDNS service from synology can provide you with a DNS name, you can add the local ip adres in de Subject Alternative Name field. Click Apply



Enable SSH
Since the custom configuration of HAProxy is only available through the command line we must enable SSH to connect to the NAS.

Open Control panel

Open Terminal en SNMP
 Select Enable SSH Service and click Apply

Installation of the Package

Now we can install haproxy. Since a requirement is Python 2.7 or higher we first install Python.
Open Package Center

 Select Community

Look for the package python and click install

Wait until the installation is finished

Look for the application HAProxy and click install

HAProxy uses an username and password to protect the status page. Enter those here.
Default is admin admin
Click Next

Make sure the checkbox is ticked to run the application, and click apply

With version 1.5-dev25-12 there is an problem in the configuration which doesn't allow the application to run. We can however fix it ourselves.

Download putty

Open the downloaded program file and connect to the IPAdres of your NAS over SSH
The username is always root
The password is your admin password

Change the current folder to "/volume1/@appstore/haproxy/var and open the file haproxy.cfg

Commands:
  cd /volume1/@appstore/haproxy/var/
  vi haproxy.cfg

When the file opens scroll down to the part backend gateone.
Add verify none to the server line. For this press the i
add the words to the line. press ESC
type :wq [ENTER]

Now the package will run when we start it.

Conclusion
HAProxy will natively run on the ports 5080 and 5443
We can change these ports in the configuration file or you can modify your firewall (router) to forward the request incoming on port 80 or 443 to the ports of haproxy. By default the applications are only available over the https (5443) port but you can copy those lines to the http (5080) port option. This makes it less secure!!





Synology : Make sure it is up to date and you are informed of updates. (2014-08-11T10:08:00.000+02:00)

Author: Bas Steelooper

My first in a series is the advice to make sure your system is always up to date. The press release of Synology states that the current versions of the software where NOT vulnerable for this virus. So first we make your system send you emails if there is an update for your Synology.


Click on the start button (Top Left corner) and open Control Panel










Open Notification












If you have information of sending emails through a SMTPServer (Mail Server) you can use the first tab (Email) to enter this information.

Be sure to test the configuration. 



















If you don't have access to an email server to send the emails you can choose to use the Synology notification email server. you find this on the tab "Push Service"
Fill in your emailaddress, click Apply, after a few seconds a new button appears. Click on this button "send verification mail", open your email box and click on the verification link in this email.
Email notifications will now be send. 


















In the "Advanced" tab you can select which notifications you want to receive. I have selected all notifications



In the left menu go to "Update & Restore", in the page click on the button "Update Settings" and make sure that the system is checking for New and All updates and that the checkbox is checked to check and download these updates.


















Next close all the open pages, and open the Package Center













When the Package Center opens click on the Settings button














Make sure both options are selected on the General Tab



















On the tab Auto Update you can choose to Auto Update the Synology Packages



















Now you will receive emails if there are updates available for your Synology System or applications.

Apple OSX 10.10 Yosemite sluggish and unresponsive or snappy as expected?? (2014-06-05T22:58:00.000+02:00)

Author: Bas Steelooper

Last week Apple presented Mac OSX 10.10 Code name Yosemite. Now with better integration with your phone and ipad.... Off course I have to try this so I installed iOS 8 on my Phone(s) and OSX 10.10 on my Mac.

And then the troubles began... Not on the phone but on my Mac. It was unresponsive, memory hogging and throughout terrible. I even considered reverting back to OSX 10.9 Mavericks.
But I am not a quitter so the search for a solution started...

There is a side note that there is a NDA on OSX 10.10 and therefor there is little found on the internet about it and the problems which are found..

When I started looking at the resource usage I couldn't find anything off other than that kernel_task was using a lot of memory, but other than that nothing wrong... But whenever I switch between applications the screen froze and a colourful skippybal came in place of my cursor.. Since I have a lot of tweaks installed, I instantly started blaming them, and cleaned them away from my system.. But it didn't solve anything...

Maybe it where the add-ins I am using such as dropbox and bitcasa.. so deleted those. Still no response from my system..
In the meantime a forum was started for Yosemite where people started sharing their problems. On that forum someone shared that he had an unresponsive system and no sound. I had sound, but still worth a look. (http://forums.macrumors.com/showthread.php?t=1740460) In this thread it was suggested to remove a driver from a third-party add-on.
I checked if I had the same driver on my system, but no such luck.

Off to more digging into this issue, but still no luck in finding something. resetting the SMC and PRAM both didn't help and all other suggestions found on the internet for versions since 10.5

At that time I started looking at all open processes and applications. All tweaks where already removed but legitimate application such as VMWare Fusion, Parallels and Microsoft where still on my machine. Only one application was still running and that was Parallels Access. I had never used it and had always thought it part of parallels itself.
So I searched for problems between Yosemite and Parallels Access. But couldn't find any. I did find a post that it is an agent which allows you to use your iPad to control the Mac (http://forums.macrumors.com/showpost.php?p=18300289&postcount=25) Since it is not something I use, and I was in a PenTesting class where we just learned not to have anything installed you are not using since that might get attacked, I decided to uninstall the agent. In the link in the post was a link to a knowledge base article from Parallels in how to remove it (http://kb.parallels.com/en/117142) in which they have a script (Parallels Access Uninstall script) to remove the software. Just sudo run the script from terminal and it is gone...

One reboot later my system was responsive, snappy and nice to work with again..

I am not going to share any details and screenshots just yet, but I like that I can answer SMS texts on my laptop now :)

When you logon to Facebook.... (2013-02-04T17:20:00.000+01:00)

Author: Bas Steelooper


When you logon to facebook you get the question: "How is it going, Bas?"...
Today I felt like answering the question. Below my answer.
Dear Facebook,

Thank you for asking... I am currently recuperating from a very hectic weekend.

I started the final migration of a dutch company on friday. It was the end of 4 months preparation. But although we didn't invite Murphy, he decided to show up anyways...
For the past 4 months our migration efforts were brought back to 7 or 8 scripts running at scheduled intervals. Daily manual checks were done of the logfiles and runtimes and we were very confident that the migration would be a success.

And there was Murphy and his Law (The prick)
Everything that could go wrong went wrong. Scripts failed to complete due to offline databases, disabled users, and rebooting servers.... (Who forgot to include the support team to suspend the maintenance windows)
Nothing is more frustrating than working on fixing a script to adapt to the new situation, having found the solution and than some ass decides to reboot the server you are working on...

So friday I clocked a 14 hour workday (hours after 12 are on saturday) to have finally migrated everything.... As that was what we believed... I was glad to have taken an hour of to visit Tian Dao to be treated for my high blood pressure and that was very relaxing... Thanks for that...

Saturday morning after about 3 hours sleep I started to check the logfiles. And found that all the steps are completed successful. Ahhhh Weekend was the thought.. and queue Murphy..

In this company there are some strict naming rules for users.... Which are not followed of-course. So when you want to migrate Jan Jansen you look for j.jansen conform the naming standards... And migrate someone totally different since the logon name for jan was JanJ... And you wonder why you cannot find him...

So after another long day (again 14 hours on the clock) we check into bed... for a nights rest... And a good night rest it was..

Sunday, fun day... Yeah.. last day of migration.. In the input list we found that several users were not given an email forward address to the new mail. and since a script flawless processes what you input the mail for those users were not forwarded.. Works as designed, but not as desired... So the torubleshooting starts... and remigrating those accounts.. But I managed to make it a shorter day, and after sleeping in I only managed to clock 8 hours of after care this day..

After a handover to my colleague for the aftercare on monday I went to bed for a good nights rest....

And a good nights rest it was...

So to answer your question Facebook. I am doing alright. A bit tired but fulfilled with a job well done...

So and now back to work and finish these reports which are due..

Goodday,

Bas Steelooper

In the pocket: Core Solutions of MS Exchange Server 2013 Customer Preview (2013-01-25T15:25:00.002+01:00)

Author: Bas Steelooper

Today I saw that another IT pro passed his exam and I thought about the beta exams I did for Microsoft Exchange 2013...

So I took al little trip to https://www.register.prometric.com/CandidateHistory.asp and found out that I passed the "Core Solutions of MS Exchange Server 2013 Customer Preview" (071-341) exam... To bad that I failed the "Advanced Solutions of MS Exch Serv 2013 Customer Preview" (070-342) exam..

But with the lack of experience I was able to obtain since I couldn't install Exchange 2013 in my Exchange 2010 environment I think I did rather well with only reading about all there is on Technet and other Tech blogs...

I hope to find the time to install Exchange 2013 soon in my environment and update all the scripts to this version...

Exporting mailboxes to PST-files the easy way (2013-01-21T14:22:00.002+01:00)

Author: Bas Steelooper

When doing a cross domain migration it can be usefull to export the mailboxes to a PST file.

When doing this for a large amount of mailboxes it can be useful to use a script to automate this...

As I am lazy, I searched the internet for such a script, and found one from Steve Goodman which was close to what I wanted.. But as needy as I am, I needed more.

I modified, and added to the script which you find below. And is is as good as I am going to make it. It works like a charm (as I do say so myself)

Also made it so that if you are going to export a lot of mailboxes the target share and the source servers won't die on you you can set the maximum concurrent to a number your environment will survive.
The script will start the first batch, wait until completion, and than start the second batch.

When finished it will write some info to the report folder, and the logs for the completed and the failed requests...

Thanks go to Jeff Wouters which reviewed the script for me. And to his blog for the Add-Module function, which gave me a good idea for an add-SnapIN function which does basically the same but than for SnapIns.. so if you run the script multiple times you won't get an error :-)

# Exchange 2010 SP1 Mailbox Export Script
# Original script from : Steve Goodman (http://www.stevieg.org/2010/07/using-the-exchange-2010-sp1-mailbox-export-features-for-mass-exports-to-pst/)
# input from Jeff Wouters ( www.jeffwouters.nl)
# deviations from original script:
# - option to export all in the organisation
# - option to export all in a list
# - option to include archive mailboxes
# - option to exclude dumpster
# - option to set a maximum concurrent exports
# - no need to run from Exchange PowerShell. Needed library is loaded at runtime
$starttime = get-date -displayhint time
###############
# Settings #
###############

# Pick ONE of the two below. If you choose both, it will use $Server.
$Server
$Database
$list = "\servershareusers1.csv"

# Share to export mailboxes to. Needs R/W by Exchange Trusted Subsystem
# Must be a UNC path as this is run by the CAS MRS service.
$ExportShare = "\serversharepst\"
if (!(test-path -path $ExportShare -pathtype container))
{
mkdir $ExportShare
}

# After each run a report of the exports can be dropped into the directory specified below. (The user that runs this script needs access to this share)
# Must be a UNC path or the full path of a local directory.
$ReportShare = "\serversharelog\"
if (!(test-path -path $ReportShare -pathtype container))
{
mkdir $ReportShare
}

# Shall we remove the PST file, if it exists beforehand? (The user that runs this script needs access to the $ExportShare share)
# Valid values: $true or $false
$RemovePSTBeforeExport = $true

# Do we want to include Archive Mailboxes
$IncludeArchive = $true

# Do we want to exclude dumpster
# currently not working as intended. workarround in place
$ExcludeDumpster = $false

# How many concurrent exports do we want?
# This must be an even number (2, 4, 6, 50, 100, 200, 1000 etc)
$maxConcurrentExports = 200

###############
# Code #
###############

# function created by Jeff Wouters (www.jeffwouters.nl)
function Check-LoadedModule
{
Param( [parameter(Mandatory = $true)][alias("Module")][string]$ModuleName)
$LoadedModules = Get-Module | Select Name
if (!$LoadedModules -like "*$ModuleName*") {Import-Module -Name $ModuleName}
}

# Deviation from Jeff Wouters function but for PSAddins
function Check-LoadedSnapIN
{
Param( [parameter(Mandatory = $true)][alias("SnapIN")][string]$SnapINName)
if ( (Get-PSSnapin -Name $SnapINName -ErrorAction SilentlyContinue) -eq $null )
{
Add-PsSnapin $SnapINName
}
}

# If Archives are included we get 2 exports at a time. so we need to divide the maximum by 2
if ($includeArchive){
$maxConcurrentExports = $maxConcurrentExports / 2
}

# load the Exchange powershell snapin if not loaded
Check-LoadedSnapIN Microsoft.Exchange.Management.PowerShell.E2010

# this function will create the MailboxExportRequests.
function exportMailbox ([String]$CurrentUser) {
if ($RemovePSTBeforeExport -eq $true -and (Get-Item "$($ExportShare)$($CurrentUser).PST" -ErrorAction SilentlyContinue))
{
Remove-Item "$($ExportShare)$CurrentUser.PST" -Confirm:$false -ErrorAction SilentlyContinue
Remove-Item "$($ExportShare)$CurrentUser-Archive.PST" -Confirm:$false -ErrorAction SilentlyContinue
}
if ($ExcludeDumpster){ # workarround if else. Would rather place this inline in the vode.
New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)$CurrentUser.pst" -ExcludeDumpster
if ($IncludeArchive){
New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)$CurrentUser-Archive.pst" -IsArchive -ExcludeDumpster
}
} else {
New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)$CurrentUser.pst"
if ($IncludeArchive){
New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)$CurrentUser-Archive.pst" -IsArchive
}
}
}

# This function makes the script wait for completion of all exports.
function waitForCompletion {
while ((Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -eq "Queued" -or $_.Status -eq "InProgress"}))
{
clear
Write-Output "Waiting for the exports to complete"
Get-MailboxExportRequest -BatchName $BatchName | Get-MailboxExportRequestStatistics | Where {$_.Status -eq "Queued" -or $_.Status -eq "InProgress"} | Out-Default | Format-Table
sleep 60
}
}

# Make batch name
$date=Get-Date
$BatchName = "Export_$($date.Year)-$($date.Month)-$($date.Day)_$($date.Hour)-$($date.Minute)-$($date.Second)"

if ($ExcludeDumpster){
$additionalParm = "-ExcludeDumpster $true"
} else {
$additionalParm = ""
}

# the collection of what to be export
if ($Server)
{
write-output "Using Server"
if (!(Get-ExchangeServer $Server -ErrorAction SilentlyContinue))
{
throw "Exchange Server $Server not found";
}
if (!(Get-MailboxDatabase -Server $Server -ErrorAction SilentlyContinue))
{
throw "Exchange Server $Server does not have mailbox databases";
}
$Mailboxes = Get-Mailbox -Server $Server -ResultSize Unlimited
} elseif ($Database) {
write-output "Using database"
if (!(Get-MailboxDatabase $Database -ErrorAction SilentlyContinue))
{
throw "Mailbox database $Database not found"
}
$Mailboxes = Get-Mailbox -Database $Database -ResultSize Unlimited
} elseif ($list) {
write-output "Using list: $list"
$userlist = Import-CSV $list
} else {
write-output "None of the above, so exporting all mailboxes.."
$mailboxes = Get-Mailbox -ResultSize Unlimited
}

# The Export
if ($list){
Write-Output "Queuing $($userlist.Count) mailboxes as batch '$($BatchName)'"
$teller = 0
# Queue all mailbox export requests
foreach ($user in $userlist)
{
$teller = $teller + 1
$curuser = $user.SamAccountName
exportMailbox $curuser
if ($teller -gt $maxConcurrentExports){
Write-Output "Waiting for batch to complete"
# Wait for mailbox export requests to complete
waitForCompletion
$teller = 0
}
}
# Wait for mailbox export requests to complete
waitForCompletion
}elseif ((!$Mailboxes) -and (!$Mailboxes.Count)) {
throw "No mailboxes found on $Server or single Mailbox."
} else {
Write-Output "Queuing $($Mailboxes.Count) mailboxes as batch '$($BatchName)'"
# Queue all mailbox export requests
$teller = 0
foreach ($Mailbox in $Mailboxes)
{
$teller = $teller + 1
exportMailBox $Mailbox.alias
if ($teller -gt $maxConcurrentExports){
Write-Output "Waiting for batch to complete"
# Wait for mailbox export requests to complete
waitForCompletion
$teller = 0
}
}
# Wait for mailbox export requests to complete
waitForCompletion
}

# Write reports if required
if ($ReportShare)
{
Write-Output "Writing reports to $($ReportShare)"
$Completed = Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -eq "Completed"} | Get-MailboxExportRequestStatistics | Format-List
if ($Completed)
{
$Completed | Out-File -FilePath "$($ReportShare)$($BatchName)_Completed.txt"
}
$Incomplete = Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -ne "Completed"} | Get-MailboxExportRequestStatistics
if ($Incomplete)
{
$Incomplete | Format-List | Out-File -FilePath "$($ReportShare)$($BatchName)_Incomplete_Report.txt"

if (!$list){
$list = "$($ReportShare)$($BatchName)_failedpst.csv"
}
set-content -Value "Failed-PST" -Path $list".new"
foreach ($woops in $Incomplete) {
add-content -Value $woops.FilePath -Path $list".new"
}

}
}

$endtime = get-date -displayhint time

$runtimefile = "$($ReportShare)$($BatchName)_runtime.txt"
$runtimeentry0 = $starttime.tostring() + ' - ' + $endtime.tostring()
$runtimeentry1 = "Completed exports: " + $completed.count
$runtimeentry2 = "Failedexports: " + $Incomplete.count
$runtimeentry3 = "Errored users:"
$runtimeentry4 = ( get-content -Path $list".new" | out-string)
Set-Content -Value $runtimeentry0 -Path $runtimefile
add-content -Value $runtimeentry1 -Path $runtimefile
add-content -Value $runtimeentry2 -Path $runtimefile
add-content -Value $runtimeentry3 -Path $runtimefile
add-content -Value $runtimeentry4 -Path $runtimefile

# Remove Requests
Write-Output "Removing requests created as part of batch '$($BatchName)'"
Get-MailboxExportRequest -BatchName $BatchName | Remove-MailboxExportRequest -Confirm:$false

Get Directory permission with powershell (2013-01-21T12:23:00.000+01:00)

Author: Bas Steelooper

One of my customers was facing a migration of their data to a new location. It was a cross domain migration so we don't want to take all the permissions with us in the migration (robocopy /DATS) and needed to find out the current situation.

Before I used the tool Security Explorer from Little Wonders.. And found out that through several take overs this is now Dell... (Scriptlogic -> Quest --> Dell)

since the software had gotten richer over the years with additional functions the price had also gone up, and is now only available in a time limited license..

So I thought, I can do this myself in PowerShell... And the result was very good (as I do say so myself)

I started out with the following script to get the permissions on the first 3 levels..

$OutFile = "C:tempfolder-Permissions.csv"
$Header = "Folder Path,IdentityReference,AccessControlType,FileSystemRights,IsInherited"
Del $OutFile
Add-Content -Value $Header -Path $OutFile

$RootPath = "z:\"

$Folders = get-CHildItem $RootPath | where {$_.psiscontainer -eq $true}

foreach ($Folder in $Folders){
$ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access }
Foreach ($ACL in $ACLs){
if ($ACL.IdentityReference -eq "BUILTINAdministrators"){
}else{
$OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
Add-Content -Value $OutInfo -Path $OutFile
}
}
}

$Folders = get-CHildItem $RootPath* | where {$_.psiscontainer -eq $true}

foreach ($Folder in $Folders){
$ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access }
Foreach ($ACL in $ACLs){
if ($ACL.IdentityReference -eq "BUILTINAdministrators"){
}else{
$OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
Add-Content -Value $OutInfo -Path $OutFile
}
}
}

$Folders = get-CHildItem $RootPath** | where {$_.psiscontainer -eq $true}

foreach ($Folder in $Folders){
$ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access }
Foreach ($ACL in $ACLs){
if ($ACL.IdentityReference -eq "BUILTINAdministrators"){
}else{
$OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
Add-Content -Value $OutInfo -Path $OutFile
}
}
}

$Folders = get-CHildItem $RootPath*** | where {$_.psiscontainer -eq $true}

foreach ($Folder in $Folders){
$ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access }
Foreach ($ACL in $ACLs){
if ($ACL.IdentityReference -eq "BUILTINAdministrators"){
}else{
$OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
Add-Content -Value $OutInfo -Path $OutFile
}
}
}

So since this worked, I started optimizing the code for posting on my blog.. and came up with the following. (Remember I want only the first 3 levels)

$OutFile = "C:tempfolder-Permissions.csv"
$Header = "Folder Path,IdentityReference,AccessControlType,FileSystemRights,IsInherited"
Del $OutFile
Add-Content -Value $Header -Path $OutFile

$RootPath = "z:\"

Function getSubFolderpermissions ($folders){
foreach ($Folder in $Folders){
$ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access }
Foreach ($ACL in $ACLs){
if ($ACL.IdentityReference -eq "BUILTINAdministrators"){
}else{
$OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
Add-Content -Value $OutInfo -Path $OutFile
}
}
}
}


$Folders = get-CHildItem $RootPath | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $folders

$Folders = get-CHildItem $RootPath* | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $folders

$Folders = get-CHildItem $RootPath** | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $folders

$Folders = get-CHildItem $RootPath*** | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $folders


but still I didn't like this..

so after I little active rewriting I found this:
$OutFile = "C:tempfolder-Permissions.csv"
$Header = "Folder Path,IdentityReference,AccessControlType,FileSystemRights,IsInherited"
remove-item $OutFile
Add-Content -Value $Header -Path $OutFile

$RootPath = "\san2hdswbr$Docs"
$levelsdeep = 3

Function getSubFolderpermissions ($Folders, $currentlevel){
if ($currentlevel -lt ($levelsdeep + 1)){
foreach ($map in $Folders){
$subfolders = get-CHildItem $map.fullname | where {$_.psiscontainer -eq $true}
if (!($subfolders -eq $null)){
getSubFolderPermissions $subfolders ($currentlevel +1)
}
$ACLs = get-acl $map.fullname | ForEach-Object { $_.Access }
Foreach ($ACL in $ACLs){
if ($ACL.IdentityReference -eq "BUILTINAdministrators"){
}else{
$OutInfo = $map.Fullname + ";" + $ACL.IdentityReference + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
Add-Content -Value $OutInfo -Path $OutFile
}
}
}
}
}

$Mappen = get-CHildItem $RootPath | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $Mappen, 0

Why my MacBook Air keeps crashing (2012-11-01T20:31:00.001+01:00)

Author: Bas Steelooper

Since I am somewhat profound on using Microsoft Software, I thought I needed a new challenge. So I bought myself a Apple MacBook Air.

I was very happy using it, didn’t miss that much functionality which I couldn’t add in another way with a simple application. I can manage all Microsoft Networks at ease… So I kept on using Mac OSX. (I do have a dual boot to Windows 8 which I work on regularly)

Since the beginning of June my MacBook started freezing, or Crashing… and I couldn’t find out why. So I started my troubleshooting skills on it and finally I found it…

What I noticed was the following. When the power is disconnected for a few seconds, and than reconnected the freeze would occur, but not always..

So It could be a power thingy, or a power save thingy… But still a little vague. And since it is doesn’t happen always it was extra strange… So I started to note which Applications I have open on the system when the crash or freeze occurs…

Mostly I had the same programs running in the system:

* Outlook
* iTAP RDP
* Google Chrome
* Word
* Excel

But finally saturday at home I found it. I had only one program running when the freeze occurred: Google Chrome.

So I switched back to Safari, and stopped using Chrome. And am crash free for a few days now.

But a program such as Google Chrome should not be able to freeze or crash my system. So I started my search on the internet, and apparently I am not the only one with this problem since I found a load of references. The consensus seems to be that it has to do with the GPU acceleration used in Google Chrome. So my initial idea that it was a Power Safe Thingy might be right. When the power is disconnected the Mac switches from the highpower gpu to an internal low power GPU. When the power is reconnected Google Chrome starts to panic and keeps feeding the internal GPU and with that overloading the system bus and therefor freezing the system.

On a google Chrome forum I found that Google acknowledges this problem with the GPU and has disabled some features to track the problem down, but still haven’t found it. Now they have filed a bug report with Apple in the hope that Apple can fix something on their end.

So until this is fixed, I am to use Safari or Firefox.. But I think that for now I stick to Safari.

Create an Import Export Management Group with rights (2012-09-27T11:39:00.003+02:00)

Author: Bas Steelooper

To be able to use the other script to import PST Files, you first must have the permission to do so.

Since I am in favor of RBAC I created a little script to create an Exchange Import and Export Management Group, add the current user to this group and assign the appropriate rights to the group.

# To be able to import PST files you must be member of the Import Export Management Role.
# Bas Steelooper, XOBIT IT Services
#
# This script will create an AD Group in the users OU named Exchange-ImportExport-Management
# And add the current user to this group.
# You have to logoff and logon again to use the newly acquired rights

# Configure here the name of the group to create
$GroupName = "Exchange-ImportExport-Management"

#============================
# Do not edit below this line
#============================

#Prepare the needed modules
Import-Module ActiveDirectory
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010

# Create the AD Group as a Universal Group
New-ADgroup -Name $GroupName -GroupScope 2

# Add the current logged on user to the Group
Add-ADGroupMember -Identity $GroupName $env:username

# Assign the Import Export Rights to the Group
New-ManagementRoleAssignment -Name "ImportExport-Management" -SecurityGroup $GroupName -Role "Mailbox Import Export"


Importing a ####-Load of PST Files into Exchange (2012-09-24T12:22:00.001+02:00)

Author: Bas Steelooper

For a migration we needed to import a lot of PST files into the mailboxes of migrated users.. Since I am an IT guy, and therefor lazy, I created a script to do this.

This script creates a folder for each PST file with the name: "Import ()"

Prereqs for the script are:
* For each user with to be imported PST files create a folder with the first part of the emailadres (everything in front of the @-sign)
* add the PST files in the appropriate folder
* Edit the first two lines of the script to point to the share where the data resides, and the domainname with the @-Sign
* User must have the Import and Export management role assigned

# PST Import script.
# Bas Steelooper, XOBIT IT Services
#
# This script will import the PST files from a given location.
# The PST files must reside in a folder which is named as the part of the emailadres in front of the @-sign
#
# This script will import each folder one at a time and cleanup all the completed imports
# With the command Get-MailBoxImportRequest you can view all the failed import requests

# Configure the parameters.
# $pstpath contains the share location where the PST Files are stored. ( The AD Computer account must have access to this location)
# $emaildomain contains the rest of the emailadres for all users
# $forceimport if $TRUE thePST-File will be forced imported, items which cannot be imported are skipped. Default is $FALSE
$pstpath = "\<server><share>UsersPSTData"
$emaildomain = "@steelooper.com"
$forceimport = $TRUE

#============================
# Do not edit below this line
#============================

#Load the Exchange powershell Snap-IN
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010

get-ChildItem $pstpath | Foreach-object{

$curuser = ""
$curuser = $_
$PSTFiles = get-ChildItem $pstpath$curuser
$PSTFiles | Foreach-Object{
if ($forceimport) {
New-MailboxImportRequest -BatchName $curuser -BadItemLimit 200 -AcceptLargeDataLoss -Name $_ -MailBox $curuser$emaildomain -FilePath $pstpath$curuser$_ -TargetRootFolder "INBOX/Import ($_)"
}
else {
New-MailboxImportRequest -BatchName $curuser -Name $_ -MailBox $curuser$emaildomain -FilePath $pstpath$curuser$_ -TargetRootFolder "INBOX/Import ($_)"
}
}

while ((Get-MailboxImportRequest -BatchName $curuser | Where {$_.Status -eq "Queued" -or $_.Status -eq "InProgress"}))
{
sleep 60
}
Get-MailboxImportRequest -BatchName $curuser | Where {$_.Status -eq "Completed"} | Remove-MailboxImportRequest -Confirm:$false;
}


Dell Business Client Operating System Deployment - The .CAB Files - The Dell TechCenter (2010-03-29T11:46:00.001+02:00)

Author: Bas Steelooper

Dell Business Client Operating System Deployment - The .CAB Files - The Dell TechCenter

I was creating an 64 Bit MDT Boot image and added the WinPE 64 Bit drivers to the Boot image. The Boot image generation failed for the following drivers:
* DELL CERC SATA 1.5/6ch RAID Controller
* DELL CERC SATA 1.5/6ch RAID Management Device
* DELL PERC 5/E Adapter RAID Controller
* DELL PERC RAID Virtual Device
* Dell PERC S100 S300 Controller [storport]
* Dell SAS 5/E Adapter
* ATI AHCI Compatible RAID Controller
* Broadcom HT1000 SATA Controller(AMD64 Release)
The creation of the Boot image was successful after removal of the above drivers.

In the description it states that these are Vista Drivers. Is it possible these are not compatible with Windows7 PE?

Regards,

Bas Steelooper

The Standard Setting Session (2010-02-13T19:25:00.001+01:00)

Author: Bas Steelooper

Due to the NDA I cannot tell you what went on during the Session. But I can tell you that it is a very nice experience. I wouldn't have missed it for the world.
Also it was very nice to meet Krista for once. I had never met her in person and enjoyed meeting her.
There were 5 other SME's in the session and 4 Microsoft employees.

It started at 8:30 at which we received coupons to get breakfast. Then we started the real session, with a break at 11:45 to get some lunch (also with coupons). The session was over at 17:30 so a bit later than the other SME's had expected. They had all done this before so they did know what to expect, as I didn't.

What I thought was very good of Microsoft is the care for the environment. All materials used are compostable (Not the tin cans ofcourse, but those are recycled)

I really enjoyed being there, and being part of this session.

[update: Arrived in Redmond] No longer At the airport waiting to board........ (2010-02-10T10:15:00.002+01:00)

Author: Bas Steelooper

Today I am at the airport awaiting boarding. I am going to the United States of America and to be specific to Redmond, WA.

Yes there is the head office of Microsoft. I am invited to join a Set the Standard Session for an upcoming OS Examination. (Details are not allowed according to the NDA) I am invited since I passed the exam excellent or near excellent...

All arrangements are made, flight is booked, I cleared the security and am awaiting boarding.
At arrival in Seattle there should be a car waiting so I have some freedom driving around and seeing things. The hotel is also booked....
Tomorrow (11 feb 2010) I am expected at Microsoft at 8:30 and will be there the whole day. Friday I have some freetime to do a little sight seeing and I fly back on saturday.

I will keep you updated...

[update]
I successfully boarded and exited the plane, cleared the US Customs, and am in my hotel room now.....

I will take it easy and go to Microsoft tomorrow.....

Out of Office in outlook 2010 (2010-01-08T10:35:00.002+01:00)

Author: Bas Steelooper

A lot of people ask me how to set the "Out Of Office" in the new and improved Outlook 2010.

This is why I thought up to make a little how to. And here it is.

To set the Out of Office (Automatic Reply as is it is called now) you start Outlook 2010.

When Outlook is started you click on the yellow File button in the top left corner (See image below)


















In the new screen make sure that Info is selected on the left hand site, and then click on Automatic Replys (Out of Office) (See image below)

























In the new screen, which is similar as the Office 2007 Out Of Office Assistant screen, you can set your Automatic Reply

To do this select "Send automatic replies"

Optional: if only during a certain time frame this message must be send select "Only send during this time range:" and fill in the dates with times.

Insert your message in the "Inside My Organization" part. (This message will only be send within the same exchange organization)

Note: To send Automatic replies to people outside your organization ( for instance customers) you can add a message in the "Outside my organization" tab

71-693 - Promotion not found for the Netherlands :-( (2009-12-14T10:06:00.003+01:00)

Author: Bas Steelooper

Today we all could register for the 71-693 Exam. That is everyone with an SME profile. Disappointing it was that I set the alarmclock at 6 AM (12:00 EST) to register for the exam. Only to get the following message: Promotion not found. (In green as it must be a good thing???)
Contacted Microsoft but they didn't have a clue either... Than wait until 8 AM to call Prometric.
Prometric was very busy this morning so I was on hold for about 20 - 25 minutes before a Customer Service Representative could talk to me. But they were not able to help me with the registration :-( They escalated this, but for the moment with no result.
We have to wait until 12 PM or 1 PM before this can be resolved. And by then the slots will be full.

Helmer has also posted on his blog and several people have responded that they were unable to register.

I'll update this post if something changes.

UPDATE:
Just phoned Prometric again. Escalation is started from Europe, but the escalation seems to be only an email message to Prometric in the United States. They will start to wake up (come into the office) around 2PM (14:00 CET) and start with a cup of coffee, talk about the weekend and then read the mails about this problem. And then start to fix it. This will probably take a few hours to investigate and fix so registration must be possible around 8PM (20:00 CET). I asked them what kind of escalation process this is, but they are bound by the rules which are created in the States.
There is nothing we can do but wait....

UPDATE 2:
A colleague called me that the problem was resolved and yes I was able to register....
So where all the people who I know were stressing to register for the exam....

New version installer template Version 1.2 (2009-12-08T10:39:00.008+01:00)

Author: Bas Steelooper

Updated the installer template to a new version.
Changes are:

ADDED:
isApplicationInstalled : Check if an application is installed.
isApplicationInstalledGUID : Check if an application is installed by its Identifier.
Usefull when the Add Remove Programname is not unique
isProcessActive : Check if a process is active.
MODIFIED:
uninstallAppGUID : Fixed the exit code to be unique.

Download link: Install_Template-1.2.vbs

Changes are below:

'==========================================================================
'
' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2009
'
' NAME: Installer script template V1.2
' AUTHOR: Bas Steelooper , Steelooper Consulting
' DATE : 08-12-2009
'
' Modifications
' V1.1
' ADDED:
' uninstallAppGUID : Uninstall an application by its Identifier.
' Usefull when the Add Remove Programname is not unique
' MODIFIED:
' s_ForceUseCSCript : added variable forceCscriptSilent.
' If set to TRUE the script will NOT notify the end user that it is being relaunched
' s_ForceUseCSCript : WSHShell.run modified to hidden.
' When relaunched the script now doesn't show a cscript window.
'
' V1.2
' ADDED:
' isApplicationInstalled : Check if an application is installed.
' isApplicationInstalledGUID : Check if an application is installed by its Identifier.
' Usefull when the Add Remove Programname is not unique
' isProcessActive : Check if a process is active.
' MODIFIED:
' uninstallAppGUID : Fixed the exit code to be unique.
'
'==========================================================================

........

Const APPVER = "1.2"

........

Sub showHelp()
'===============================================================================
'# Purpose : show help information on how to use the script #
'# #
'# Modified in version 1.2 #
'===============================================================================

.....

If debug Then

.....

WScript.Echo vbTab & "66600005"& vbTab & " : uninstallAppGUID is called without information"'added in version 1.2
WScript.Echo vbTab & "66600006"& vbTab & " : isProcessActive is called without information"'added in version 1.2
WScript.Echo vbTab & "66600007"& vbTab & " : isApplicationInstalled is called without information"'added in version 1.2
WScript.Echo vbTab & "66600008"& vbTab & " : isApplicationInstalledGUID is called without information"'added in version 1.2
End If

.....

End Sub

.........

Function isProcessActive(objWMIService, arrProcName)
'==============================================================================================================================
'# purpose : check if the processes passed to this service are active #
'# input : objWMIService : initialised object from GetObject("winmgmts:"& "{impersonationLevel=impersonate}!\.rootcimv2") #
'# arrProcName : Array which contains the names of the processes to be checked #
'# String which contains one name of a process to be checked #
'# #
'# Example: arrProcName = Array("outlook", "communicator", "winword", "excel", "powerpnt", "access") #
'# isProcessActive objWMI, arrProcName  #

'# #
'# Added in version 1.2 #
'==============================================================================================================================
writeLog "starting isProcessActive", "Starting isProcessActive", "isProcessActive"
Dim colProcesses, strQuery, procName, first
strQuery = "Select * from Win32_Process where "
first = True

If IsArray( arrProcName ) Then
For Each procName In arrProcName
If Not first Then
strQuery = strQuery & "OR "
End If
strQuery = strQuery & "Name Like '%"& procName &"%'"
first = false
Next
Else
If arrProcName = "" Then
writeLog "ERROR isProcessActive", "ERROR - Started isProcessActive with no Process te check "& _
"- Terminiting script now with errorcode 66600006", "isProcessActive"
WScript.Quit (66600006)
Else
strQuery = strQuery & "Name Like '%"& arrProcName &"%'"
End if
End If

Set colProcesses = objWMIService.ExecQuery(strQuery)
Dim Process
isProcessActive = False
For Each Process In colProcesses
isProcessActive = True
Next
End Function

..........

Private Sub uninstallAppGUID( objWMIService, arrAppName )

.......

writeLog "ERROR UNINSTALL","Error uninstalling because no parameter was set. exiting with errorcode 66600005", "uninstallAppGUID"'fixed in version 1.2

.......

End Sub

Private Function isApplicationInstalled( objWMIService, arrAppName )
'==============================================================================================================================
'# purpose : check if the applications which are given in the input are installed #
'# input : objWMIService : initialised object from GetObject("winmgmts:"& "{impersonationLevel=impersonate}!\.rootcimv2") #
'# arrAppName : Array which contains the names of the applications to be checked #
'# String which contains one name of a applications to be checked #
'# #
'# Example: arrCheckAppName = Array("Office 2003 Proofing", "Microsoft Office Proof", "visio viewer") #
'# isApplicationInstalled objWMI, arrCheckAppName #
'# #
'# Added in version 1.2 #
'==============================================================================================================================
writeLog "starting isApplicationInstalled","starting to run the sub isApplicationInstalled", "isApplicationInstalled"
Dim colSoftware, objSoftware, strQuery, first, strAppName
strQuery = "Select * from Win32_Product Where "
first = True
on error resume next
If IsArray( arrAppName ) Then
For Each strAppName In arrAppName
If Not first Then
strQuery = strQuery & "OR "
End If
strQuery = strQuery & "Name Like '%"& strAppName &"%'"
first = false
Next
Else
If arrAppName = "" Then
writeLog "ERROR CHECK","Error checking because no parameter was set. exiting with errorcode 66600007", "isApplicationInstalled"
WScript.Quit (66600007)
End if
strQuery = strQuery & "Name Like '%"& arrAppName &"%'"
End If
Set colSoftware = objWMIService.ExecQuery (strQuery)
on error resume next
isApplicationInstalled = False
For Each objSoftware in colSoftware
writeLog "checking application","Now checking "& objSoftware.Name, "isApplicationInstalled"
isApplicationInstalled = True
Next
on error goto 0
End Function

Private Function isApplicationInstalledGUID( objWMIService, arrAppName )
'==============================================================================================================================
'# purpose : check if the applications which are given in the input are installed #
'# input : objWMIService : initialised object from GetObject("winmgmts:"& "{impersonationLevel=impersonate}!\.rootcimv2") #
'# arrAppName : Array which contains the names of the applications to be checked #
'# String which contains one name of a applications to be checked #
'# #
'# Example: arrCheckAppName = Array("{34E9AA45-3D13-4DBD-8BC9-7F06AB39B090}", "{34666A45-3D13-4DBD-8BC9-7F0612345690}") #
'# isApplicationInstalledGUID objWMI, arrCheckAppName #
'# #
'# Added in version 1.2 #
'==============================================================================================================================
writeLog "starting isApplicationInstalledGUID","starting to run the sub isApplicationInstalledGUID", "isApplicationInstalledGUID"
Dim colSoftware, objSoftware, strQuery, first, strAppName
strQuery = "Select * from Win32_Product Where "
first = True

If IsArray( arrAppName ) Then
For Each strAppName In arrAppName
If Not first Then
strQuery = strQuery & "OR "
End If
strQuery = strQuery & "IdentifyingNumber = '%"& strAppName &"%'"
first = false
Next
Else
If arrAppName = "" Then
writeLog "ERROR CHECK","Error checking because no parameter was set. exiting with errorcode 66600008", "isApplicationInstalledGUID"
WScript.Quit (66600008)
End if
strQuery = strQuery & "IdentifyingNumber = '%"& arrAppName &"%'"
End If
Set colSoftware = objWMIService.ExecQuery (strQuery)
on error resume next
isApplicationInstalled = False
For Each objSoftware in colSoftware
writeLog "checking application","Now checking "& objSoftware.Name, "isApplicationInstalledGUID"
isApplicationInstalled = True
Next
on error goto 0
End Function

Use it freely if you want. But please post here if you do.

Sys internals AD Explorer bypasses security settings in AD (2009-12-07T15:42:00.004+01:00)

Author: Bas Steelooper

I recently found that the AD Explorer tool from Sysinternals has a different way of handling the display of OU structures.

In an active directory an OU is setup with security rights so that only administrators can view the contents. If you fire up Active Directory Users and Computers this won't show the contents of this folder as suspected.

Since I also use alternative tools to do thing I also us AD Explorer. Since a collegue had trouble seeing the contents of hte OU, I found that I was able to view the contents of the OU. This is strange since we have similar user rights.

I haven't found out yet why AD explorer behaves different apposed to the native tooling. Especially since Microsoft acquired Systinternals and the tools are placed on technet.

Update:
Today I was unable to access the same OU. The only thing changed is that all members are now changed with security rights to only be visible to administrators. Looks like that when an object in an OU is visible to the user, AD Explorer will open the OU to show this object (and all others)

New version installer template 1.1 (2009-12-07T12:49:00.004+01:00)

Author: Bas Steelooper

Updated the installer template to a new version.
Changes are:

ADDED:
uninstallAppGUID : Uninstall an application by is Identifier.
Usefull when the Add Remove Programname is not unique
MODIFIED:
s_ForceUseCSCript : added variable forceCscriptSilent.
If set to TRUE the script will NOT notify the end user that it is being relaunched
s_ForceUseCSCript : WSHShell.run modified to hidden.
When relaunched the script now doesn't show a cscript window.


'==========================================================================
'
' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2009
'
' NAME: Installer script template V1.1
' AUTHOR: Bas Steelooper , Steelooper Consulting
' DATE : 07-12-2009
'
' COMMENT: This is the installer script template
' Create a foler to hold the install sources and this script
' Following folder structure:
'
' APPLICATION-XYZ
' |------ INSTALLATION-SOURCES
' | |--- ..........
' |
' ------ install_Template.vbs
'
' Modify the following functions to your needs
' parseCommandLineArguments
' If additional commandline options are required
' showHelp
' If additional commandline options are possible describe them here
' runTask
' The installtion tasks
'
' Start from SMS/SCCM with commandline "cscript install_Template.vbs [-debug] [logfolder]"
'
' Modifications
' V1.1
' ADDED:
' uninstallAppGUID : Uninstall an application by is Identifier.
' Usefull when the Add Remove Programname is not unique
' MODIFIED:
' s_ForceUseCSCript : added variable forceCscriptSilent.
' If set to TRUE the script will NOT notify the end user that it is being relaunched
' s_ForceUseCSCript : WSHShell.run modified to hidden.
' When relaunched the script now doesn't show a cscript window.
'
'==========================================================================

'=========================
'# Constants declaration #
'=========================
Const FILENAME = "install_Template.vbs"
Const APPNAME = "Tempalte-Installer"
Const APPDESCRIPTION = "This is the installer script template"
Const APPVER = "1.1"
Const COPYYEAR = "2009"
Const AUTHOR = "Bas Steelooper"
Const COMPANYNAME = "Steelooper Consulting"

'constants for registry editing
Const HKEY_CLASSES_ROOT = &H80000000
Const HKEY_CURRENT_USER = &H80000001
Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_USERS = &H80000003
Const HKEY_PERFORMANCE_DATA = &H80000004
Const HKEY_CURRENT_CONFIG= &H80000005
Const HKEY_DYN_DATA = &H80000006

'constants for textfiles
Const FORREADING = 1
Const FORWRITING = 2
Const FORAPPENDING = 8

'constants for eventlog
Const SUCCESS = 0
Const ERRORL = 1
Const WARNING = 2
Const INFORMATION = 4

'constants for disk access
Const HARD_DISK = 3
Const CONVERT_GB = 1073741824

'Constants for MSI
const msiUILevelNoChange = 0 'Does not change UI level.
const msiUILevelDefault = 1 'Uses default UI level.
const msiUILevelNone = 2 'Silent installation.
const msiUILevelBasic = 3 'Simple progress and error handling.
const msiUILevelReduced = 4 'Authored UI and wizard dialog boxes suppressed.
const msiUILevelFull = 5 'Authored UI with wizards, progress, and errors.
const msiUILevelHideCancel = 32 'If combined with the msiUILevelBasic value, the installer shows progress dialog boxes but does not display a Cancel button on the dialog box to prevent users from canceling the installation.
const msiUILevelProgressOnly = 64 'If combined with the msiUILevelBasic value, the installer displays progress dialog boxes but does not display any modal dialog boxes or error dialog boxes.
const msiUILevelEndDialog = 128 'If combined with any above value, the installer displays a modal dialog box at the end of a successful installation or if there has been an error. No dialog box is displayed if the user cancels.

'=========================
'# Variables declaration #
'=========================
Dim WshShell, scriptPath, objWMI, objProcess, objFSO, strPath
Dim hostname, logFile ,debug

'=========================
'# Object initialization #
'=========================
set WshShell = CreateObject("WScript.Shell")
Set objWMI = GetObject("winmgmts:"&"{impersonationLevel=impersonate}!\.rootcimv2")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\.rootdefault:StdRegProv")
hostname = WshShell.ExpandEnvironmentStrings("%COMPUTERNAME%")

'=============================
'# Determine script location #
'=============================
scriptPath = left(Wscript.scriptFullName, (len(Wscript.scriptFullName) - len(WScript.ScriptName)))

'=============================================================
'#Check if script is invoked by cscript engine, force if not #
'=============================================================
Const forceCscriptSilent = False
s_ForceUseCScript

'================================================================
'# Parse the commandline parameters and start the actual script #
'================================================================
parseCommandLineArguments

'=========================
'# Functions declaration #
'=========================

Sub parseCommandLineArguments ()
'====================================================================
'# Purpose : Parse the command line parameters #
'# Input : #
'====================================================================
Dim noUninstall, onlyProof, noProof, logFolder
debug = False
logFolder = WshShell.ExpandEnvironmentStrings("%SystemRoot%") &"temp\"
For Each argument In WScript.Arguments
Select Case argument
Case "-debug"
debug = True
Case Else
If StrComp(Right(argument,1), "\") <> 0 Then
logFolder = argument &"\"
End If
If Not objFSO.FolderExists( logFolder ) Then
WScript.Quit(80040005)
End If
End Select
Next

On Error Resume Next
Set logFile = objFSO.CreateTextFile(logfolder & hostname &"-"& APPNAME &"-trace.log", FORAPPENDING, True)
If Err.Number = 70 Or Err.Number = 46 Then
WScript.Echo "not running as administrator....."
logfolder = WshShell.ExpandEnvironmentStrings("%temp%") &"\"
WScript.Echo logfolder
Set logFile = objFSO.CreateTextFile(logfolder & hostname &"-"& APPNAME &"-trace.log", FORAPPENDING, True)
writeLog "LogfileError", "ERROR|Not running as administrator", "parseCommandLineArguments"
End If
On Error GoTo 0
'===================
'# Show the banner #
'===================
scriptBanner

'======================
'# Show the Help info #
'======================
showHelp

'======================================================
'# Start the main app #
'# if additional arguments are possible add them here #
'======================================================
Call runTask( )

'======================
'# Cleanup and exit #
'======================
'Close the logfile
logFile.Close
'quit with exitcode 0
WScript.quit
'quit with exitcode 3010 (For SCCM if reboot is required)
WScript.quit(3010)
End Sub

Sub showHelp()
'===============================================================================
'# Purpose : show help information on how to use the script #
'===============================================================================
wscript.echo "usage: cscript "& FILENAME &" [-debug] [-nouninstall] [-onlyproof] [logfolder]"
wscript.echo vbTab &"-debug"& vbTab & vbTab &"Show debug information"
wscript.echo vbTab &"logfolder"& vbTab &"Alterantive logfolder"
wscript.echo vbTab &"Default logfolder is c:windowstemp"
WScript.Echo ""
WScript.Echo "Possible error codes: "
If debug Then
WScript.Echo vbTab &"66600001"& vbTab &" : patchApp is called without information"
WScript.Echo vbTab &"66600002"& vbTab &" : installApp is called without information"
WScript.Echo vbTab &"66600003"& vbTab &" : killProcesses is called without information"
WScript.Echo vbTab &"66600004"& vbTab &" : uninstallApp is called without information"
End If
WScript.Echo vbTab &"80040005"& vbTab &" : Logfolder not accessible"
WScript.Echo ""
WScript.Echo "To see the returncode you start the script form a command prompt"
Wscript.Echo "and issue the command:"
WScript.Echo vbTab &"echo %errorlevel%"
End Sub

Sub runTask( )
'==============================================================================================================================
'# purpose : the actual script to run. #
'==============================================================================================================================
writeLog "start Runtask", "runTask started with the following parramenters "& _
"*debug = "& debug, "runtask"
Dim arrRemoveApps, arrKillProcesses, strDiskSize, strKeyPath, strValueName, strValue, strCMD, dwordValue

'===================================================
'# Optional: Not in use with SCCM #
'# Disckspace check for use when not in SMS / SCCM #
'===================================================
Set objLogicalDisk = objWMI.Get("Win32_LogicalDisk.DeviceID='c:'")
strDiskSize = (objLogicalDisk.FreeSpace / CONVERT_GB)
If strDiskSize < 2 Then
writeLog "checkDiskSize", "ERROR : Disksize is less than required. Why am I running???"& _
" If I am not started from SCCM this line should be changed."& _
" If run from SMS/SCCM the minimal disc requirement must be set!!!!", "runtask"
'Solve in SMS / SCCM When not in SMS / SCCM uncomment the following line
'wscript.Quit(666)
End If

'===========================================
'# Kill some Running processes if required #
'===========================================
arrKillProcesses = Array("dummy123","dummy234","dummy567")
killProcesses objWMI, arrKillProcesses

'===============================================
'# Uninstalling some obsolete applications #
'===============================================
'By application name from Add Remove Programs
arrRemoveApps = Array("Dummy123", "Dummy234", "Dummy456")
uninstallApp objWMI, arrRemoveApps

'By GUID (Product ID)
arrRemoveApps = Array("{34E9AA45-3D13-4DBD-8BC9-7F06AB39B090}", "{34666A45-3D13-4DBD-8BC9-7F0612345690}")
uninstallAppGUID objWMI, arrRemoveApps

'============================================
'# Installing the application by executable #
'============================================
writeLog "startInstall","Starting installation of Application XYZ", "runtask"
strCMD = scriptPath &"APPLICATIONSOURCEsetup.exe"
WshShell.Run strCMD, 2, True

'==========================================
'# Installing the application by msi file #
'==========================================
'With an MST file
installApp "APPLICATION-SOURCESmyapp.msi", "APPLICATIONSOURCEmyapp.mst", "LAUNCHEDBYSETUPEXE=1"
'Without an MST file
installApp "APPLICATION-SOURCESmyapp.msi", "", "LAUNCHEDBYSETUPEXE=1"
'Without properties
installApp "APPLICATION-SOURCESmyapp.msi", "APPLICATIONSOURCEmyapp.mst", ""

'==========================================
'# Patch the application With an msp file #
'==========================================
'With properties
patchApp "APPLICATIONSOURCEmyapp.msp", "MYPROPERTIE=TRUE"
'Without properties
patchApp "APPLICATIONSOURCEmyapp.msp", ""

'========================================
'# Remove legacy folder from Start Menu #
'========================================
strPath = WshShell.ExpandEnvironmentStrings("%ALLUSERSPROFILE%")&"Start MenuPrograms\"&"My Dummy String"
If objFSO.FolderExists (strPath) Then
writeLog "delete folder","Deleting the obsolete folder", "runtask"
objFSO.DeleteFolder(strPath)
End If


'===================================
'# Write something To the registry #
'===================================
strKeyPath = "SOFTWAREGetronicsConsulting"
strValueName = "Bas"
strValue = "Steelooper"
dwordValue = "2009"
'Write an String value
oReg.SetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue
'Write an DWord value
oReg.SetDwordValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, dwordValue

'====================================
'# Read something from the registry #
'====================================
strKeyPath = "SOFTWAREGetronicsConsulting"
strValueName = "Bas"
strValue = ""
dwordValue = ""
'Read an String value into strValue
oReg.getStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue
'Read an DWord value into dwordValue
oReg.getDwordValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, dwordValue

'=========================================
'# Finished processing all install tasks #
'=========================================
writeLog "Finished runTask","Finished processing the runtask sequence", "runtask"
End Sub

Private Sub uninstallApp( objWMIService, arrAppName )
'==============================================================================================================================
'# purpose : uninstall the applications which are given in the input #
'# input : objWMIService : initialised object from GetObject("winmgmts:"&"{impersonationLevel=impersonate}!\.rootcimv2") #
'# arrAppName : Array which contains the names of the applications to be uninstalled #
'# String which contains one name of a applications to be uninstalled #
'# #
'# Example: arrRemoveApps = Array("Office 2003 Proofing", "Microsoft Office Proof", "visio viewer") #
'# uninstallApp objWMI, arrRemoveApps #
'==============================================================================================================================
writeLog "starting uninstallApp","starting to run the sub uninstallApp", "uninstallApp"
Dim colSoftware, objSoftware, strQuery, first, strAppName
strQuery = "Select * from Win32_Product Where "
first = True
on error resume next
If IsArray( arrAppName ) Then
For Each strAppName In arrAppName
If Not first Then
strQuery = strQuery &"OR "
End If
strQuery = strQuery &"Name Like '%"& strAppName &"%'"
first = false
Next
Else
If arrAppName = "" Then
writeLog "ERROR UNINSTALL","Error uninstalling because no parameter was set. exiting with errorcode 66600004", "uninstallApp"
WScript.Quit (66600004)
End if
strQuery = strQuery &"Name Like '%"& arrAppName &"%'"
End If
Set colSoftware = objWMIService.ExecQuery (strQuery)
For Each objSoftware in colSoftware
writeLog "uninstalling","Now uninstalling "& objSoftware.Name, "uninstallApp"
objSoftware.Uninstall()
Next
on error goto 0
End Sub

Private Sub uninstallAppGUID( objWMIService, arrAppName )
'==============================================================================================================================
'# purpose : uninstall the applications which are given in the input #
'# input : objWMIService : initialised object from GetObject("winmgmts:"&"{impersonationLevel=impersonate}!\.rootcimv2") #
'# arrAppName : Array which contains the names of the applications to be uninstalled #
'# String which contains one name of a applications to be uninstalled #
'# #
'# Example: arrRemoveApps = Array("{34E9AA45-3D13-4DBD-8BC9-7F06AB39B090}", "{34666A45-3D13-4DBD-8BC9-7F0612345690}") #
'# uninstallAppGUID objWMI, arrRemoveApps #
'==============================================================================================================================
writeLog "starting uninstallApp","starting to run the sub uninstallApp", "uninstallApp"
Dim colSoftware, objSoftware, strQuery, first, strAppName
strQuery = "Select * from Win32_Product Where "
first = True

If IsArray( arrAppName ) Then
For Each strAppName In arrAppName
If Not first Then
strQuery = strQuery &"OR "
End If
strQuery = strQuery &"IdentifyingNumber = '%"& strAppName &"%'"
first = false
Next
Else
If arrAppName = "" Then
writeLog "ERROR UNINSTALL","Error uninstalling because no parameter was set. exiting with errorcode 66600004", "uninstallApp"
WScript.Quit (66600004)
End if
strQuery = strQuery &"IdentifyingNumber = '%"& arrAppName &"%'"
End If
Set colSoftware = objWMIService.ExecQuery (strQuery)
on error resume next
For Each objSoftware in colSoftware
writeLog "uninstalling","Now uninstalling "& objSoftware.Name, "uninstallApp"
objSoftware.Uninstall()
Next
on error goto 0
End Sub

Private Sub killProcesses ( objWMIService, arrKillProc )
'==============================================================================================================================
'# purpose : kill the processes which are passed to the function #
'# input : objWMIService : initialised object from GetObject("winmgmts:"&"{impersonationLevel=impersonate}!\.rootcimv2") #
'# arrKillProc : Array which contains the names of the processes to be terminated #
'# String which contains one name of a process to be terminated #
'# #
'# Example: arrKillProcesses = Array("outlook", "communicator", "winword", "excel", "powerpnt", "access") #
'# killProcesses objWMI, arrKillProcesses #
'==============================================================================================================================
writeLog "starting killProcesses", "Starting killProcesses", "killProcesses"

Dim colSoftware, objSoftware, strQuery, first, procName
strQuery = "Select * from Win32_Process where "
first = True

If IsArray( arrKillProc ) Then
For Each procName In arrKillProc
If Not first Then
strQuery = strQuery &"OR "
End If
strQuery = strQuery &"Name Like '%"& procName &"%'"
first = false
Next
Else
If arrKillProc = "" Then
writeLog "ERROR killProcesses", "ERROR - Started killProcesses with no Process te kill "& _
"- Terminiting script now with errorcode 66600003", "killProcesses"
WScript.Quit (66600003)
Else
strQuery = strQuery &"Name Like '%"& procName &"%'"
End if
End If

Set colProcess = objWMIService.ExecQuery (strQuery)
For Each objProcess in colProcess
writeLog "running killProcesses", "Killing process : "& objProcess.name, "killProcesses"
objProcess.Terminate()
Next
End Sub

Private Sub installApp( strMSI, strMST, properties )
'==========================================================================================================================
'# purpose : Install an application by directly using the Windows Installer API instead of using msiexec #
'# input : strMSI : path to the msi file to install located in a subfolder of this scriptfile #
'# strMST : path to the mst file used transform the install located in a subfolder of this scriptfile #
'# properties : String containing additional properties to pass on to the installation #
'# Standard the following are added ALLUSERS=TRUE REBOOT=REALLYSUPPRESS #
'# ALLUSERS=TRUE > if the application is scripted per user. this will install for all users #
'# REBOOT=REALLYSUPPRESS > Make sure that the installation will not reboot the machine #
'# #
'# Example: installApp "ProofingExtraPROOF_DEProof.msi", "ProofingExtraPROOF_DEProof.mst", "LAUNCHEDBYSETUPEXE=1" #
'==========================================================================================================================
writeLog "starting installApp","starting to run the sub installApp", "installApp"
If IsEmpty(strMSI) Or strMSI = "" Then
writeLog "ERROR INSTALL","Error installing because no msi parameter was set. exiting with errorcode 66600002", "installApp"
WScript.Quit(66600002)
End if
Dim objInstaller
set objInstaller = createobject("WindowsInstaller.Installer")
objInstaller.uilevel = msiUILevelNone
If strMST <>"" then
writeLog "Start installation","starting the installation of MSI File: '"& strMSI &"' with Transform file : '"& strMST &"'", "installApp"
writeLog "Start installation","Applying the properties: 'ALLUSERS=TRUE REBOOT=REALLYSUPPRESS "& strMST &"'", "installApp"
objInstaller.InstallProduct scriptPath & strMSI, "TRANSFORMS="& scriptPath & strMST &" ALLUSERS=TRUE REBOOT=REALLYSUPPRESS "& properties
Else
writeLog "Start installation","starting the installation of MSI File: "& strMSI, "installApp"
writeLog "Start installation","Applying the properties: 'ALLUSERS=TRUE REBOOT=REALLYSUPPRESS "& strMST &"'", "installApp"
objInstaller.InstallProduct scriptPath & strMSI, "ALLUSERS=TRUE REBOOT=REALLYSUPPRESS "& properties
End If
writeLog "Finished installation","Finished the installation of MSI : '"& strMSI &"'", "installApp"
End Sub

Private Sub patchApp( strMSP, properties )
'====================================================================================================================
'# purpose : Patch an application by directlu using the Windows Installer API instead of using msiexec #
'# input : strMSP : path to the msp file to install located in a subfolder of this scriptfile #
'# properties : String containing additional properties to pass on to the installation #
'# Standard the following are added REBOOT=REALLYSUPPRESS #
'# REBOOT=REALLYSUPPRESS > Make sure that the installation will not reboot the machine #
'# #
'# Example : patchApp "ProofingExtraSP2proofsp2-de-de.msp", "" #
'====================================================================================================================
writeLog "starting patchApp","starting to run the sub patchApp", "patchApp"
If IsEmpty(strMSP) Or strMSP = "" Then
writeLog "ERROR PATCHING","Error patching because no msp parameter was set. exiting with errorcode 66600001", "patchApp"
WScript.Quit(66600001)
End If
Dim objInstaller
Set objInstaller = createobject("WindowsInstaller.Installer")
objInstaller.uilevel = msiUILevelNone
writeLog "Start installation","starting the installation of MSP File: "& strMSP, "patchApp"
writeLog "Start installation","Applying the properties: 'REBOOT=REALLYSUPPRESS "& strMST &"'", "patchApp"
objInstaller.ApplyPatch scriptPath & strMSP, "", 0, " REBOOT=REALLYSUPPRESS "& properties
writeLog "Finished installation","Finished the installation of MSP : '"& strMSP &"'", "patchApp"
End Sub

Sub s_Error(i,s)
'========================================================================
'# Purpose : Show errors generated by engine and abort script operation #
'# Input : i : err.number (integer) #
'# s : err.description (string) #
'========================================================================

wscript.echo "ERROR!"
wscript.echo "The error code was : "& i
wscript.echo "The error code in hex : "& Hex(i)
wscript.echo "The error description : "& s
wscript.quit

End Sub

Sub writeLog(strEvent, strDescription, strLocation )
'====================================================================
'# Purpose : Write logging to a file. #
'# Input : strEvent : The event to log to file #
'# strDescription : The description to log to file #
'# strLocation : the location where the logging came from #
'====================================================================
Dim strDate, strTime
strDate = parsedigits(DAY(date()),2) &"-"& _
parsedigits(MONTH(date()),2) &"-"& _
parsedigits(YEAR(date()),2)
strTime = parsedigits(Hour(Now),2) &":"& _
parsedigits(minute(Now),2) &":"& _
parsedigits(Second(Now),2)
logFile.WriteLine(strTime &"|"& strDate &"|"& strLocation &"|"& strEvent &"|"& strDescription)
if debug then wscript.echo(strTime &"|"& strDate &"|"& strLocation &"|"& strEvent &"|"& strDescription)
End Sub

Sub scriptBanner()
'====================================================================
'# Purpose : show the banner and copyright of the script #
'# Input : #
'====================================================================
wscript.echo APPNAME &" - "& APPDESCRIPTION &"."
wscript.echo "Copyright (c) "& COPYYEAR &" - "& COMPANYNAME &" - "& AUTHOR
wscript.echo ""
writeLog "APPNAME", APPNAME &" - "& APPDESCRIPTION &".", "scriptBanner"
writeLog "APPNAME", "Copyright (c) "& COPYYEAR &" - "& COMPANYNAME &" - "& AUTHOR, "scriptBanner"
writeLog "", "", ""
End Sub

Function parsedigits(valuetoparse, totalDigits)
'====================================================================
'# Purpose : Return a value which is the number of digits required #
'# Input : valuetoparse : The values which must be parsed #
'# totalDigits : The number of digits required to fill #
'# #
'# example : parsedigits(2,2) returns 02 #
'# parsedigits(2,1) returns 2 #
'# parsedigits(2,3) returns 002 #
'====================================================================
if totalDigits > len(valuetoparse) then
parsedigits = String(totalDigits-len(valuetoparse),"") & valuetoparse
else
parsedigits = valuetoparse
end if
End Function

Sub s_ForceUseCScript()
'********************************************
' Purpose: Force script to use cscript engine
'********************************************
dim strScriptEngine, exitcode
strScriptEngine = Right(WScript.FullName,len(WScript.FullName) - instrrev(WScript.FullName,"\"))
If Not LCase(strScriptEngine) = "cscript.exe" And Not LCase(strScriptEngine) = "primalhost.dll" Then
If Not forceCscriptSilent Then
WshShell.Popup "Script is not invoked uder cscript engine. Relaunching under cscript...",5,"WSCRIPT"
End If
dim strArguments
strArguments = ""
For Each arg In WScript.Arguments
If arg &"\"<> scriptPath Then strArguments = strArguments &""& arg
Next
exitcode = WshShell.Run( "cmd.exe /C "& WshShell.ExpandEnvironmentStrings("%SystemRoot%") &"system32cscript.exe //NOLOGO "& Chr(34) & WScript.scriptFullName & Chr(34) & strArguments, 0, True)
WScript.Quit(exitcode)
End If

End Sub

'GENERIC INFORMATION

'REGISTRY
'Initialise registry
' sComputer = "."'(Localhost)
' Set oRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}//"& _
' sComputer &"/root/default:StdRegProv")

'Functions for registry editing
' GetBinaryValue - reads regisry value of BINARY type
' GetDWORDValue - reads registry value of DWORD type
' GetExpandedStringValue - reads registry value of EXPANDED STRING type
' GetMultiStringValue - reads registry value of MULTI STRING type
' GetStringValue - reads registry value of STRING type
' CreateKey - creates registry key
' SetBinaryValue - writes registry value of BINARY type
' SetDWORDValue - writes registry value of DWORD type
' SetExpandedStringValue - writes registry value of EXPANDED STRING type
' SetMultiStringValue - writes registry value of MULTI STRING type
' SetStringValue - writes registry value of STRING type
' DeleteKey - deletes registry key
' DeleteValue - deleting registry value
' EnumKey - enumerates registry key
' EnumValues - enumerates registry value
' CheckAccess - checks permissions on registry key

'WINDOWS INSTALLER
'initialisatie Windows Installer
' Set objInstaller = createobject("WindowsInstaller.Installer")

'Functions for Windows Installer Object
' AddSource - Adds a source to the list of valid network sources in the sourcelist.
' AdvertiseProduct - Advertises an installation package.
' AdvertiseScript - Advertises an installation package.
' ApplyPatch - Invokes an installation and sets the PATCH property to the path of the patch package for each product listed by the patch package as eligible to receive the patch.
' ApplyMultiplePatches - Applies one or more patches to products eligible to receive the patch. Sets the PATCH property to the path of the patch packages provided.
' ClearSourceList - Removes all network sources from the sourcelist.
' CollectUserInfo - Invokes a user interface wizard sequence that collects and stores both user information and the product code.
' ConfigureFeature - Configures the installed state of a product feature.
' ConfigureProduct - Installs or uninstalls a product.
' CreateAdvertiseScript - Generates an advertise script.
' CreateRecord - Returns a new Record object with the requested number of fields.
' EnableLog - Enables logging of the selected message type for all subsequent installation sessions in the current process space.
' ExtractPatchXMLData - Extracts information from a patch as an XML string.
' FileHash - Takes the path to a file and returns a 128-bit hash of that file.
' FileSignatureInfo - Takes the path to a file and returns a SAFEARRAY of bytes that represents the hash or the encoded certificate.
' FileSize - Returns the size of the specified file.
' FileVersion - Returns the version string or language string of the specified path.
' ForceSourceListResolution - Forces the installer to search the source list for a valid product source the next time a source is required.
' InstallProduct - Opens an installer package and initializes an installation session.
' LastErrorRecord - Returns a Record object that contains error parameters for the most recent error from the function that produced the error record.
' OpenDatabase - Opens an existing database or creates a new one.
' OpenPackage - Opens an installer package for use with functions that access the product database and install engine.
' OpenProduct - Opens an installer package for an installed product using the product code.
' ProvideAssembly - Returns the installed path of an assembly.
' ProvideComponent - Returns the full component path and performs any necessary installation.
' ProvideQualifiedComponent - Returns the full component path and performs any necessary installation.
' RegistryValue - Reads information about a specified registry key of value.
' ReinstallFeature - Reinstalls features or corrects problems with installed features.
' ReinstallProduct - Reinstalls a product or corrects installation problems in an installed product.
' RemovePatches - Removes one or more patches to products eligible to receive the patch.
' UseFeature - Increments the usage count for a particular feature and returns the installation state for that feature.

'Properties for Windows Installer Object
' ClientsEx - Read-only - Returns a RecordList object that lists products that use a specified installed component.
' Windows Installer 4.5 and earlier: Not supported.
' ComponentClients - Read-only - Returns a StringList object enumerating the set of clients of a specified component.
' ComponentPath - Read-only - Returns the full path to an installed component.
' ComponentPathEx - Read-only - Returns a RecordList object that gives the full path of a specified installed component.
' Windows Installer 4.5 and earlier: Not supported.
' ComponentQualifiers - Read-only - Returns a StringList object enumerating the set of registered qualifiers for the specified component.
' Components - Read-only - Returns a StringList object enumerating the set of installed components for all products.
' ComponentsEx - Read-only - Returns a RecordList object that lists installed components.
' Windows Installer 4.5 and earlier: Not supported.
' Environment - Read-only - The string value for an environment variable of the current process.
' FeatureParent - Read-only - Specifies the parent feature of a feature.
' Features - Read-only - Returns a StringList object enumerating the set of published features for the specified product.
' FeatureState - Read-only - Returns the installed state of a feature.
' FeatureUsageCount - Read-only - Returns the number of times that the feature has been used.
' FeatureUsageDate - Read-only - Returns the date that the specified feature was last used.
' FileAttributes - Read-only - Returns a number that represents the combined file attributes for the designated path to a file or folder.
' Patches - Read-only - Returns a StringList object that contains all the patches applied to the product.
' PatchesEx - Read-only - Enumerates a collection of Patch objects.
' PatchFiles - Read-only - Returns a StringList object that contains a list of files that can be updated by the provided list of patches.
' PatchInfo - Read-only - Returns information about a patch.
' PatchTransforms - Read-only - Returns the semicolon delimited list of transforms that are in the specified patch package and applied to the specified product.
' ProductElevated - Read-only - Returns True if the product is managed or False if the product is not managed.
' ProductInfo - Read-only - Returns the value of the specified attribute for an installed or published product.
' ProductInfoFromScript - Read-only - Returns the value of the specified attribute that is stored in an advertise script.
' Products - Read-only - Returns a StringList object enumerating the set of all products installed or advertised for the current user and machine.
' ProductsEx - Read-only - Enumerates a collection of Product objects.
' ProductState - Read-only - Returns the install state information for a product.
' QualifierDescription - Read-only - Returns a text string that describes the qualified component.
' RelatedProducts - Read-only - Returns a StringList object enumerating the set of all products installed or advertised for the current user and machine with a specified UpgradeCode property in their property table.
' ShortcutTarget - Read-only - Examines a shortcut and returns its product, feature name and component if available.
' SummaryInformation - Read-only - Returns a SummaryInfo object that can be used to examine, update and add properties to the summary information stream of a package or transform.
' UILevel - Read-Write - Indicates the type of user interface to be used when opening and processing subsequent packages within the current process space.
' Version - Read-only - Returns the string representation of the current version of Windows Installer



Use it freely if you want. But please post here if you do.

Trust my own domain in Windows XP and IE 7 (2009-09-08T17:10:00.002+02:00)

Author: Bas Steelooper

With the introduction of Internet Explorer 7 we found that some script in GPO's and programs
on shares failed to run. This because a File Security Warning was shown.

Because we don't want to restrict users from adding sites to the Trusted Zone it was not an
option to do this with the internet explorer option in the GPO. For this purpose this script
is created to perform just this task.


'==========================================================================
'
' NAME: Add the current AD Domain to local intranet zone for Windows XP and Internet Explorer 7
'
' AUTHOR: Bas Steelooper , Steelooper Consulting
' DATE : 8-12-2008
'
' COMMENT: With the introduction of Internet Explorer 7 we found that some script in GPO's and programs
' on shares failed to run. This because a File Security Warning was shown.
'
' Because we don't want to restrict users from adding sites to the Trusted Zone it was not an
' option to do this with the internet explorer option in the GPO. For this purpose this script
' is created to perform just this task.
'
'==========================================================================


On Error Resume Next

Const HKEY_CURRENT_USER = &H80000001
Const HKEY_USERS = &H80000003

strComputer = "."
Set objReg = GetObject("winmgmts:"&"{impersonationLevel=impersonate}\"& strComputer &"rootdefault:StdRegProv")

strKeyPath = ".DEFAULTSoftwareMicrosoftWindowsCurrentVersionInternet Settings\"&"ZoneMapDomainssteelooper.com*.blog"
objReg.CreateKey HKEY_USERS,strKeyPath
strValueName = "*"
dwValue = 1
objReg.SetDWORDValue HKEY_USERS,strKeyPath,strValueName,dwValue

strKeyPath = ".DEFAULTSoftwareMicrosoftWindowsCurrentVersionInternet Settings\"&"ZoneMapDomainssteelooper.comblog"
objReg.CreateKey HKEY_USERS,strKeyPath
strValueName = "*"
dwValue = 1
objReg.SetDWORDValue HKEY_USERS,strKeyPath,strValueName,dwValue

strKeyPath = "SoftwareMicrosoftWindowsCurrentVersionInternet Settings\"&"ZoneMapDomainssteelooper.com*.blog"
objReg.CreateKey HKEY_CURRENT_USER,strKeyPath
strValueName = "*"
dwValue = 1
objReg.SetDWORDValue HKEY_CURRENT_USER,strKeyPath,strValueName,dwValue

strKeyPath = "SoftwareMicrosoftWindowsCurrentVersionInternet Settings\"&"ZoneMapDomainssteelooper.comblog"
objReg.CreateKey HKEY_CURRENT_USER,strKeyPath
strValueName = "*"
dwValue = 1
objReg.SetDWORDValue HKEY_CURRENT_USER,strKeyPath,strValueName,dwValue



Use it freely if you want. But please post here if you do.

Manage local admins through Active Directory (2009-09-08T17:01:00.002+02:00)

Author: Bas Steelooper

For a Client we needed a way to grant a user local admin rights to his / her PC/laptop. We could use Group Policy but than we need an GPO per computer, we could use AD Groups, but than we need an AD Group for each computer and maintain that.

For this I came up with the idea to use the Managed By field of a computer object in AD. You enter a username in that field and assign the following script to run at startup through GPO.

Problem solved.....


'==========================================================================
'
' NAME: Managed By to Local Admin
'
' AUTHOR: Bas Steelooper , Steelooper Consulting
' DATE : 18-11-2008
'
' COMMENT: Add the managed by user to the local administrators.
'
'==========================================================================

On Error Resume Next
Const ADS_SCOPE_SUBTREE = 2

dim hostname
dim objGroup

Set wshshell = CreateObject("WScript.Shell")
Set ObjEnv = WshShell.Environment("Process")
hostname = ObjEnv("COMPUTERNAME")

Set objGroup = GetObject("WinNT://./Administrators,group")

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")

objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"

Set objCommand.ActiveConnection = objConnection
objCommand.CommandText = _
"Select Name, ManagedBy from "& _
"'LDAP://DC=code1,DC=emi,DC=philips,DC=com' where objectClass='computer' and name='"& hostname &"'"
objCommand.Properties("Page Size") = 10
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst


Do Until objRecordSet.EOF

Set objUser = GetObject( "LDAP://"& objRecordSet.Fields("ManagedBy") )

username = objUser.sAMAccountName
objGroup.add("WinNT://Code1/"&username&",user")

Set objGroup = Nothing
objRecordSet.MoveNext
Loop


Use it freely if you want. But please post here if you do.