Skip to content

Commit b0c42a2

Browse files
small changes to allow CIPPW32ScriptApplications.
1 parent c11ea82 commit b0c42a2

1 file changed

Lines changed: 105 additions & 76 deletions

File tree

Lines changed: 105 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
function Add-CIPPW32ScriptApplication {
22
<#
33
.SYNOPSIS
4-
Adds a Win32 app with PowerShell script installer to Intune.
4+
Adds a Win32 app with PowerShell script installer to Intune using the standard Chocolatey package.
55
66
.DESCRIPTION
7-
Creates a Win32 app using the PowerShell script installer feature.
8-
Uploads an intunewin file and PowerShell scripts via the scripts endpoint.
7+
Creates a Win32 app that uses the standard Chocolatey intunewin package but with custom PowerShell scripts.
8+
Always uploads the same Choco package, but uses user-provided scripts for install/uninstall commands.
99
1010
.PARAMETER TenantFilter
1111
Tenant ID or domain name for the Graph API call.
@@ -17,91 +17,134 @@ function Add-CIPPW32ScriptApplication {
1717
- publisher: Publisher name
1818
- installScript (required): PowerShell install script content (plaintext)
1919
- uninstallScript: PowerShell uninstall script content (plaintext)
20-
- detectionScript: PowerShell detection script content (plaintext)
20+
- detectionPath (required): Full path to the file or folder to detect (e.g., 'C:\\Program Files\\MyApp')
21+
- detectionFile: File name to detect (optional, for folder path detection)
22+
- detectionType: 'exists', 'modifiedDate', 'createdDate', 'version', 'sizeInMB' (default: 'exists')
23+
- check32BitOn64System: Boolean, check 32-bit registry/paths on 64-bit systems (default: false)
2124
- runAsAccount: 'system' or 'user' (default: 'system')
2225
- deviceRestartBehavior: 'allow', 'suppress', or 'force' (default: 'suppress')
23-
- runAs32Bit: Boolean, run scripts as 32-bit on 64-bit clients (default: false)
24-
- enforceSignatureCheck: Boolean, enforce script signature validation (default: false)
25-
26-
.PARAMETER FilePath
27-
Path to the intunewin file.
28-
29-
.PARAMETER FileName
30-
Name of the file from XML metadata.
31-
32-
.PARAMETER UnencryptedSize
33-
Unencrypted size of the file from XML metadata.
34-
35-
.PARAMETER EncryptionInfo
36-
Hashtable containing encryption information from XML.
3726
3827
.EXAMPLE
3928
$Properties = @{
4029
displayName = 'My Script App'
4130
installScript = 'Write-Host "Installing..."'
31+
detectionPath = 'C:\\Program Files\\MyApp'
32+
detectionFile = 'app.exe'
4233
}
43-
$EncryptionInfo = @{ EncryptionKey = '...'; MacKey = '...'; ... }
44-
Add-CIPPW32ScriptApplication -TenantFilter 'contoso.com' -Properties $Properties -FilePath 'app.intunewin' -FileName 'app.intunewin' -UnencryptedSize 1024000 -EncryptionInfo $EncryptionInfo
34+
Add-CIPPW32ScriptApplication -TenantFilter 'contoso.com' -Properties $Properties
4535
#>
4636
[CmdletBinding()]
4737
param(
4838
[Parameter(Mandatory = $true)]
4939
[string]$TenantFilter,
5040

5141
[Parameter(Mandatory = $true)]
52-
[PSCustomObject]$Properties,
42+
[PSCustomObject]$Properties
43+
)
5344

54-
[Parameter(Mandatory = $true)]
55-
[string]$FilePath,
45+
# Get the standard Chocolatey package location (relative to function app root)
46+
$IntuneWinFile = 'AddChocoApp\IntunePackage.intunewin'
47+
$ChocoXmlFile = 'AddChocoApp\Choco.App.xml'
5648

57-
[Parameter(Mandatory = $true)]
58-
[string]$FileName,
49+
if (-not (Test-Path $IntuneWinFile)) {
50+
throw "Chocolatey IntunePackage.intunewin not found at: $IntuneWinFile (Current directory: $PWD)"
51+
}
5952

60-
[Parameter(Mandatory = $true)]
61-
[int64]$UnencryptedSize,
53+
if (-not (Test-Path $ChocoXmlFile)) {
54+
throw "Choco.App.xml not found at: $ChocoXmlFile (Current directory: $PWD)"
55+
}
6256

63-
[Parameter(Mandatory = $true)]
64-
[hashtable]$EncryptionInfo
65-
)
57+
# Parse the Choco XML to get encryption info
58+
[xml]$ChocoXml = Get-Content $ChocoXmlFile
59+
$EncryptionInfo = @{
60+
EncryptionKey = $ChocoXml.ApplicationInfo.EncryptionInfo.EncryptionKey
61+
MacKey = $ChocoXml.ApplicationInfo.EncryptionInfo.MacKey
62+
InitializationVector = $ChocoXml.ApplicationInfo.EncryptionInfo.InitializationVector
63+
Mac = $ChocoXml.ApplicationInfo.EncryptionInfo.Mac
64+
ProfileIdentifier = $ChocoXml.ApplicationInfo.EncryptionInfo.ProfileIdentifier
65+
FileDigest = $ChocoXml.ApplicationInfo.EncryptionInfo.FileDigest
66+
FileDigestAlgorithm = $ChocoXml.ApplicationInfo.EncryptionInfo.FileDigestAlgorithm
67+
}
68+
69+
$FileName = $ChocoXml.ApplicationInfo.FileName
70+
$UnencryptedSize = [int64]$ChocoXml.ApplicationInfo.UnencryptedContentSize
71+
72+
# Build detection rules
73+
if ($Properties.detectionPath) {
74+
# Determine if this is a file or folder detection
75+
$DetectionRule = @{
76+
'@odata.type' = '#microsoft.graph.win32LobAppFileSystemDetection'
77+
check32BitOn64System = if ($null -ne $Properties.check32BitOn64System) { [bool]$Properties.check32BitOn64System } else { $false }
78+
detectionType = if ($Properties.detectionType) { $Properties.detectionType } else { 'exists' }
79+
}
80+
81+
if ($Properties.detectionFile) {
82+
# File detection (path + file)
83+
$DetectionRule['path'] = $Properties.detectionPath
84+
$DetectionRule['fileOrFolderName'] = $Properties.detectionFile
85+
} else {
86+
# Folder/File detection (full path)
87+
# Split the path into directory and file/folder name
88+
$PathItem = Split-Path $Properties.detectionPath -Leaf
89+
$ParentPath = Split-Path $Properties.detectionPath -Parent
90+
91+
if ([string]::IsNullOrEmpty($ParentPath)) {
92+
throw "Invalid detection path: $($Properties.detectionPath). Must be a full path."
93+
}
6694

67-
# Build Win32 app body
68-
$intuneBody = @{
69-
'@odata.type' = '#microsoft.graph.win32LobApp'
70-
displayName = $Properties.displayName
71-
description = $Properties.description
72-
publisher = $Properties.publisher
73-
fileName = $FileName
74-
setupFilePath = 'N/A'
75-
minimumSupportedWindowsRelease = '1607'
76-
returnCodes = @(
95+
$DetectionRule['path'] = $ParentPath
96+
$DetectionRule['fileOrFolderName'] = $PathItem
97+
}
98+
99+
$DetectionRules = @($DetectionRule)
100+
} else {
101+
# Default detection: Check for a marker file in ProgramData
102+
$DetectionRules = @(
103+
@{
104+
'@odata.type' = '#microsoft.graph.win32LobAppFileSystemDetection'
105+
path = '%ProgramData%\CIPPApps'
106+
fileOrFolderName = "$($Properties.displayName -replace '[^a-zA-Z0-9]', '_').txt"
107+
check32BitOn64System = $false
108+
detectionType = 'exists'
109+
}
110+
)
111+
}
112+
113+
# Build the Win32 app body
114+
$AppBody = @{
115+
'@odata.type' = '#microsoft.graph.win32LobApp'
116+
displayName = $Properties.displayName
117+
description = $Properties.description
118+
publisher = if ($Properties.publisher) { $Properties.publisher } else { 'CIPP' }
119+
fileName = $FileName
120+
setupFilePath = 'N/A'
121+
installCommandLine = 'powershell.exe -ExecutionPolicy Bypass -File install.ps1'
122+
uninstallCommandLine = 'powershell.exe -ExecutionPolicy Bypass -File uninstall.ps1'
123+
minimumSupportedWindowsRelease = '1607'
124+
detectionRules = $DetectionRules
125+
returnCodes = @(
77126
@{ returnCode = 0; type = 'success' }
78127
@{ returnCode = 1707; type = 'success' }
79128
@{ returnCode = 3010; type = 'softReboot' }
80129
@{ returnCode = 1641; type = 'hardReboot' }
81130
@{ returnCode = 1618; type = 'retry' }
82131
)
132+
installExperience = @{
133+
'@odata.type' = 'microsoft.graph.win32LobAppInstallExperience'
134+
runAsAccount = if ($Properties.runAsAccount) { $Properties.runAsAccount } else { 'system' }
135+
deviceRestartBehavior = if ($Properties.deviceRestartBehavior) { $Properties.deviceRestartBehavior } else { 'suppress' }
136+
}
83137
}
84138

85-
# Add install experience
86-
$intuneBody.installExperience = @{
87-
'@odata.type' = 'microsoft.graph.win32LobAppInstallExperience'
88-
runAsAccount = if ($Properties.runAsAccount) { $Properties.runAsAccount } else { 'system' }
89-
deviceRestartBehavior = if ($Properties.deviceRestartBehavior) { $Properties.deviceRestartBehavior } else { 'suppress' }
90-
maxRunTimeInMinutes = 60
91-
}
92-
93-
# Create the app
139+
# Create the app first
94140
$Baseuri = 'https://graph.microsoft.com/beta/deviceAppManagement/mobileApps'
95-
$NewApp = New-GraphPostRequest -Uri $Baseuri -Body ($intuneBody | ConvertTo-Json -Depth 10) -Type POST -tenantid $TenantFilter
141+
$NewApp = New-GraphPostRequest -Uri $Baseuri -Body ($AppBody | ConvertTo-Json -Depth 10) -Type POST -tenantid $TenantFilter
96142
Start-Sleep -Milliseconds 200
97143

98-
# Upload intunewin file using shared helper
99-
Add-CIPPWin32LobAppContent -AppId $NewApp.id -FilePath $FilePath -FileName $FileName -UnencryptedSize $UnencryptedSize -EncryptionInfo $EncryptionInfo -TenantFilter $TenantFilter
100-
101-
# Upload PowerShell scripts via the scripts endpoint
102-
$RunAs32Bit = if ($null -ne $Properties.runAs32Bit) { [bool]$Properties.runAs32Bit } else { $false }
103-
$EnforceSignatureCheck = if ($null -ne $Properties.enforceSignatureCheck) { [bool]$Properties.enforceSignatureCheck } else { $false }
144+
# Upload the Chocolatey intunewin content
145+
Add-CIPPWin32LobAppContent -AppId $NewApp.id -FilePath $IntuneWinFile -FileName $FileName -UnencryptedSize $UnencryptedSize -EncryptionInfo $EncryptionInfo -TenantFilter $TenantFilter
104146

147+
# Upload PowerShell scripts via the scripts endpoint (newer method)
105148
$InstallScriptId = $null
106149
$UninstallScriptId = $null
107150

@@ -110,8 +153,8 @@ function Add-CIPPW32ScriptApplication {
110153
$InstallScriptBody = @{
111154
'@odata.type' = '#microsoft.graph.win32LobAppInstallPowerShellScript'
112155
displayName = 'install.ps1'
113-
enforceSignatureCheck = $EnforceSignatureCheck
114-
runAs32Bit = $RunAs32Bit
156+
enforceSignatureCheck = $false
157+
runAs32Bit = $false
115158
content = $InstallScriptContent
116159
} | ConvertTo-Json
117160

@@ -133,8 +176,8 @@ function Add-CIPPW32ScriptApplication {
133176
$UninstallScriptBody = @{
134177
'@odata.type' = '#microsoft.graph.win32LobAppUninstallPowerShellScript'
135178
displayName = 'uninstall.ps1'
136-
enforceSignatureCheck = $EnforceSignatureCheck
137-
runAs32Bit = $RunAs32Bit
179+
enforceSignatureCheck = $false
180+
runAs32Bit = $false
138181
content = $UninstallScriptContent
139182
} | ConvertTo-Json
140183

@@ -153,8 +196,8 @@ function Add-CIPPW32ScriptApplication {
153196

154197
# Build final commit body with active script references
155198
$CommitBody = @{
156-
'@odata.type' = '#microsoft.graph.win32LobApp'
157-
committedContentVersion = '1'
199+
'@odata.type' = '#microsoft.graph.win32LobApp'
200+
committedContentVersion = '1'
158201
}
159202

160203
if ($InstallScriptId) {
@@ -165,22 +208,8 @@ function Add-CIPPW32ScriptApplication {
165208
$CommitBody['activeUninstallScript'] = @{ targetId = $UninstallScriptId }
166209
}
167210

168-
# Add detection rules if provided
169-
if ($Properties.detectionScript) {
170-
$DetectionScriptContent = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($Properties.detectionScript))
171-
$CommitBody['detectionRules'] = @(
172-
@{
173-
'@odata.type' = '#microsoft.graph.win32LobAppPowerShellScriptDetection'
174-
scriptContent = $DetectionScriptContent
175-
enforceSignatureCheck = $EnforceSignatureCheck
176-
runAs32Bit = $RunAs32Bit
177-
}
178-
)
179-
}
180-
181211
# Commit the app with script references
182212
$null = New-GraphPostRequest -Uri "$Baseuri/$($NewApp.id)" -tenantid $TenantFilter -Body ($CommitBody | ConvertTo-Json -Depth 10) -Type PATCH
183213

184214
return $NewApp
185-
186215
}

0 commit comments

Comments
 (0)