Ich spreche beim PASS Meetup in München über Azure SQL DB

Ich bin am 12.September 2019 zu Gast beim SQL PASS Meetup der Regionalgruppe Bayern und werde einen Überblick über die verschiedenen Azure SQL Databases geben. Kommt natürlich gerne vorbei, jeder ist herzlich eingeladen, die Veranstaltung ist kostenlos und nicht umsonst 😉

Hier kommt eine Kurzbeschreibung meines Vortrages:

Jeder spricht davon, in die Cloud zu gehen, auch mit seinen Datenbanken. Lassen Sie mich Ihnen die Azure SQL Database in all ihren wunderschönen Farben und Optionen vorstellen. Es geht von der allgemeinen Beschreibung über die verschiedenen Engines / Dienste und natürlich die Features, die Sie für Ihr Geld bekommen. Desweiteren werden wir die unterschiedlichen Bereitstellungs-Methoden und Migrationspfade Ihrer Daten anschauen.
Nach meiner Session können Sie die verschiedenen Datenbank-Dienste unterscheiden und wissen, welcher für Sie und Ihre Anwendung der richtige sein könnte!

Ich freue mich auf einen spannenden Abend mit Ihnen!
Anmeldungen bitte hier vornehmen 😉
https://www.meetup.com/de-DE/pass-bayern/events/264489827/

An diesem Abend werde ich aber nicht der einzige Vortragende sein, denn Sebastian Sproß (Microsoft Cloud Architekt) wird auch eine spannende Geschichte zu Datenbanken CI/CD erzählen und was das Ganze mit (Azure) Devops zu tun hat. Auch auf diesen Vortrag freue ich mich schon sehr.

CommunityRocks

Aha-Effekt beim Setzen von SQL Instanz Parametern mit dbatools

In der letzten Woche habe ich bei einem Kunden mehrere SQL Server installiert und musste diese alle identisch installieren und konfigurieren. Was liegt hier näher als dies mit einem Powershell Skript zu machen, daher habe ich mir die „Mühe“ gemacht und die einzelnen Schritte der SQL Server Konfiguration mit dbatools zu realisieren. Ich möchte in diesem Beitrag nicht auf alle Schritte der Konfiguration eingehen, sondern nur einen Teil davon zeigen, der mir einen gewissen „Aha-Effekt“ brachte.

Im Rahmen der SQL Server Konfiguration sollten die Default-Werte von „MaxDop“ und „Cost Threshold for Parallelism“ angepasst werden. Das Setzen von MaxDoP mittels Powershell bzw dbatools ist relativ einfach da es hierfür einen eigenen Befehl gibt, aber auf für den „Cost Threshold for Parallelism“ hat dbatools einen „Workaround“, hier gibt es leider (noch) keinen direkten Befehl für.

Set-DbaMaxDop -SqlInstance sql2008, sql2012

Diese Befehlszeile legt den Wert von „Max DOP“ (Maximal Degree of Parallelism) auf den empfohlenen Wert für die SQL Server Instanzen „SQL2008“ und „SQL2012“ fest. Immer in Verbindung mit diesem Konfigurations-Parameter steht immer der „Cost Threshold“, welcher per Default immer noch auf 5 steht.

Alle SQL Server Instanzen auf einmal…

Um alle SQL Server Instanzen relativ schnell und einfach zu konfigurieren, habe ich mir das Kommando „Get-DbaRegisteredServer“ (als Alias von Get-DbaRegServer) vorgenommen. Als Vorbereitung hierfür habe ich auf allen Servern im SQL Server Management Studio die notwendigen Server (hier 2 Server mit je 3 Instanzen) als „Registered Server“ angelegt und konnte dann mit Powershell aka dbatools darauf zugreifen.

Laut dbatools-Dokumentation, ruft dieser Befehl eine Liste der SQL Server-Objekte ab, die in lokal registrierten Gruppen sowohl im Azure Data Studio als auch auf dem zentralen Verwaltungsserver gespeichert sind.

geborgt bei dbatools.io - Vielen Dank an Chrissy

Mit diesem Befehl und der Möglichkeit die Objekte aus dem Ergebnis-Objekt als Pipeline weiterzugeben, kann man schöne Dinge machen, wie eben den Wert für „MaxDoP“ auf allen Server bzw Instanzen in einer Kommandozeile zu konfigurieren…

Get-DbaRegisteredServer | Set-DbaMaxDop

Nun aber zu meinem Aha-Effekt mit einer weiteren Kommandozeile 😉

Cost Threshold For Parallelism

Wie oben schon angedeutet, geht die Anpassung nur über eine Work-around mit dbatools und nicht mit einem dbatools-Kommando, hierzu verwende ich jetzt „Set-DbaSpConfigure“. Natürlich könnte ich auch den „MaxDoP“ mit diesem Kommando konfigurieren, dann muss ich aber selber für die vorherige Ermittlung und Berechnung des jeweiligen Wertes für MaxDoP sorgen, also die vorhandenen Kerne ermitteln, diese dann gegen die Best-Practise matchen und den Wert über eine Variable an den Set-Befehl weitergeben. Ich setze diesen Werte in 98% aller Instanzen auf 40 (ausser der Kunde oder die Applikation möchten etwas anderes), daher benötige ich hier keine Logik.

Meiner obigen Logik bzw der Dokumentation folgend habe ich es mit folgender Kommandozeile versucht:

Get-DbaRegisteredServer | Set-DbaSpConfigure -Name 'CostThresholdForParallelism' -Value 40

Dies brachte mich aber zu einem (auf den ersten Blick) nicht nachvollziehbaren Fehler (auch mein Versuch den Wert als String zu übergeben war nicht erfolgreich):

WARNING: [13:02:23][Set-DbaSpConfigure] Value out of range for Server1\Instanz1 ( <-> )
WARNING: [13:02:23][Set-DbaSpConfigure] Value out of range for Server2\Instanz1 ( <-> )
WARNING: [13:02:23][Set-DbaSpConfigure] Value out of range for Server1\Instanz2 ( <-> )
WARNING: [13:02:23][Set-DbaSpConfigure] Value out of range for Server2\Instanz2 ( <-> )
WARNING: [13:02:23][Set-DbaSpConfigure] Value out of range for Server1\Instanz3 ( <-> )
WARNING: [13:02:23][Set-DbaSpConfigure] Value out of range for Server2\Instanz3 ( <-> )

Ich habe den Grund hierfür leider noch nicht wirklich gefunden, vielleicht kann mir jemand das Phänomen näher bringen… vielleicht ist dies ja aber auch so gewollt oder ggfs sogar ein „Bug“…

Aber ich war vorher schon so erfolgreich mit dem Pipelining, dass ich das auch hier angewendet habe… also Ermitteln wir erst alle SQL-Instanzen, ermitteln dann auf diesen Instanzen den aktuellen Parameter für den „Cost Threshold For Parallelism“ und setzen ihn dann auf den neuen Wert 40.

Get-DbaRegisteredServer | Get-DbaSpConfigure -Name 'CostThresholdForParallelism' | Set-DbaSpConfigure -Value 40
ComputerName  : Server1
InstanceName  : Instanz1
SqlInstance   : Server1\Instanz1
ConfigName    : CostThresholdForParallelism
PreviousValue : 5
NewValue      : 40

ComputerName  : Server2
InstanceName  : Instanz1
SqlInstance   : Server2\Instanz1
ConfigName    : CostThresholdForParallelism
PreviousValue : 5
NewValue      : 40

ComputerName  : Server1
InstanceName  : Instanz2
SqlInstance   : Server1\Instanz2
ConfigName    : CostThresholdForParallelism
PreviousValue : 5
NewValue      : 40

ComputerName  : Server2
InstanceName  : Instanz2
SqlInstance   : Server2\Instanz2
ConfigName    : CostThresholdForParallelism
PreviousValue : 5
NewValue      : 40

ComputerName  : Server1
InstanceName  : Instanz3
SqlInstance   : Server1\Instanz3
ConfigName    : CostThresholdForParallelism
PreviousValue : 5
NewValue      : 40

ComputerName  : Server2
InstanceName  : Instanz3
SqlInstance   : Server2\Instanz3
ConfigName    : CostThresholdForParallelism
PreviousValue : 5
NewValue      : 40

Und schon habe ich wieder etwas großartiges für mich selber herausgefunden und bin um eine Erfahrung im Umgang mit dbatools reicher!

Ich liebe dieses Powershell-Modul, mit dem ich zahlreiche (nahezu alles!) Dinge am und um den SQL Server herum anpassen, optimieren und automatisieren kann. Ich verwende es sehr gerne (wie man auch meinen anderen Blog-Posts sehen kann) und mittlerweile bei allen meinen Kunden. VIELEN DANK an @Chrissy und die vielen anderen Contributors, die sich die Mühe rund um dieses Community-Tool zu machen!

Beitragsbild – von Ben White auf Unsplash

Screenshots für Dokumentation und Blogbeiträge

Gerade für uns technischen Blog-Beitrag-Schreiber ist es aus mehreren Gründen relevant gute Screenshots in unsere Beiträge einzubinden. Wie aber kommen wir zu qualitativ hochwertigen Screenshots für unsere Beiträge oder auch für Vorträge jeglicher Art?
Es gibt sicherlich eine Vielzahl von Tools, die man für solche Zwecke nutzen kann… ich möchte euch heute mein Tool/ meinen Favoriten zeigen.

Techsmith Snagit

Es gab in den letzten Jahren viele Tools, die ich genutzt habe um Screenshots für meine Dokumentation, Vorträge oder Blogbeiträge zu erstellen… da waren auch echt gute (freie) Tools (zum Beispiel Greenshot) drunter, aber wenn man dann etwas mehr damit machen wollte, als schnell und einfach einen bloßen Copyright-Text hinzufügen, dann wurde es schwer und ich musste oftmals weitere Tools wie zum Beispiel Gimp nutzen. Aber es hat als MVP (Microsoft Most Valuable Professional) den einen oder anderen Vorteil, denn wir erhalten von einigen Herstellern Software zum Testen und oft auch für ein Jahr zur Nutzung for free. So auch Snagit von Techsmith, was in der 2019 Version schon echt gut ist, denn man kann nicht nur bloße Screenshots damit machen, sondern auch Videos aufzeichnen und diese editieren!

bestimmte Bereiche als Screenshots erfassen

Snagit 2019 erkennt eigenständig erfassbare Bildschirmbereiche, wie Kopfzeilen, Menübänder oder das eigentliche Fenster… man kann natürlich auch selber bestimmte Bereiche des sichtbaren Bereiches auswählen. Hierbei bietet Snagit auch die Möglichkeit des „Scrolling Screenshot“, bei dem auch größere Bereiche erfasst werden können. Dies ist zum Beispiel sehr gut nutzbar, wenn man eine ganze Webseite – bei der man scrollen müsste – erfassen und als Screenshots abspeichern.

Beispiele, Anleitungen und Videos dazu man in der Dokumentation von Techsmith

auch Animationen oder kleine Videos möglich

Mit Snagit 2019 kann man nicht nur einfache Screenshots erstellen, sondern auch Videosequenzen aufzeichnen, zum Beispiel für Klickfolgen mit Eingabe der entsprechende Werte in die zu benutzenden Felder. So kann man dem Betrachter schnell und einfach eine Handlungsanweisung erstellen und diese im Snagit-Editor bearbeiten. Auch wenn man die Bearbeitung im Editor nicht mit einem richtigen Schnittprogramm vergleichen kann, so lassen sich doch erstaunliche Ergebnisse erzielen.

Das Entfernen/Rausschneiden von ungewünschten Anfängen oder Enden, zu lange Ladevorgänge können ebenso für die Darstellung entfernt werden. Diese Funktion ist sehr nützlich für Vorträge, Demonstrationen oder zur Veranschaulichung in Schulungen, um nicht zuviel (unnötige) Zeit zu verlieren.

Fazit – großartiges Tool nicht nur Screenshots

Ich scheine nicht alleine zu sein mit meiner Meinung, denn knapp 83% 5 Sterne aus allen Bewertungen im Techsmith-Store sind schon ein deutliches Indiz für eine sehr gut nutzbare Software. Ja, dieses Tool um Screenshots zu erstellen ist nicht kostenfrei, sondern kostet (April 2019) ~52 Euro (je nach Wechselkurs), dieses Geld ist aber sehr gut investiert, denn man erhält ein wirklich professionelles Tool für zwei Arbeitsplätze!

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…

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

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!