Logfiles roteren met Powershell

In een typische shared hosting omgeving krijg je binnen de map van de gebruiker een locatie waar log bestanden worden weggeschreven.   Als hoster heb je dan een groot aantal (liefst Knipogende emoticon) mappen met in elk van die mappen een map “logs” waarin al snel (alles samen) duizenden log files staan.  Het volgende Powershell script overloopt alle mappen (zeg maar alle klanten) en neemt alle log bestanden die minstens 7 dagen oud zijn, steekt die in een zip bestandje met als naam JAAR-WEEKINJAAR.ZIP en verwijdert die file vervolgens.   Het script is makkelijk aanpasbaar om dit bvb. maandelijks te doen ipv wekelijks.

$TargetFolder = "c:\Sites"
$Now = Get-Date
$ArchiveFrom = $Now.AddDays(-7)
 
$mappen = get-childitem -Path $TargetFolder
          | Where {$_.psIsContainer -eq $true}
foreach ($map in $mappen)
{
  $mapuse = "$TargetFolder\$map\log"
  if (Test-Path ($mapuse))
  {
    $logbestanden = dir -Recurse $mapuse | Where {($_.LastWriteTime -le "$ArchiveFrom") 
            -and ($_.extension -eq ".log")}
    $bestandsnaam = get-date -uFormat %Y-%V
    $zipfile = "$mapuse\$bestandsnaam.zip"
    echo $zipfile
    set-content "$zipfile" ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
 
    (dir $zipfile).IsReadOnly = $false
    $shellApplication = new-object -com shell.application
    $zipPackage = $shellApplication.NameSpace($zipfile)
    foreach ($logfile in $logbestanden)
    {
            $zipPackage.CopyHere($logfile.FullName)
            Start-sleep -milliseconds 1000
            Remove-Item $file | out-null
 
    }
  }
}

Bij vragen of opmerkingen, hoor ik graag van u !


Foto’s sorteren met PowerShell op basis van EXIF informatie

Misschien heb je het zelf ook ooit eens voorgehad en dan weet je hoe onprettig het is: Je hebt duizenden foto’s van jaren ver netjes onderverdeeld in mapjes en submapjes en om een of andere reden krijg je ze allemaal netjes onder elkaar met een nietszeggende naam in één map. Met het powershell scriptje hieronder kan je alvast die vele duizenden bestanden terug in mapjes plaatsen op basis van het tijdstip waarop ze genomen werden.  Tenminste voor zover de bestanden EXIF informatie bevatten (elk deftig toestel van de laatste 5 jaar plaatst dit in elk foto die gemaakt wordt).

Om dit scriptje te kunnen uitvoeren heb je wel de image module nodig die je als onderdeel van het PowerShellPack vindt. Downloaden kan hier : http://archive.msdn.microsoft.com/PowerShellPack  Controleren of je de module hebt kan met dit commando (psimagetools)

Get-Module -ListAvailable
 
De module inladen (kan eventueel als eerste lijntje in het script toegevoegd worden) kan met het commando
 
Import-Module PSImageTools
 
En dan is dit het scriptje die de bestanden maand per maand in mapjes plaatst
 
$bestanden = get-childitem "d:\testps" | 
                          where {$_.extension -eq ".jpg"}
foreach ($bestand in $bestanden)
{
  $datum = ((Get-Image $bestand | Get-ImageProperty).dt);
  $maand = $datum.month
  $jaar = $datum.year;
  
  if (!(Test-Path "d:\testps\$jaar-$maand"))
  {
     md $jaar-$maand;
  }
  Move-Item $bestand "d:\testps\$jaar-$maand";
}

PHP, JSON en Javascript

Wie vandaag de dag niet minstens een handvol van die hippe Ajax gif’s heeft staan draaien op zijn website is niet meer mee met deze tijd. En toch krijg ik dagdagelijks de vraag hoe dit correct te implementeren. Easy … toch ?

<img src="ajax.gif" alt="How cool is this" /> <!-- Yup, developpers humor -->

Zelfs als je er nog wat asynchrone communicatie bij wil blijft het eenvoudig. Ongeacht of je nu PHP, ASP … gebruikt als server scripting taal en of je nu jquery, prototype, … gebruikt als client side scripting taal. Bij voorkeur gebruik je JSON als formaat om gegevens te transporteren.

JSON is even eenvoudig als krachtig.  Je hebt altijd paren van “identifiers” en “values” die van elkaar gescheiden worden door middel van een : (dubbel punt). Verder worden objecten omsloten door { }, array’s worden omsloten door  [ ], Strings worden omsloten door dubbele quotes.   En op eenvolgende paren van identifier+value worden van elkaar gescheiden door een komma. Dit is even kort door de bocht maar is toch wel 95% volledig. 

Omdat voorbeelden vaak veel meer zeggen dan al te veel bla bla, dit stukje PHP code waarin ik op een geheel onorthodoxe wijze een aantal objecten aanmaak.

   1:    class Person
   2:    {
   3:        public $name;
   4:        public $givenname;
   5:        public $age;
   6:        public $adult;
   7:    }
   8:   
   9:    class Family
  10:    {
  11:      public $father;
  12:      public $mother;
  13:      public $kids;
  14:    }
  15:    
  16:    $a = new Family();
  17:    
  18:    $a->father = new Person();
  19:    $a->mother = new Person();
  20:    $a->kids = array();
  21:   
  22:    $a->father->name = "Depuydt";
  23:    $a->father->givenname = "Dieter";
  24:    $a->father->age = 27; // I Wish
  25:    $a->father->adult = true;
  26:    
  27:    $a->mother->name = "My"; 
  28:    $a->mother->givenname = "Wife";
  29:    $a->mother->age = 27; 
  30:    $a->mother->adult = true;
  31:   
  32:    $b = new Person();
  33:    $b->name = "Depuydt";
  34:    $b->givenname = "Daughter";
  35:    $b->age = 4;
  36:    $b->adult = false;
  37:    
  38:    $c = new Person();
  39:    $c->name = "Depuydt";
  40:    $c->givenname = "Son";
  41:    $c->age = 2;
  42:    $c->adult = false;
  43:   
  44:    array_push($a->kids, $b);
  45:    array_push($a->kids, $c);

Dit resulteert dus in een family object “a”, dat 4 person objecten bevat, 2 los in het object (father en mother) en 2 in een array (kids).  We hebben zowel tekst, getallen als booleans.  Dit omzetten in JSON geeft ons

   1:  {
   2:    "father":
   3:        {"name":"Depuydt","givenname":"Dieter","age":27,"adult":true},
   4:   
   5:    "mother":
   6:        {"name":"My","givenname":"Wife","age":27,"adult":true},
   7:   
   8:    "kids":
   9:     [
  10:        {"name":"Depuydt","givenname":"Daughter","age":4,"adult":false},
  11:        {"name":"Depuydt","givenname":"Son","age":2,"adult":false}
  12:     ]
  13:  }
 

De omzetting van PHP object naar JSON string kan je volledig zelf programmeren maar in PHP is dat niet nodig, er bestaat een kant en klare functie die het werk voor ons doet :

   1:  json_encode($a);

Nu rest ons enkel nog het object in JSON formaat op te vragen, de tijd dat het duurt om de informatie te ontvangen ons uber hip ajax symbooltje te tonen en uiteindelijk eens de (json) informatie ontvangen er iets mee aan te vangen.  Dit kan met elke vorm van client side scripting, hier gebruiken we de prototype library.

In onderstaand voorbeeldje gaan we ervan uit dat de HTML pagina waarin we werken een DIV met ID “json” heeft.   We vragen onze PHP pagina op waarin onze object structuur zit alsook het commando om het object om te zetten in json. Het resultaat daarvan wordt gewoon ge-echo’d.

 
   1:  <script type="text/javascript">
   2:  var url = 'index.php';
   3:   
   4:  new Ajax.Request(url, {
   5:      method: 'get',
   6:      onLoading : function() {
   7:          $('json').innerHTML = "<img src='ajax.gif' alt='How cool is this' />";
   8:      },
   9:      onSuccess: function(originalRequest) {
  10:          var invoer = originalRequest.responseText.evalJSON();
  11:          $('json').innerHTML = invoer.kids[1].givenname;
  12:      }
  13:  });
  14:  </script>

Op lijn 6 zie je dat we bij het begin van de aanvraag alvast ons ajax.gif symbooltje aan de gebruikers presenteren.

Op lijn 9 ontvangen we als alles goed gaat de JSON string, die we verwerken met evalJSON() en het resultaat daarvan opnieuw kunnen gaan gebruiken als objecten/arrays. zoals je kan zien op lijn 11.


IIS 7 scripting met PowerShell

Het configureren van een website in IIS 7 en alles daarrond kan flink wat van je tijd opslopren als je dat telkens volgens een uniforme wijze wil gedaan hebben. Gelukkig kunnen we een aardig stukje scripten. Anno 2011 gaat dat bijzonder eenvoudig met behulp van Powershell en de nodige snap-in’s. 

Zie hier een scriptje dat op een voor de eindgebruiker eenvoudige wijze een propere website configureert.  Er wordt een website aangemaakt, in een eigen app pool ondergebracht, er wordt een map voorzien om de IIS logs in te plaatsen (LOGS), een map waarin de website kan schrijven (DATA), plaats voor een eventuele Access DB …

 
# Enkele Variabelen
 
$basis = "c:\webserver"
$defaultpass = "*********"
$ftpsite = "FTP General"
 
# Inladen van de belangrijkste module van dit script WebAdministration
 Import-Module WebAdministration
 
# Domeinnaam opvragen en indien nodig converteren naar upper case
 do
 {
    $domain = Read-Host "Domein ? (geen http:// of www) "
 } while (Test-Path("$basis\$domain"))
 $domain = $domain.ToUpper()
 
# Filesysteem klaarmaken voor onze nieuwe website
 md "$basis\$domain"
 md "$basis\$domain\WWW"
 md "$basis\$domain\LOGS"
 md "$basis\$domain\DATA"
 md "$basis\$domain\DB"
 
# Application pool aanmaken en de .NET versie instellen op 4
 New-WebAppPool -Name $domain
 $AppPool = Get-Item "IIS:\AppPools\$domain"
 $AppPool.managedRuntimeVersion = "v4.0"
 $AppPool.Enable32BitAppOnWin64 = "true"
 $AppPool | Set-Item
 
# Website aanmaken met 2 hostheaders (domain + www.domain), 
juiste app pool gebruiken, logs juist plaatsen
 New-WebSite -Name $domain -Port 80 -HostHeader $domain 
    -PhysicalPath "$basis\$domain\www"
 Set-ItemProperty "IIS:\Sites\$domain" ApplicationPool $Domain
 New-ItemProperty "IIS:\Sites\$domain" -name bindings 
    -value (@{protocol="http";bindingInformation="*:80:WWW.$domain"})
 Set-ItemProperty "IIS:\Sites\$domain" -name logFile.directory 
    -value "$basis\$domain\logs"
 
# Gebruiker aanmaken met default password
$objOu = [ADSI]"WinNT://localhost"
$objUser = $objOU.Create("User", $domain)
$objUser.setpassword($defaultpass)
$objUser.SetInfo()
 
# Modify rechten voor de Gebruiker op de root van de hosting
$acl = Get-Acl "$basis\$domain"
$permission = "$domain","Modify","ContainerInherit, 
    ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.
    FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
$acl | Set-Acl "$basis\$domain"
 
# Lees en uitvoer rechten voor de App Pool gebruiker op de 
# root van de hosting
$acl = Get-Acl "$basis\$domain"
$permission = "IIS AppPool\$domain","ReadAndExecute","ContainerInherit, 
    ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.
    FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
$acl | Set-Acl "$basis\$domain"
 
# Modify rechten voor de App Pool gebruiker op de DB en DATA map
$acl = Get-Acl "$basis\$domain\DATA"
$permission = "IIS AppPool\$domain","Modify","ContainerInherit, 
    ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.
    FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
$acl | Set-Acl "$basis\$domain\DATA"
 
# Modify rechten voor de App Pool gebruiker op de DB en DATA map
$acl = Get-Acl "$basis\$domain\DB"
$permission = "IIS AppPool\$domain","Modify","ContainerInherit, 
    ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.
    FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
$acl | Set-Acl "$basis\$domain\DB"
 
# FTP Virtuale map aanmaken (virtuel map naam = gebruikersnaam = 
#    direct binnenkomen in deze map)
New-WebVirtualDirectory -Site "$ftpsite" -Name "$domain" 
    -PhysicalPath "$basis\$domain"
 
# Op niveau van de FTP site (niet op de virtuele map) geven we de user
# toestemming op de FTP site te lezen/schrijven (NTFS rechten beperken de rest)
Add-WebConfiguration -Filter /System.FtpServer/Security/Authorization 
    -Value (@{AccessType="Allow"; Users="$domain"; 
        Permissions="Read, Write"}) 
    -PSPath IIS: -Location "$ftpsite"
 
 
Een van de komende dagen komt er nog een uitbreiding van het script met de mogelijkheid om een aantal specifieke zaken in te stellen op niveau van IIS 7.

Bij vragen of problemen met dit script, aarzel niet mij te contacteren.


Belgacom boost het Internet …

In een advertentie die ik dit weekend van tussen de croissants en de boterkoeken opmerkte stond te lezen dat Belgacom het Internet gaat boosten … waarmee ze bedoelden dat ze de achtervolging inzetten op Telenet op vlak van data volume en snelheid.   De perfecte aanleiding om mijn eigen Internet pakket eens na te kijken (@Telenet) en de pakketten eens te vergelijken.

De snelheden variëren van 15 Mbps tot 30 Mbps (bij Belgacom) en van 20 Mbps tot 100 Mbps (bij Belgacom).   Toen ik minder dan 10 jaar geleden voor het eerst een breedband verbinding had was ik de koning te rijk met 1 Mbps.  Voor particulieren die laat ons zeggen max. 4 pc’s in huis hebben lijkt 15 Mbps (het minimum nog verkrijgbaar blijkbaar) MEER dan voldoende.

Het datavolume varieert van 50 GB tot onbeperkt (yeah right)  bij beide providers.  Als je nu niet de ganse maand een top quality streaming audio laat opstaan en geen pogingen onderneemt om een mirror op te zetten van YouTube dan volstaat dit voor de meeste particulieren.

Ik vraag mij dus af welke mensen een duurder abonnement dan het allergoedkoopste nodig hebben. En hoeveel mensen zich een duurder hebben laten aansmeren zonder dat nodig te hebben.   Hoogtijd om ook UW internet factuur onder de loep te nemen !!


Ongelezen berichten in openbare mappen met PowerShell

In tegenstelling tot klassieke mailmappen is het bij Openbare mappen (de zogenaamde Public Folders) niet mogelijk het aantal ongelezen berichten weer te geven en/of de map in kwestie vetjes te plaatsen als er tout court ongelezen berichten zijn. Behoorlijk vervelend als je zo’n 100 mapjes hebt die mail enabled zijn …

Met regels op die mappen kan je de berichten uiteraard naar je eigen mailbox laten doorsturen bij wijze van “alarm” maar met dit klein PowerShell scriptje heb je direct een overzichtje zonder je eigen mailbox te laten vollopen.

 1: $ol = new-object -comobject Outlook.Application
 2: $folderarray= @()
 3: $prefix = ""
 4: 
 5: function GetRecurrentFolder($map)
 6: {
 7:   $prefix += "--"
 8:   foreach ($item in $map.Folders)
 9:   {
 10:     $olkf = New-Object PSObject -Property @{
 11:         tName = $prefix + $($item.Name)
 12:         tUnRead = $($item.UnReadItemCount)
 13: 
 14:     }
 15:     $global:folderarray += $olkf
 16:     GetRecurrentFolder $item
 17:     }
 18: }
 19: 
 20: foreach ($x in ($ol.Session.Folders | where { $_.FolderPath -match '\\my public folder'}))
 21: {
 22:     GetRecurrentFolder $x
 23: }
 24: $global:folderarray| ft

 

Het scriptje geef het aantal ONGELEZEN mailtjes in de MAP zelf weer en niet de cumul met eventuele onderliggende mappen.


Powershell scripts digitaal ondertekenen

Out-of-the-box is uitvoeren van PowerShell scriptjes niet toestaan uit veiligheidsoverweging. Tijdens “de speeltijd” is dit makkelijk aan te passen met het PowerShell commando “Set-ExecutionPolicy”. Er zijn 4 verschillende execution policy’s nl.”Restricted” (default), “AllSigned”, “RemoteSigned” en “Unrestricted”.

In de standaard policy is scripts uitvoeren dus totaal onmogelijk. Wanneer de policy gewijzigd wordt naar “Unrestricted” dan kunnen alle scripts probleemloos uitgevoerd worden. Wordt de policy ingesteld op “AllSigned” kunnen alleen digitaal ondertekende scripts uitgevoerd worden en tenslotte als er geopteerd wordt voor “RemoteSigned” dan kunnen scripts op de lokale harde schijf sowieso uitgevoerd worden terwijl scripts vanop webpagina’s, e-mail etc … enkel uitgevoerd worden als ze digitaal ondertekend zijn.

Om na te gaan in welke modus je computer nu staat maak je gebruik van het commando “Get-ExecutionPolicy”

 1: PS C:\Users\DDIT\Documents> Get-ExecutionPolicy
 2: Restricted

 

En om in een test fase hier geen “last” meer van te hebben bedien je je van het commando

 1: Set-ExecutionPolicy -ExecutionPolicy Unrestricted

Voor het uitvoeren van het commando “Set-ExecutionPolicy” zijn wel administrator rechten nodig ! Maar zoals gezegd is deze oplossing sowieso enkel geschikt binnen development en testing doeleinden en niet echt op productie machines. We gaan onze scripts digitaal ondertekenen. We kunnen dat doen met aangekocht certificaten bij GlobalSign of Thawte maar we kunnen ook onze eigen certificaten uitschrijven. Die zijn technisch gezien perfect evenwaardig met de commerciële alternatieven …

We beginnen met ons “Root” certificaat te maken, we promoveren ons als het ware tot een soort GlobalSign. Op servers waar onze scripts moeten uitgevoerd worden zal dit root certificaat moeten toegevoegd worden aan de vertrouwde basis certificaten.

Certificaten maken kan met het gratis programmaatje “makecert.exe” dat oa. in de Windows SDK te vinden is. Als developper of sysadmin heb je die wellicht sowieso op je computer staan anders => http://msdn.microsoft.com/en-us/windowsserver/bb980924.aspxHet root certificaat dat je aanmaakt zal je kunnen beveiligen met een wachtwoord.

makecert
-n "CN=DDIT Root Cert"  <= naam van het root cert
-a sha1  <= hashing algoritme (kon md5 geweest zijn ook)
-eku 1.3.6.1.5.5.7.3.3  <= doel van het certificaat
-r  <= self signed
-sv root.pvk root.cer  <= bestandsnaam voor het certificaat + private key
-ss Root  <= de cert store waarin het cert geplaatst wordt
-sr localMachine <= de cert store location (default is Current User en we willen het cert toch voor iedereen op onze computer :) ).

 

Nu gaan we op basis van ons net gemaakt root certificaat een certificaat maken om onze code mee te ondertekenen. Dit certificaat is wat je zou krijgen van GlobalSign / Thawte.

makecert
-pe  <= zorgt ervoor dat het certificaat geëxporteerd kan worden
-n "CN=PowerShell Dieter"  <= Naam van het certificaat
-ss MY  <=
-a sha1  <= Hashing algoritme
-eku 1.3.6.1.5.5.7.3.3  <= doel van het certificaat (code signing)
-iv root.pvk  <= Private key file van het root certificaat
-ic root.cer <= Root certificaat

 

Voor het aanmaken van het certificaat heb je het paswoord nodig van het root certificaat. Tijd om even te controleren in de GUI jQuery1520729151956219397_1312664369995 Start een MMC module en voeg de “Certificaten” module toe. ( mmc => Bestand, Module toevoegen of verwijderen => Certificaten => Mijn Gebruikersaccount). We vinden ons root certificaat

1

en ons zelf uitgeschreven certificaat

2

Met het PowerShell commando “get-childitem cert:\CurrentUser\My -codesigning” kan je alle certificaten opvragen die je ter beschikking hebt om code te ondertekenen. Wellicht zal dat er maar eentje zijn. Als de output hier al goed is kan je veder gaan met het ondertekenen van je script.

Set-AuthenticodeSignature
.\GetRunningProcess.ps1  <= te ondertekenen file
@(Get-ChildItem cert:\CurrentUser\My -codesigning)[0] <= handtekening

 

Na het uitvoeren van bovenstaand commando is de script file uitgebreid met je digitale handtekening. Mission Accomplished !!

3

Als je er nu voor zorgt dat de executionpolicy op AllSigned staat kan je het script uitvoeren … maar … je krijgt een melding dat het script getekend is door een onbekend iemand … Het volstaat om één keer “A” te antwoorden. Je code certificaat wordt dan ook toegevoegd aan de “Trusted Publishers”

4

Dit alles werkt nu op die ene computer waarop we de hele tijd gewerkt hebben. Als we ons script gaan uitvoeren op een andere computer waar de executionpolicy ingesteld staat op AllSigned zal ons script niet uitgevoerd worden omdat de uitgever van het certificaat niet gekend is (dat is ook logisch het root cert in kwestie bestaat nog maar net :) ). Om dat probleem op te lossen moet je je zelf gemaakt root certificaat exporteren en importeren op de doel computer. Dit zijn zaken die je NIET hoeft te doen als je een certificaat koopt. De root certificaten van oa. GlobalSign, Thawte, VeriSign zitten standaard in de verschillende Windows omgevingen …

  1. MMC Module openen
  2. Module toevoegen/Verwijderen
  3. Certificaten
  4. Vertrouwde basiscertificeringsinstanties => Certificaten
  5. Rechtermuisklik op dit root certificaat => Alle Taken => Exporteren
  6. 2 x VOLGENDE => bestandslocatie + naam kiezen
  7. VOLTOOIEN
  1. Herhaal de stappen 1 – 4 maar nu op de doelcomputer
  2. Rechtermuisklik => Alle Taken => IMPORTEREN
  3. Kies het CER bestand
  4. Zorg ervoor dat het bestand geïmporteerd wordt in de “Vertrouwde basiscertificeringsinstanties”.

Windows XP Prefetcher

De prefetcher is een functie in Windows XP die poogt de computer performanter te maken door enerzijds het boot proces te monitoren en anderzijds het opstarten van applicaties in het oog te houden. Het kijkt daarbij vooral welke bestanden nodig zijn bij opstarten van Windows en veel gebruikte applicaties. De prefetcher gaat afhankelijk van die bevindingen de volgende keer dat het systeem opstart (of dat er een applicatie opstart) zoveel mogelijk bestanden op voorhand reeds in het geheugen plaatsen.
Standaard staat de prefetcher aan en die mag in 99% van de gevallen ook gewoon aanblijven, alleen in situaties waar RAM geheugen een issue wordt kan je overwegen om de prefetcher bij te sturen.

In Windows XP bestaat daar geen GUI voor, je moet zelf een sleutel wijzigen in het register. Open het register met je favoriete editor (regedit?) en ga naar de volgende sleutel

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Session Manager \ Memory Management \ PrefetchParameters \ EnablePrefetcher
Standaard staat deze op “3” wat erop wijst dat zowel applicaties als het bootproces mogen “geprefetched” worden. Je kan deze sleutel wijzigen in “0” => niets prefetchen, “1” enkel applicaties prefetchen en tenslotte “2” om enkel het boot proces te prefetchen.

De prefetcher bewaart zijn bevindingen in de map “c:\windows\prefetch”, daarin vind je niet de programma’s die in het geheugen geladen zullen worden maar een soort logboek per applicatie/bootproces die door de prefetcher ingelezen wordt bij het opstarten of inladen van een applicatie. Sommige mensen wissen af en toe de inhoud van die map maar dat heeft weinig zin. In een record tempo zal de logboeken terug opstappelen in de map … daarnaast zal de prefetcher sowieso af en toe grote schoonmaak houden in haar eigen bestanden.

Conclusie : het leegmaken van de prefetcher map en het bijsturen van de werking van de prefetcher is enkel zinvol in zeer specifieke situaties zoals vb. debugging/troubleshooting


Exchange 2010 upgrade perikelen

Bij het upgraden van een Exchange 2010 installatie naar Exchange 2010 SP1 hadden we recent ernstige problemen. Na een probleemloze installatie van de prerequisites vatten we de eigenlijke installatie van SP1 aan. Deze crashte ongeveer op het ogenblik dat de Hub Transport Server werd geupgrade. Een totaal “gebrickte” Exhange 2010 blijft achter. (Geen enkele management console werkt nog, OWA weigert dienst, …).

Verschillende Internet fora maakten melding van onstabiele hotfixes in de prerequisites en het advies om de meest recente versie van die hotfixes aan te vragen bij Microsoft. Maar geen soelaas …

Uiteindelijk bleek het toch om een bug te gaan die zowel in de installer van Exchange 2010 als Exchange 2010 SP1 zou zitten. Wanneer in het register, meer bepaald in de sleutel

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers] meer dan 64 sleutels zitten (en dat verkrijg je vb. door EN exchange EN sharepoint op je machine te installeren) dan sneuvelt de installer.

Het volstaat om hier (tijdelijk) grote schoonmaak in te hoduen en de SP1 installer opnieuw uit te voeren. Dit keer verloop de upgrade probleemloos en verkrijgen we een perfect draaiende Exchange 2010 SP1. Achteraf kunnen de gewiste register sleutels overigens zonder problemen teruggezet worden.


FSRM API in C# gebruiken

In sommige situaties is het interessanter om quota’s te plaatsen op mappen ipv die te koppelen aan personeen. Het klassieke quota systeem ingebouwd in Windows 2003 is hiervoor niet geschikt. In Windows 2003 SP2 en Windows 2008 komt daarvoor echter een oplossing nl. de File System Resource Manager of kortweg FSRM waarin quota’s op mappen kunnen geplaatst worden.

Hoewel er geen .NET Wrapper is voor de FSRM API kan deze toch heel makkelijk gebruikt worden in C#.  Het volstaat de de juiste DLL (c:\windows\system32\srm.dll) te referencen omd aan de slag te kunnen.

Enkele code voorbeelden.  Quota plaatsen op een map waar nog geen quota op staat kan als volgt.

 1: public static bool AddDiskQuota(string Folder, double quota)
 2: {
 3:     FsrmQuotaManager quotao = new FsrmQuotaManager();
 4:     IFsrmQuota quotadef = quotao.CreateQuota(Folder);
 5:     quotadef.QuotaLimit = quota * (1024 * 1024);
 6:     quotadef.Commit();
 7:     return true;
 8: }

Nagaan hoeveel quota op een bepaalde map werd toegekend kan met volgende code

 1: public static double GetDiskQuota(string Folder)
 2: {
 3:         FsrmQuotaManager quota = new FsrmQuotaManager();
 4:         if (quota.GetQuota(Folder) != null)
 5:             return (Convert.ToDouble(quota.GetQuota(Folder).QuotaLimit));
 6:         else
 7:             return -1;
 8: }

Ook handig is de mogelijkheid om na te gaan hoeveel schijfruimte er al gebruikt wordt binnen de map

 1: public static double GetUsedQuota(string folder)
 2: {
 3:         FsrmQuotaManager quota = new FsrmQuotaManager();
 4:         if (quota.GetQuota(folder) != null)
 5:             return (Convert.ToDouble(quota.GetQuota(folder).QuotaUsed));
 6:         else
 7:             return -1;
 8: }

Er kan max. één quota entrie op een map geplaatst worden, daarom is het goed vb. de GetUsedQuota functie te gebruiken om na te gaan of er al een Quota entry op de map staat.   Als dat het geval is kan je de entry aanpassen ipv een nieuwe aan te maken.

 1: public static bool ChangeDiskQuota(string Folder, double quota)
 2: {
 3:         if (GetDiskQuota(Folder) != Convert.ToDouble(-1))
 4:         {
 5:             FsrmQuotaManager quotao = new FsrmQuotaManager();
 6:             IFsrmQuota test = quotao.GetQuota(Folder);
 7:             test.QuotaLimit = quota * (1024 * 1024);
 8:             test.Commit();
 9:             return true;
 10:         }
 11:         else
 12:             return false;
 13: }

Happy coding !