Drücke "Enter", um den Text zu überspringen.

Kategorie: PowerShell

Azure – VMs nach zeit gesteuert hoch- und runterfahren

In meinen Workshops und anderen Kundenterminen kommt immer wieder die Frage, wie man Virtuelle Maschinen in Azure nach Zeit gesteuert hoch- und wieder runterfahren kann. Das ist eigentlich ganz einfach – man benötigt dazu nur folgendes:

  • Einen Azure Automation Account
  • Ein PowerShell Runbook mit entsprechendem Skript
  • VMs mit den entsprechenden Tags

Ich habe mich dazu zu folgenden Tags entschieden:

  • AutoShutdown – Entscheidet, ob die VM automatisch heruntergefahren werden soll; kennt die Werte “Yes” and “No”
  • AutoShutdownTime – enthält die entsprechende Zeit für den Shutdown im Format HH:mm:ss nach UTC
  • AutoStartup – Entscheidet, ob die VM automatisch gestartet werden soll; kennt die Werte “Yes” and “No”
  • AutoStartupTime – enthält die entsprechende Zeit für den Start im Format HH:mm:ss nach UTC

image

Das PowerShell-Skript findet ihr in meinem GitHub Repo:

https://github.com/HaikoHertes/scripts/blob/master/Azure/Automation/Snoozing/StartAndStopVMsWithAzureAutomation.ps1

Das Skript ist etwas komplexer als die beiden anderen im Repo, berücksichtigt dabei aber auch, dass eine VM ggf. morgens heruntergefahren und abends gestartet werden soll.

image

Auf Youtube habe ich ein Video veröffentlicht, dass das Vorgehen mit anderen Skripten zeigt:

YoutubeStartfolieAzure

Probiert es einfach mal aus – viel Spaß!

Schreibe einen Kommentar...

PowerShell 7 – Erste Preview verfügbar

Seit ein paar Stunden ist sie nun endlich verfügbar – die erste Preview-Version von PowerShell 7, genannt „PowerShell 7 Preview.1“. Sie kann wie üblich auf verschiedensten Wegen bezogen werden. Einer davon ist der direkte Download aus GitHub:

https://github.com/PowerShell/PowerShell

(Aufpassen, dass ihr die Spalte „Downloads (preview)“ benutzt, sonst bekommt ihr die Stable-Version 6.2)

Das PowerShell-Team beschreibt in einem langen Blog-Post einige Details zum Release und wie die nahe Zukunft aussehen wird:

Auf der GitHub-Seite zum Release stehen auch jede Menge Changes und Bugfixes:

https://github.com/PowerShell/PowerShell/releases/tag/v7.0.0-preview.1

Also, dann viel Spaß beim Ausprobieren der neuen Version! Und denkt daran – Preview heisst, es gibt keinen Support und die Version sollte nicht produktiv eingesetzt werden!

Schreibe einen Kommentar...

PowerShell 7 anstatt 6.3 – und wie es weitergeht

Vor wenigen Tagen hat Steve Lee, Principal Software Engineer Manager für PowerShell, in einem umfangreichen Blog-Post dargestellt, wie es mit PowerShell weitergeht, und warum das nächste Release PowerShell 7 und nicht PowerShell 6.3 heißen wird. Die neue PowerShell Version wird dann auf .NET Core 3.0 basieren.

Im Post ist zu lesen, das abhängig von der Integration von PowerShell und .NET Core 3, eine erste Version von PowerShell 7 im Mai zu erwarten ist. Wir dürfen also gespannt sein!

Schreibe einen Kommentar...

PowerShell Core 6.2 ist GA!

Seit heute ist die neueste Version von PowerShell, PowerShell Core 6.2, allgemein verfügbar.

Zur Installation, siehe hier: https://aka.ms/install-powershell

Neben Bugfixes, Performanceoptimierung und co. gibt es auch ein paar kleine Features, einige davon experimentell, z.B. die automatischen Empfehlungen für Cmdlets, falls die Eingabe falsch/unvollständig ist.

Mehr zu den Features findet ihr auf dem offizielen Microsoft Blog:

Viel Spaß beim Benutzen!

Schreibe einen Kommentar...

Azure / PowerShell – Azure SQL Performance Empfehlungen per PowerShell abholen und verteilen

Azure und insbesondere Azure SQL ist klasse – es nimmt einem viele Dinge der täglichen Verwaltung ab, einiges davon sogar automatisch. Klar, das hat seinen Preis, immerhin ist Azure SQL nicht ganz billig, aber wenn man es schon bezahlt, dann kann man auch seine Fähigkeiten nutzen. Eine davon ist, automatisch anhand der Nutzung einer Datenbank Empfehlungen für die Leistungsoptimierung zu geben. Diese kann man sich im UI bzw. dem Azure Portal anschauen. Dazu öffnet man entweder links im Blade den Punkt „Recommondations“ unterhalb von „Intelligent Performance“ oder den Punkt „Performance“ auf der Main-Page bei den Notifications:

Dort sieht man dann einige Empfehlungen aufgeführt (vorausgesetzt, Azure hat etwas gefunden, was wiederum eine regelmäßige Nutzung der Datenbank voraussetzt):

Diese Daten kann man sich auch automatisch abrufen und auf Wunsch dann z.B. an die Entwickler verteilen. Dazu bediene ich mich einfach der PowerShell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
$ErrorActionPreference = "Stop"
$SubscriptionId = "YOUR_SUBSCRIPTION_ID"
 
function Get-SQLServerRecommendations()
{
    # Define the resource types
    $resourceTypes = ("Microsoft.Sql/servers/databases")
    $advisors = ("CreateIndex", "DropIndex","DbParameterization","SchemaIssue");
    $results = @()
 
    # Loop through all subscriptions
 
    $rgs = Get-AzureRmResourceGroup
 
    # Loop through all resource groups
    foreach($rg in $rgs) {
        $rgname = $rg.ResourceGroupName;
 
        # Loop through all resource types
        foreach($resourceType in $resourceTypes) {
            $resources = Get-AzureRmResource -ResourceGroupName $rgname -ResourceType $resourceType
 
            # Loop through all databases
            # Extract resource groups, servers and databases
            foreach ($resource in $resources) {
                $resourceId = $resource.ResourceId
                if ($resourceId -match ".*RESOURCEGROUPS/(?<content>.*)/PROVIDERS.*") {
                    $ResourceGroupName = $matches['content']
                } else {
                    continue
                }
                if ($resourceId -match ".*SERVERS/(?<content>.*)/DATABASES.*") {
                    $ServerName = $matches['content']
                } else {
                    continue
                }
                if ($resourceId -match ".*/DATABASES/(?<content>.*)") {
                    $DatabaseName = $matches['content']
                } else {
                    continue
                }
 
                # Skip if master
                if ($DatabaseName -eq "master") {
                    continue
                }
 
                # Loop through all Automatic tuning recommendation types
                foreach ($advisor in ($advisors -notmatch "SchemaIssue")) {
                    $recs = Get-AzureRmSqlDatabaseRecommendedAction -ResourceGroupName $ResourceGroupName -ServerName $ServerName  -DatabaseName $DatabaseName -AdvisorName $advisor
                    foreach ($r in $recs) {
                        if ($r.State.CurrentValue -eq "Active") {
                            $object = New-Object -TypeName PSObject
                            $object | Add-Member -Name 'SubscriptionId' -MemberType Noteproperty -Value $subscriptionId
                            $object | Add-Member -Name 'ResourceGroupName' -MemberType Noteproperty -Value $r.ResourceGroupName
                            $object | Add-Member -Name 'ServerName' -MemberType Noteproperty -Value $r.ServerName
                            $object | Add-Member -Name 'DatabaseName' -MemberType Noteproperty -Value $r.DatabaseName
                            $object | Add-Member -Name 'Advisor' -MemberType Noteproperty -Value $advisor
                            $object | Add-Member -Name 'Script' -MemberType Noteproperty -Value $r.ImplementationDetails.Script
                            $results += $object
                        }
                    }
                }
            }
        }
    }
    Return $results
}
 
$AzurePasswordSecure = ConvertTo-SecureString "$($YOUR_AZURE_PASSWORD)" -AsPlainText -Force
$AzureCredentials = New-Object System.Management.Automation.PSCredential ("$YOUR_AZURE_USER", $AzurePasswordSecure)
Connect-AzureRmAccount -Credential $AzureCredentials | Out-Null
Select-AzureRmSubscription -Subscription $SubscriptionId | Out-Null
 
$Recommendations = Get-SQLServerRecommendations
$table = $Recommendations | Sort-Object DatabaseName,Advisor | Format-Table Databasename,Advisor,Script -AutoSize -Wrap
Write-Output $table
 
$head = "<style>
td {background-color:lightgrey;}
table {width:100%;}
th {font-size:14pt;background-color:lightblue;}
</style>
<title>SQL Server performance recommendations</title>"
 
[string]$html = $Recommendations | ConvertTo-Html -Property Databasename,Advisor,Script -Body "<h1>Azure SQL Server automatic tuning recommendations for $stage</h1>Auto-generated by PUT_SOMETHING_HERE<br><br>" -Head $head
 
Send-MailMessage -Body $html -SmtpServer YOUR.SMTPSERVER.COM -From sender@domain.com -To recipient@domain.com -Subject "MS SQL Recommendations - $(Get-Date -Format "yyyy-dd-MM HH:mm:ss")" -BodyAsHtml

Dieses Script wiederum kann man dann z.B. per Jenkins regelmäßig auslösen. Oder alternativ ein Azure Automation Runbook dafür anlegen… Viel Spaß beim Ausprobieren!

Die Mails sehen dann in etwa so aus:

Schreibe einen Kommentar...

Azure / PowerShell – Die App Settings mehrerer / aller Web Apps exportieren

Jüngst wollte ich mir den Überblick über alle App Settings der vielen Web Apps, die wir einsetzen, und deren Werten verschaffen und dabei auch schauen, ob die Settings in allen Entwicklungs-Stages gleich bzw. analog passend sind. Dazu habe ich ein PowerShell Skript geschrieben, was alle Web Apps in allen aufgeführten Ressource Groups prüft und deren App Settings in ein gemeinsames CSV File exportiert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Adjust theese as needed
 
# Change this to the subscription you want to query
$SubscriptionId = "1234567-890123-132312312"
 
# Name the RG's here, that you want to check
[string[]]$ResourceGroups = "RG-A","RG-B","RG-C"
 
### no changes needed below ###
 
Connect-AzureRmAccount -Subscription $SubscriptionId
Set-AzureRmContext -SubscriptionId $SubscriptionId
 
$AllSettings = @()
[string[]]$AllURLs = $null
 
# Iterate over all RGs
Foreach($RG in $ResourceGroups)
{
    Write-Host "$RG..."
    # Get all WebApps in this RG
    $AllWebAppsInRG = Get-AzureRmWebApp -ResourceGroupName $RG
    Foreach($WebApp in ($AllWebAppsInRG))
    {
        Write-Host "$($WebApp.SiteName)..."
        $webAppObject = Get-AzureRmWebApp -ResourceGroupName $RG -Name $($WebApp.SiteName)
        $AppSettings = $webAppObject.SiteConfig.AppSettings
        $AllURLs += $WebApp.DefaultHostName
 
        ForEach($Setting in $AppSettings)
        {
            Write-Host "$($Setting.Name)"
            $SettingObject = New-Object PSCustomObject
            $SettingObject | Add-Member -Type NoteProperty -Name "Ressource Group" -Value $RG
            $SettingObject | Add-Member -Type NoteProperty -Name "WebApp Name" -Value $($WebApp.SiteName)
            $SettingObject | Add-Member -Type NoteProperty -Name "WebApp URL" -Value $($WebApp.DefaultHostName)
            $SettingObject | Add-Member -Type NoteProperty -Name "Setting Name" -Value $($Setting.Name)
            $SettingObject | Add-Member -Type NoteProperty -Name "Setting Value" -Value $($Setting.Value)
            $AllSettings += $SettingObject
        }
 
    }
 
}
 
$AllSettings | ConvertTo-Csv -Delimiter ";" -NoTypeInformation | Out-File "AllAppSettings.csv"

 

Danach sind die Settings alle in der Datei AllAppSettings im aktuellen Verzeichnis, und zwar so, dass man die Datei direkt in Excel öffnen kann. Viel Spaß beim Ausprobieren!

Schreibe einen Kommentar...

Azure / PowerShell – HttpsOnly für alle Web Apps aktivieren

In Azure stellt jeder App Service Plan ab B1 (d.h., alle außer F1 “Free” und D1 “Shared”) SSL entweder mit einem von Azure generierten oder einem eigenen Zertifikat zur Verfügung:

image

Allerdings lassen die App Services auch weiterhin HTTP ohne SSL zu, es sei denn, man aktiviert die Option “HTTPS Only”:

image

Diese Option kann man natürlich auch per PowerShell und damit ganz bequem gleich für eine größere Menge App Services setzen. Dazu habe ich dieses Skript geschrieben:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Adjust theese as needed
$SubscriptionId = "9feacb87-1fe6-447e-a0f4-4ae1ba2496e3"
[string[]]$ResourceGroups = "RG-A","RG-B","RG-C"
 
### no changes needed below ###
 
Connect-AzureRmAccount -Subscription $SubscriptionId
Set-AzureRmContext -SubscriptionId $SubscriptionId
 
# Iterate over all RGs
Foreach($RG in $ResourceGroups)
{
    Write-Host "$RG..."
    # Get all WebApps in this RG
    $AllWebAppsInRG = Get-AzureRmWebApp -ResourceGroupName $RG
    Foreach($WebApp in $AllWebAppsInRG)
    {
        Write-Host "$($WebApp.Name)..."
        # State before setting it:
        (Get-AzureRmWebApp -ResourceGroupName $RG -Name $($WebApp.Name)).HttpsOnly
        # Enabling HttpsOnly
        Set-AzureRmWebApp -ResourceGroupName $RG -Name $($WebApp.Name) -HttpsOnly $true
    }
}

 

Viel Spaß beim Ausprobieren!

Schreibe einen Kommentar...

Azure / PowerShell – App Settings von einer Web App zur anderen kopieren

Insbesondere, wenn man viele App Settings (Umgebungsvariablen für eine Web App) in Azure verwendet und die Web App ein zweites Mal benötigt, z.B. um eine Test- oder Entwicklungs-Stage abzubilden, kann es sehr mühselig sein, die Settings zu übertragen. Hier bietet es sich an, diese per PowerShell zu kopieren.  Voraussetzung dazu ist nur das Azure PowerShell RM Modul, welches man auf diesem Weg installieren kann:

Install-Module -Name AzureRM -AllowClobber

Dabei muss ggf. ein Sicherheitshinweis bestätigt werden. Wer das Modul schon installiert hat, muss natürlich nichts tun.

Zum Kopieren der Settings kann dann dieses Skript verwendet werden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Adjust theese as needed
 
$SubscriptionId = "123456-7890-1234-12132"
 
$ResourceGroupSource = "RG-Source"
$ResourceGroupTarget = "RG-Target"
 
$WebAppSource = "WebApp-Source"
$WebAppTarget = "WebApp-Target"
 
### no changes needed below ###
 
Connect-AzureRmAccount -Subscription $SubscriptionId -Scope Process
Set-AzureRmContext -SubscriptionId $SubscriptionId
 
$webAppSource = Get-AzureRmWebApp -ResourceGroupName $ResourceGroupSource -Name $WebAppSource 
 
# Get reference to the source app settings
$AppSettingsSource = $WebAppSource.SiteConfig.AppSettings
 
# Create empty Hash table variable for App Settings
$AppSettingsTarget = @{}
 
# Copy over all existing App Settings to the Hash table
ForEach ($AppSettingSource in $AppSettingsSource) {
    $AppSettingsTarget[$AppSettingSource.Name] = $AppSettingSource.Value
}
 
# Save strings to target Web App
Set-AzureRmWebApp -ResourceGroupName $ResourceGroupTarget -Name $WebAppTarget -AppSettings $AppSettingsTarget

Viel Spaß beim Ausprobieren – mir spart das immer wieder viel Arbeit!

Schreibe einen Kommentar...

PowerShell – Where-Object – Wildcards und -in kombinieren

Manchmal hat man den Bedarf, eine Objektliste gegen eine Liste von Ausdrücken zu filtern und dabei Wildcards zu verwenden, z.B. in dieser Form

[Alle Tiere – „Eisvogel“,“Hauspferd“,“Lisztaffe“,“Bergziege“] | Where-Object Name -in „*affe“,“*vogel“

Where-Object kann dabei ENTWEDER mit -in eine Liste verwenden ODER mit * Wildcards verwenden – beides zusammen geht (erstmal) nicht. Aber es gibt eine Lösung: Man muss die Liste der Wildcards zuerst expandieren, um die realen Werte dort drauf stehen zu haben. Das kann man z.B. so machen (am Beispiel von Verteilern):

1
2
3
4
5
6
$items = Get-DistributionGroup # Die Objektliste
$search = @("*Finanzen*","*Einkauf*","*IT*") # Die Wildcard-Ausdrücke, nach denen gesucht wird
$result = $search |
    Select-Object @{ Name="ExpandedItem"; Expression={ $items -Like $_ }} |
    Select-Object -ExpandProperty ExpandedItem -Unique
$result

ich hoffe, das hilft dem Einen oder Anderen…

Schreibe einen Kommentar...