ChromeOS – eine Alternative für ältere Geräte?

Ein Teil meiner privaten Computer erfüllen die Anforderungen von Windows 11 nicht mehr. Um nicht für jedes Familienmitglied einen neuen Rechner anschaffen zu müssen, schaue ich mir aktuell mögliche Alternativen an. Eine erste Alternative ist das mit den Chromebooks ausgelieferte ChromeOS – genauer genommen das ChromeOS Flex, welches frei für viele Geräte verfügbar ist.

Weiterlesen

Projekt Backups in DaVinci Resolve

Seit längerem arbeite ich laienhaft mit DaVinci Resolve als Videoschnitt Software. Als ich kürzlich Probleme damit hatte, bemerkte ich, dass eine Sicherung der lokalen Projektdatenbank gar nicht so intuitiv ist.

Backup mit GUI

Mit ein wenig Recherche fand ich dann aber einen Artikel, welcher aufs Handbuch referenzierte (jaja, wer lesen kann ist klar im Vorteil). Kurz zusammengefasst, gibt es im GUI folgende Möglichkeit:

Man wählt im Projektmanager die lokale Projektdatenbank und klickt auf das kleine ‚i‘ rechts davon. Im nächsten Menü hat man die Option eines Backups:

Im nächsten Fenster wählt man einfach den gewünschten Speicherort und die Datenbank ist gesichert:

Die Sicherung ist nichts anderes als ein ZIP Archiv. Wenn man dieses z.B. in 7-Zip wieder öffnet, erkennt man die Ordnerstruktur aus dem %AppData% Ordner:

Backup mit Script

Im Rahmen der oben genannten Fehlersuche bin ich noch auf mehrere Ordner gestossen, welche gesichert werden könnten. Ich habe mir deshalb kurzum ein kleines Backup Script geschrieben:

REM ############################################
REM
REM		USER VARIABLES
REM
REM ############################################

SET DRBackupPath=S:\PITBackupDrive\DavinciResolveBackup

In der Variable DRBackupPath kann ein individueller Sicherungsordner definiert werden.

REM Create time stamp variable for backup files
SET Timestamp=%date:~6,8%%date:~3,2%%date:~0,2%-%time:~0,2%%time:~3,2%

REM Define several paths
SET ZipPath=%ProgramFiles%\7-Zip
SET ZipExe=%ZipPath%\7z.exe
SET DRProgDataPath=%ProgramData%\Blackmagic Design\DaVinci Resolve
SET DRAppDataPath=%AppData%\Blackmagic Design\DaVinci Resolve
SET DRLibraryPath=%DRAppDataPath%\Support\Resolve Project Library

Die verschiedenen Variablen definieren u.a. einen Zeitstempel (Timestamp), den Pfad zu 7-Zip und die verschiedenen Ordnerpfade von Davinci Resolve.

REM Backup Resolve Project folder
"%ZipExe%" a -tzip "%DRBackupPath%\Resolve Projects-%Timestamp%.zip" "%DRLibraryPath%\Resolve Projects"

PAUSE

REM Backup Resolve AppData folder
"%ZipExe%" a -tzip "%DRBackupPath%\DaVinciResolveAppData-%Timestamp%.zip" "%DRAppDataPath%"

PAUSE

REM Backup Resolve ProgramData folder
"%ZipExe%" a -tzip "%DRBackupPath%\DaVinciResolveProgramData-%Timestamp%.zip" "%DRProgDataPath%"

PAUSE

Schlussendlich folgen die drei Sicherungsblöcke. Die Pausen können natürlich auch entfernt werden. Ich habe mir diese zur optischen Prüfung eingebaut, da ich das Script aktuell nur manuell ausführen werde.

Viel Spass beim Nachbauen :-)


Da der Upload von TXT Dateien scheinbar ohne grössere WP Modifikation nicht mehr funktioniert, hier noch das komplette Script:

@ECHO OFF

REM ****************************************
REM    	DavinciResolveBackup.bat
REM		
REM		Author: Urs Heeb
REM
REM		Changelog:
REM			20250529 - Script created
REM
REM		Description
REM			Script creates a backup of following
REM			Davinci Resolve folders:
REM				%ProgramData%\Blackmagic Design\DaVinci Resolve
REM				%AppData%\Blackmagic Design\DaVinci Resolve
REM				%AppData%\Blackmagic Design\DaVinci Resolve\Support\Resolve Project Library
REM			The destination path can be defined
REM			user variables
REM
REM		PRE-REQ:
REM			Installed 7-Zip (path defined in script)
REM
REM ****************************************

CLS

REM ############################################
REM
REM		USER VARIABLES
REM
REM ############################################

SET DRBackupPath=S:\PITBackupDrive\DavinciResolveBackup


REM Create time stamp variable for backup files
SET Timestamp=%date:~6,8%%date:~3,2%%date:~0,2%-%time:~0,2%%time:~3,2%

REM Define several paths
SET ZipPath=%ProgramFiles%\7-Zip
SET ZipExe=%ZipPath%\7z.exe
SET DRProgDataPath=%ProgramData%\Blackmagic Design\DaVinci Resolve
SET DRAppDataPath=%AppData%\Blackmagic Design\DaVinci Resolve
SET DRLibraryPath=%DRAppDataPath%\Support\Resolve Project Library

REM Backup Resolve Project folder
"%ZipExe%" a -tzip "%DRBackupPath%\Resolve Projects-%Timestamp%.zip" "%DRLibraryPath%\Resolve Projects"

PAUSE

REM Backup Resolve AppData folder
"%ZipExe%" a -tzip "%DRBackupPath%\DaVinciResolveAppData-%Timestamp%.zip" "%DRAppDataPath%"

PAUSE

REM Backup Resolve ProgramData folder
"%ZipExe%" a -tzip "%DRBackupPath%\DaVinciResolveProgramData-%Timestamp%.zip" "%DRProgDataPath%"

PAUSE

Windows Loginscripte & Co.

Ich denke jeder Windows Admin kennt es. Die Benutzer möchten ihre Laufwerke gemappt und am liebsten auch gleich die Drucker verbunden haben. Ich möchte an dieser Stelle meine Sicht auf verschiedene Mechanismen werfen immer auch mit dem Fokus eines Citrix Admins.

Weiterlesen

WSUS – Konfiguration für MDT Umgebung

Ich habe mich in letzter Zeit mit MDT (Microsoft Deployment Toolkit) beschäftigt und mir da auch Gedanken zum WSUS gemacht. In meinem Umfeld wird MDT vor allem für die Installation/Wartung von Citrix Workern (Terminalserver und VDI) genutzt. Diese sind sehr oft auch aus dem Internet zugänglich und sollten daher auch auf einem zeitnahen Patch-Stand sein. Nur wie löst man dies am einfachsten?

Weiterlesen

WSUS – Automatisiertes Update Management

So cool WSUS (Windows Server Update Service) auch ist, so hat er sich leider seit dem Erscheinen mit Windows Server 2003 nicht wirklich weiter entwickelt. Im Bereich der Update-Pflege (Freigabe, Ablehnung, etc.) ist mir der WSUS noch immer nicht flexibel genug. Glücklicherweise kann man hier aber mit PowerShell Abhilfe schaffen und dafür habe ich in meinem Lab mehrere Scripte integriert.

Weiterlesen

WSUS – Clients zum Update Report zwingen

Wahrscheinlich kennt jeder Administrator, welcher auch WSUS im Einsatz hat die Thematik, dass die Clients mit den Reports auf sich warten lassen.

Nach ein wenig Recherche bin ich bei div. Blogs auf Scripts gestossen, welche den WU Client dazu bringen, dem WSUS sofort einen entsprechenden Report zu senden. Genanntes Script habe ich für mich so modifiziert, dass es nicht vom WSUS aus mittels „Invoke“ sondern direkt auf dem Client (Desktop OS wie auch Server OS) ausgeführt wird.

Voraussetzung ist natürlich, dass die entsprechenden GPO Einstellungen für die WSUS Kommunikation eingerichtet und funktionell sind. ;-)

Das unten verfügbare Script kann dann mittels geplantem Task als „SYSTEM“ regelmässig ausgeführt werden, damit der WSUS auch stets den aktuellen Patch-Stand seiner Zielcomputer weiss.

Parameter für den geplanten Task:
– Programm: PowerShell.exe
– Parameter: -ExecutionPolicy Bypass <Pfad zum Script>

Viel Spass beim Nachbauen. :-)

Installierte .NET Framework Version prüfen

Disclaimer: Bei diesem Artikel handelt es sich definitiv nicht um eine eigene „Entwicklung“.

Nicht selten setzen Programme eine bestimmte .NET Version voraus. Windows bietet leider keine einfache Möglichkeit um diese herauszufinden. Einzig der definierte Registry Wert gibt uns einen Aufschluss auf die interne Build-Nummer, aber nicht auf die konkrete Version.

Ich bin bei Microsoft selbst auf ein Skript gestossen, welches ich seither auf mit der entsprechenden Build Tabelle nachgeführt habe:

    $dotNet4Builds = @{
        '30319'  = @{ Version = [System.Version]'4.0'                                                     }
        '378389' = @{ Version = [System.Version]'4.5'                                                     }
        '378675' = @{ Version = [System.Version]'4.5.1'   ; Comment = '(8.1/2012R2)'                      }
        '378758' = @{ Version = [System.Version]'4.5.1'   ; Comment = '(8/7 SP1/Vista SP2)'               }
        '379893' = @{ Version = [System.Version]'4.5.2'   ; Comment = '(all Windows OS)'                  }
        '380042' = @{ Version = [System.Version]'4.5'     ; Comment = 'and later with KB3168275 rollup'   }
        '393295' = @{ Version = [System.Version]'4.6'     ; Comment = '(Windows 10)'                      }
        '393297' = @{ Version = [System.Version]'4.6'     ; Comment = '(NON Windows 10)'                  }
        '394254' = @{ Version = [System.Version]'4.6.1'   ; Comment = '(Windows 10)'                      }
        '394271' = @{ Version = [System.Version]'4.6.1'   ; Comment = '(NON Windows 10)'                  }
        '394802' = @{ Version = [System.Version]'4.6.2'   ; Comment = '(Windows 10 Anniversary Update)'   }
        '394806' = @{ Version = [System.Version]'4.6.2'   ; Comment = '(NON Windows 10)'                  }
        '460798' = @{ Version = [System.Version]'4.7'     ; Comment = '(Windows 10 Creators Update)'      }
        '460805' = @{ Version = [System.Version]'4.7'     ; Comment = '(NON Windows 10)'                  }
        '461308' = @{ Version = [System.Version]'4.7.1'   ; Comment = '(Windows 10 Fall Creators Update)' }
        '461310' = @{ Version = [System.Version]'4.7.1'   ; Comment = '(NON Windows 10)'                  }
        '461808' = @{ Version = [System.Version]'4.7.2'   ; Comment = '(Windows 10 / 1803)'               }
        '461814' = @{ Version = [System.Version]'4.7.2'   ; Comment = '(other OS than Windows 10 1803)'   }
        '528040' = @{ Version = [System.Version]'4.8'     ; Comment = '(Windows 10 / 1905 & 1911)'        }
        '528372' = @{ Version = [System.Version]'4.8'     ; Comment = '(Windows 10 / 2005 & 2010 & 2105)' }
        '528449' = @{ Version = [System.Version]'4.8'     ; Comment = '(Windows 11 / Server 2022)'        }
        '528049' = @{ Version = [System.Version]'4.8'     ; Comment = '(other OS or Windows 10 builds)'   }
        '533320' = @{ Version = [System.Version]'4.8.1'   ; Comment = '(Windows 11 / 2022)'               }
        '533325' = @{ Version = [System.Version]'4.8.1'   ; Comment = '(other OS or Windows 10 builds)'   }
    }

Die Ausführung sieht dann wie folgt aus:

Ich denke mit diesen Informationen kann man mehr anfangen als den reinen Build Nummern. ;-)

Viel Spass beim Nachbauen :-)

Installierte Windows Sprachpakete prüfen

In unseren Terminalservern und VDIs wollten wir mittels Scripten die Benutzer die OS Sprache ändern lassen. Die Aufbereitung des Images mittels Citrix AppLayering hatte so seine Tücken und für eine einfache Prüfung, ob und welche Sprachen zur Auswahl stehen, habe ich folgendes kleines Skript erstellt.

Es liest über WMI die OS Parameter aus und listet diese im Anschluss in der PowerShell Ausgabe:

$OSInfo = Get-WmiObject -Class Win32_OperatingSystem
$LanguagePacks = $OSInfo.MUILanguages
$LanguagePacks

Die Ausgabe sieht dann wie folgt aus:

Viel Spass beim Nachbauen :-)

Citrix PVS Store – Replikationsskript V2

Im kürzlich erschienene Artikel habe ich die erste Fassung des Replikationsskriptes vorgestellt. In der aktuell überarbeiteten Version habe ich einerseits die Ausgaben ein wenig „verschönert“ und vor allem werden die Stores nun direkt aus dem PVS ausgelesen.

Voraussetzungen dafür sind:

  • Citrix PVS PowerShell Module an den Standardpfaden (kann in einer Variable angepasst werden)
  • Der ausführende Benutzer muss entsprechende PVS Rechte besitzen
  • Die Stores sollten verständliche Namen (Auswahl) und Beschreibungen (Hilfetexte bei Auswahl) vorweisen.

Zuerst wird nun also der Store Array dynamisch aus dem PVS ausgelesen. Voraussetzung dazu ist ein Laden des entsprechenden PVS PowerShell Moduls:

# Script variables
$PVSModulePath = "C:\Program Files\Citrix\Provisioning Services Console\Citrix.PVS.SnapIn.dll"

# Load PVS PowerShell module
Import-Module $PVSModulePath
# Get PVS vDisk stores from PVS configuration
# Create an array for later use
$Stores = Get-PvsStore

$StoreArray = $null
$StoreArray = @()
$StoreID = 0
ForEach ($Store in $Stores){
    $StoreID = $StoreID +1
    $SplitChar = $Store.Path.IndexOf(":")
    $StoreDisk = $Store.Path.Substring(0,$SplitChar)
    $StorePath = $Store.Path.Substring($SplitChar+1)
    $StoreName = $Store.StoreName
    $StoreArray += [pscustomobject]@{StoreID=$StoreID;Store=$StoreName;StoreDisk=$StoreDisk;StorePath=$StorePath;StoreDescription=$Store.Description}
}

Nun wird aus dem Array eine entsprechende PowerShell Auswahl generiert, wobei hier aktuell auch eine Limite von maximal 5 Stores eingebaut ist:

# Prompt for Store choice
$StoreTitle = "PVS vDisk stores"
$StoreMessage = "Chose the store to replicate:"
$CancelAll = New-Object System.Management.Automation.Host.ChoiceDescription "&Cancel", "Skip this operation and all subsequent operations."

# Generate choice output of each vDisk store to replicate
$StoreOptionCount = 0
ForEach ($Store2 in $StoreArray) {
    $StoreOptionCount = $StoreOptionCount + 1
    $ChoiceID = $Store2.StoreID
    $ChoiceStore = $Store2.Store
    $ChoiceHelp = $Store2.StoreDescription
    $ChoiceCmd = New-Object System.Management.Automation.Host.ChoiceDescription "&$ChoiceID $ChoiceStore", $ChoiceHelp
    New-Variable "StoreOption$ChoiceID" $ChoiceCmd
}

# Generate $StoreOptions variable for final choice output depending on the amount of options
Switch ($StoreOptionCount) {
    0 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll)}
    1 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1)}
    2 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1, $StoreOption2)}
    3 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1, $StoreOption2, $StoreOption3)}
    4 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1, $StoreOption2, $StoreOption3, $StoreOption4)}
    5 {$StoreOptions = [System.Management.Automation.Host.ChoiceDescription[]]($CancelAll, $StoreOption1, $StoreOption2, $StoreOption3, $StoreOption4, $StoreOption5)}
}

Zu guter Letzt werden anhand der Auswahl die Variablen definiert:

# Prepare variables after the user entry
If ($Store2Replicate -eq 0) {
    # Cancel all
    return; break
}
Else {
    $IDStore = $Store2Replicate-1
    $StoreDisk = $StoreArray[$IDStore].StoreDisk
    $StorePath = $StoreArray[$IDStore].StorePath
    $LocalStore = $StoreDisk + ":" + $StorePath + "\"
    $RemoteStore = "\\" + $PVSRemote + "\" + $StoreDisk + "$" + $StorePath + "\"
    $LocalStorePath = $LocalStore + "*"
    $RemoteStorePath = $RemoteStore + "*"
}

Der restliche Teil ist soweit gleich geblieben und im ersten Artikel bereits beschrieben.

Viel Spass beim Nachbauen :-)