Office 365 auf Azure Windows 10 – Admin-Berechtigung

Als Erinnerung für mich selber und für den einen oder anderen von euch… die Probleme haben Office 365 auf einer Windows 10 VM in Azure zu installieren. Bei meinen ersten Versuchen bin ich auch auf diesen Fehler / dieses Problem gestoßen, konnte aber leider keine wirkliche Lösung im Netz finden (hatte aber wohl auch keine Zeit und Geduld um intensiver auf die Suche zu gehen. Jetzt trat dieses Problem erneut auf und ich habe dieses Mal auf Anhieb etwas gefunden oder einfach nur die richtigen Suchbegriffe eingegeben 😉

Ausgangslage – meine virtuelle Windows 10 Maschine

Aus verschiedenen Gründen hatte ich mir in Azure eine Workstation ausgerollt, damit ich „flexibel“ bin und alles an einem Ort bearbeiten kann, ohne dabei meinen (Firmen-)Laptop nutzen zu müssen. Da ich mit dieser virtuellen Maschine nur lokale Tätigkeiten – beispielsweise Powershell-Programmierung, Powerpoint oder Erstellung von Demos – machen möchte, brauche ich keine Anbindung an das Azure Active Directory und nutze den initial eingerichteten User (mit administrativen Rechten) für meinen Login bzw meine Arbeiten.

Nun brauche ich aber für meine Vorträge eine aktuelle Powerpoint-Umgebung, um alle Vorteile nutzen zu können und eine durchdachte und optisch ansprechende Präsentation zu erstellen. Und dank meines MVPs habe ich auch die Möglichkeit auf mehreren Maschinen Office 365 zu installieren. Also habe ich das Office 365 Click-to-Run Installations-Packet heruntergeladen und versucht zu installieren… erhielt aber – egal was ich versuchte obige Fehlermeldung. Also musste ich nach einer Lösung suchen, da ich mir nicht vorstellen konnte, dass das so von Microsoft gewollt ist…

verschiedene Lösungsansätze zur Installation von Office 365

Bei meiner Suche nach einer Lösung bin ich heute morgen über einen Beitrag in der Microsoft Dynamics Community gestolpert und habe dort erste weiterführende Informationen erhalten. Man könne das Problem für diese „einmalige“ Problem relativ schnell und leicht umgehen, in dem man einfach einen neuen User mit Administrator-Rechten anlegt und diesen dann zur Installation der Software nutzt. Ausprobiert habe ich dies nicht, da ich eine „dauerhafte“ Lösung wollte und auch wissen wollte, wie ich das zukünftig auf allen Maschinen umgehen kann. Ich suchte also nach einer Lösung und keinem „Work-around“… 😉

Also weiterlesen in dem Beitrag… im Text versteckt gibt es einen weiteren Link zu einer Seite, die noch mehr Lösungen beinhaltet, darunter auch „dauerhafte“ Lösungen! Also weiterlesen…

Das Problem trat bei mir nur auf, wenn ich Office 365 installieren wollte, aber anscheinend tritt das auch bei der Installation weiterer Software auf und nicht nur in Azure sondern auch on-premise…

Nun kann mal beispielsweise über die UAC (User Account Control) eine Stufe herunterschalten, um dem Problem aus dem Weg zu gehen, aber in gewissen Umgebungen mag dies nicht möglich sein, ich fand den Lösungsweg 2 wesentlich charmanter und sicherer…

Method 2: Enable Admin Approval Mode for the Built-in Administrator Account

Das Folgende habe ich aus dem Blogbeitrag kopiert und übersetzt.

  1.  Über Win+R den Ausführen-Dialog öffnen
  2. secpol.msc eingeben und mit OK bestätigen.
  3. Dann im Baum links die folgenden Ordner öffnen
    • Local Policies => Security Options
  4. Im rechten Fenster User Account Control: Admin Approval Mode for the Built-in Administrator account suchen. Über einen Rechts-Klick und dann auf Eigenschaften.
  5. Die Option Enabled auswählen. Mit Apply und dann OK bestätigen.
  6. Erneut über Win+R den Ausführen-Dialog öffnen und regedit eingeben und ausführen.
  7. Dann den folgenden Pfad suchen :HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\UIPI . Auf der rechten Seite über einen Rechts-Klick auf „Default“ und dann „Modify“ den Wert ändern.
  8. Einzugebender Wert is : 0x00000001(1)
  9. Die Änderungen mit einem Klick auf den OK Button schliessen.

Nicht zu vergessen, danach zu booten, damit die Werte einwandfrei übernommen werden… ich konnte direkt im Anschluss einwandfrei mein Office 365 Paket installieren und meine Präsentationen für die SQL-Konferenz in Darmstadt vorbereiten 😉

(Werbung)

Wir sehen uns auf der SQL-Konferenz ansonsten vielen Dank für das Lesen dieses Beitrages und ich hoffe wie immer, zumindest einem geholfen zu haben !!!

Desired State Configuration #4 – SQL Server Installation und Konfiguration

So endlich ist es soweit… ich habe meine SQL Server Installation mit Powershell Desired State Configuration fertig und möchte euch nun meinen abschließenden Blog-Beitrag präsentieren. Auch wenn noch nicht alles 100% fertig ist und der Ablauf leider noch nicht so ganz so ist, wie ich es mir vorstelle, – es müssen eigentlich noch zu viele Dinge manuell gemacht werden und wie ich mit dem Thema Reboot umgehe ist noch ungeklärt – dennoch möchte ich euch hier meinen Code vorstellen.

Einleitung zur Vorgehensweise

Ich schreibe hier aktuell über Desired State Configuration als Push-Modell, ggfs kommt ein Pull-Modell später noch hinzu. Das heißt ich führe meine Skripte von meiner Workstation aus, die eigentlichen Skripte liegen auf dem Domänen-Controller, alle Server und Workstations sind in einer Domäne und ich führe die Skripte als Domänen-Administrator aus. Noch einmal zur Verdeutlichung meiner Umgebung hier ein Bild von meiner Test-Umgebung:

Powershell Desired State Configuration - Overview - New Environment

Die Verzeichnisstruktur liegt auf dem Domänen-Controller in der allgemein zugänglichen SYSVOL-Freigabe, kann aber natürlich auch auf jeder anderen (zentralen) Freigabe liegen. Hier liegen die Ordner für die notwendigen Powershell-Module und SQL Server Installationsmedien.

  • DC01
    • SYSVOL
      • DSC
        • SQL
          • Updates
        • Modules
        • Scripts
        • Configurations

Auf den Ziel-Servern kann man sich ebenfalls eine frei wählbare Struktur ausdenken, erst einmal geht es aber um das Kopieren von Quell- auf Ziel-Server… die Powershell-Module kopiere ich in das Standard-WindowsPowershell-Verzeichnis ( C:\Windows\system32\WindowsPowerShell\v1.0\Modules) und das SQL Server Setup liegt auf dem D-Laufwerk meiner Azure-Maschinen (D:\SQL2017).

Voraussetzungen für Desired State Configuration

Natürlich müssen auch gewisse Voraussetzungen für die Nutzung von DSC gegeben sein, ich beschränke mich hier auf die rudimentären Themen und verweise ansonsten gerne auf den ersten Teil meiner DSC-Blogpost-Serie, in dem ich auf die Details dazu eingehe. Mir ist im Zuge meiner Recherchen bzw Versuche noch ein Problem untergekommen, auf das ich kurz hinweisen möchte (kann sich aber um ein Problem speziell aus meiner Test-Umgebung handeln)… ich konnte erfolgreich die ersten 3 Server mittels DSC ausrollen, beim vierten allerdings bekam ich immer die Fehlermeldung, dass der Server nicht erreicht werden kann… auf ein Löschen/Re-Deploy des Servers (Azure sei Dank) brachte keine Besserung… hier hatte sich der DNS-Server eine falsche lokale IP-Adresse für den Server „gemerkt“ und konnte somit nicht die Namensauflösung vollbringen. Nachdem ich allerdings auf meiner Workstation den DNS-Cache gelöscht hatte, war es mir möglich auch den vierten SQL Server erfolgreich zu installieren und konfigurieren.

Also nachdem ich nun alle Server entsprechend in der Domäne habe, alle Firewalls und Dienste konfiguriert sind, können wir loslegen mit dem eigentlichen SQL Server Rollout mittels DSC. Entgegen meiner ersten Versuche (siehe Beitrag #2 zu DSC) bin ich jetzt dazu übergegangen alles mit Desired State Configuration zu machen und nur noch wenige Schritte mit reinem Powershell. Aber dazu kommen wir gleich…

In meinem aktuellen Projekt geht es um die regelmäßige Bereitstellung einer SQL Server Umgebung mit AlwaysOn AvailibilityGroups für einige Applikationen OHNE Patching. Das heißt es muss jeden Monat eine neue Umgebung ausgerollt, welche immer den letzten Patch-Level hat. Um dies zu erreichen, habe ich diese Skripte geschrieben. Damit meine Skripte mehrfach bzw modular einsetzbar sind, habe ich die Arbeitsschritte aufgeteilt:

  1. Vorbereitung, Installation und Konfiguration eines SQL Servers (2017 Developer)
  2. Migration der vorhandenen Umgebung auf die neue Umgebung
  3. Vorbereitung, Rollout und Aktivierung der AlwaysOn AvailibilityGroups

Meine Powershell Skripte

Desired-State-Configuration - Meine-Powershell-Skripte

Kurz zur Erläuterung:
Meine Hilfsskripte, welche ich im letzten Blogbeitrag schon erläutert habe

  • Connect Network Share => Erstellt eine Verbindung mit meinem Azure-Fileshare, setzt die PSGallery auf Trusted und „Unblocked“ meine Powershell-Skripte
  • Init_new_Machines => Öffnet die Windows-Firewall für die Netzwerk sowie File und Print-Dienste, formatiert alle Laufwerke, Domänen-Join
  • Remove AG and its secDB => Löscht auf beiden Servern die AGs und auf dem Secondary die verbliebene Datenbank
  • Update Modules => wie der Name sagt, es werden die notwendigen Powershell bzw DSC-Module aktualisiert.
  • 1_SQLServer-Rollout-DSC => Es erfolgt eine Standalone-Installation eines SQL Server 2017 mit Konfiguration nach Best-Practices und Installation der Ola Hallengren Maintenance Skripte
  • 2_Migrate_UserDatabases => Migration aller Datenbank-Objekte mit dbatools
  • 3_Rollout-Start-AvailGroup => Es erfolgt die Vorbereitung, Konfiguration und Start der einzurichtenden Availibilty-Groups mittels DSC und dbatools (noch… eventuell baue ich das auch auf DSC um, aber es ist so schön einfach 😉 )
  • SQLServerRollutwithAG => Ist ein Sammelskript bzw soll ein Sammelskript werden, welches alle Skripte / den Workflow entsprechend steuert
  • SQLServerConfiguration => ein JSON-File, was die Parameter für die Umgebung enthält

Part 1 – Installation und Konfiguration eines SQL Servers mit Desired State Configuration

Ich werde nicht im Detail auf das Skript eingehen und auch nicht alle Code-Zeilen zeigen, sondern „nur“ einen groben Überblick geben, wie ich vorgegangen bin und was ich womit realisiert habe…
Einleitung erfolgt mit der benötigten Powershell-Version, DSC-Modulen und Modulversionen… anschließend die Parameter, die man bei der Nutzung per Kommandozeile eingeben kann/muss.

## At the time of this writing, above modules/version were used. Future versions of this module could have breaking changes and will need to be retested
#Requires -Version 5
#Requires -Modules @{ ModuleName="xPSDesiredStateConfiguration"; ModuleVersion="8.4.0.0" }
#Requires -Modules @{ ModuleName="SqlServerDsc"; ModuleVersion="12.1.0.0" }
#Requires -Modules @{ ModuleName="SecurityPolicyDsc"; ModuleVersion="2.6.0.0" }
#Requires -Modules @{ ModuleName="StorageDSC"; ModuleVersion="4.3.0.0" }
## At the time of this writing, above modules/version were used. Future versions of this module could have breaking changes and will need to be retested

param
(
    # Computer name to install SQL Server On
    [Parameter(Mandatory=$true)]
    [String]
    $ComputerName,

    # Plaintext Password of User who has installation permissons on destination server
    [Parameter(Mandatory = $false)]
    [String]
    $InstallerPwd,

    # Plaintext Password of User who should run the sql server service => e.g. DEV2\sqlserv
    [Parameter(Mandatory = $false)]
    [String]
    $SQLServicePwd,

    # Plaintext Password of User who should run the sql Agent service => e.g. DEV2\sqlserv
    [Parameter(Mandatory = $false)]
    [String]
    $SQLAgentPwd,

    # Plaintext Password of the SA User
    [Parameter(Mandatory = $false)]
    [String]
    $SAPwd,

    # Will it be just for preparation?
    [Parameter(Mandatory=$false)]
    [Switch]
    $Prepare,

    # Will it be just for SQL Server configuration?
    [Parameter(Mandatory=$false)]
    [Switch]
    $Configure
)

Es folgen einige einleitende Zeilen, um die Konfigurationdatei einzulesen und aus JSON umzuwandeln, sowie den „OutputPath“ zu definieren. Der OutputPath ist der Ablage-Ordner für die MOF-Files (also die eigentliche Konfigurationsdatei).

Clear-Host
Write-host "Starting DSC process on"$ComputerName.ToUpper()

## Getting ConfigurationValues from JSON-File
$ConfigurationFile = "SQLServerConfiguration.json"
$Configuration = (Get-Content $ConfigurationFile) -join "`n"  | ConvertFrom-Json

## Defining path to MOF-Files
$OutputPath = $Configuration.General.DSCConfigFolder

Die Parameter werden anschließend überprüft und zu Credentials umgewandelt, damit man später sowohl Username und Passwort getrennt und als Credential verwenden kann. Und schon geht es los mit den ersten DSC-Configurations für das Bereitstellen der notwendigen Powershell-Module, der Installationsmedien und Mounten des ISO-Images . Ich habe aus Debug- und Flexibilitätsgründen mehrere Configurations gebaut um später das Skript für weitere Zwecke (wie man in den Parametern erahnen kann) zu nutzen. Man kann grundsätzlich alles in eine Configuration legen, aber um modular zu bleiben…

Vorbereitungen – Kopieren der Powershell Module und Installationsmedien

Configuration Preparation {
    Import-DscResource -ModuleName PSDesiredStateConfiguration
    
    Node $AllNodes.NodeName {
        LocalConfigurationManager {
            DebugMode = "ForceModuleImport"
            RebootNodeIfNeeded = $true
        }

        File PowershellModules {
            Ensure = 'Present'
            Type = 'Directory'
            SourcePath = $Configuration.InstallationMedia.ModuleSourcePath
            DestinationPath = $Configuration.InstallationMedia.ModuleDestinationPath
            Recurse = $true
        }

        File InstallationFolder {
            Ensure = 'Present'
            Type = 'Directory'
            SourcePath = $Configuration.InstallationMedia.InstallationMediaSourcePath
            DestinationPath = $Configuration.InstallationMedia.InstallationMediaDestinationPath
            Recurse = $true
        }

        WindowsFeature NET-Framework-Core {
            Name = "NET-Framework-Core"
            Ensure = "Present"
            IncludeAllSubFeature = $true
        }
    }
}

Configuration ISOMount {
    Import-DscResource -Module PSDesiredStateConfiguration
    Import-DscResource -ModuleName StorageDsc
    
    Node $AllNodes.NodeName {
        MountImage ISO {
            ImagePath   = $Node.SourcePath
            DriveLetter = 'S'
        }

        WaitForVolume WaitForISO {
            DriveLetter      = 'S'
            RetryIntervalSec = 5
            RetryCount       = 10
        }
    }
}

Wenn also das kopierte ISO-Image am Zielserver gemountet wurde, könnte man – wie ich es im ersten Versuch gemacht habe bzw Chris Lumnah in seinem Blogbeitrag beschrieben hat – mittels Script-Ressource realisiert, könnte man die „setup.exe“ mit der „ConfigurationFile.ini“ aufrufen und eine „unattend-Installation“ durchführen. Ich habe nach zahlreichen Versuchen und einigem Lesen mich für das SQLServerDSC-Modul entschieden, das ist „einfacher“ und nicht ganz so Fehler-anfällig.

Ausführung des eigentlichen SQL Server Setup

Configuration SQLServerSetup {
    Import-DscResource -Module PSDesiredStateConfiguration
    Import-DscResource -Module SqlServerDsc
    Import-DscResource -ModuleName StorageDsc

    Node $AllNodes.NodeName {
        LocalConfigurationManager {
            DebugMode               = "ForceModuleImport"
            RebootNodeIfNeeded      = $true
        }

        WindowsFeature NET-Framework-Core {
            Name                    = "NET-Framework-Core"
            Ensure                  = "Present"
            IncludeAllSubFeature    = $true
        }

        SQLSetup InstallDefaultInstance {
            PsDscRunAsCredential    = $InstallerCredentials
            DependsOn               = '[WindowsFeature]NET-Framework-Core'
            Action                  = "Install"
            UpdateEnabled           = $Configuration.InstallSQL.UpdateEnabled
            UpdateSource            = $Configuration.InstallSQL.UpdateSource
            Features                = $Configuration.InstallSQL.Features
            InstanceName            = $Configuration.InstallSQL.InstanceName
            SQLCollation            = $Configuration.InstallSQL.SQLCollation

            SecurityMode            = $Configuration.InstallSQL.SecurityMode
            SAPwd                   = $SQLSACredentials
            
            AgtSvcAccount           = $SQLServiceCredentials
            SQLSvcAccount           = $SQLServiceCredentials
            #ISSvcAccount           = $Node.ISSvcAccount
            #FTSvcAccount           = $Node.FTSvcAccount
            
            InstallSharedDir        = $Configuration.InstallSQL.InstallSharedDir
            InstallSharedWOWDir     = $Configuration.InstallSQL.InstallSharedWOWDir
            InstanceDir             = $Configuration.InstallSQL.InstanceDir
            InstallSQLDataDir       = $Configuration.InstallSQL.InstallSQLDataDir
            SQLUserDBDir            = $Configuration.InstallSQL.SQLUserDBDir
            SQLUserDBLogDir         = $Configuration.InstallSQL.SQLUserDBLogDir
            SQLTempDBDir            = $Configuration.InstallSQL.SQLTempDBDir
            SQLTempDBLogDir         = $Configuration.InstallSQL.SQLTempDBLogDir
            SQLBackupDir            = $Configuration.InstallSQL.SQLBackupDir

            SourcePath              = 'S:\'
        }
    }
}

Viel brauche ich dazu wohl nicht zu schreiben, da es recht selbst erklärend ist! Weiter geht es mit der eigentlichen Konfiguration des SQL Server nachdem die Installation erfolgreich durchgeführt wurde. Hier richte mich nach den gängigen Best-Practice Empfehlungen der Community zu SQL Servern, wie zum Beispiel „MaxDOP“ und den „Cost Threshold For Parallelism“ oder den maximalen Speicherbedarf des SQL Servers zu begrenzen. Auszugsweise 😉

abschließende Konfiguration des SQL Servers

SqlServerNetwork 'ChangeTcpIpOnDefaultInstance'
        {
            ...
        }
        
        SQLServerMemory SetMAXMemory {
            ...
        }

        SQLServerMaxDop SetMAXDOP {
            ...
        }

        SQLServerConfiguration 'CostThreshold4Parallelism' {
            ...
        }

        UserRightsAssignment PerformVolumeMaintenanceTasks {
            ...
        }

        UserRightsAssignment LockPagesInMemory {
            ...
        }

        SqlWindowsFirewall Create_FirewallRules_For_SQL2017 {
            ...
        }

        SqlServiceAccount SetServiceAccount_User {
            ...
        }

        SqlServiceAccount SetAgentAccount_User {
            ...
        }

Wie man die einzelnen DSC-Ressourcen einsetzt und welche Wert benötigt werden oder nur optional sind, kann man sehr gut in der Microsoft-Dokumentation (nicht alle Examples sind 100%, aber man erhält einen Eindruck) nachlesen. => https://github.com/PowerShell/SqlServerDsc
Nun fehlt nur noch das „Unmount“ des ISO-Images, danach die Schritte „Vorbereitung“, „Installation“ und „Konfiguration“ abgeschlossen. Wie in Desired State Configuration mit Powershell üblich, kommen jetzt am Ende des Skriptes noch die Zuweisungen, „Berechnungen“ und Aufrufe. Beispielsweise für MaxDOP und MaxMemory verwende ich folgende Zeilen:

## Getting CPU-Count and calculate MaxDOP
$CpuCount = 0
$Memory = Get-CimInstance Win32_PhysicalMemory -cn $ComputerName | Measure-Object -Property capacity -Sum 
$MaxMemory = [math]::round((($Memory.Sum * 0.8)/1MB),0)
$CPUCount = (Get-CimInstance Win32_Processor -cn $ComputerName -Property NumberOfLogicalProcessors).NumberOfLogicalProcessors
if ($CPUCount -eq 1) {
    $CPUCount = 1
} elseif ($CPUCount -gt 8) {
    $CPUCount = 8
} else {
    $CPUCount = $CPUCount/2
}

Erstellen der MOF-Datei und Starten der DSC-Konfiguration auf dem Zielserver

Um einen Eindruck davon zu vermitteln, wie ich die einzelnen Schritte der DSC-Installation aufrufe bzw einteile, hier noch ein Beispiel-Abschnitt aus meinem Skript:

if ($Prepare) { 
    $ConfigurationData.AllNodes += @{
        NodeName = $ComputerName
    }
    ## Create MOF-Files
    Preparation -ConfigurationData $ConfigurationData -OutputPath "$OutputPath\Preparation\"
    ## Providing all PowerShell Modules
    Start-DscConfiguration -ComputerName $ComputerName -Path "$OutputPath\Preparation" -Verbose -Wait -Force
}

Im „Prepare“-Schritt benötige ich als Parameter nur den Namen des Zielservers, erstelle mit dem Aufruf des Configuration-Teils, der Übergabe der ConfigurationData und dem „OutputPath“ eine MOF-Datei und meta.MOF-Datei. Diese MOF-Datei kann man separat erstellen, um sie dann als späteren Schritt im Skript oder wie hier direkt nach dem Erstellen auszuführen, theoretisch kann man die MOF-Datei auch mit einem eigenen Skript erstellen und mit einem zweiten Powershell-Skript einlesen und dann auf dem Zielserver ausführen. Ich starte hier die DSC-Konfiguration im direkt Anschluss an das Erstellen gegen den Zielserver aus.

SQL Server Datenbank Wartung mit Ola Hallengren

Als abschließenden Schritt in meiner langen Aufführung möchte ich die Grundlage schaffen, dass Backups und Index-Pflege mit den bekannten Skripten von Ola Hallengren erfolgen können. Da ich auch in weiteren Schritten meines Deployments – Migration und Anlage der Availibility-Groups – auf das Powershell-Community-Modul „dbatools“ nutze, greife auch hier auf die Vereinfachung dafür zurück. Wenn also eine Internet-Verbindung besteht, wird das Skript automatisch heruntergeladen und installiert, wenn nicht wird auf die lokale Kopie zurück gegriffen. (natürlich muss die Datei vorher manuell herunterladen und ablegen)

## Check if Internet is available and download Ola Hallengren Database Maintenance otherwise look into given folder
If (Test-Connection -computer "www.google.com" -count 1 -quiet) {
## Internet-Connection is available
    Write-Host -ForegroundColor Green "$(Get-Date): Connection up!"
    Write-Host "Installing OH-MaintenanceScript from the Internet"
    Install-DbaMaintenanceSolution -SqlInstance $ComputerName -BackupLocation $Configuration.InstallSQL.SQLBACKUPDIR -CleanupTime 167 -ReplaceExisting -InstallJobs
} else {
    Invoke-DbaQuery -SqlInstance $ComputerName -File $Configuration.InstallSQL.InstallationMediaSourcePath"\MaintenanceSolution.sql"
}

In den nächsten Tagen werde ich diese Reihe weiterführen und erzählen wie ich die Migration bewerkstellige und wie das Skript zur Vorbereitung und zum Rollout der Availibility-Groups aussieht. Denn auch hier gibt es das ein oder andere zu beachten.
Für Fragen und/oder Diskussionen rund um das Thema stehe ich gerne zur Verfügung!

Desired State Configuration #3.1 – Lessons learned – Powershell-Skripte

Wie ich in meinem letzten Blog-Beitrag geschrieben habe, musste ich meine DSC-Entwicklungsumgebung komplett neu aufbauen, was sehr ärgerlich war, aber mir eben auch einen Neuanfang bescherte. Da ich bereits bei meinen ersten Versuchen mich hin und wieder geärgert hatte, dass ich alles manuell gemacht habe, mussten nun ein paar Skripte gebaut werden, damit auch alles nachvollziehbar und reproduzierbar ist. Da ich mir sicher sein wollte, auch im Falle eines Re-Deployments, alles identisch aufzusetzen.

Meine Test-Umgebung in Azure

Das Aufsetzen der Maschinen in Azure ist im Grunde jedem selber überlassen, wie er es macht, hier kommt mein Ansatz um preisgünstige, identische Maschinen auszurollen, die nur aus dem Betriebssystem Windows 2016 Datacenter und 4 Datenplatten bestehen. Zusätzlich habe ich – aus Kostengründen – einen automatisierten Shutdown-Schedule eingefügt, da ich das Stoppen der Maschinen manchmal vergesse.

DSC - Overview - New Environment
Clear-Host
#
# Login into Azure and define which Subscription should be used
#
Write-Host "Defining Azure Credentials"

$azureAccountName ="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$azurePassword = ConvertTo-SecureString "XYZ" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAccountName, $azurePassword)
$mySubscriptionID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

function Login
{
    Add-AzureRmAccount -Credential $psCred -ServicePrincipal -TenantId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | Out-null
}

Write-Host "Credentials defined"
Login
####

Set-AzureRmContext -SubscriptionId $mySubscriptionID | Out-null

# Variables for SQL Server VM
## Global
$servername = "SQLVM04"
$resourcegroupname = "RG-SQLServer-Testumgebung"

## Storage
$vm_storagename = "rgsqlservertestumgebungd"
$vm_storagesku = 'Premium_LRS'

## Network
$vm_publicIPName = $servername + '-ip'
$vm_interfacename = $servername + '-nic'
$vm_vnetname = "Demo-VNet"
$vm_subnetname = 'Standard'
$vm_VNetAddressPrefix = '10.1.0.0/16'
$vm_VNetSubnetAddressPrefix = '10.1.0.0/24'
$vm_TCPIPAllocationMethod = 'Dynamic'
$vm_domainname = $servername + 'domain'

##Compute
$vm_vmname = $servername
$vm_computername = $vm_vmname
$vm_size = 'Standard_DS1_v2'
$vm_osdiskname = $servername + '_OSDisk'

##Image
$vm_publishername = 'MicrosoftWindowsServer'
$vm_offername = 'WindowsServer'
$vm_sku = '2016-Datacenter'
$vm_version = 'latest'

Clear-Host 
$ErrorActionPreference = "Stop"

#
#   Process
#
# Start
Write-Host "Starting with 'Create Azure Virtual Machine'" -foregroundcolor "white"
Write-Host "Checking if Resourcegroup exists..." -foregroundcolor "white"

# Create a resource group
Get-AzureRmResourceGroup -Name $resourcegroupname -ev notPresent -ea 0 | out-null
if ($notPresent) {
    Write-Host $resourcegroupname "does not exist... have to create it..." -foregroundcolor "DarkYellow"
    New-AzureRmResourceGroup -Name $resourcegroupname -Location $location | Out-null
    Write-Host $resourcegroupname "successfully created" -foregroundcolor "white"
} else {
    $location = (Get-AzureRmResourceGroup -Name $resourcegroupname).Location
    Write-Host $resourcegroupname "already exists" -foregroundcolor "green"
}

# Storage
Write-Host "Checking if StorageAccount exists..." -foregroundcolor "white"
Get-AzureRmStorageAccount -ResourceGroupName $resourcegroupname -Name $vm_storagename -ev notPresent -ea 0 | out-null
if ($notPresent) {
    $StorageAccount = New-AzureRmStorageAccount -ResourceGroupName $resourcegroupname -Name $vm_storagename -SkuName $vm_storagesku -Kind "Storage" -Location $location | out-null
} else {
    Write-Host "StorageAccount" $vm_storagename "already exists" -foregroundcolor "green"
    $StorageAccount = Get-AzureRmStorageAccount -ResourceGroupName $resourcegroupname -Name $vm_storagename
}

# Network
Write-Host "Configuration of Network Objects..." -foregroundcolor "white"
Get-AzureRmVirtualNetwork -ResourceGroupName $resourcegroupname -Name $vm_vnetname -ev notPresent -ea 0 | out-null
if ($notPresent) {
    $SubnetConfig = New-AzureRmVirtualNetworkSubnetConfig -Name $vm_subnetname -AddressPrefix $vm_VNetSubnetAddressPrefix #-WarningAction SilentlyContinue | Out-Null
    $VNet = New-AzureRmVirtualNetwork -Name $vm_vnetname -ResourceGroupName $resourcegroupname -Location $location -AddressPrefix $vm_VNetAddressPrefix -Subnet $SubnetConfig #-WarningAction SilentlyContinue | Out-Null
    $PublicIp = New-AzureRmPublicIpAddress -Name $vm_interfacename -ResourceGroupName $resourcegroupname -Location $location -AllocationMethod $vm_TCPIPAllocationMethod -DomainNameLabel $vm_domainname.toLower() -WarningAction SilentlyContinue | Out-Null
    $Interface = New-AzureRmNetworkInterface -Name $vm_interfacename -ResourceGroupName $resourcegroupname -Location $location -SubnetId $VNet.Subnets[0].Id -PublicIpAddressId $PublicIp.Id #-WarningAction SilentlyContinue | Out-Null
} else {
    $VNet = Get-AzureRmVirtualNetwork -Name $vm_vnetname -ResourceGroupName $resourcegroupname 
    $SubnetConfig = Get-AzureRmVirtualNetworkSubnetConfig -VirtualNetwork $VNet -Name $vm_subnetname 
    $PublicIp = New-AzureRmPublicIpAddress -Name $vm_publicIPName -ResourceGroupName $resourcegroupname -Location $location -AllocationMethod $vm_TCPIPAllocationMethod -DomainNameLabel $vm_domainname.ToLower() -WarningAction SilentlyContinue | Out-Null
    $Interface = New-AzureRmNetworkInterface -Name $vm_interfacename.ToLower() -ResourceGroupName $resourcegroupname -Location $location -SubnetId $VNet.Subnets[0].Id -PublicIpAddressId $PublicIp.Id
}
Write-Host "Configuration of Network Objects... successfully finished" -foregroundcolor "green"

# Compute
Write-Host "Configuration of Compute Objects..." -foregroundcolor "white"
$VirtualMachine = New-AzureRmVMConfig -VMName $vm_vmname -VMSize $vm_size -WarningAction SilentlyContinue
$Credential = Get-Credential -Message "Type the name and password of the local administrator account."
$VirtualMachine = Set-AzureRmVMOperatingSystem -VM $VirtualMachine -Windows -ComputerName $vm_computername -Credential $Credential -ProvisionVMAgent -EnableAutoUpdate -WarningAction SilentlyContinue #-TimeZone = $TimeZone
$VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $Interface.Id -WarningAction SilentlyContinue
$StorageAccount = Get-AzureRmStorageAccount -ResourceGroupName $resourcegroupname -Name $vm_storagename
$OSDiskUri = $StorageAccount.PrimaryEndpoints.Blob.ToString() + "vhds/" + $vm_osdiskname + ".vhd"
$VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -Name $vm_osdiskname -VhdUri $OSDiskUri -Caching ReadOnly -CreateOption FromImage -WarningAction SilentlyContinue

# Image
Write-Host "Configuration of Image for the VirtualMachine..." -foregroundcolor "white"
$VirtualMachine = Set-AzureRmVMSourceImage -VM $VirtualMachine -PublisherName $vm_publishername -Offer $vm_offername -Skus $vm_sku -Version $vm_version -WarningAction SilentlyContinue

# Create the VM in Azure
Write-Host "Creation of the completely configured VirtualMachine..." -foregroundcolor "white"
New-AzureRmVM -ResourceGroupName $resourcegroupname -Location $location -VM $VirtualMachine -WarningAction SilentlyContinue

# Enable Auto-Shutdown
$VM = Get-AzureRmVM -ResourceGroupName $resourcegroupname -Name $vm_vmname
$VMResourceId = $VM.Id

$Properties = @{}
$Properties.Add('status', 'Enabled')
$Properties.Add('taskType', 'ComputeVmShutdownTask')
$Properties.Add('dailyRecurrence', @{'time'= 2300})
$Properties.Add('timeZoneId', "W. Europe Standard Time")
$Properties.Add('notificationSettings', @{status='Disabled'; timeInMinutes=15})
$Properties.Add('targetResourceId', $VMResourceId)

#Error
try {
    $ScheduledShutdownResourceId = "/subscriptions/$mySubscriptionID/resourceGroups/$resourcegroupname/providers/microsoft.devtestlab/schedules/shutdown-computevm-$vm_vmname"
    Get-AzureRmResource -Location $location -ResourceId $ScheduledShutdownResourceId -ErrorAction Stop
    Set-AzureRmResource -ResourceId $ScheduledShutdownResourceId -Properties $Properties  -Force
}
catch {
    New-AzureRmResource -Location $location -ResourceId $ScheduledShutdownResourceId -Properties $Properties  -Force    
}

## Add Datadiscs
for ($i=1; $i -le 4; $i++) {
    $DiskName = "$servername-datadisk-$i"
    $VhdUri = "https://" + $vm_storagename + ".blob.core.windows.net/vhds/" + $DiskName + ".vhd"
    Add-AzureRmVMDataDisk -VM $VM -Name $DiskName -VhdUri $VhdUri -LUN $i -Caching ReadOnly -DiskSizeinGB 256 -CreateOption Empty
}

Update-AzureRmVM -ResourceGroupName $ResourceGroupName -VM $VM 

# THE END
Write-Host "Script finished!" -foregroundcolor "green"

Vielleicht kann man es einfacher machen, aber da meine Ressourcengruppe bereits besteht/bestand und ich im Falle eines „Neuaufbaus“ weder meine Entwickler-Workstation und auch nicht meinen Domänen-Controller erneuern wollte, wäre dieses Skript in der Lage entweder alles komplett neu anzulegen (inkl. Ressourcengruppe und StorageAccount) oder eben auf bereits vorhandenem aufzusetzen. Ich bin also weiterhin relativ flexibel…
Was mir noch als „Fehler“ aufgefallen ist und ich noch nicht gefixt habe… es wird zwar eine Public-IP vergeben, diese aber nicht der Maschine zugewiesen (attached)… das habe ich erst einmal über das Portal korrigiert und wenn ich die Zeit dazu finde, werde ich auch das Powershell Skript anpassen.

Kurz zu den einzelnen Maschinen

Die Azure Windows Server „Standard DS1 v2“ sind derzeit mit nur 1 vCPU und 3,75GB RAM ausgestattet, verfügen über maximal 3200 IOPS und einem 7GB großen D-Laufwerk (derzeitige Kosten pro Monat – 83,45 Euro). Diese Ausstattung reicht für meine Desired State Configuration Versuche absolut aus, da es nicht um SQL Server Workloads geht, sondern rein um das automatisierte Deployment.

Die zusätzlich angehängten Datenplatten sind auch nur einfache Standard-HDD, um die Konfiguration des SQL Server gleich „richtig“ anzupassen, d.h. die Datendateien und TransactionLogFiles sowie die TempDB entsprechend aufzuteilen. Womit wir auch schon beim nächsten Powershell-Skript sind, was mir die Neu-Erstellung der Umgebung ein wenig vereinfacht hat…

Konfiguration der Ziel-SQL Server mit Powershell

Hier gibt es eigentlich keine große „MAGIC“ aber es ist halt schneller machbar und man muss nicht alle Einstellungen in den unterschiedlichen Snap-ins manuell suchen und ändern. Zumal das Initialisieren, Formatieren und Zuweisen eines Laufwerks-Buchstaben kann unter Umständen (bei der Ausstattung meiner Server 😉 ) etwas länger dauern…

Powershell - Einbinden der Laufwerke - Freischalten der Firewall - Einbinden in die Domäne

Die paar Zeilen konnte ich so aus dem Internet kopieren
Das Öffnen der Firewall um das Browsen im Netzwerk zu erlauben, ebenso um File- und Printer-Sharing zu ermöglichen kommt zum Beispiel von hier => TechNet-Forum – Windows 10 Support

  1. Network Discovery:
    netsh advfirewall firewall set rule group=”network discovery” new enable=yes
  2. File and Printer Sharing:
    netsh firewall set service type=fileandprint mode=enable profile=all

die zweite Zeile gibt einen Fehler/Hinweis aus, dass sie mittlerweile „deprecated“ ist und man doch bitte das Kommando anpassen sollte.
netsh advfirewall firewall set rule group=”File and Printer Sharing” new enable=yes

Das Formatieren und Benennen der eingehängten Datenplatten kommt von den „Scripting Guys“

Get-Disk |
Where partitionstyle -eq 'raw' |
Initialize-Disk -PartitionStyle MBR -PassThru |
New-Partition -AssignDriveLetter -UseMaximumSize |
Format-Volume -FileSystem NTFS -NewFileSystemLabel "disk2" -Confirm:$false

Einzig NewFileSystemLabel habe ich entfernt, da ich diesen Wert nicht weiter brauche. Und zu guter letzt, das „Joinen“ der Server in die SQLScripting Domäne.

Add-Computer -DomainName sqlscripting -Credential sqlscripting\admin -Restart -Force

Vorbereitung ist alles – gerade bei Automatisierung

Also musste noch ein Skript her, welches mir meine Powershell Module immer wieder aktualisiert (wenn ich es denn möchte) und diese an den relevanten Punkten im Netz bereitstellt, so dass ich damit überall arbeiten kann. So bekommt ihr auch einen Überblick welche Powershell-Module ich alle heruntergeladen habe bzw für mein DSC-Projekt benötige. Auch hilft mir dieses Skript, diese Module zu verteilen, da ich ja von den Servern aus keinen Zugriff auf das Internet habe und alternativ muss ich die Module auf meinem Internet-PC herunterladen und sie dann manuell auf meine Entwicklungs-Workstation (ggfs ohne Internet) zu kopieren.

clear-Host

## Definde Variables
$LocalModuleDir = "C:\Program Files\WindowsPowerShell\Modules"
$RemoteModuleDir = "\\dc01\SYSVOL\sqlscripting.demo.org\DSC\Modules"

Write-Host "Starting to update local modules folder and import necessary modules"

## Check if local folder exists
Write-Host "Checking if Folder exists"
if(!(Test-Path -Path $RemoteModuleDir )){
    New-Item -ItemType directory -Path $RemoteModuleDir
} else {
    Remove-Item -Path "$RemoteModuleDir\*" -Recurse -Force
    Start-Sleep 10
}

If (Test-Connection -computer "www.google.com" -count 1 -quiet) {
    ## Internet-Connection is available
    Write-Host -ForegroundColor Green "$(Get-Date): Connection up!"
    
    ## Download and save modules to folder for DSC
    Write-Host "Downloading Modules from the Internet"
    Save-Module -LiteralPath $RemoteModuleDir -Name "xPSDesiredStateConfiguration" -Repository "PSGallery"
    Save-Module -LiteralPath $RemoteModuleDir -Name "dbatools" -Repository "PSGallery"
    Save-Module -LiteralPath $RemoteModuleDir -Name "xSQLServer" -Repository "PSGallery"
    Save-Module -LiteralPath $RemoteModuleDir -Name "SQLServer" -Repository "PSGallery"
    Save-Module -LiteralPath $RemoteModuleDir -Name "SecurityPolicyDsc" -Repository "PSGallery"
    Save-Module -LiteralPath $RemoteModuleDir -Name "xPendingReboot" -Repository "PSGallery"
    Save-Module -LiteralPath $RemoteModuleDir -Name "StorageDSC" -Repository "PSGallery"

    ## Load Modules for Developement and Debugging
    Install-Module -Name "xPSDesiredStateConfiguration"
    Install-Module -Name "dbatools"
    Install-Module -Name "xSQLServer"
    Install-Module -Name "SqlServer"
    Install-Module -Name "SecurityPolicyDsc"
    Install-Module -Name "xPendingReboot"
    Install-Module -Name "StorageDSC"

} else {
    ## Internet-Connection is available
    Write-Host -ForegroundColor DarkYellow "$(Get-Date): Connection missing! Working locally!"
    
    ## Load Modules for Developement and Debugging
    Import-Module -Name "xPSDesiredStateConfiguration"
    Import-Module -Name "dbatools"
    Import-Module -Name "xSQLServer"
    Import-Module -Name "SqlServer"
    Import-Module -Name "SecurityPolicyDsc"
    Import-Module -Name "xPendingReboot"
    Import-Module -Name "StorageDSC"
}

## Copy Modules from Download-Path to Module-Path
Write-Host "Copying Modules from $RemoteModuleDir to $LocalModuleDir"
Start-Job -Name CopyModulesJob -ScriptBlock { 
    Copy-Item -Path $RemoteModuleDir -Destination $LocalModuleDir -Recurse -Force
}
Wait-Job -Name CopyModulesJob | Remove-Job

Write-Host "Module Updates successfully finished!"

Ich hoffe euch helfen meine Skripte ein wenig eure eigenen Projekte umzusetzen oder zumindest zeigen Sie euch einen Weg wie man dorthin kommen könnte. Für Fragen oder Anregungen stehe ich natürlich immer zur Verfügung bzw bin ich jederzeit offen.

Update 08. Januar 2019
Ich habe das obige Skript noch einmal angepasst, da ich für die folgende Schritte in der Automatisierung weitere Module brauche und irgendwie war mir das bei 3 Zeilen für jedes Modul einfach zu viel…
Daher habe ich die Module erst einmal in ein Array gepackt und durchlaufe das Array entsprechend. Macht die Administration des Skriptes später wesentlich einfacher 😉 ( und das Skript kürzer )

clear-Host

## Definde Variables
$LocalModuleDir = "C:\Program Files\WindowsPowerShell\Modules"
$RemoteModuleDir = "\\dc01\SYSVOL\sqlscripting.demo.org\DSC\Modules"

$NeededModules = @(
    "xPSDesiredStateConfiguration",
    "dbatools",
    "xSQLServer",
    "SqlServer",
    "SecurityPolicyDsc",
    "xPendingReboot",
    "StorageDSC",
    "NetworkingDsc",
    "xActiveDirectory",
    "ComputerManagementDsc", 
    "xFailOverCluster",
    "xSmbShare"
)

Write-Host "Starting to update local modules folder and import necessary modules"
## Check if local folder exists
Write-Host "Checking if Folder exists"
if(!(Test-Path -Path $RemoteModuleDir )){
    New-Item -ItemType directory -Path $RemoteModuleDir
} else {
    Write-Host -ForegroundColor darkyellow "Folder exists - we have to clean up! Wait a moment..."
    Remove-Item -Path "$RemoteModuleDir\*" -Recurse -Force
    Start-Sleep 10
}

If (Test-Connection -computer "www.google.com" -count 1 -quiet) {
    ## Internet-Connection is available
    Write-Host -ForegroundColor Green "$(Get-Date): Connection up!"
    Write-Host "Downloading Modules from the Internet"
    for ($i=0; $i -lt $NeededModules.length; $i++) {
        Write-Host "Saving and installing Module"$NeededModules[$i].tostring()
        ## Download and save modules to folder for DSC
        Save-Module -LiteralPath $RemoteModuleDir -Name $NeededModules[$i] -Repository "PSGallery"
        ## Load Modules for Developement and Debugging
        Install-Module -Name $NeededModules[$i] -Force
    }
} else {
    ## Internet-Connection is available
    Write-Host -ForegroundColor DarkYellow "$(Get-Date): Connection missing! Working locally!"
    ## Load Modules for Developement and Debugging
    for ($i=0; $i -lt $NeededModules.length; $i++) {
        Write-Host "just importing this - '"+$NeededModules[$i]+"'"
        Import-Module -Name $NeededModules[$i]
    }
}

## Copy Modules from Download-Path to Module-Path
Write-Host "Copying Modules from $RemoteModuleDir to $LocalModuleDir"
Start-Job -Name CopyModulesJob -ScriptBlock { 
    Copy-Item -Path $RemoteModuleDir -Destination $LocalModuleDir -Recurse -Force
}
Wait-Job -Name CopyModulesJob | Remove-Job

Write-Host "Module Updates successfully finished!"

Desired State Configuration #3 – Details zu SQL Server Installation mit Murphy

EDIT:
Falls ihr nach einer fertigen Lösung sucht, bitte geduldet euch… ich erläutere hier meinen Projekt-Verlauf, wie ich wann wie vorgegangen bin… als letzten Blogbeitrag werde ich die „fertige“ Lösung vorstellen.

Vielen Dank für euer Verständnis

Mit dem folgenden Beitrag möchte ich ein wenig in die Tiefe einsteigen, um euch zu zeigen, wie ich was wo kopiert und angepasst habe, damit mein Desired State Configuration SQL Server Rollout einwandfrei läuft. Nachdem ich in den ersten beiden Beiträgen die Vorbereitungen und Grundlagen meines Deployments erklärt und dargestellt habe, möchte ich heute auf die eigentliche Installation erläutern wie ich sie umgesetzt habe (es gibt auch einen anderen Weg, den ich später ausprobieren möchte – wie das so in Projekten ist herrscht ein wenig Termindruck 😉 )

Meine Skripte befinden sich während ich diesen Beitrag schreibe in einem Zustand, den man „Funktioniert“ nennen kann. Meine Skripte sind aktuell in der Lage von einem zentralen Server aus, auf einem (oder mehreren) Server alle notwendigen Ordner zu erstellen, die benötigten Dateien (ISO-Image, Updates, Powershell Module etc) auf den ZielServer zu kopieren, dort dann gemäß Vorgaben einen SQL Server 2017 inklusive letztem Patch-Level zu installieren und dann diesen SQL Server gemäß Best-Practice-Vorgaben zu konfigurieren.

Wie bereits im zweiten Teil der DSC Serie erläutert, habe ich mittels DSC-Configuration alle notwendigen Dateien – unter anderem das aktuelle ISO-Image des SQL Servers 2017 und das letzte Cumulative Update – auf den Zielserver kopiert. (Im Bild wurde nur noch der SOLL-Zustand kontrolliert, es waren keine Aktionen notwendig!)

Auf diesem Stand kann man aufbauen und endlich mit der eigentlichen Installation beginnen, dazu benötigen wir

  • das ISO-Image (en_sql_server_2017_developer_x64_dvd_11296168.iso)
  • das letzte Update (SQLServer2017-KB4466404-x64.exe)
  • die ConfigurationFile.ini
  • und die benötigten Powershell-Module (z.B. dbatools, SecurityPolicyDsc, SqlServerDsc usw.)

In der ConfigData.psd habe ich hinterlegt, welche Rolle bzw welche Konfigurations-Parameter der einzelne Server erhalten soll, was in meinem aktuellen Beispiel für alle Server identisch ist, aber in anderen Umgebungen unter Umständen anders sein kann.

@{
    AllNodes = @(
        @{
            NodeName        = "*"
            PSDscAllowPlainTextPassword = $true
            PSDscAllowDomainUser =$true
            SQLInstallPath     = "D:\SQL2017"
            InstanceName    = "MSSQLServer"
        },
        @{
            NodeName        = "sqlvm01"
            Role            = "SqlServer"
        },
        @{
            NodeName        = "sqlvm02"
            Role            = "SqlServer"
        }
        @{
            NodeName        = "sqlvm03"
            Role            = "SqlServer"
        }
        @{
            NodeName        = "sqlvm04"
            Role            = "SqlServer"
        }
    )
}
Dreams are broken - Photo by freestocks.org

Murphy hat auch zugeschlagen

Aber von vorne… Auf meinen Test-Maschinen sqlvm01 und sqlvm02 habe ich „rumgespielt“, ohne wirklich zu protokollieren, was ich wie wann warum gemacht habe… also was habe ich – aus welchen Gründen auf den beiden Maschinen lokal ausgeführt bzw durchgeführt, was hinterher dazu führte, dass meine Skripte funktionierten??? Bereits beim sqlvm03 und später auch beim sqlvm04 funktionierten meine Skripte nicht mehr wie gewünscht… Eigentlich war ich sehr zufrieden wie meine Skripte auf den ersten beiden Maschinen sauber alle Dateien erhielten, dann der SQL Server 2017 installiert wurde und abschließend konfiguriert wurde mittels Desired State Configuration. Alle vier SQL Server wurden identisch in der selben Ressourcengruppe ausgerollt, konfiguriert. Folgende Aktivitäten habe ich auf allen Maschinen durchgeführt, insbesondere auf den Maschinen sqlvm03 und sqlvm04 (dort explizit nur diese Aktivitäten)

  • Network Discovery aktiviert
  • alle Platten eingebunden und formatiert
  • in die Ziel-Domäne gehängt

Und dann vom Domänen-Controller aus mittels DSC-Push die Configurations – wie zuvor beschrieben – auf die Zielserver ausgerollt… aber leider wollte die Script-Ressource nicht so wie ich… auf 01/02 konnte ohne Probleme das ISO-Image für die SQL Server Installation als Laufwerk gemountet werden, aber auf 03/04 ums verr….en nicht… Egal was ich machte, egal wie ich es auch drehte, ich konnte nie auf das Laufwerk und somit auch nicht auf die „setup.exe“ zugreifen.

Der Neubeginn – Alles zurück auf 0,25

Wie es dann manchmal auch so ist… man hat natürlich keine Sicherung von irgendwelchen Skripten (egal ob funktionierend oder nicht)… ich hatte zumindest im selben Ordner immer wieder Version-Ordner angelegt, wenn ich mit „Meilensteinen“ erfolgreich war, aber eine richtige Sicherung hatte ich nicht und schon gar nicht meine Arbeiten in eine Versionierungs-Software eingebunden. So kam es, wie es kommen musste! Ich löschte mittels Powershell den falschen Ordner und alles war weg, nur was noch in Visual Studio Code geöffnet war (3 Dateien) konnte ich retten.
Eigentlich habe ich – keine Ahnung wo der Fehler herkam – nahezu die komplette C-Platte gelöscht… kein Internet Browser mehr, kein Powershell mehr, es ging fast nichts mehr… es war halt am einfachsten den Server neu aufzusetzen (wenn man wie ich kein Backup hat) => es war ja auch nur der Domänen-Controller 😮

Dieses unschöne Ereignisse habe ich aber zum Anlass genommen, meine komplette Entwicklungsumgebung aufzuräumen und „ein wenig anders“ aufzusetzen… eigentlich ist alles beim alten geblieben, nur das ich nicht mehr auf dem Domänen-Controller selber entwickeln werde und meine Skripte nicht mehr lokal auf dem Server ablege, bei anderen Projekten bin ich bereits diesen Weg gegangen. Also einen neuen Windows Server 2016 (Standard DS1 v2) aufsetzen, die Active Directory und DNS Rolle ausrollen und konfigurieren. Zusätzlich gibt es jetzt eine Windows 10 Maschine (Standard A4m v2), auf der ich meine Skripte entwickeln werde.

Übersicht zur neuen Entwicklungs-Umgebung für meine Desired State Configuration - DSC - Skripte

aus Fehlern lernen macht stärker

Um also meinem Lernziel oder auch dem Projektziel in Sachen „Automatisierte Installation von SQL Servern mit Desired State Configuration“ wieder näher zukommen, musste ich leider wieder von vorne beginnen… diesmal aber mit einem etwas anderen Lösungsansatz. 😉
Meine erste Lessions-learned… Erstelle eine Sicherung aus einer „Blanko-Maschine“, damit man schneller auf den ursprünglichen Server zurückkommt. Meine zweite Lessions-learned… mache ansonsten alles mit Skripten (die werde ich in einem weiteren Blog-Post veröffentlichen)

Aber wieder zurück zum Theme DSC – ich bleibe bei meinen einleitenden Aktivitäten, dem Kopieren der Powershell-Module und den Installationsmedien auf den jeweiligen Zielserver, was auch geblieben ist ist das Überprüfen ob das notwendige .NET-Framework installiert ist, ansonsten wird es nachinstalliert. Diesmal orientiere ich mich ein wenig (oder auch etwas mehr) an Chris Lumnah (Blog), der anhand einer Einführung in DSC aus der Microsoft Virtual Academy und eigenem Wissen ein Script zusammen gebaut hat, welches ich adaptieren möchte, da es nicht mit der DSC-Script-Ressource arbeitet, sondern mit der „richtigen“ SQLServer-DSC-Ressource.

Mehr dann im nächsten Blog-Beitrag, da ich nun leider wieder einen Tag für das Neu-Aufsetzen bzw den Neuanfang meiner DSC-Skripte aufbringen musste…
Sorry und Danke für euer Verständnis!

Mein Jahres-Rückblick 2018

Ich möchte in diesem Beitrag einmal mein Jahr 2018 Review passieren lassen, was ich alles in der Community erlebt habe, mit bzw für die Community getan habe und wie es (hoffentlich) weitergehen wird. Im Zuge dessen möchte ich auch einige Personen nicht unerwähnt lassen, die mich immer wieder inspirieren und mit denen ich gerne zusammen arbeite.

Azure Meetup Hamburg

Das Azure Meetup Hamburg lief erstaunlicherweise sehr unkompliziert weiter und macht immer noch großen Spaß. Dazu muss ich auch sagen, dass ich mir vor etwa 2 Jahren, als ich das Azure Meetup gegründet habe nicht vorstellen konnte, dass wir so wachsen… wir sind (Stand 27.12.2018) 804 Teilnehmer !!! Vielen Dank für euer Interesse und eure Unterstützung !!! Ohne euch macht es keinen Sinn und vor allem keinen Spaß… ich hoffe, ich kann euch auch weiterhin interessante Themen und Sprecher präsentieren 🙂

Anfang des Jahres waren wir wieder bei Microsoft zu Besuch und durften auch im März für einen SAP 4/Hana Vortrag bei der direkt-Gruppe zu Gast sein, die folgenden Monate waren wir zu Besuch bei Atos und zum Schluss des Jahres waren wir jetzt zweimal bei WeWork in der Europa-Passage. Inhaltlich hatten wir ein recht rundes Programm, von IaaS über PaaS war sehr vieles vertreten und auch die Tiefe der Vorträge variierte, so dass (hoffentlich) für jeden etwas dabei war. So wird es in 2019 wohl auch weitergehen und wir haben noch zahlreiche Ideen in der Hinterhand und würden uns von euch wünschen, dass ihr eure Wünsche ebenso äussert. Denn wir sind eine Community, die gemeinsam an einem Ziel arbeitet. Wir wollen die Microsoft Public Cloud Azure besser verstehen und optimal für unsere Zwecke oder die Zwecke unserer Kunden einsetzen.

Vielen DANK für eure Teilnahmen und euer Interesse an unserer Community!

Azure Community - Azure Meetup Hamburg im November 2018

SQL PASS – RegionalGruppe, SQL Saturdays und PASSCamp

Auch wenn ich dieses Jahr nicht oft und vor allem nicht regelmäßig an den Treffen der Regionalgruppe Hamburg teilgenommen habe, so möchte ich mich bei Conny und Sascha recht herzlich für ihre Mühen und Arbeit recht herzlich bedanken, denn wo wäre ich ohne Conny und die PASS 😉 Beide haben bisher ihren Teil dazu beigetragen, dass ich überhaupt in der Community aktiv geworden bin und nun auch noch Spaß daran gefunden habe 😉

Vor allem Conny treffe ich auf zahlreichen Events der SQL Community in Deutschland immer wieder, wie zum Beispiel den zwei deutschen SQLSaturdays in 2018. Der erste fand wieder in Sankt Augustin im Rheinland statt. Ich konnte wieder am Freitag Morgen anreisen und konnte so auch noch in Ruhe an der „PreCon“ teilnehmen und vieles lernen. Am eigentlichen Samstag hatte ich neben meinen zwei (!) Sessions (Danke an das Orga-Team) noch zusätzlich den Azure Meetup Germany Stand gemeinsam mit Gregor Reimling und Raphael Köllner zu betreuen. Aber der SQLSaturday #760 war nicht mein erster in 2018, denn der fand bereits im Jänner 2018 in Wien statt! Ich war sehr glücklich, dass mich das Orga-Team um Wolfgang Strasser (b|t) und Markus Ehrenmüller (b|t) mich als Sprecher ausgewählt hatten! Es war großartig Teil einer „internationalen“ Veranstaltung zu sein und hat – wie soviele Veranstaltungen der Community – riesigen Spaß bereitet. Ich darf auch 2019 wieder Teil des SQLSaturdays in Österreich sein, diesmal findet dieser in Linz statt!

Dank der Bemühungen einiger Mitglieder der Community konnte auch ein zweiter deutscher SQLSaturday wieder belebt werden, mit einem Jahr Pause fand wieder eine solche Zusammenkunft der Community in München statt. Vielen Dank an Microsoft, Erik und seine zahlreichen Helfer!!! In der Hoffnung für 2019 😉 Freundlicherweise stelle Microsoft wieder seine Räumlichkeiten für eine PreCon und die eigentliche Veranstaltung zur Verfügung, so dass reichlich Platz war für die Vielzahl an Teilnehmern. Dank Kaffee, anderer Getränke und hervorragendem Catering war dies wieder ein sehr lohnenswerte Veranstaltung der Community für die Community!

Das PASS-Camp ist jedes Jahr wieder ein Highlight im Kalender, erst recht für mich persönlich wie ich bereits im letzten Jahr dazu schrieb. Auch in diesem Jahr wurde ich von der Organisation des PASS-Camps eingeladen einen Vortrag zur Azure SQL Database – Managed Instance zu halten, welcher ich gerne nachkam. In diesem Jahr schon viel erfolgreicher als im letzten, denn schließlich lernt man mit jedem Vortrag und weiß was man anderes bzw besser machen muss. Vor allem half dieses Jahr die Tatsache, dass die Managed Instance mittlerweile „General Available“ war und ich den Teilnehmern auch entsprechende Hands-On-Sessions geben konnte. Diese HandsOn-Sessions sind schließlich das Salz in der Suppe vom PASS-Camp!
In der Community gibt es ein neues „Projekt“ einiger Aktivisten 😉 => „Please talk Data to me“, ein Podcast rund um die Microsoft-Data-Platform, die eine neue Folge für den Podcast im Rahmen des PASS-Camps in Seeheim aufgenommen haben, unvorbereitet und spontan wurde ich Teil dieser Aufzeichnung. Es hat viel Spaß gemacht mit den anderen Verrückten gemeinsam an einem Thema zu arbeiten… DANKE

Please talk Data to me - Aufnahme der Podcast-Folge #7

SQLGrillen 2018 in Lingen (Ems)

Auch 2018 durfte ich wieder – nach meinem Sprecher-Debut mit Gabi Münster in 2017 – wieder als Sprecher beim SQLGrillen dabei sein. Als ein Teil des stetigen Wachstums dieser Veranstaltung und dem mittlerweile internationalen Bekanntheitsgrad dieser (eigentlich Community-)Veranstaltung, empfinde ich dies als große Auszeichnung. Hier kommen Größen der #SQLFamily wie Catherine Wilhelmsen, Grant Fritchey oder Thomas LaRock, oder gestandene Sprecher der deutschen #sqlpass_de Community wie Uwe Ricken, Oliver Engels oder Marcos Freccia und viele weitere großartige Sprecher aus dem europäischen Ausland. Ebenso steigt mit jedem Jahr die Teilnehmerzahl und damit auch das Ansehen dieser Veranstaltung… hier möchte ich nicht unerwähnt lassen, dass William Durkin als federführender Organistator, auch für 2019 wieder zu dieser Veranstaltung einlädt… allerdings dieses Mal nicht mehr nur einen Tag, sondern gleich zwei (!!!) Tage und somit der doppelten Menge Sessions und alles wieder ohne Eintrittsgeld!!! (Aber man muss schnell sein, Stand 27.12.2018 sind 191 von 200 Tickets bereits vergeben!)

Ach ja und ganz wichtig… aus dem SQLGrillen wird 2019 das DataGrillen, da es sich nicht mehr nur um den SQL Server handelt sondern um die komplette Microsoft-Data-Platform! Schnell sein und dabei sein, es wird garantiert wieder eine großartige Veranstaltung!!!

SQLDays 2018 in München

Nicht wirklich Community aber … ich wurde zu meiner ersten „kommerziellen“ Veranstaltung im Oktober 2018 eingeladen, die ppedv hatte wieder zur alljährigen Trainingsveranstaltung „SQLDays“ nach München-Erding eingeladen. Vergleichsweise viele Teilnehmer kamen zu diesem gut besetzten mehrtägigen (4 Tage) Training, um sich über die neuesten Themen, Features, Produkten und Updates zu informieren. Zahlreiche renommierte Sprecher aus Deutschland und Österreich trafen auf interessierte und neugierige Teilnehmer, um mit Ihnen nicht nur in den Sessions sondern auch in den Pausen oder Abendveranstaltungen, über Themen wie „GDPR“, „Modern Dataware-Housing“ oder „Managed Instances“ zu sprechen. Ich traf hier auf viele bekannte Gesichter, die ich schon von anderen (Community-)Veranstaltungen her kannte und konnte im Kreise von Freunden einige Stunden verbringen.
Vielleicht bin ich auch 2019 wieder als Sprecher auf den SQLDays in München… mal schauen mit welchem Thema ich dort vorstellig werde…

MVP-Award – Data Platform

Im Juli 2018 wurde ich erneut zum Microsoft Most Valuable Professional ausgezeichnet, jetzt schon zum zweiten Mal, allerdings mit einem Wechsel der Kategorie (von Cloud & Datacenter Management zu Data Platform). Man arbeitet das ganze Jahr darauf hin und sitzt am Tag der Verkündung (1.Juli) vor dem Computer und drückt gefühlt alle 30 Sekunden die „F5“-Taste… wann kommt endlich die offizielle Mail von Microsoft… WANN ???
Meine Mail kam um 17:21, endlich die Erlösung, die Arbeit hat sich also erneut gelohnt! Mein Einsatz für die Community war groß genug, um wieder als MVP ausgewählt zu werden! Welch eine Ehre!!! Einer aus dieser erlesenen Gruppe von Community-Enthusiasten zu sein, die sich (neben vielen anderen) Tag ein, Tag aus für die Community einsetzen. Ich kenne „Mitstreiter“, die machen eigentlich nichts anderes mehr, als sich in nahezu jeder freien Minuten irgendwas neues, spannedes für einen anstehenden Event auszudenken, aber auch Leute wie mich, die sich in regelmäßigen monatlichen Terminen für die Community engagieren und sich dann auch noch ehrenamtlich auf Veranstaltungen bewerben, um ihr eigenes Wissen unter die Leute zu bringen! DANKE, dass es euch gibt! Es macht mir sehr viel Spaß und Freude gemeinsam mit euch auf diesen Veranstaltungen für „Sharing is Caring“ zu engagieren!

Unsplash - Photo by kevin Xue - THANK YOU