Skip to content

Instantly share code, notes, and snippets.

@dotps1
Last active June 16, 2021 17:56
Show Gist options
  • Save dotps1/492023ebd737f9cc46aa to your computer and use it in GitHub Desktop.
Save dotps1/492023ebd737f9cc46aa to your computer and use it in GitHub Desktop.
Creates a new Sccm Java Application and Deployment Type. All three functions are required. (See comments for details.)
Param (
[Parameter(
Mandatory = $true
)]
[String]
$SourcePackageCreationPath,
[Parameter(
Mandatory = $true
)]
[String]
$ComputerName,
[Parameter()]
[PSCredential]
$Credential,
[Parameter(
Mandatory = $true
)]
[String]
$SiteCode,
[Parameter()]
[String]
$ApplicationFolder,
[Parameter()]
[System.Security.Cryptography.X509Certificates.X509Certificate2]
$CodeSigningCertificate
)
#region Main
$ErrorActionPreference = 'Stop'
if (($installers = Invoke-JavaDownloadAndMsiExtraction -Verbose:$VerbosePreference) -eq $null) {
throw $_
}
# Installer script to be generated in package directory.
$installScript = @"
`$location = Split-Path -Path `$(`$global:MyInvocation.MyCommand.Path)
`$architecture = (Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' -Name 'PROCESSOR_ARCHITECTURE').PROCESSOR_ARCHITECTURE
# Uninstall existing versions of Java $($installers.VersionInfo.ProductMajorPart).
foreach (`$install in (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object { `$_.DisplayName -match 'Java $($installers.VersionInfo.ProductMajorPart) Update \d+' })) {
Start-Process -FilePath "msiexec.exe" -ArgumentList "/x `$(`$install.PSChildName) /quiet" -Wait
}
if (-not (Test-Path -Path "`$env:ProgramData\Oracle\Java")) {
New-Item -Path "`$env:ProgramData\Oracle\Java" -ItemType Directory -Force | Out-Null
}
# Ensure Java Settings Config file exists in the ProgramData Directory.
Copy-Item -Path `${location}\java.settings.cfg -Destination "`$env:ProgramData\Oracle\Java" -Force
if (`$architecture -eq 'AMD64') {
foreach (`$install in (Get-ItemProperty -Path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object { `$_.DisplayName -match 'Java $($installers.VersionInfo.ProductMajorPart) Update \d+' })) {
Start-Process -FilePath "msiexec.exe" -ArgumentList "/x `$(`$install.PSChildName) /quiet" -Wait
}
}
try {
# Install x86.
Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i `${location}\x86.msi INSTALLCFG=`${location}\java.settings.cfg /quiet" -Wait -ErrorAction Stop
# Install x64 on compatiable systems.
if (`$architecture -eq 'AMD64') {
Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i `${location}\x64.msi INSTALLCFG=`${location}\java.settings.cfg /quiet" -Wait -ErrorAction Stop
}
exit 0
} catch {
exit 1
}
"@
# Java installer config file to be generated in package directory.
$installSettings = @'
AUTO_UPDATE=0
REBOOT=0
NOSTARTMENU=1
'@
# Create output folder for package.
try {
Write-Verbose -Message "Creating output directory: $SourcePackageCreationPath\$($installers.VersionDisplayName)."
$package = New-Item -Path $SourcePackageCreationPath -Name $installers.VersionDisplayName -ItemType Directory -Force -ErrorAction Stop
} catch {
throw $_
}
# Copy installers to folder.
try {
Write-Verbose -Message "Copying $($installers.x86Msi.FullName) to $($package.FullName)\x86.msi."
Copy-Item -Path $installers.x86Msi.FullName -Destination "$($package.FullName)\x86.msi" -Force -ErrorAction Stop
Write-Verbose -Message "Copying $($installers.x64Msi.FullName) to $($package.FullName)\x64.msi."
Copy-Item -Path $installers.x64Msi.FullName -Destination "$($package.FullName)\x64.msi" -Force -ErrorAction Stop
} catch {
throw $_
}
# Extract install script and settings file to package folder.
try {
Write-Verbose -Message "Extracting Install-Java.ps1 to $($package.FullName)."
Out-File -FilePath "$($package.FullName)\Install-Java.ps1" -InputObject $installScript -Encoding ascii -NoNewline -Force -ErrorAction Stop
# Sign the extracted script.
if ($PSBoundParameters.ContainsKey('CodeSigningCertificate')) {
try {
Write-Verbose -Message "Signing $($package.FullName)\Install-Java.ps1 with $($CodeSigningCertificate.Subject)."
Set-AuthenticodeSignature -Certificate $CodeSigningCertificate -FilePath "$($package.FullName)\Install-Java.ps1" -ErrorAction Stop | Out-Null
} catch {
throw $_
}
}
Write-Verbose -Message "Extracting java.settings.cfg to $($package.FullName)."
Out-File -FilePath "$($package.FullName)\java.settings.cfg" -InputObject $installSettings -Encoding ascii -NoNewline -Force -ErrorAction Stop
} catch {
throw $_
}
#region CreateSccmApplicaion.
try {
$currentVerbosePreference = $VerbosePreference
$VerbosePreference = 'SilentlyContinue'
$sessionParams = @{
ComputerName = $ComputerName
}
if ($PSBoundParameters.ContainsKey('Credential')) {
$sessionParams.Add('Credential', $Credential)
}
$session = New-PSSession @sessionParams
Invoke-Command -Session $session -ScriptBlock {
Import-Module -Name "$(Split-Path $Env:SMS_ADMIN_UI_PATH)\ConfigurationManager.psd1" -Verbose:$false
Set-Location -Path "$(Get-PSDrive -PSProvider CMSite):\"
}
Import-PSSession -Session $session -Module ConfigurationManager -AllowClobber | Out-Null
$VerbosePreference = $currentVerbosePreference
} catch {
throw $_
}
if (Get-CMApplication -Name $installers.VersionInfo.ProductName) {
throw "The application $($installers.VersionInfo.ProductName) already exists."
}
$applicationParams = @{
Name = $installers.VersionInfo.ProductName
Description = "$($installers.VersionInfo.ProductName)"
SoftwareVersion = $installers.VersionInfo.ProductVersion
LocalizedName = "$($installers.VersionInfo.ProductName)"
LocalizedDescription = "Installs and configures $($installers.VersionInfo.ProductName) for both x86 and x64 Systems. Please restart any open browsers after running this install."
}
try {
Write-Verbose -Message 'Creating application.'
$application = New-CMApplication @applicationParams
} catch {
throw $_
}
$deploymentParams = @{
ApplicationName = $application.LocalizedDisplayName
ProductCode = "{$($installers.x86MsiProductCode)}"
DeploymentTypeName = "$($installers.VersionInfo.ProductName) - Script Installer"
InstallCommand = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\Install-Java.ps1"
ContentLocation = $package.FullName
EstimatedRuntimeMins = 5
MaximumRuntimeMins = 15
LogonRequirementType = 'WhereOrNotUserLoggedOn'
UserInteractionMode = 'Hidden'
}
try {
Write-Verbose -Message 'Creating deployment type.'
$deployment = Add-CMScriptDeploymentType @deploymentParams
} catch {
throw $_
}
if ($PSBoundParameters.ContainsKey('ApplicationFolder')) {
try {
Write-Verbose -Message "Moving application to appropriate folder."
$applicationID = Get-WmiObject -Namespace Root\SMS\Site_$SiteCode -Class SMS_ApplicationLatest -Filter "LocalizedDisplayName='$($installers.VersionInfo.ProductName)'" -ComputerName $ComputerName
$targetFolderID = Get-WmiObject -Namespace Root\SMS\Site_$SiteCode -Class SMS_ObjectContainerNode -Filter "Name='$($ApplicationFolder)' and ObjectType='6000'" -ComputerName $ComputerName
$currentFolderID = 0
$wmiConnection = [WMIClass]"\\$($ComputerName)\root\SMS\Site_$($SiteCode):SMS_objectContainerItem"
$moveItem = $wmiConnection.psbase.GetMethodParameters("MoveMembers")
$moveItem.ContainerNodeID = $currentFolderId
$moveItem.InstanceKeys = $applicationID.ModelName
$moveItem.ObjectType = 6000
$moveItem.TargetContainerNodeID = $targetFolderID.ContainerNodeID
$wmiConnection.psbase.InvokeMethod("MoveMembers",$moveItem,$null) | Out-Null
} catch {
throw $_
}
}
Write-Verbose -Message 'Application created succsesfully in the root application folder.'
#endregion CreateSccmApplication
#endregion Main
<#
.SYNOPSIS
Gets the product code from a Windows Installer Database.
.DESCRIPTION
Opens a Windows Installer Database (.msi) and querys for the product code.
.INPUTS
System.String.
.OUTPUTS
System.Guid.
.EXAMPLE
PS C:\> Get-MsiProductCode -Path C:\my.msi
.LINK
http://dotps1.github.io
#>
Function Get-MsiProductCode {
[OutputType([Guid])]
Param (
[Parameter(
Mandatory = $true,
ValueFromPipeLine = $true
)]
[String]
$Path
)
try {
$windowsInstaller = New-Object -com WindowsInstaller.Installer
$database = $windowsInstaller.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $null, $windowsInstaller, @((Get-Item -Path $Path).FullName, 0))
$view = $database.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $database, ("SELECT Value FROM Property WHERE Property = 'ProductCode'"))
$view.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $view, $null)
$record = $view.GetType().InvokeMember('Fetch', 'InvokeMethod', $null, $view, $null)
return $($record.GetType().InvokeMember('StringData', 'GetProperty', $null, $record, 1))
$view.GetType().InvokeMember('Close', 'InvokeMethod', $null, $view, $null)
[Void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($windowsInstaller)
} catch {
throw $_
}
}
<#
.SYNOPSIS
Downloads and extracts the latest version of Java Runtime Environment.
.DESCRIPTION
Download the x86 and x64 offline installer executables for the Java Website.
Runs each exeacuatble, which then extracts the MSIs to the current users APPDATA.
.INPUTS
None.
.OUTPUTS
System.Management.Automation.PSCustomObject.
.EXAMPLE
Invoke-JavaDownloadAndExtraction
.EXAMPLE
Invoke-JavaDownloadAndExtraction -Verbose
.NOTES
The current Java Installer Staging directory will be removed then recreated.
.LINK
http://www.java.com/en/download/manual.jsp
#>
Function Invoke-JavaDownloadAndMsiExtraction {
[CmdletBinding()]
[OutputType(
[PSCustomObject]
)]
Param (
)
Begin {
# Verify Admin Rights before running.
if (-not ([System.Security.Principal.WindowsPrincipal][System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]'Administrator')) {
throw 'This cmdlet cannot be used in this context. Restart PowerShell using the Run As Administrator option.'
}
}
Process {
# Download offline installers.
$downloadPage = Invoke-WebRequest -Uri 'http://www.java.com/en/download/manual.jsp'
$x86Download = ($downloadPage.Links | Where-Object { $_.innerText -eq 'Windows Offline' }).href
$x64Download = ($downloadPage.Links | Where-Object { $_.innerText -eq 'Windows Offline (64-Bit)' }).href
$downloader = New-Object -TypeName System.Net.WebClient
try {
Write-Verbose -Message "Downloading Java x86 Offline Installer. URL: $x86Download"
$downloader.DownloadFile($x86Download, "$env:USERPROFILE\Downloads\Java_x86.exe")
Write-Verbose -Message "Downloading Java x64 Offline Installer. URL: $x64Download"
$downloader.DownloadFile($x64Download, "$env:USERPROFILE\Downloads\Java_x64.exe")
$x86Exe = Get-Item -Path "$env:USERPROFILE\Downloads\Java_x86.exe"
$x64Exe = Get-Item -Path "$env:USERPROFILE\Downloads\Java_x64.exe"
} catch {
throw $_
}
# Delete Java Install staging directory.
try {
$stagingDirectory = "$env:USERPROFILE\AppData\LocalLow\Oracle"
if (Test-Path -Path $stagingDirectory) {
Write-Verbose -Message "Removing existing Java Install Staging Directory: $stagingDirectory."
Remove-Item -Path $stagingDirectory -Recurse -Force -ErrorAction Stop
}
# Recreate the directory to make sure the path exists for the get child item.
Write-Verbose -Message "Creating new Java Install Staging Directory: $stagingDirectory."
$stagingDirectory = New-Item -Path $stagingDirectory -Name 'Java' -ItemType Directory -Force
} catch {
throw $_
}
# Trigger x86 .exe to extract msi to install staging directory.
Write-Verbose -Message "Starting Java 32-bit Installer to extract msi to $stagingDirectory."
Write-Warning -Message 'DO NOT CLOSE THE JAVA INSTALLER WINDOW, IT WILL CLOSE IT SELF AFTER THE MSI IS EXTRACTED.'
Start-Process -FilePath $x86Exe.FullName
do {
$x86Msi = Get-ChildItem -Path "$($stagingDirectory.FullName)\jre*" -Filter 'jre*.msi' -Recurse
Start-Sleep -Milliseconds 2500
} until ($x86Msi.Exists)
Write-Verbose -Message "32-bit msi extracted, terminating Java processes."
do {
$processes = Get-WmiObject -Class Win32_Process | Where-Object { $_.Path -match 'Java' }
foreach ($process in $processes) {
Invoke-WmiMethod -InputObject $process -Name Terminate | Out-Null
}
Start-Sleep -Milliseconds 2500
} until ($processes.Count -eq 0)
Write-Verbose -Message "Starting Java 64-bit Installer to extract msi to $stagingDirectory."
Write-Warning -Message 'DO NOT CLOSE THE JAVA INSTALLER WINDOW, IT WILL CLOSE IT SELF AFTER THE MSI IS EXTRACTED.'
Start-Process -FilePath $x64Exe.FullName
do {
$x64Msi = Get-ChildItem -Path "$($stagingDirectory.FullName)\jre*x64" -Filter 'jre*.msi' -Recurse
Start-Sleep -Milliseconds 2500
} until ($x64Msi.Exists)
Write-Verbose -Message "64-bit msi extracted, terminating Java processes."
do {
$processes = Get-WmiObject -Class Win32_Process | Where-Object { $_.Path -match 'Java' }
foreach ($process in $processes) {
Invoke-WmiMethod -InputObject $process -Name Terminate | Out-Null
}
Start-Sleep -Milliseconds 2500
} until ($processes.Count -eq 0)
[PSCustomObject]$psCustomObject = @{
x86Msi = $x86Msi
x86MsiProductCode = [Guid]::New((Get-MsiProductCode -Path $x86Msi.FullName))
x64Msi = $x64Msi
x64MsiProductCode = [Guid]::New((Get-MsiProductCode -Path $x64Msi.FullName))
VersionDisplayName = $x86Msi.PSParentPath.Substring($x86Msi.PSParentPath.LastIndexOf([System.IO.Path]::DirectorySeparatorChar) +1)
VersionInfo = $x86Exe.VersionInfo
}
}
End {
Write-Verbose -Message "Deleting Java Offline Installers."
Remove-Item -Path $x86Exe.FullName -Force
Remove-Item -Path $x64Exe.FullName -Force
return $psCustomObject
}
}
@dotps1
Copy link
Author

dotps1 commented Aug 31, 2015

  1. Download both x86 and x64 versions of the Java Offline Installer.
  2. Run the x86 exe which extracts the msi to the current users Application Data. (This will show the Java installer windows, DO NOT CLOSE THIS WINDOW! The script will do so at the appropriate time.)
  3. After the msi exists, terminate all the running java process.
  4. Run the x64 exe which extracts the msi to the current users Application Data. (This will show the Java installer windows, DO NOT CLOSE THIS WINDOW! The script will do so at the appropriate time.)
  5. After the msi exists, terminate all the running java process.
  6. Create the package directory specified in the SoucesPath.
  7. Copy both msi's to that path.
  8. Extract the Installer Script to the package directory.
  9. Sign the installer script.
  10. Extract the java installer properties file to the package directory.
  11. Import the Config Manager assemblies, (I did this by sharing the programs dir, notice line 143/144, the 'AdminConsole$' is my sharename).
  12. Create the Application Management Object.
  13. Create the Deployment Type Object.
  14. Create the Content Object.
  15. Add the Content Object and the Deployment Type Object to the Application Management Object.
  16. Create the application on the SCCM Server.
  17. Move the application to the correct folder, (if a folder was supplied, else it will exist in the root application directory).

@dotps1
Copy link
Author

dotps1 commented Apr 11, 2016

_UPDATE_
Now invokes an implicit PSSession to the SCCM Server to get the ConfigurationManager ps module, so the share is no longer needed to get tto that.

@sbergene
Copy link

running .New-SccmJavaApplication.ps1 :
I get error:
The term 'Invoke-JavaDownloadAndMsiExtraction' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1

  • .New-SccmJavaApplication.ps1
  •   + CategoryInfo          : ObjectNotFound: (Invoke-JavaDownloadAndMsiExtraction:String) [.New-SccmJavaApplication.p
     s1], CommandNotFoundException
      + FullyQualifiedErrorId : CommandNotFoundException,.New-SccmJavaApplication.ps1
    
    
    

Suggestion [3,General]: The command Invoke-JavaDownloadAndMsiExtraction was not found, but does exist in the current
location. Windows PowerShell does not load commands from the current location by default. If you trust this command,
instead type: ".\Invoke-JavaDownloadAndMsiExtraction". See "get-help about_Command_Precedence" for more details.

After doing the change in New-SccmJavaApplication.ps1, I get:

ScriptHalted
At .... .New-SccmJavaApplication.ps1:38 char:5

  • throw $_
    
  • ~~~~~~~~
    
    • CategoryInfo : OperationStopped: (:) [], RuntimeException
    • FullyQualifiedErrorId : ScriptHalted

Any Idea ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment