Desired State Configuration und Group Managed Service Accounts

Ausgangslage

In meinem Unternehmen setzen wir IBM Urban Code Deploy ein für die Provisionierung der Server. Nun da dies einen manuellen Mehraufwand bedeutet muss dieses Vorgehen effizienter gestaltet werden. Aus diesem Grund habe ich mit für die Konfiguration mittels Desired State Configuration (DSC) entschieden.

Ziel

Durchführung

Für die Durchführung orientieren wir uns an den gesteckten Zielen.

Ist JAVA instaliert?

Hat man JAVA installiert, so wird dies meistens in ein Verzeichnis wie JDK oder JAVA gemacht und im Pfad wird das entsprechende angegeben. Die Konfiguration wird nicht gestartet, sollte JAVA nicht installiert sein. Dies kann man auf einfache Art und Weise überprüfen.

if(($env:Path.Split(';') | Where-Object { Where-Object { $_ -like "*JDK*" -or $_ -like "*JAVA*" } ))

Nun gut, wenn alles korrekt verläuft dann kann die Konfiguration beginnen.

Installation des Agenten

Der Agent wird mittels XCOPY Installation auf dem System installiert. Das hat den Vorteil, dass der Agent bereits als Vorlage "gezipped" zur Verfügung steht und dann noch an die richtige Stelle kopiert wird. Um diesen Vorgang auszuführen braucht es die Resource Archive, die bereits standardmässig von Windows zur Verfügung steht. Die Resource sieht wie folgt aus:

            Archive UrbanCodeBinaries
            {
                Destination = "C:\Program Files"
                Ensure =  "Present"
                Path = $agentSource
                Force = $true                
            }

Die Destination ist das Ziel in welche die binären Dateien extrahiert werden. Der Path wird durch das Aufrufen des Konfigurationsscriptes mitgegeben.

Konfiguration des Dienstes für den Agenten

Für die Konfiguration des Agenten ist die Service Resource verwendet worden, die wie folgt konfiguriert wird.


            # Preconfigure the properties for the service
            $agentName = ("ucd-agent-{0}" -f $env:COMPUTERNAME)
            $servicePathArguments = "//RS//{0}" -f $agentName
            $servicePath = Join-Path -Path $env:ProgramFiles -ChildPath "ibm-ucd-agent\native\x64\winservice.exe"

            Service UrbanCodeAgentService
            {
                Ensure = "Present"
                Name = $agentName
                StartupType = "Manual"
                Path = ("`"{0}`" {1}" -f $servicePath, $servicePathArguments)
                Description =  "IBM Urban Code Agent"                
                DisplayName = $agentName  
                State = "Stopped"                             
            }

Vor der Ressource sind die notwendigen Parameter vorkonfiguriert worden, da dieser JAVA Agent über einen Windows-Dienst Wrappter mit Argumenten gestartet wird. Der Dienst ist nun konfiguriert nur noch nicht so wie gewünscht.

Konfiguration des Dienstes für den Agent

Die Dienst Resource lässt nur zu einen Benutzer-Account mit Passwort zu verknüpfen. Da kein Object PSCredential Objekt ohne Passwort erstellt werden kann und das Passwort für den Group Managed Service Account unbekannt ist, muss man sich mittels WMI den Dienst wie gewünscht konfigurieren. Dies geschieht mittels der Script Resource

            # Third Set the Service with a script Resource
            Script ServiceScript{
                DependsOn = "[Service]UrbanCodeAgentService"
                GetScript = {                    
                    return Get-WmiObject -Class win32_Service | Where-Object -Property Name -like ("*{0}*" -f $using:agentName)
                }
                TestScript = {                    
                    $service = [scriptblock]::Create($GetScript).Invoke()                    
                    if($service){
                        return ($service.StartName -eq $using:groupManagedServiceAccount)
                    }
                    return $false
                }
                SetScript = {                    
                    $service = [scriptblock]::Create($GetScript).Invoke()
                    if($service){
                        $service.Change($null, $null, $null, $null, $null, $null, $using:groupManagedServiceAccount, $null, $null, $null, $null)
                    }                    
                }
            }

Wichtig an dieser Stelle ist zu erwähnen, dass diese Script-Resource mit dem DependsOn versehen ist. Das bedeutet, dass diese Ressource erst durchgeführt wird, wenn die angegeben Ressource erfolgreich appliziert werden konnte.

Hier noch das ganze Script

param([Parameter(Mandatory=$true,HelpMessage="The full path to the template ucd agent zip")]
      [ValidateNotNullOrEmpty()]
      [string]$agentSource="C:\Temp\ibm-ucd-agent.zip",
      [Parameter(Mandatory=$true,HelpMessage="The Group Managed Account that is used as service account.")]
      [ValidateNotNullOrEmpty()]
      [string]$groupManagedServiceAccount="IFC1\srvgp-ucd-r$"
      )

Configuration UrbanCodeAgentConfiguration{

    Import-DscResource -ModuleName PSDesiredStateConfiguration 

    if(($env:Path.Split(';') | Where-Object { $_ -like "*JDK*" -or $_ -like "*JAVA*" } )){
        Node $env:COMPUTERNAME
        {            
            # First Extract the service binaries to the Destination
            Archive UrbanCodeBinaries
            {
                Destination = "C:\Program Files"
                Ensure =  "Present"
                Path = $agentSource
                Force = $true                
            }

            # Preconfigure the properties for the service
            $agentName = ("ucd-agent-{0}" -f $env:COMPUTERNAME)
            $servicePathArguments = "//RS//{0}" -f $agentName
            $servicePath = Join-Path -Path $env:ProgramFiles -ChildPath "ibm-ucd-agent\native\x64\winservice.exe"

            # Second configure the service
            Service UrbanCodeAgentService
            {
                Ensure = "Present"
                Name = $agentName
                StartupType = "Manual"
                Path = ("`"{0}`" {1}" -f $servicePath, $servicePathArguments)
                Description =  "IBM Urban Code Agent"                
                DisplayName = $agentName  
                State = "Stopped"                             
            }  
            
            # Third Set the Service with a script Resource
            Script ServiceScript{
                DependsOn = "[Service]UrbanCodeAgentService"
                GetScript = {                    
                    return Get-WmiObject -Class win32_Service | Where-Object -Property Name -like ("*{0}*" -f $using:agentName)
                }
                TestScript = {                    
                    $service = [scriptblock]::Create($GetScript).Invoke()                    
                    if($service){
                        return ($service.StartName -eq $using:groupManagedServiceAccount)
                    }
                    return $false
                }
                SetScript = {                    
                    $service = [scriptblock]::Create($GetScript).Invoke()
                    if($service){
                        $service.Change($null, $null, $null, $null, $null, $null, $using:groupManagedServiceAccount, $null, $null, $null, $null)
                    }                    
                }
            }
        }        
    }else {
        Write-Host "Java is not installed"
    }
}

UrbanCodeAgentConfiguration

Eine Bemerkung zum Node: Started man die Desired State Configuration, so ist eine MOF-Datei das Resultat. Will man diese archivieren, so würde diese standardmässig "localhost" heissen, was nicht hilfreich wäre. Aus diesem Grund verwende ich immer die Variable $env:COMPUTERNAME um so eine sprechende MOF-Datei zu erhalten.

Fazit

Nicht alles was bereits standardmässig zur Verüfung steht, kann gleich für jeden Anwendungsfall verwendet werden. Mit der Script-Ressource ist es möglich eine gewisse Flexibilität gegeben und man kann auch ohne dedizierte Scripts Aktionen ausführen, die von keiner Ressource bereitgestellt werden. Für Fragen und Anregungen bin ich offen und wenn Dir der Artikel gefallen hat, dann freue ich mich über ein like

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s