General
In order to install packages using the Microsoft Intune Scripting Framework, the Scripting Framework Engine must be installed on the client. The documentation describes how to perform the rollout of the SF Engine on the devices via Intune.
A PowerShell script is used for the rollout of the Engine, which is integrated into Intune. PowerShell scripts are executed before Win32 apps, ensuring that the SF Engine is installed before the first application installation:
- 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
The PowerShell script "Install-ScriptingFrameworkEngine.ps1" downloads the Scripting Framework Engine from a URL and then proceeds with the installation:
# 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
Preparing Scripting Framework Engine
The installation files for the Scripting Framework Engine package, including the license file, are packed into a ZIP file named "Scripting_Framework_Engine.zip":
The created ZIP file "Scripting_Framework_Engine.zip" is now made available on a web server that is also accessible externally, for example: https://www.scriptingframework.ch/Scripting_Framework_Engine.zip.
Intune - PowerShell script for Engine installation
The PowerShell script performs the installation of the SF Engine on the Intune clients. The functionality is as follows:
- Downloading the created ZIP file, for example from: https://www.scriptingframework.ch/Scripting_Framework_Engine.zip
- Extracting the ZIP file
- Executing the Install.cmd file, which is included in the ZIP file
- Cleanup
All actions are logged in a log file located at: C:\Windows\Temp\Install-ScriptingFrameworkEngine.log.
The PowerShell script "Install-ScriptingFrameworkEngine.ps1" for installing the Engine on devices is now registered in the Intune portal: Intune-Portal registriert:
Add –> Windows 10 and later
For example, assign the name "Installation - Scripting Framework Engine" and then click on "Next"
Choose the script "Install-ScriptingFrameworkEngine.ps1" (the code is above in the blog) -> Next
Add the assignment to all devices –> Next
Add:
The script was successfully created in Intune:
The SF Engine will now be automatically installed on the Intune devices, making them ready for the distribution of software.