Allgemein
Um mit dem Microsoft Intune Scripting Framework Pakete installieren zu können, muss die Scripting Framework Engine auf dem Client installiert sein. Die Dokumentation beschreibt, wie der Rollout der SF Engine per Intune auf die Geräte durchgeführt werden kann.
Für den Rollout der Engine wird ein PowerShell-Skript verwendet, das in Intune integriert wird. PowerShell-Skripte werden vor der Ausführung von Win32-Apps ausgeführt. Dadurch wird sichergestellt, dass die SF Engine vor der ersten Installation einer Anwendung installiert ist:
- PowerShell scripts are executed before Win32 apps run. In other words, PowerShell scripts execute first. Then, Win32 apps execute.
https://docs.microsoft.com/en-us/mem/intune/apps/intune-management-extension
Das PowerShell-Skript „Install-ScriptingFrameworkEngine.ps1“ lädt die Scripting Framework Engine von einer URL herunter und führt anschliessend die Installation aus:
# Parameters
$SFExpectedVersion = [System.Version]"3.1.1.0"
$Url = "https://www.yourserver.ch/Company_Scripting_Framework_Engine.zip"
# Set Flag
$StartInstallation = $false
#region #### Helper Functions
Function Download-File {
param(
[string]$URL,
[string]$Destination
)
Write-Log "Starting download: $URL" -Severity Info
# Ensure TLS 1.2 is used for secure downloads
[Net.ServicePointManager]::SecurityProtocol = 'Tls12'
# Retrieve proxy settings
$proxyUrl = ([System.Net.WebRequest]::GetSystemWebProxy()).GetProxy("https://www.google.com").OriginalString
if ($proxyUrl -eq "https://www.google.com") {
$proxyUrl = $null
}
Write-Log "Using proxy: $proxyUrl" -Severity Info
# Remove existing file if it exists
if (Test-Path $Destination) {
Remove-Item -Path $Destination -Force -ErrorAction SilentlyContinue
}
# Download file
try {
Write-Log "Download in progress, please wait..." -Severity Info
Invoke-WebRequest -Uri $URL -OutFile $Destination -Proxy $proxyUrl -UseBasicParsing
Write-Log "Download completed: $Destination" -Severity Info
} catch {
Write-Log "Download failed: $($_.Exception.Message)" -Severity Error
return $false
}
# Unblock file after download
Unblock-File -Path $Destination -ErrorAction SilentlyContinue
return $true
}
Function Initialize-Log {
param ([string]$Filename)
$Script:Logfile = "$([System.IO.Path]::GetTempPath())\$Filename.log"
# If log file exists and is larger than 1MB, delete it
if (Test-Path $Script:Logfile) {
$LogSizeKB = (Get-Item $Script:Logfile).Length / 1KB
if ($LogSizeKB -gt 1024) {
Remove-Item -Path $Script:Logfile -Force
}
}
Write-Log "Log initialization completed." -Severity Title
}
Function Write-Log {
param (
[string]$Message,
[ValidateSet('Error', 'Info', 'Warning', 'Title')]
[string]$Severity = "Info"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logMessage = switch ($Severity) {
"Title" { "$timestamp ***** $Message " + ("*" * (120 - $Message.Length)) }
"Error" { "$timestamp ERROR: $Message" }
"Warning" { "$timestamp WARNING: $Message" }
Default { "$timestamp INFO: $Message" }
}
# Write log entry to file and console
Write-Output $logMessage | Out-File $Script:Logfile -Append -ErrorAction SilentlyContinue
Write-Host $logMessage
}
#endregion
# --- Start script execution ---
cls
# Check for Administrator Privileges
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "This action requires administrator privileges." -ForegroundColor Red
Return
}
# Check for a custom SF installation path
$SFPath = Get-ItemProperty -Path "HKLM:\SOFTWARE\Wow6432Node\ScriptingFramework\Config" -Name "Path" -ErrorAction SilentlyContinue
If ($SFPath -eq $null) {
$SFDirectory = "$($env:windir)\_ScriptingFramework\Modul"
}
Else {
$SFDirectory = (Split-Path -Path $SFPath -Parent)
}
# Check if SF Engine is already installed
If (-not (Test-Path -Path "$($SFDirectory)\Engine.exe" -ErrorAction SilentlyContinue))
{
$StartInstallation = $true
}
# License - If the license is expiring in less than 10 days, the script triggers an installation
If (Test-Path -Path "$($SFDirectory)\License.lic" -ErrorAction SilentlyContinue)
{
# Read License File
$LicenseContent = Get-Content "$($SFDirectory)\License.lic" -ErrorAction 'SilentlyContinue'
$LicenseExpireDate = $LicenseContent.Split("|")[1]
If ($LicenseExpireDate -ne "Unlimited") {
$LicenseExpireDate = [datetime]::ParseExact($LicenseExpireDate, "dd.MM.yyyy", $null)
# Check if the license is expiring soon
If ((Get-Date).AddDays(+10) -ge $LicenseExpireDate) {
# License Expired
$StartInstallation = $true
}
}
}
# Check Version
If (Test-Path -Path "$($SFDirectory)\Engine.exe" -ErrorAction SilentlyContinue) {
$FileVersion = (Get-Item -Path "$($SFDirectory)\Engine.exe").VersionInfo.FileVersion
$SFCurrentVersion = [System.Version]$FileVersion
# Compare versions
If ($SFCurrentVersion -ge $SFExpectedVersion) {
#Write-Host "Engine.exe version is up to date ($CurrentVersion ≥ $SFExpectedVersion)"
} Else {
#Write-Host "Engine.exe version is outdated ($CurrentVersion < $SFExpectedVersion). Update required."
$StartInstallation = $true
}
}
# Check for Action
If ($StartInstallation -eq $false) {
# No Action
Write-Host "Scripting Framework Engine is already installed and up to date. No update required."
Return
}
# Initialize Log
Initialize-Log -Filename "Install-ScriptingFrameworkEngine"
# Log
Write-Log "START Installation" -Severity Title
try {
# Download the file
$ZipFileName = [System.IO.Path]::GetFileName($url)
if (-not (Download-File -URL $Url -Destination "filesystem::$($env:temp)\$($ZipFileName)")) {
throw "File download failed."
}
# Extract the archive
Write-Log "Extracting archive to: $($env:temp)\SFEngine" -Severity Info
Expand-Archive -LiteralPath "$($env:temp)\$($ZipFileName)" -DestinationPath "$($env:temp)\SFEngine" -Force
# Execute setup
Write-Log "Start Scripting Framework Setup: $($env:temp)\SFEngine\Install.cmd" -Severity Info
$Process = Start-Process -FilePath "filesystem::$($env:temp)\SFEngine\Install.cmd" -WindowStyle Hidden -PassThru -Wait
Write-Log "Exit Code: $($Process.ExitCode)" -Severity Info
} catch {
Write-Log "Error: $($_.Exception.Message)" -Severity Error
Exit 1
} finally {
# Cleanup temporary files
Write-Log "Cleaning up temporary files." -Severity Info
Remove-Item -Path "$($env:temp)\SFEngine" -ErrorAction SilentlyContinue -Force -Recurse
Remove-Item -Path "$($env:temp)\$($ZipFileName)" -ErrorAction SilentlyContinue -Force
}
Write-Log "END Installation" -Severity Title
Scripting Framework Engine vorbereiten
Die Installationsdateien von dem Scripting Framework Engine Paket werden inklusive der Lizenzdatei in eine ZIP-Datei mit dem Namen „Scripting_Framework_Engine.zip“ gepackt:
Die erstellte ZIP-Datei „Scripting_Framework_Engine.zip“ wird nun auf einem Webserver bereitgestellt, der auch von extern erreichbar ist. Zum Beispiel: https://www.scriptingframework.ch/Scripting_Framework_Engine.zip.
Intune – PowerShell Script für die Engine Installation
Der PowerShell-Skript führt auf den Intune-Clients die Installation der SF Engine durch. Die Funktionsweise ist dabei wie folgt:
- Herunterladen der erstellten ZIP-Datei, zum Beispiel von https://www.scriptingframework.ch/Scripting_Framework_Engine.zip
- Extrahieren der Zip-Datei
- Ausführen der Install.cmd, die in der ZIP-Datei enthalten ist
- Bereinigung
Alle Aktionen werden in einem Log protokolliert: C:\Windows\Temp\Install-ScriptingFrameworkEngine.log.
Das PowerShell-Skript „Install-ScriptingFrameworkEngine.ps1“ für die Installation der Engine auf den Geräten wird nun im Intune-Portal registriert:
Add –> Windows 10 and later
Zum Beispiel den Namen „Installation – Scripting Framework Engine“ vergeben und dann auf „Next“
Wählen Sie das Skript „Install-ScriptingFrameworkEngine.ps1“ aus (der Code ist oben im Blog) –> Next
Die Zuweisung auf alle Geräte hinzufügen –> Next
Hinzufügen:
Das Script wurde erfolgreich im Intune angelegt:
Auf den Intune-Geräten wird nun automatisch die SF Engine installiert und sie sind somit bereit für die Verteilung von Software.