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

Haikos Blog Posts

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 – Portal ermöglicht jetzt auch DENY für Berechtigungen / IAM / RBAC

Bis gestern kannte das Azure Portal nur die Möglichkeit, Berechtigungen zu gewähren (ALLOW). Seit heute kann man nun (neben der neuen Möglichkeit, sich die effektiven Berechtigungen eines Users anzeigen zu lassen, die sich aus Vererbung und co. ergeben) auch Berechtigungen explizit entziehen (DENY). Dadurch wird es jetzt viel einfacher möglich, einem Account z.B. Rechte auf „alles“ außer einem bestimmten Bereich zu geben. Bisher war es nicht möglich, jemandem z.B. zum Contributor auf einer Subscription zu machen, aber zu verhindern, dass er in eine bestimmte Ressource Group schauen kann. Dies ist nun möglich:

 

 

 

 

 

 

Immer wieder schön, wenn man über Nacht neue Features bekommt und diese dann entdeckt 🙂 Viel Spaß beim Ausprobieren…

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

Azure / PowerShell – Das OS Image eines VMSS ändern

Da es hierzu keine gute Dokumentation im Netz gibt und ich heute dieses Problem hatte schreibe ich diesen kurzen Blog-Artikel.

Das Problem:

In verschiedenen bestehenden Virtual Maschine Scale Sets (VMSS) in Azure wird ein angepasstes Windows Server 2016 Image verwendet. Dieses Image sollte nun aktualisiert und weiter angepasst werden. Dazu habe ich aus dem Image eine VM erstellt, diese entsprechend hergerichtet und dann mit sysprep generalisiert. Danach habe ich mit Azure ein Image davon aufzeichnen lassen. Nun möchte ich dieses Image in den bestehenden VMSS einsetzen. Über das Portal geht das nicht und die PowerShell-Befehle sind nur unzureichend beschrieben.

Die Lösung:

Dieses kleine PowerShell-Skript legt das Basis-OS-Image für ein definiertes VMSS neu fest und löst danach das Re-Image der Instanzen aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Parameters
[string]$NewVmssBaseImageName = "VMSS-Base-Image-Name"
[string]$SubscriptionId = "123456789"
[string]$VMSSRessourceGroup = "RessourceGroupName"
[string]$VMSSName = "VMSSName"
 
# Connect to Azure
Connect-AzureRmAccount -Subscription $SubscriptionId
Set-AzureRmContext -SubscriptionId $SubscriptionId
 
# Get Image ID
$ImageId = (Get-AzureRmImage | Where Name -eq $NewVmssBaseImageName).Id
# Get VMSS
$VMSS = Get-AzureRmVmss -ResourceGroupName $VMSSRessourceGroup -VMScaleSetName $VMSSName
# Set new OS Image
$VMSS | Update-AzureRmVmss -ImageReferenceId $ImageId
# Upgrade VM instances to latest model
Update-AzureRmVmssInstance -InstanceId (Get-AzureRmVmssVM -VMScaleSetName $VMSS.Name -ResourceGroupName $VMSS.ResourceGroupName).InstanceId -ResourceGroupName $VMSSRessourceGroup -VMScaleSetName $VMSSName
Schreibe einen Kommentar...

Office 365 / Azure AD – Fehler bei der Synchronisierung

Ich hatte vor Kurzem eine sehr interessante Konstellation: Ich hatte einen bereits im lokalen AD deaktivierten Benutzer wieder aktiviert, da der betroffene Mitarbeiter neuerlich für uns tätig werden sollte. Danach kam es zu Fehlern bei der Synchronisierung zwischen unserem lokalen Active Directory und dem AzureAD, das wir als Grundlage für Office 365 verwenden:

Screenshot (183)

Auch der Versuch, das betroffene Konto in Office 365 aus den gelöschten Objekten wiederherzustellen, schlug fehl:

Screenshot (181)

Screenshot (180)

Dadurch hat sich aber der Grund für das merkwürdige Verhalten offenbart: Das Konto war exakt einen Monat vorher deaktiviert bzw. gelöscht worden – und existierte dadurch scheinbar nur noch halb.

Um das Problem zu lösen, habe ich das betreffende Konto in Office 365 per PowerShell dauerhaft gelöscht:

1
2
3
4
5
$UserCredential= Get-Credential -UserName "h.hertes@DOMAIN.COM" -Message "Bitte das Passwort für O365 eingeben!"
$ExchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $ExchangeSession -AllowClobber
Connect-MsolService -Credential $UserCredential
Get-MsolUser -ReturnDeletedUsers | Where UserPrincipalName -eq "USER@DOMAIN.COM" | Remove-MsolUser -RemoveFromRecycleBin
Schreibe einen Kommentar...

Zum dritten Mal in Folge Microsoft MVP

Es ist geschafft – zum dritten Mal in Folge hat mich Microsoft zum MVP ernannt. Dafür möchte ich Danke sagen – danke an alle, die meinen Blog hier lesen, meine Youtube Videos schauen oder an meinen Community-Treffen teilnehmen. Ihr seid es, die diesen Award mit Leben füllen und ihn möglich machen.

mvp

Gleichzeitig beglückwünsche ich alle anderen MVPs, die es geschafft haben, Ihren Aware zu erneuern oder neu ins Programm aufgenommen worden! Well deserved..

Schreibe einen Kommentar...

PowerShell – Windows Client oder Windows Server als NTP Server benutzen

Sicherlich ist den Meisten bekannt, dass Windows seit vielen Generationen out-of-the-box als NTP-Client genutzt werden kann – also die Uhrzeit von einem NTP-Server beziehen kann. Aber dass sowohl Windows Server (seit WS2003) als auch Windows Client (seit Win XP) auch mit Bordmitteln als NTP-Server genutzt werden können, dürfte weitgehend unbekannt sein. Das Ganze lässt sich in einigen wenigen Schritten erreichen:

  • Windows Zeitdienst W32Time auf automatischen Start setzen
  • W32Time als NTP-Server konfigurieren (Registrierungsschlüssel)
  • W32Time Dienst neustarten
  • Firewall auf udp/123 für Verbindungen von außen öffnen

Natürlich kann man das sehr effizient mittels PowerShell erledigen. Dazu habe ich ein einfaches Script geschrieben:

# This script makes a Windows 10 PC acting as a NTP server 
 
#Enable autostart for W32Time Service
Set-Service -Name W32Time -StartupType Automatic
 
# Configure W32Time Service to act as a NTP server
Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer -Name Enabled -Value 1
 
# Update W32Time service
w32tm.exe /config /update
 
# Restart W32Time service
Restart-Service -Name W32Time
 
# Check configuration - VMICTimeProvider / Enabled should be "1" now
w32tm.exe /query /configuration
 
# Create an inbound rule for the Windows Firewall
New-NetFirewallRule -DisplayName "Allow NTP UDP/123 Incomming" -Profile Any -Action Allow -Direction Inbound -LocalPort 123 -Protocol udp -Enabled true
1 Kommentar

Office 365 – Verteiler eines Benutzers mittels PowerShell herausfinden

Immer mal wieder stell sich uns die Frage, in welchen Verteilern ein bestimmter Benutzer Mitglied ist. Natürlich kann man sich im Office365 Admin-Portal das Postfach ansehen, dort wird einem aufgelistet, wo der User Mitglied ist – allerdings werden hier nur die direkten Mitgliedschaften aufgelistet. In der Regel sind Verteiler / Distribution Lists aber in einander verschachtelt, um z.B. Team- / Gruppen- /Abteilungsstrukturen abzubilden. Um nun nicht von Hand alle Verteiler auf deren Mitgliedschaft in weiter oben liegenden Verteilern prüfen zu müssen, habe ich ein PowerShell-Skript geschrieben.

Dieses ermittelt zunächst, in welchen Verteilern der Benutzer unmittelbar enthalten ist und prüft dann diese Verteiler auf “Eltern”, also weiter oben stehende Verteiler, die den betreffenden Verteiler (und damit dann eben indirekt den Bnutzer) enthalten.

Hier ist das Skript:

[string[]]$global:AllreadyChecked = $null
 
function Get-DistributionGroupAllParents
{
    param ([string]$GroupName)
 
    [string[]]$Parents = $null
 
    ForEach ($Group in Get-DistributionGroup) 
    {
       If((Get-DistributionGroupMember $Group.Name | Where RecipientType -NE "UserMailbox").Name -contains $Groupname)
       {
          # Make sure, we are only checking every DGs parents once as many DG tree leafs may lead to the same parent DG
          If($global:AllreadyChecked -notcontains ($Group.Name))
          {
                $Parents += $Group.Name
                Get-DistributionGroupAllParents -GroupName $Group.Name
                $global:AllreadyChecked += $Group.Name
          }
       } 
    }
    Return $Parents
}
 
# Connect to Office 365
If((Get-PSSession | Where Computername –like "*ps.outlook.com*" | Where State –eq "Opened" | Measure-Object).Count -lt 1)
{
    $Credentials = Get-Credential –UserName "USER@DOMAIN.COM" -Message "Please enter your Office 365 / Azure AD password!"
    $ExchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $Credentials -Authentication Basic -AllowRedirection -WarningAction SilentlyContinue
    Import-PSSession $ExchangeSession -AllowClobber -DisableNameChecking >> $null
}
elseif((Get-PSSession | Where Computername -like "*ps.outlook.com*" | Where Availability -eq "Available" | Where State -ne "Opened" | Measure-Object).Count -ge 1)
{
    Import-PSSession -Session (Get-PSSession | Where Computername -like "*ps.outlook.com*" | Where Availability -eq "Available" | Select -Last 1)
}
 
# Get all DGs a user is member of
$User = Read-Host -Prompt "Enter User to check!" 
$Recipient = (Get-Recipient -RecipientType UserMailbox -Identity $User).Name
Write-Host "Script started discovery - this could take a while" -ForegroundColor Red
 
[string[]]$AllParents = $null
ForEach ($Group in Get-DistributionGroup) 
{
   If((Get-DistributionGroupMember $Group.Name).Name -contains $Recipient)  # Find all Groups the User is immediate member of:
   {
      $AllParents += $Group.Name
      Write-Host -ForegroundColor Green "$($Group.Name) ($($Group.PrimarySmtpAddress))"
      $AllParents += (Get-DistributionGroupAllParents -Group $Group.Name)
   } 
}
 
Write-Host "User is member of these groups (for some of them, he may be member through nested groups!):"
$AllParents.Where({ $_ -ne "" }) | select -uniq | sort | Get-DistributionGroup | ft DisplayName,Name,PrimarySmtpAddress -AutoSize

 

Viel Spaß damit!

Schreibe einen Kommentar...