CategorieGeek

Windows 8 : een app afsluiten

W

De apps in Windows 8, heel plezant, maar de eerste momenten zitten we toch allemaal te kijken van “waar staat die sluit knop”. Bij Microsoft promoten ze dat je alles maar moet laten openstaan, dat apps die niet gebruikt worden toch geen systeembronnen aanspreekt. Jammer, maar we zijn nu eenmaal van het ordelijke type, wat we niet meer nodig hebben willen we liever afsluiten.

De goeie ouwe sneltoetst ALT+F4 helpt ons een handje, maar hebben we daarvoor 20 jaar Windows versies versleten? Dat moet beter kunnen … En dat kan ook beter. Plaats je cursor bovenaan de app (de cursor verandert in een handje) en sleep in één beweging de app naar de onderkant van het scherm.  De sleepbewegingen … je merkt dat bij het maken van Windows 8 altijd rekening werd gehouden met de tablet gebruikers.

Heb je hier vragen of opmerkingen bij, dan hoor ik graag van je!

Getallen converteren Decimaal naar Octaal, Hex, Binair

G

Een oefeningetje die we in de lessen technologische opvoeding allemaal wel hebben moeten maken? Getallen omzetten van het ene talstelsel naar het andere. Nu nog makkelijker met Powershell (zonder de ingebouwde functies)

cls
$i = Read-Host("Geef een getal tussen 0 en heeel veel :")
while ($stelsel -ne "2" -and $stelsel -ne "8" -and $stelsel -ne "16")
{
  $stelsel = Read-Host("Wil je converteren naar Binair (2), Octaal (8) of Hexadecimaal (16) ?")
}
$hexArray = @("0", "1","2","3","4","5","6","7","8","9","A","B","C","D","E","F")

$reststring = ""
while ($i -gt 0)
{
  $reststring = $hexArray[$i % $stelsel] + " " + $reststring
  $i = [Math]::Truncate($i / $stelsel)
}
  Write-Host "=>" $reststring "<="

Tekenset en -codering

T

Verrassend vaak nog krijg ik (zelfs van IT professionals) de vraag waarom hun website van de ene dag op de andere plots “vreemde” tekentjes vertoont op plaatsen waar je een é of een ç of aan µ verwacht. Het gebruik van karaktersets is namelijk even eenvoudig als belangrijk …

Welke karakters een browser op ons scherm plaatst wordt bepaald door de tekenset en tekencodering. De tekenset is de verzameling van beschikbare karakters.  Ons alfabet zou als een tekenset van 26 tekens beschouwd kunnen worden.  UNICODE is een voorbeeld van een zeer veel gebruikte tekenset in de IT wereld, deze set probeert alle karakters te verzamelen die nodig zijn om quasi elke taal compleet te kunnen weergeven. Tekencodering is dan weer de manier om een karakter op te slaan in de vorm van bytes.  UTF-8 is een veel gebruikte vorm van tekencodering.

In praktijk worden de termen tekenset en tekencodering door elkaar gebruikt. Zo zal je vaak lezen dat een tekst is opgebouwd met de UTF-8 tekenset, … niet 100% correct maar iedereen begrijpt wat er bedoeld wordt.

Als onze webpagina gecodeerd is op basis van tekstcodering A en de browser probeert ze te decoderen op basis van tekstcodering B dan krijgen we de gekke tekens op het scherm. Het komt er dus op aan tekstcodering A te gebruiken en de browser duidelijk te maken dat we A gebruiken en niets anders. Elke deftige teksteditor voorziet in de mogelijkheid om de codering te bepalen, zelfs Kladblok van Windows. Zorg er dus voor dat je goed weet welke tekstcodering je gebruikt. (UTF-8 is absoluut aan te bevelen !!).

image

1. De webserver kan deze informatie meegeven in de vorm van een “Content-Type” HTTP header. Zo’n header instellen kan in de config bestanden van de meeste webservers (vb .htaccess in een apache webserver)

AddCharset UTF-8 .html

of kan door een scripting taal voorzien worden (vb. PHP).

<?php
header('Content-Type: text/plain; charset=UTF-8');
?>

2. De HTML pagina  kan deze informatie meegeven in de vorm van een “META” – tag

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

De eerste manier geniet de voorkeur maar is niet altijd haalbaar, daarom is de tweede manier een absolute must have in elk HTML document.  Als de tekstcodering niet opgegeven wordt moet de browser raden welke tekstcodering hij moet gebruiken. Afhankelijk van browser tot browser en van webpagina tot webpagina lukt dat soms wel, soms niet.

Bij statische pagina’s zijn de problemen onmiddellijk duidelijk en mits wat trial en error kan elk aapje het in orde krijgen.  Dynamische webpagina’s die tekst ophalen uit een databank staan echter voor heel wat meer problemen.

Wanneer je tekst in de databank wil invoeren moet er tussen je programmeertaal en de databank afgesproken worden welke taal je spreekt tijdens de communicatie, de databank moet de data opslaan op basis van een karakterset die alle karakters bevat die jij wil gebruiken en tot slot … als je data ophaalt uit de databank moet je die krijgen in het formaat van je HTML pagina.  Immers als je bovenaan je pagina aangeeft dat je HTML pagina in “UTF-8”  gecodeerd is moet je databank er niet zomaar wat ISO 8859-1 komen tussen gooien.

Tekst aanbieden aan je databank doe je vaak nadat iemand een HTML formulier gepost heeft naar een pagina. Je gaat de $_POST[‘xxxx’] al dan niet na bewerking in de databank opslaan.  De $_POST[] variabelen gebruiken de tekstcodering van de HTML/PHP pagina.   Verwittig je databank dat je UTF-8 tekst gaat aanleveren :

mysql_set_charset(‘utf8’);

Voor elk veldje in elke tabel van elke databank van elke MySQL server kan je bepalen hoe tekst wordt opgeslagen (= met welke codering). Kies een karakterset die alle karakters bevat die je wil opslaan in je databank, bij voorkeur dezelfde tekenset als die die je in je HTML/PHP pagina gebruikt en die die je gebruikt om te communiceren met de databank.  Je kan de tekencodering (de Collation) bepalen op 4 niveau’s. Het laagste niveau heeft prioriteit. Als je dus je tabel collation instelt op “Latin-1” maar je veld op “UTF-8” dan zal de tekst in dat veld met UTF-8 gecodeerd worden.  Stel je geen specifieke collation in voor een veld dan wordt de tabel collation genomen. Is er geen specifieke tabel collation ingesteld dan wordt de databank collation genomen enz …

Tot slot … als je een HTML/PHP Pagina hebt die in UTF-8 gecodeerd is dan wil je dat de tekst uit de databank ook in UTF-8 aangeleverd wordt.  Dat doe je ook met

mysql_set_charset(‘utf8’);

Dat problemen soms pas “op termijn” boven water komen is normaal. De meeste vormen van tekstcodering gebruiken dezelfde codering voor veel voorkomende karakters als a-z, A-Z, 0-9, enz … De codering wordt pas afwijkend op het ogenblik dat je karakters gebruikt als è, à, é, µ, ~, ..

Samenvattend : consequent één vorm van tekst codering gebruiken voor zowel de opmaak van de HTML/PHP pagina, communicatie met de databank als opslag in de databank combineren met deze tekstcodering duidelijk definiëren op alle niveau’s is de enige garantie op een website zonder gekke tekentjes !

Toch nog problemen met tekenset en tekencodering? Contacteer ons !

Grootte POST variabele in PHP

G

Ondertussen is PHP versie 5.3.9 al eventjes op de markt en meer en meer servers beginnen deze versie te gebruiken. Wie dan niet aandachtig de changelog naleest kan plots problemen krijgen met het posten van grote forms.  Plots is de form “te groot”.

In een spontane reflex gaan we kijken naar de “post_max_size” parameter in php.ini maar die blijkt ruim voldoende te zijn.  Sinds PHP 5.3.9 werd een nieuwe parameter toegevoegd nl. “max_input_vars” die het maximaal aantal input variabelen standaard beperkt tot 1000. Wil je meer dan 1000 values posten (toch even nadenken over je performance !!) dan moet je deze parameter in PHP.INI of via INI_SET aanpassen.

Gebruik je de Suhosin patch op je servers dan moet je ook de parameters “suhosin.post.max_vars” en “suhosin.request.max_vars” aanpassen.

Lazy evaluation in PHP, ASP.NET, …

L

Wanneer ik gevraagd word als consultant op vlak van performance tuning van maatsoftware is er één zaak die bijna elke keer terugkomt. Heel wat programmeurs maken onvoldoende gebruik van Lazy evaluation. Quasi elke programmeertaal voorziet standaard in lazy evaluation. Eenvoudig gezegd komt het hierop hier dat een programmeertaal stopt met vergelijkingen evalueren op het ogenblik dat het toch geen zin meer heeft. Een voorbeeldje.

Je schrijft een functie die een getal als input krijgt en als dat getal ofwel deelbaar is door 4 ofwel een priemgetal dan returned de functie true anders false.

if (($input % 4 == 0) || (ispriemgetal($input)))
{
    return true;
}
else
{
    return false;
}

Als onze invoer variabele gelijk is aan pakweg 12 dan zal het tweede gedeelte van de if constructie niet meer uitgevoerd worden omdat het toch geen zin heeft, wat het resultaat ook is van “ispriemgetal($input)” het eindresulaat is toch true.  Het is dus belangrijk om de minst cpu intensieve vergelijking eerst te plaatsen zodat de meer cpu intensieve vergelijkingen niet uitgevoerd worden als dat niet echt nodig is. Ons voorbeeld is dus correct vanuit een performance tuning standpunt omdat we ervan mogen uitgaan dat controleren of een getal deelbaar is door 4 minder kracht vergt dan controleren of een getal een priemgetal is.  Dit zou minder goed zijn :

if ((ispriemgetal($input)) || ($input % 4 == 0))

In dit concreet geval zou het trouwens echt zinloos zijn omdat een priemgetal per definitie niet deelbaar is door 4 of een getal deelbaar door 4 per definitie geen priemgetal kan zijn.

Logfiles roteren met Powershell

L

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$maplog"
  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

F

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

P

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

I

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$domainWWW"
 md "$basis$domainLOGS"
 md "$basis$domainDATA"
 md "$basis$domainDB"

# 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$domainwww"
 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$domainlogs"

# 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$domainDATA"
$permission = "IIS AppPool$domain","Modify","ContainerInherit, 
    ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.
    FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
$acl | Set-Acl "$basis$domainDATA"

# Modify rechten voor de App Pool gebruiker op de DB en DATA map
$acl = Get-Acl "$basis$domainDB"
$permission = "IIS AppPool$domain","Modify","ContainerInherit, 
    ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.
    FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
$acl | Set-Acl "$basis$domainDB"

# 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"


Bij vragen of problemen met dit script hoor ik graag van u.

Powershell scripts digitaal ondertekenen

P

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:UsersDDITDocuments> 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

3

en ons zelf uitgeschreven certificaat

2

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

 

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

1

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”.

Laatste berichten