├── README.md ├── ADMX–OneDrive.admx-KFM.json ├── DeviceConfiguration_Add_Windows_Custom_CredentialGuard.ps1 ├── DeviceConfiguration_Add_Windows_Custom_SystemServices.ps1 ├── DeviceConfiguration_Add_Windows_Custom_Password-PINreset.ps1 ├── DeviceConfiguration_Add_Windows_Update_Insider_FastRing.ps1 ├── DeviceConfiguration_Add_Windows_Custom_LocalPoliciesSecurityOptions.ps1 ├── Edge crash WDAC fix.ps1 ├── WindowsAutopilot_CreateProfile.ps1 ├── Application_LOB_Add_MSTeams.ps1 └── Application_LOB_Add - Google.ps1 /README.md: -------------------------------------------------------------------------------- 1 | # IntunePowerShellAutomation 2 | Intune Powershell Automation Scripts with Intune Graph API 3 | -------------------------------------------------------------------------------- /ADMX–OneDrive.admx-KFM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pelarsen/IntunePowerShellAutomation/HEAD/ADMX–OneDrive.admx-KFM.json -------------------------------------------------------------------------------- /DeviceConfiguration_Add_Windows_Custom_CredentialGuard.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pelarsen/IntunePowerShellAutomation/HEAD/DeviceConfiguration_Add_Windows_Custom_CredentialGuard.ps1 -------------------------------------------------------------------------------- /DeviceConfiguration_Add_Windows_Custom_SystemServices.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pelarsen/IntunePowerShellAutomation/HEAD/DeviceConfiguration_Add_Windows_Custom_SystemServices.ps1 -------------------------------------------------------------------------------- /DeviceConfiguration_Add_Windows_Custom_Password-PINreset.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pelarsen/IntunePowerShellAutomation/HEAD/DeviceConfiguration_Add_Windows_Custom_Password-PINreset.ps1 -------------------------------------------------------------------------------- /DeviceConfiguration_Add_Windows_Update_Insider_FastRing.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pelarsen/IntunePowerShellAutomation/HEAD/DeviceConfiguration_Add_Windows_Update_Insider_FastRing.ps1 -------------------------------------------------------------------------------- /DeviceConfiguration_Add_Windows_Custom_LocalPoliciesSecurityOptions.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pelarsen/IntunePowerShellAutomation/HEAD/DeviceConfiguration_Add_Windows_Custom_LocalPoliciesSecurityOptions.ps1 -------------------------------------------------------------------------------- /Edge crash WDAC fix.ps1: -------------------------------------------------------------------------------- 1 | New-Item -Path HKCU:\Software\Microsoft\Internet Explorer\Spartan –Force 2 | $registryPath = "HKCU:\Software\Microsoft\Internet Explorer\Spartan" 3 | 4 | #Fix Edge on 1803 with WDAG or Applocker enabled 5 | $Name = "RAC_LaunchFlags" 6 | $value = "00000035" 7 | IF(!(Test-Path $registryPath)) 8 | { 9 | New-Item -Path $registryPath -Force | Out-Null 10 | New-ItemProperty -Path $registryPath -Name $name -Value $value ` 11 | -PropertyType String -Force | Out-Null} 12 | ELSE { 13 | New-ItemProperty -Path $registryPath -Name $name -Value $value ` 14 | -PropertyType String -Force | Out-Null} 15 | 16 | -------------------------------------------------------------------------------- /WindowsAutopilot_CreateProfile.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | .COPYRIGHT 4 | Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. 5 | See LICENSE in the project root for license information. 6 | 7 | #> 8 | 9 | #################################################### 10 | 11 | function Get-AuthToken { 12 | 13 | <# 14 | .SYNOPSIS 15 | This function is used to authenticate with the Graph API REST interface 16 | .DESCRIPTION 17 | The function authenticate with the Graph API Interface with the tenant name 18 | .EXAMPLE 19 | Get-AuthToken 20 | Authenticates you with the Graph API interface 21 | .NOTES 22 | NAME: Get-AuthToken 23 | #> 24 | 25 | [cmdletbinding()] 26 | 27 | param 28 | ( 29 | [Parameter(Mandatory=$true)] 30 | $User 31 | ) 32 | 33 | $userUpn = New-Object "System.Net.Mail.MailAddress" -ArgumentList $User 34 | 35 | $tenant = $userUpn.Host 36 | 37 | Write-Host "Checking for AzureAD module..." 38 | 39 | $AadModule = Get-Module -Name "AzureAD" -ListAvailable 40 | 41 | if ($AadModule -eq $null) { 42 | 43 | Write-Host "AzureAD PowerShell module not found, looking for AzureADPreview" 44 | $AadModule = Get-Module -Name "AzureADPreview" -ListAvailable 45 | 46 | } 47 | 48 | if ($AadModule -eq $null) { 49 | write-host 50 | write-host "AzureAD Powershell module not installed..." -f Red 51 | write-host "Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt" -f Yellow 52 | write-host "Script can't continue..." -f Red 53 | write-host 54 | exit 55 | } 56 | 57 | # Getting path to ActiveDirectory Assemblies 58 | # If the module count is greater than 1 find the latest version 59 | 60 | if($AadModule.count -gt 1){ 61 | 62 | $Latest_Version = ($AadModule | select version | Sort-Object)[-1] 63 | 64 | $aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version } 65 | 66 | # Checking if there are multiple versions of the same module found 67 | 68 | if($AadModule.count -gt 1){ 69 | 70 | $aadModule = $AadModule | select -Unique 71 | 72 | } 73 | 74 | $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" 75 | $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll" 76 | 77 | } 78 | 79 | else { 80 | 81 | $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" 82 | $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll" 83 | 84 | } 85 | 86 | [System.Reflection.Assembly]::LoadFrom($adal) | Out-Null 87 | 88 | [System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null 89 | 90 | $clientId = "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" 91 | 92 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 93 | 94 | $resourceAppIdURI = "https://graph.microsoft.com" 95 | 96 | $authority = "https://login.microsoftonline.com/$Tenant" 97 | 98 | try { 99 | 100 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 101 | 102 | # https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx 103 | # Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession 104 | 105 | $platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto" 106 | 107 | $userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($User, "OptionalDisplayableId") 108 | 109 | $authResult = $authContext.AcquireTokenAsync($resourceAppIdURI,$clientId,$redirectUri,$platformParameters,$userId).Result 110 | 111 | # If the accesstoken is valid then create the authentication header 112 | 113 | if($authResult.AccessToken){ 114 | 115 | # Creating header for Authorization token 116 | 117 | $authHeader = @{ 118 | 'Content-Type'='application/json' 119 | 'Authorization'="Bearer " + $authResult.AccessToken 120 | 'ExpiresOn'=$authResult.ExpiresOn 121 | } 122 | 123 | return $authHeader 124 | 125 | } 126 | 127 | else { 128 | 129 | Write-Host 130 | Write-Host "Authorization Access Token is null, please re-run authentication..." -ForegroundColor Red 131 | Write-Host 132 | break 133 | 134 | } 135 | 136 | } 137 | 138 | catch { 139 | 140 | write-host $_.Exception.Message -f Red 141 | write-host $_.Exception.ItemName -f Red 142 | write-host 143 | break 144 | 145 | } 146 | 147 | } 148 | 149 | #################################################### 150 | 151 | Function Add-windowsAutopilotDeploymentProfiles(){ 152 | 153 | <# 154 | .SYNOPSIS 155 | This function is used to add an device configuration policy using the Graph API REST interface 156 | .DESCRIPTION 157 | The function connects to the Graph API Interface and adds a device configuration policy 158 | .EXAMPLE 159 | Add-DeviceConfigurationPolicy -JSON $JSON 160 | Adds a device configuration policy in Intune 161 | .NOTES 162 | NAME: Add-DeviceConfigurationPolicy 163 | #> 164 | 165 | [cmdletbinding()] 166 | 167 | param 168 | ( 169 | $JSON 170 | ) 171 | 172 | $graphApiVersion = "Beta" 173 | $DCP_resource = "deviceManagement/windowsAutopilotDeploymentProfiles" 174 | Write-Verbose "Resource: $DCP_resource" 175 | 176 | try { 177 | 178 | if($JSON -eq "" -or $JSON -eq $null){ 179 | 180 | write-host "No JSON specified, please specify valid JSON for the Autopilot Policy..." -f Red 181 | 182 | } 183 | 184 | else { 185 | 186 | Test-JSON -JSON $JSON 187 | 188 | $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)" 189 | Invoke-RestMethod -Uri $uri -Headers $authToken -Method Post -Body $JSON -ContentType "application/json" 190 | 191 | } 192 | 193 | } 194 | 195 | catch { 196 | 197 | $ex = $_.Exception 198 | $errorResponse = $ex.Response.GetResponseStream() 199 | $reader = New-Object System.IO.StreamReader($errorResponse) 200 | $reader.BaseStream.Position = 0 201 | $reader.DiscardBufferedData() 202 | $responseBody = $reader.ReadToEnd(); 203 | Write-Host "Response content:`n$responseBody" -f Red 204 | Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)" 205 | write-host 206 | break 207 | 208 | } 209 | 210 | } 211 | 212 | #################################################### 213 | 214 | Function Test-JSON(){ 215 | 216 | <# 217 | .SYNOPSIS 218 | This function is used to test if the JSON passed to a REST Post request is valid 219 | .DESCRIPTION 220 | The function tests if the JSON passed to the REST Post is valid 221 | .EXAMPLE 222 | Test-JSON -JSON $JSON 223 | Test if the JSON is valid before calling the Graph REST interface 224 | .NOTES 225 | NAME: Test-AuthHeader 226 | #> 227 | 228 | param ( 229 | 230 | $JSON 231 | 232 | ) 233 | 234 | try { 235 | 236 | $TestJSON = ConvertFrom-Json $JSON -ErrorAction Stop 237 | $validJson = $true 238 | 239 | } 240 | 241 | catch { 242 | 243 | $validJson = $false 244 | $_.Exception 245 | 246 | } 247 | 248 | if (!$validJson){ 249 | 250 | Write-Host "Provided JSON isn't in valid JSON format" -f Red 251 | break 252 | 253 | } 254 | 255 | } 256 | 257 | #################################################### 258 | 259 | #region Authentication 260 | 261 | write-host 262 | 263 | # Checking if authToken exists before running authentication 264 | if($global:authToken){ 265 | 266 | # Setting DateTime to Universal time to work in all timezones 267 | $DateTime = (Get-Date).ToUniversalTime() 268 | 269 | # If the authToken exists checking when it expires 270 | $TokenExpires = ($authToken.ExpiresOn.datetime - $DateTime).Minutes 271 | 272 | if($TokenExpires -le 0){ 273 | 274 | write-host "Authentication Token expired" $TokenExpires "minutes ago" -ForegroundColor Yellow 275 | write-host 276 | 277 | # Defining User Principal Name if not present 278 | 279 | if($User -eq $null -or $User -eq ""){ 280 | 281 | $User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication" 282 | Write-Host 283 | 284 | } 285 | 286 | $global:authToken = Get-AuthToken -User $User 287 | 288 | } 289 | } 290 | 291 | # Authentication doesn't exist, calling Get-AuthToken function 292 | 293 | else { 294 | 295 | if($User -eq $null -or $User -eq ""){ 296 | 297 | $User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication" 298 | Write-Host 299 | 300 | } 301 | 302 | # Getting the authorization token 303 | $global:authToken = Get-AuthToken -User $User 304 | 305 | } 306 | 307 | #endregion 308 | 309 | #################################################### 310 | 311 | $AutoPilotProfile = @" 312 | 313 | 314 | { 315 | "@odata.context": "https://graph.microsoft.com/beta/$metadata#deviceManagement/windowsAutopilotDeploymentProfiles/$entity", 316 | "@odata.type": "#microsoft.graph.azureADWindowsAutopilotDeploymentProfile", 317 | "id": "1647e8a1-d391-44bc-839e-bfcf5845ca28", 318 | "displayName": "Windows AutoPilot Default Profile Graph", 319 | "description": "", 320 | "language": "", 321 | "createdDateTime": "2017-10-20T05:47:54.8669437Z", 322 | "lastModifiedDateTime": "2018-10-21T09:51:59.7606979Z", 323 | "enrollmentStatusScreenSettings": null, 324 | "extractHardwareHash": true, 325 | "deviceNameTemplate": "OSD-%RAND:5%", 326 | "outOfBoxExperienceSettings": { 327 | "hidePrivacySettings": true, 328 | "hideEULA": true, 329 | "userType": "standard", 330 | "deviceUsageType": "singleUser", 331 | "skipKeyboardSelectionPage": false, 332 | "hideEscapeLink": true 333 | } 334 | } 335 | 336 | "@ 337 | 338 | #################################################### 339 | 340 | $AutoPilotProfileShared = @" 341 | 342 | { 343 | "@odata.context": "https://graph.microsoft.com/beta/$metadata#deviceManagement/windowsAutopilotDeploymentProfiles/$entity", 344 | "@odata.type": "#microsoft.graph.azureADWindowsAutopilotDeploymentProfile", 345 | "id": "91cb14fc-9d13-4cba-99d4-580f091e6843", 346 | "displayName": "Windows AutoPilot Shared Device Graph", 347 | "description": "", 348 | "language": "da-DK", 349 | "createdDateTime": "2018-06-08T11:47:49.5770529Z", 350 | "lastModifiedDateTime": "2018-10-21T09:53:48.2334846Z", 351 | "enrollmentStatusScreenSettings": null, 352 | "extractHardwareHash": false, 353 | "deviceNameTemplate": "SHARED-%RAND:5%", 354 | "outOfBoxExperienceSettings": { 355 | "hidePrivacySettings": true, 356 | "hideEULA": true, 357 | "userType": "standard", 358 | "deviceUsageType": "shared", 359 | "skipKeyboardSelectionPage": true, 360 | "hideEscapeLink": true 361 | } 362 | } 363 | 364 | "@ 365 | 366 | #################################################### 367 | 368 | Add-windowsAutopilotDeploymentProfiles -Json $AutoPilotProfile 369 | Add-windowsAutopilotDeploymentProfiles -Json $AutoPilotProfileShared 370 | 371 | -------------------------------------------------------------------------------- /Application_LOB_Add_MSTeams.ps1: -------------------------------------------------------------------------------- 1 | 2 | <# 3 | 4 | .COPYRIGHT 5 | Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. 6 | See LICENSE in the project root for license information. 7 | 8 | #> 9 | 10 | #################################################### 11 | 12 | function Get-AuthToken { 13 | 14 | <# 15 | .SYNOPSIS 16 | This function is used to authenticate with the Graph API REST interface 17 | .DESCRIPTION 18 | The function authenticate with the Graph API Interface with the tenant name 19 | .EXAMPLE 20 | Get-AuthToken 21 | Authenticates you with the Graph API interface 22 | .NOTES 23 | NAME: Get-AuthToken 24 | #> 25 | 26 | [cmdletbinding()] 27 | 28 | param 29 | ( 30 | [Parameter(Mandatory=$true)] 31 | $User 32 | ) 33 | 34 | $userUpn = New-Object "System.Net.Mail.MailAddress" -ArgumentList $User 35 | 36 | $tenant = $userUpn.Host 37 | 38 | Write-Host "Checking for AzureAD module..." 39 | 40 | $AadModule = Get-Module -Name "AzureAD" -ListAvailable 41 | 42 | if ($AadModule -eq $null) { 43 | 44 | Write-Host "AzureAD PowerShell module not found, looking for AzureADPreview" 45 | $AadModule = Get-Module -Name "AzureADPreview" -ListAvailable 46 | 47 | } 48 | 49 | if ($AadModule -eq $null) { 50 | write-host 51 | write-host "AzureAD Powershell module not installed..." -f Red 52 | write-host "Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt" -f Yellow 53 | write-host "Script can't continue..." -f Red 54 | write-host 55 | exit 56 | } 57 | 58 | # Getting path to ActiveDirectory Assemblies 59 | # If the module count is greater than 1 find the latest version 60 | 61 | if($AadModule.count -gt 1){ 62 | 63 | $Latest_Version = ($AadModule | select version | Sort-Object)[-1] 64 | 65 | $aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version } 66 | 67 | # Checking if there are multiple versions of the same module found 68 | 69 | if($AadModule.count -gt 1){ 70 | 71 | $aadModule = $AadModule | select -Unique 72 | 73 | } 74 | 75 | $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" 76 | $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll" 77 | 78 | } 79 | 80 | else { 81 | 82 | $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" 83 | $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll" 84 | 85 | } 86 | 87 | [System.Reflection.Assembly]::LoadFrom($adal) | Out-Null 88 | 89 | [System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null 90 | 91 | $clientId = "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" 92 | 93 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 94 | 95 | $resourceAppIdURI = "https://graph.microsoft.com" 96 | 97 | $authority = "https://login.microsoftonline.com/$Tenant" 98 | 99 | try { 100 | 101 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 102 | 103 | # https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx 104 | # Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession 105 | 106 | $platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto" 107 | 108 | $userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($User, "OptionalDisplayableId") 109 | 110 | $authResult = $authContext.AcquireTokenAsync($resourceAppIdURI,$clientId,$redirectUri,$platformParameters,$userId).Result 111 | 112 | # If the accesstoken is valid then create the authentication header 113 | 114 | if($authResult.AccessToken){ 115 | 116 | # Creating header for Authorization token 117 | 118 | $authHeader = @{ 119 | 'Content-Type'='application/json' 120 | 'Authorization'="Bearer " + $authResult.AccessToken 121 | 'ExpiresOn'=$authResult.ExpiresOn 122 | } 123 | 124 | return $authHeader 125 | 126 | } 127 | 128 | else { 129 | 130 | Write-Host 131 | Write-Host "Authorization Access Token is null, please re-run authentication..." -ForegroundColor Red 132 | Write-Host 133 | break 134 | 135 | } 136 | 137 | } 138 | 139 | catch { 140 | 141 | write-host $_.Exception.Message -f Red 142 | write-host $_.Exception.ItemName -f Red 143 | write-host 144 | break 145 | 146 | } 147 | 148 | } 149 |   150 | #################################################### 151 | 152 | function CloneObject($object){ 153 | 154 | $stream = New-Object IO.MemoryStream; 155 | $formatter = New-Object Runtime.Serialization.Formatters.Binary.BinaryFormatter; 156 | $formatter.Serialize($stream, $object); 157 | $stream.Position = 0; 158 | $formatter.Deserialize($stream); 159 | } 160 | 161 | #################################################### 162 | 163 | function WriteHeaders($authToken){ 164 | 165 | foreach ($header in $authToken.GetEnumerator()) 166 | { 167 | if ($header.Name.ToLower() -eq "authorization") 168 | { 169 | continue; 170 | } 171 | 172 | Write-Host -ForegroundColor Gray "$($header.Name): $($header.Value)"; 173 | } 174 | } 175 | 176 | #################################################### 177 | 178 | function MakeGetRequest($collectionPath){ 179 | 180 | $uri = "$baseUrl$collectionPath"; 181 | $request = "GET $uri"; 182 | 183 | if ($logRequestUris) { Write-Host $request; } 184 | if ($logHeaders) { WriteHeaders $authToken; } 185 | 186 | try 187 | { 188 | $response = Invoke-RestMethod $uri -Method Get -Headers $authToken; 189 | $response; 190 | } 191 | catch 192 | { 193 | Write-Host -ForegroundColor Red $request; 194 | Write-Host -ForegroundColor Red $_.Exception.Message; 195 | throw; 196 | } 197 | } 198 | 199 | #################################################### 200 | 201 | function MakePatchRequest($collectionPath, $body){ 202 | 203 | MakeRequest "PATCH" $collectionPath $body; 204 | 205 | } 206 | 207 | #################################################### 208 | 209 | function MakePostRequest($collectionPath, $body){ 210 | 211 | MakeRequest "POST" $collectionPath $body; 212 | 213 | } 214 | 215 | #################################################### 216 | 217 | function MakeRequest($verb, $collectionPath, $body){ 218 | 219 | $uri = "$baseUrl$collectionPath"; 220 | $request = "$verb $uri"; 221 | 222 | $clonedHeaders = CloneObject $authToken; 223 | $clonedHeaders["content-length"] = $body.Length; 224 | $clonedHeaders["content-type"] = "application/json"; 225 | 226 | if ($logRequestUris) { Write-Host $request; } 227 | if ($logHeaders) { WriteHeaders $clonedHeaders; } 228 | if ($logContent) { Write-Host -ForegroundColor Gray $body; } 229 | 230 | try 231 | { 232 | $response = Invoke-RestMethod $uri -Method $verb -Headers $clonedHeaders -Body $body; 233 | $response; 234 | } 235 | catch 236 | { 237 | Write-Host -ForegroundColor Red $request; 238 | Write-Host -ForegroundColor Red $_.Exception.Message; 239 | throw; 240 | } 241 | } 242 | 243 | #################################################### 244 | 245 | function UploadAzureStorageChunk($sasUri, $id, $body){ 246 | 247 | $uri = "$sasUri&comp=block&blockid=$id"; 248 | $request = "PUT $uri"; 249 | 250 | $iso = [System.Text.Encoding]::GetEncoding("iso-8859-1"); 251 | $encodedBody = $iso.GetString($body); 252 | $headers = @{ 253 | "x-ms-blob-type" = "BlockBlob" 254 | }; 255 | 256 | if ($logRequestUris) { Write-Host $request; } 257 | if ($logHeaders) { WriteHeaders $headers; } 258 | 259 | try 260 | { 261 | $response = Invoke-WebRequest $uri -Method Put -Headers $headers -Body $encodedBody; 262 | } 263 | catch 264 | { 265 | Write-Host -ForegroundColor Red $request; 266 | Write-Host -ForegroundColor Red $_.Exception.Message; 267 | throw; 268 | } 269 | 270 | } 271 | 272 | #################################################### 273 | 274 | function FinalizeAzureStorageUpload($sasUri, $ids){ 275 | 276 | $uri = "$sasUri&comp=blocklist"; 277 | $request = "PUT $uri"; 278 | 279 | $xml = ''; 280 | foreach ($id in $ids) 281 | { 282 | $xml += "$id"; 283 | } 284 | $xml += ''; 285 | 286 | if ($logRequestUris) { Write-Host $request; } 287 | if ($logContent) { Write-Host -ForegroundColor Gray $xml; } 288 | 289 | try 290 | { 291 | Invoke-RestMethod $uri -Method Put -Body $xml; 292 | } 293 | catch 294 | { 295 | Write-Host -ForegroundColor Red $request; 296 | Write-Host -ForegroundColor Red $_.Exception.Message; 297 | throw; 298 | } 299 | } 300 | 301 | #################################################### 302 | 303 | function UploadFileToAzureStorage($sasUri, $filepath){ 304 | 305 | # Chunk size = 1 MiB 306 | $chunkSizeInBytes = 1024 * 1024; 307 | 308 | # Read the whole file and find the total chunks. 309 | #[byte[]]$bytes = Get-Content $filepath -Encoding byte; 310 | # Using ReadAllBytes method as the Get-Content used alot of memory on the machine 311 | [byte[]]$bytes = [System.IO.File]::ReadAllBytes($filepath); 312 | $chunks = [Math]::Ceiling($bytes.Length / $chunkSizeInBytes); 313 | 314 | # Upload each chunk. 315 | $ids = @(); 316 | $cc = 1 317 | 318 | for ($chunk = 0; $chunk -lt $chunks; $chunk++) 319 | { 320 | $id = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($chunk.ToString("0000"))); 321 | $ids += $id; 322 | 323 | $start = $chunk * $chunkSizeInBytes; 324 | $end = [Math]::Min($start + $chunkSizeInBytes - 1, $bytes.Length - 1); 325 | $body = $bytes[$start..$end]; 326 | 327 | Write-Progress -Activity "Uploading File to Azure Storage" -status "Uploading chunk $cc of $chunks" ` 328 | -percentComplete ($cc / $chunks*100) 329 | $cc++ 330 | 331 | $uploadResponse = UploadAzureStorageChunk $sasUri $id $body; 332 | 333 | 334 | } 335 | 336 | Write-Progress -Completed -Activity "Uploading File to Azure Storage" 337 | 338 | Write-Host 339 | 340 | # Finalize the upload. 341 | $uploadResponse = FinalizeAzureStorageUpload $sasUri $ids; 342 | } 343 | 344 | #################################################### 345 | 346 | function GenerateKey{ 347 | 348 | try 349 | { 350 | $aes = [System.Security.Cryptography.Aes]::Create(); 351 | $aesProvider = New-Object System.Security.Cryptography.AesCryptoServiceProvider; 352 | $aesProvider.GenerateKey(); 353 | $aesProvider.Key; 354 | } 355 | finally 356 | { 357 | if ($aesProvider -ne $null) { $aesProvider.Dispose(); } 358 | if ($aes -ne $null) { $aes.Dispose(); } 359 | } 360 | } 361 | 362 | #################################################### 363 | 364 | function GenerateIV{ 365 | 366 | try 367 | { 368 | $aes = [System.Security.Cryptography.Aes]::Create(); 369 | $aes.IV; 370 | } 371 | finally 372 | { 373 | if ($aes -ne $null) { $aes.Dispose(); } 374 | } 375 | } 376 | 377 | #################################################### 378 | 379 | function EncryptFileWithIV($sourceFile, $targetFile, $encryptionKey, $hmacKey, $initializationVector){ 380 | 381 | $bufferBlockSize = 1024 * 4; 382 | $computedMac = $null; 383 | 384 | try 385 | { 386 | $aes = [System.Security.Cryptography.Aes]::Create(); 387 | $hmacSha256 = New-Object System.Security.Cryptography.HMACSHA256; 388 | $hmacSha256.Key = $hmacKey; 389 | $hmacLength = $hmacSha256.HashSize / 8; 390 | 391 | $buffer = New-Object byte[] $bufferBlockSize; 392 | $bytesRead = 0; 393 | 394 | $targetStream = [System.IO.File]::Open($targetFile, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::Read); 395 | $targetStream.Write($buffer, 0, $hmacLength + $initializationVector.Length); 396 | 397 | try 398 | { 399 | $encryptor = $aes.CreateEncryptor($encryptionKey, $initializationVector); 400 | $sourceStream = [System.IO.File]::Open($sourceFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read); 401 | $cryptoStream = New-Object System.Security.Cryptography.CryptoStream -ArgumentList @($targetStream, $encryptor, [System.Security.Cryptography.CryptoStreamMode]::Write); 402 | 403 | $targetStream = $null; 404 | while (($bytesRead = $sourceStream.Read($buffer, 0, $bufferBlockSize)) -gt 0) 405 | { 406 | $cryptoStream.Write($buffer, 0, $bytesRead); 407 | $cryptoStream.Flush(); 408 | } 409 | $cryptoStream.FlushFinalBlock(); 410 | } 411 | finally 412 | { 413 | if ($cryptoStream -ne $null) { $cryptoStream.Dispose(); } 414 | if ($sourceStream -ne $null) { $sourceStream.Dispose(); } 415 | if ($encryptor -ne $null) { $encryptor.Dispose(); } 416 | } 417 | 418 | try 419 | { 420 | $finalStream = [System.IO.File]::Open($targetFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::Read) 421 | 422 | $finalStream.Seek($hmacLength, [System.IO.SeekOrigin]::Begin) > $null; 423 | $finalStream.Write($initializationVector, 0, $initializationVector.Length); 424 | $finalStream.Seek($hmacLength, [System.IO.SeekOrigin]::Begin) > $null; 425 | 426 | $hmac = $hmacSha256.ComputeHash($finalStream); 427 | $computedMac = $hmac; 428 | 429 | $finalStream.Seek(0, [System.IO.SeekOrigin]::Begin) > $null; 430 | $finalStream.Write($hmac, 0, $hmac.Length); 431 | } 432 | finally 433 | { 434 | if ($finalStream -ne $null) { $finalStream.Dispose(); } 435 | } 436 | } 437 | finally 438 | { 439 | if ($targetStream -ne $null) { $targetStream.Dispose(); } 440 | if ($aes -ne $null) { $aes.Dispose(); } 441 | } 442 | 443 | $computedMac; 444 | } 445 | 446 | #################################################### 447 | 448 | function EncryptFile($sourceFile, $targetFile){ 449 | 450 | $encryptionKey = GenerateKey; 451 | $hmacKey = GenerateKey; 452 | $initializationVector = GenerateIV; 453 | 454 | # Create the encrypted target file and compute the HMAC value. 455 | $mac = EncryptFileWithIV $sourceFile $targetFile $encryptionKey $hmacKey $initializationVector; 456 | 457 | # Compute the SHA256 hash of the source file and convert the result to bytes. 458 | $fileDigest = (Get-FileHash $sourceFile -Algorithm SHA256).Hash; 459 | $fileDigestBytes = New-Object byte[] ($fileDigest.Length / 2); 460 | for ($i = 0; $i -lt $fileDigest.Length; $i += 2) 461 | { 462 | $fileDigestBytes[$i / 2] = [System.Convert]::ToByte($fileDigest.Substring($i, 2), 16); 463 | } 464 | 465 | # Return an object that will serialize correctly to the file commit Graph API. 466 | $encryptionInfo = @{}; 467 | $encryptionInfo.encryptionKey = [System.Convert]::ToBase64String($encryptionKey); 468 | $encryptionInfo.macKey = [System.Convert]::ToBase64String($hmacKey); 469 | $encryptionInfo.initializationVector = [System.Convert]::ToBase64String($initializationVector); 470 | $encryptionInfo.mac = [System.Convert]::ToBase64String($mac); 471 | $encryptionInfo.profileIdentifier = "ProfileVersion1"; 472 | $encryptionInfo.fileDigest = [System.Convert]::ToBase64String($fileDigestBytes); 473 | $encryptionInfo.fileDigestAlgorithm = "SHA256"; 474 | 475 | $fileEncryptionInfo = @{}; 476 | $fileEncryptionInfo.fileEncryptionInfo = $encryptionInfo; 477 | 478 | $fileEncryptionInfo; 479 | 480 | } 481 | 482 | #################################################### 483 | 484 | function WaitForFileProcessing($fileUri, $stage){ 485 | 486 | $attempts= 60; 487 | $waitTimeInSeconds = 1; 488 | 489 | $successState = "$($stage)Success"; 490 | $pendingState = "$($stage)Pending"; 491 | $failedState = "$($stage)Failed"; 492 | $timedOutState = "$($stage)TimedOut"; 493 | 494 | $file = $null; 495 | while ($attempts -gt 0) 496 | { 497 | $file = MakeGetRequest $fileUri; 498 | 499 | if ($file.uploadState -eq $successState) 500 | { 501 | break; 502 | } 503 | elseif ($file.uploadState -ne $pendingState) 504 | { 505 | throw "File upload state is not success: $($file.uploadState)"; 506 | } 507 | 508 | Start-Sleep $waitTimeInSeconds; 509 | $attempts--; 510 | } 511 | 512 | if ($file -eq $null) 513 | { 514 | throw "File request did not complete in the allotted time."; 515 | } 516 | 517 | $file; 518 | 519 | } 520 | 521 | #################################################### 522 | 523 | function GetAndroidAppBody($displayName, $publisher, $description, $filename, $identityName, $identityVersion, $versionName, $minimumSupportedOperatingSystem){ 524 | 525 | $body = @{ "@odata.type" = "#microsoft.graph.androidLOBApp" }; 526 | $body.categories = @(); 527 | $body.displayName = $displayName; 528 | $body.publisher = $publisher; 529 | $body.description = $description; 530 | $body.fileName = $filename; 531 | $body.identityName = $identityName; 532 | $body.identityVersion = $identityVersion; 533 | 534 | if ($minimumSupportedOperatingSystem -eq $null){ 535 | 536 | $body.minimumSupportedOperatingSystem = @{ "v4_4" = $true }; 537 | 538 | } 539 | 540 | else { 541 | 542 | $body.minimumSupportedOperatingSystem = $minimumSupportedOperatingSystem; 543 | 544 | } 545 | 546 | $body.informationUrl = $null; 547 | $body.isFeatured = $false; 548 | $body.privacyInformationUrl = $null; 549 | $body.developer = ""; 550 | $body.notes = ""; 551 | $body.owner = ""; 552 | $body.versionCode = $identityVersion; 553 | $body.versionName = $versionName; 554 | 555 | $body; 556 | } 557 | 558 | #################################################### 559 | 560 | function GetiOSAppBody($displayName, $publisher, $description, $filename, $bundleId, $identityVersion, $versionNumber, $expirationDateTime){ 561 | 562 | $body = @{ "@odata.type" = "#microsoft.graph.iosLOBApp" }; 563 | $body.applicableDeviceType = @{ "iPad" = $true; "iPhoneAndIPod" = $true } 564 | $body.categories = @(); 565 | $body.displayName = $displayName; 566 | $body.publisher = $publisher; 567 | $body.description = $description; 568 | $body.fileName = $filename; 569 | $body.bundleId = $bundleId; 570 | $body.identityVersion = $identityVersion; 571 | if ($minimumSupportedOperatingSystem -eq $null) 572 | { 573 | $body.minimumSupportedOperatingSystem = @{ "v9_0" = $true }; 574 | } 575 | else 576 | { 577 | $body.minimumSupportedOperatingSystem = $minimumSupportedOperatingSystem; 578 | } 579 | 580 | $body.informationUrl = $null; 581 | $body.isFeatured = $false; 582 | $body.privacyInformationUrl = $null; 583 | $body.developer = ""; 584 | $body.notes = ""; 585 | $body.owner = ""; 586 | $body.expirationDateTime = $expirationDateTime; 587 | $body.versionNumber = $versionNumber; 588 | 589 | $body; 590 | } 591 | 592 | #################################################### 593 | 594 | function GetMSIAppBody($displayName, $publisher, $description, $filename, $identityVersion, $ProductCode){ 595 | 596 | $body = @{ "@odata.type" = "#microsoft.graph.windowsMobileMSI" }; 597 | $body.displayName = $displayName; 598 | $body.publisher = $publisher; 599 | $body.description = $description; 600 | $body.fileName = $filename; 601 | $body.identityVersion = $identityVersion; 602 | $body.informationUrl = $null; 603 | $body.isFeatured = $false; 604 | $body.privacyInformationUrl = $null; 605 | $body.developer = ""; 606 | $body.notes = ""; 607 | $body.owner = ""; 608 | $body.productCode = "$ProductCode"; 609 | $body.productVersion = "$identityVersion"; 610 | 611 | $body; 612 | } 613 | 614 | #################################################### 615 | 616 | function GetAppFileBody($name, $size, $sizeEncrypted, $manifest){ 617 | 618 | $body = @{ "@odata.type" = "#microsoft.graph.mobileAppContentFile" }; 619 | $body.name = $name; 620 | $body.size = $size; 621 | $body.sizeEncrypted = $sizeEncrypted; 622 | $body.manifest = $manifest; 623 | 624 | $body; 625 | } 626 | 627 | #################################################### 628 | 629 | function GetAppCommitBody($contentVersionId, $LobType){ 630 | 631 | $body = @{ "@odata.type" = "#$LobType" }; 632 | $body.committedContentVersion = $contentVersionId; 633 | 634 | $body; 635 | 636 | } 637 | 638 | #################################################### 639 | 640 | Function Get-MSIFileInformation(){ 641 | 642 | # https://www.scconfigmgr.com/2014/08/22/how-to-get-msi-file-information-with-powershell/ 643 | 644 | param( 645 |     [parameter(Mandatory=$true)] 646 |     [ValidateNotNullOrEmpty()] 647 |     [System.IO.FileInfo]$Path, 648 |   649 |     [parameter(Mandatory=$true)] 650 |     [ValidateNotNullOrEmpty()] 651 |     [ValidateSet("ProductCode", "ProductVersion", "ProductName", "Manufacturer", "ProductLanguage", "FullVersion")] 652 |     [string]$Property 653 | ) 654 | Process { 655 | 656 |     try { 657 |         # Read property from MSI database 658 |         $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer 659 |         $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $WindowsInstaller, @($Path.FullName, 0)) 660 |         $Query = "SELECT Value FROM Property WHERE Property = '$($Property)'" 661 |         $View = $MSIDatabase.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $MSIDatabase, ($Query)) 662 |         $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null) 663 |         $Record = $View.GetType().InvokeMember("Fetch", "InvokeMethod", $null, $View, $null) 664 |         $Value = $Record.GetType().InvokeMember("StringData", "GetProperty", $null, $Record, 1) 665 |   666 |         # Commit database and close view 667 |         $MSIDatabase.GetType().InvokeMember("Commit", "InvokeMethod", $null, $MSIDatabase, $null) 668 |         $View.GetType().InvokeMember("Close", "InvokeMethod", $null, $View, $null)           669 |         $MSIDatabase = $null 670 |         $View = $null 671 |   672 |         # Return the value 673 |         return $Value 674 |     } 675 | 676 |     catch { 677 | 678 |      Write-Warning -Message $_.Exception.Message; 679 | break; 680 |      681 | } 682 | 683 | } 684 | 685 | End { 686 |      # Run garbage collection and release ComObject 687 |      [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WindowsInstaller) | Out-Null 688 |      [System.GC]::Collect() 689 | } 690 | 691 | } 692 | 693 | #################################################### 694 | 695 | Function Test-SourceFile(){ 696 | 697 | param 698 | ( 699 |     [parameter(Mandatory=$true)] 700 |     [ValidateNotNullOrEmpty()] 701 | $SourceFile 702 | ) 703 | 704 | try { 705 | 706 | if(!(test-path "$SourceFile")){ 707 | 708 | Write-Host "Source File '$sourceFile' doesn't exist..." -ForegroundColor Red 709 | throw 710 | 711 | } 712 | 713 | } 714 | 715 | catch { 716 | 717 | Write-Host -ForegroundColor Red $_.Exception.Message; 718 | Write-Host 719 | break; 720 | 721 | } 722 | 723 | } 724 | 725 | #################################################### 726 | 727 | Function Get-ApkInformation { 728 | 729 | <# 730 | .SYNOPSIS 731 | This function is used to get information about an Android APK file using the Android SDK - https://developer.android.com/studio/index.html 732 | .DESCRIPTION 733 | This function is used to get information about an Android APK file using the Android SDK - https://developer.android.com/studio/index.html 734 | .EXAMPLE 735 | Get-ApkInformation -sourceFile c:\source\application.apk 736 | Function will return two object, object[0] is the identityName and object[1] is the identityVersion 737 | .NOTES 738 | NAME: Get-ApkInformation 739 | #> 740 | 741 | [cmdletbinding()] 742 | 743 | param 744 | ( 745 | [Parameter(Mandatory=$true)] 746 | $sourceFile, 747 | [Parameter(Mandatory=$true)] 748 | $AndroidSDK 749 | ) 750 | 751 | if(!(test-path $AndroidSDK)){ 752 | 753 | Write-Host 754 | Write-Host "Android SDK isn't installed..." -ForegroundColor Red 755 | Write-Host "Please install Android Studio and install the SDK from https://developer.android.com/studio/index.html" 756 | Write-Host 757 | break 758 | 759 | } 760 | 761 | if(((gci $AndroidSDK | select name).Name).count -gt 1){ 762 | 763 | $BuildTools = ((gci $AndroidSDK | select name).Name | sort -Descending)[0] 764 | 765 | } 766 | 767 | else { 768 | 769 | $BuildTools = ((gci $AndroidSDK | select name).Name) 770 | 771 | } 772 | 773 | $aaptPath = "$AndroidSDK\$BuildTools" 774 | 775 | [ScriptBlock]$command = { 776 | 777 | cmd.exe /c "$aaptPath\aapt.exe" dump badging "$sourceFile" 778 | 779 | } 780 | 781 | $aaptRun = Invoke-Command -ScriptBlock $command 782 | 783 | $AndroidPackage = $aaptRun | ? { ($_).startswith("package") } 784 | 785 | $PackageInfo = $AndroidPackage.split(" ") 786 | 787 | $PackageInfo[1].Split("'")[1] 788 | $PackageInfo[2].Split("'")[1] 789 | $PackageInfo[3].Split("'")[1] 790 | 791 | if ($logContent) { Write-Host -ForegroundColor Gray $PackageInfo[1].Split("'")[1]; } 792 | if ($logContent) { Write-Host -ForegroundColor Gray $PackageInfo[2].Split("'")[1]; } 793 | if ($logContent) { Write-Host -ForegroundColor Gray $PackageInfo[3].Split("'")[1]; } 794 | 795 | } 796 | 797 | #################################################### 798 | 799 | function Upload-AndroidLob(){ 800 | 801 | <# 802 | .SYNOPSIS 803 | This function is used to upload an Android LOB Application to the Intune Service 804 | .DESCRIPTION 805 | This function is used to upload an Android LOB Application to the Intune Service 806 | .EXAMPLE 807 | Upload-AndroidLob -sourceFile "C:\Software\package.apk" -publisher "Publisher Name" -description "Description of Application" -identityName "com.package" -identityVersion "1" -versionName "10.1.1" 808 | This example uses all parameters required to add an Android Application into the Intune Service 809 | Upload-AndroidLob -sourceFile "C:\Software\package.apk" -publisher "Publisher Name" -description "Description of Application" 810 | This example uses the required parameters to add an Android Application into the Intune Service. This example will require the Android SDK to get identityName and identityVersion 811 | .NOTES 812 | NAME: Upload-AndroidLOB 813 | #> 814 | 815 | [cmdletbinding()] 816 | 817 | param 818 | ( 819 |     [parameter(Mandatory=$true,Position=1)] 820 |     [ValidateNotNullOrEmpty()] 821 | [string]$SourceFile, 822 | 823 |     [parameter(Mandatory=$false)] 824 | [string]$displayName, 825 | 826 | [parameter(Mandatory=$true,Position=2)] 827 |     [ValidateNotNullOrEmpty()] 828 | [string]$publisher, 829 | 830 | [parameter(Mandatory=$true,Position=3)] 831 |     [ValidateNotNullOrEmpty()] 832 | [string]$description, 833 | 834 | [parameter(Mandatory=$false)] 835 | [string]$identityName, 836 | 837 | [parameter(Mandatory=$false)] 838 | [string]$identityVersion, 839 | 840 | [parameter(Mandatory=$false)] 841 | [string]$versionName 842 | 843 | ) 844 | 845 | try 846 | { 847 | 848 | $LOBType = "microsoft.graph.androidLOBApp" 849 | 850 | Write-Host "Testing if SourceFile '$SourceFile' Path is valid..." -ForegroundColor Yellow 851 | Test-SourceFile "$SourceFile" 852 | 853 | if(!$identityName){ 854 | 855 | Write-Host 856 | Write-Host "Opening APK file to get identityName to pass to the service..." -ForegroundColor Yellow 857 | 858 | $APKInformation = Get-ApkInformation -AndroidSDK $AndroidSDKLocation -sourceFile "$SourceFile" 859 | 860 | $identityName = $APKInformation[0] 861 | 862 | } 863 | 864 | if(!$identityVersion){ 865 | 866 | Write-Host 867 | Write-Host "Opening APK file to get identityVersion to pass to the service..." -ForegroundColor Yellow 868 | 869 | $APKInformation = Get-ApkInformation -AndroidSDK $AndroidSDKLocation -sourceFile "$SourceFile" 870 | 871 | $identityVersion = $APKInformation[1] 872 | 873 | } 874 | 875 | if(!$versionName){ 876 | 877 | Write-Host 878 | Write-Host "Opening APK file to get versionName to pass to the service..." -ForegroundColor Yellow 879 | 880 | $APKInformation = Get-ApkInformation -AndroidSDK $AndroidSDKLocation -sourceFile "$SourceFile" 881 | 882 | $versionName = $APKInformation[2] 883 | 884 | } 885 | 886 | 887 | # Creating temp file name from Source File path 888 | $tempFile = [System.IO.Path]::GetDirectoryName("$SourceFile") + "\" + [System.IO.Path]::GetFileNameWithoutExtension("$SourceFile") + "_temp.bin" 889 | 890 | # Creating filename variable from Source File Path 891 | $filename = [System.IO.Path]::GetFileName("$SourceFile") 892 | 893 | if(!($displayName)){ 894 | 895 | $displayName = $filename 896 | 897 | } 898 | 899 | # Create a new Android LOB app. 900 | Write-Host 901 | Write-Host "Creating JSON data to pass to the service..." -ForegroundColor Yellow 902 | $mobileAppBody = GetAndroidAppBody "$displayName" "$Publisher" "$Description" "$filename" "$identityName" "$identityVersion" "$versionName"; 903 | 904 | Write-Host 905 | Write-Host "Creating application in Intune..." -ForegroundColor Yellow 906 | $mobileApp = MakePostRequest "mobileApps" ($mobileAppBody | ConvertTo-Json); 907 | 908 | # Get the content version for the new app (this will always be 1 until the new app is committed). 909 | Write-Host 910 | Write-Host "Creating Content Version in the service for the application..." -ForegroundColor Yellow 911 | $appId = $mobileApp.id; 912 | $contentVersionUri = "mobileApps/$appId/$LOBType/contentVersions"; 913 | $contentVersion = MakePostRequest $contentVersionUri "{}"; 914 | 915 | # Encrypt file and Get File Information 916 | Write-Host 917 | Write-Host "Ecrypting the file '$SourceFile'..." -ForegroundColor Yellow 918 | $encryptionInfo = EncryptFile "$sourceFile" "$tempFile"; 919 | $Size = (Get-Item "$sourceFile").Length 920 | $EncrySize = (Get-Item "$tempFile").Length 921 | 922 | Write-Host 923 | Write-Host "Creating the manifest file used to install the application on the device..." -ForegroundColor Yellow 924 | 925 | [xml]$manifestXML = 'com.leadapps.android.radio.ncp101.0.5.4A_Online_Radio_1.0.5.4.apk3' 926 | 927 | $manifestXML.AndroidManifestProperties.Package = "$identityName" # com.application.test 928 | $manifestXML.AndroidManifestProperties.PackageVersionCode = "$identityVersion" # 10 929 | $manifestXML.AndroidManifestProperties.PackageVersionName = "$identityVersion" # 1.0.5.4 930 | $manifestXML.AndroidManifestProperties.ApplicationName = "$filename" # name.apk 931 | 932 | $manifestXML_Output = $manifestXML.OuterXml.ToString() 933 | 934 | $Bytes = [System.Text.Encoding]::ASCII.GetBytes($manifestXML_Output) 935 | $EncodedText =[Convert]::ToBase64String($Bytes) 936 | 937 | # Create a new file for the app. 938 | Write-Host 939 | Write-Host "Creating a new file entry in Azure for the upload..." -ForegroundColor Yellow 940 | $contentVersionId = $contentVersion.id; 941 | $fileBody = GetAppFileBody "$filename" $Size $EncrySize "$EncodedText"; 942 | $filesUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files"; 943 | $file = MakePostRequest $filesUri ($fileBody | ConvertTo-Json); 944 | 945 | # Wait for the service to process the new file request. 946 | Write-Host 947 | Write-Host "Waiting for the file entry URI to be created..." -ForegroundColor Yellow 948 | $fileId = $file.id; 949 | $fileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId"; 950 | $file = WaitForFileProcessing $fileUri "AzureStorageUriRequest"; 951 | 952 | # Upload the content to Azure Storage. 953 | Write-Host 954 | Write-Host "Uploading file to Azure Storage URI..." -ForegroundColor Yellow 955 | 956 | $sasUri = $file.azureStorageUri; 957 | UploadFileToAzureStorage $file.azureStorageUri $tempFile; 958 | 959 | # Commit the file. 960 | Write-Host 961 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 962 | $commitFileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId/commit"; 963 | MakePostRequest $commitFileUri ($encryptionInfo | ConvertTo-Json); 964 | 965 | # Wait for the service to process the commit file request. 966 | Write-Host 967 | Write-Host "Waiting for the service to process the commit file request..." -ForegroundColor Yellow 968 | $file = WaitForFileProcessing $fileUri "CommitFile"; 969 | 970 | # Commit the app. 971 | Write-Host 972 | Write-Host "Committing the application to the Intune Service..." -ForegroundColor Yellow 973 | $commitAppUri = "mobileApps/$appId"; 974 | $commitAppBody = GetAppCommitBody $contentVersionId $LOBType; 975 | MakePatchRequest $commitAppUri ($commitAppBody | ConvertTo-Json); 976 | 977 | Write-Host "Removing Temporary file '$tempFile'..." -f Gray 978 | Remove-Item -Path "$tempFile" -Force 979 | Write-Host 980 | 981 | Write-Host "Sleeping for $sleep seconds to allow patch completion..." -f Magenta 982 | Start-Sleep $sleep 983 | Write-Host 984 | 985 | } 986 | catch 987 | { 988 | Write-Host ""; 989 | Write-Host -ForegroundColor Red "Aborting with exception: $($_.Exception.ToString())"; 990 | } 991 | } 992 | 993 | #################################################### 994 | 995 | function Upload-iOSLob(){ 996 | 997 | <# 998 | .SYNOPSIS 999 | This function is used to upload an iOS LOB Application to the Intune Service 1000 | .DESCRIPTION 1001 | This function is used to upload an iOS LOB Application to the Intune Service 1002 | .EXAMPLE 1003 | Upload-iOSLob -sourceFile "C:\Software\package.ipa" -displayName "package.ipa" -publisher "Publisher Name" -description "Description of Application" -bundleId "com.package" -identityVersion "1" -versionNumber "3.0.0" -expirationDateTime "2018-02-14T20:53:52Z" 1004 | This example uses all parameters required to add an iOS Application into the Intune Service 1005 | .NOTES 1006 | NAME: Upload-iOSLOB 1007 | #> 1008 | 1009 | [cmdletbinding()] 1010 | 1011 | param 1012 | ( 1013 |     [parameter(Mandatory=$true,Position=1)] 1014 |     [ValidateNotNullOrEmpty()] 1015 | [string]$SourceFile, 1016 | 1017 |     [parameter(Mandatory=$true,Position=2)] 1018 |     [ValidateNotNullOrEmpty()] 1019 | [string]$displayName, 1020 | 1021 | [parameter(Mandatory=$true,Position=3)] 1022 |     [ValidateNotNullOrEmpty()] 1023 | [string]$publisher, 1024 | 1025 | [parameter(Mandatory=$true,Position=4)] 1026 |     [ValidateNotNullOrEmpty()] 1027 | [string]$description, 1028 | 1029 | [parameter(Mandatory=$true,Position=5)] 1030 |     [ValidateNotNullOrEmpty()] 1031 | [string]$bundleId, 1032 | 1033 | [parameter(Mandatory=$true,Position=6)] 1034 |     [ValidateNotNullOrEmpty()] 1035 | [string]$identityVersion, 1036 | 1037 | [parameter(Mandatory=$true,Position=7)] 1038 |     [ValidateNotNullOrEmpty()] 1039 | [string]$versionNumber, 1040 | 1041 | [parameter(Mandatory=$true,Position=8)] 1042 |     [ValidateNotNullOrEmpty()] 1043 | [string]$expirationDateTime 1044 | ) 1045 | 1046 | try 1047 | { 1048 | 1049 | $LOBType = "microsoft.graph.iosLOBApp" 1050 | 1051 | Write-Host "Testing if SourceFile '$SourceFile' Path is valid..." -ForegroundColor Yellow 1052 | Test-SourceFile "$SourceFile" 1053 | 1054 | # Checking expirationdatetime of SourceFile to check if it can be uploaded 1055 | [datetimeoffset]$Expiration = $expirationDateTime 1056 | 1057 | $Date = get-date 1058 | 1059 | if($Expiration -lt $Date){ 1060 | 1061 | Write-Error "$SourceFile has expired Follow the guidelines provided by Apple to extend the expiration date, then try adding the app again" 1062 | throw 1063 | 1064 | } 1065 | 1066 | # Creating temp file name from Source File path 1067 | $tempFile = [System.IO.Path]::GetDirectoryName("$SourceFile") + "\" + [System.IO.Path]::GetFileNameWithoutExtension("$SourceFile") + "_temp.bin" 1068 | 1069 | # Creating filename variable from Source File Path 1070 | $filename = [System.IO.Path]::GetFileName("$SourceFile") 1071 | 1072 | # Create a new iOS LOB app. 1073 | Write-Host 1074 | Write-Host "Creating JSON data to pass to the service..." -ForegroundColor Yellow 1075 | $mobileAppBody = GetiOSAppBody "$displayName" "$Publisher" "$Description" "$filename" "$bundleId" "$identityVersion" "$versionNumber" "$expirationDateTime"; 1076 | 1077 | Write-Host 1078 | Write-Host "Creating application in Intune..." -ForegroundColor Yellow 1079 | 1080 | $mobileApp = MakePostRequest "mobileApps" ($mobileAppBody | ConvertTo-Json); 1081 | 1082 | # Get the content version for the new app (this will always be 1 until the new app is committed). 1083 | Write-Host 1084 | Write-Host "Creating Content Version in the service for the application..." -ForegroundColor Yellow 1085 | $appId = $mobileApp.id; 1086 | $contentVersionUri = "mobileApps/$appId/$LOBType/contentVersions"; 1087 | $contentVersion = MakePostRequest $contentVersionUri "{}"; 1088 | 1089 | # Encrypt file and Get File Information 1090 | Write-Host 1091 | Write-Host "Ecrypting the file '$SourceFile'..." -ForegroundColor Yellow 1092 | $encryptionInfo = EncryptFile $sourceFile $tempFile; 1093 | $Size = (Get-Item "$sourceFile").Length 1094 | $EncrySize = (Get-Item "$tempFile").Length 1095 | 1096 | Write-Host 1097 | Write-Host "Creating the manifest file used to install the application on the device..." -ForegroundColor Yellow 1098 | 1099 | [string]$manifestXML = 'itemsassetskindsoftware-packageurl{UrlPlaceHolder}metadataAppRestrictionPolicyTemplate http://management.microsoft.com/PolicyTemplates/AppRestrictions/iOS/v1AppRestrictionTechnologyWindows Intune Application Restrictions Technology for iOSIntuneMAMVersionCFBundleSupportedPlatformsiPhoneOSMinimumOSVersion9.0bundle-identifierbundleidbundle-versionbundleversionkindsoftwaresubtitleLaunchMeSubtitletitlebundletitle' 1100 | 1101 | $manifestXML = $manifestXML.replace("bundleid","$bundleId") 1102 | $manifestXML = $manifestXML.replace("bundleversion","$identityVersion") 1103 | $manifestXML = $manifestXML.replace("bundletitle","$displayName") 1104 | 1105 | $Bytes = [System.Text.Encoding]::ASCII.GetBytes($manifestXML) 1106 | $EncodedText =[Convert]::ToBase64String($Bytes) 1107 | 1108 | # Create a new file for the app. 1109 | Write-Host 1110 | Write-Host "Creating a new file entry in Azure for the upload..." -ForegroundColor Yellow 1111 | $contentVersionId = $contentVersion.id; 1112 | $fileBody = GetAppFileBody "$filename" $Size $EncrySize "$EncodedText"; 1113 | $filesUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files"; 1114 | $file = MakePostRequest $filesUri ($fileBody | ConvertTo-Json); 1115 | 1116 | # Wait for the service to process the new file request. 1117 | Write-Host 1118 | Write-Host "Waiting for the file entry URI to be created..." -ForegroundColor Yellow 1119 | $fileId = $file.id; 1120 | $fileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId"; 1121 | $file = WaitForFileProcessing $fileUri "AzureStorageUriRequest"; 1122 | 1123 | # Upload the content to Azure Storage. 1124 | Write-Host 1125 | Write-Host "Uploading file to Azure Storage..." -f Yellow 1126 | 1127 | $sasUri = $file.azureStorageUri; 1128 | UploadFileToAzureStorage $file.azureStorageUri $tempFile; 1129 | 1130 | # Commit the file. 1131 | Write-Host 1132 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 1133 | $commitFileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId/commit"; 1134 | MakePostRequest $commitFileUri ($encryptionInfo | ConvertTo-Json); 1135 | 1136 | # Wait for the service to process the commit file request. 1137 | Write-Host 1138 | Write-Host "Waiting for the service to process the commit file request..." -ForegroundColor Yellow 1139 | $file = WaitForFileProcessing $fileUri "CommitFile"; 1140 | 1141 | # Commit the app. 1142 | Write-Host 1143 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 1144 | $commitAppUri = "mobileApps/$appId"; 1145 | $commitAppBody = GetAppCommitBody $contentVersionId $LOBType; 1146 | MakePatchRequest $commitAppUri ($commitAppBody | ConvertTo-Json); 1147 | 1148 | Write-Host "Removing Temporary file '$tempFile'..." -f Gray 1149 | Remove-Item -Path "$tempFile" -Force 1150 | Write-Host 1151 | 1152 | Write-Host "Sleeping for $sleep seconds to allow patch completion..." -f Magenta 1153 | Start-Sleep $sleep 1154 | Write-Host 1155 | 1156 | } 1157 | catch 1158 | { 1159 | Write-Host ""; 1160 | Write-Host -ForegroundColor Red "Aborting with exception: $($_.Exception.ToString())"; 1161 | } 1162 | } 1163 | 1164 | #################################################### 1165 | 1166 | function Upload-MSILob(){ 1167 | 1168 | <# 1169 | .SYNOPSIS 1170 | This function is used to upload an MSI LOB Application to the Intune Service 1171 | .DESCRIPTION 1172 | This function is used to upload an MSI LOB Application to the Intune Service 1173 | .EXAMPLE 1174 | Upload-MSILob "C:\Software\Orca\Orca.Msi" -publisher "Microsoft" -description "Orca" 1175 | This example uses all parameters required to add an MSI Application into the Intune Service 1176 | .NOTES 1177 | NAME: Upload-MSILOB 1178 | #> 1179 | 1180 | [cmdletbinding()] 1181 | 1182 | param 1183 | ( 1184 |     [parameter(Mandatory=$true,Position=1)] 1185 |     [ValidateNotNullOrEmpty()] 1186 | [string]$SourceFile, 1187 | 1188 | [parameter(Mandatory=$true,Position=2)] 1189 |     [ValidateNotNullOrEmpty()] 1190 | [string]$publisher, 1191 | 1192 | [parameter(Mandatory=$true,Position=3)] 1193 |     [ValidateNotNullOrEmpty()] 1194 | [string]$description 1195 | ) 1196 | 1197 | try { 1198 | 1199 | $LOBType = "microsoft.graph.windowsMobileMSI" 1200 | 1201 | Write-Host "Testing if SourceFile '$SourceFile' Path is valid..." -ForegroundColor Yellow 1202 | Test-SourceFile "$SourceFile" 1203 | 1204 | $MSIPath = "$SourceFile" 1205 | 1206 | # Creating temp file name from Source File path 1207 | $tempFile = [System.IO.Path]::GetDirectoryName("$SourceFile") + "\" + [System.IO.Path]::GetFileNameWithoutExtension("$SourceFile") + "_temp.bin" 1208 | 1209 | Write-Host 1210 | Write-Host "Creating JSON data to pass to the service..." -ForegroundColor Yellow 1211 | 1212 | $FileName = [System.IO.Path]::GetFileName("$MSIPath") 1213 | 1214 | $PN = (Get-MSIFileInformation -Path "$MSIPath" -Property ProductName | Out-String).trimend() 1215 | $PC = (Get-MSIFileInformation -Path "$MSIPath" -Property ProductCode | Out-String).trimend() 1216 | $PV = (Get-MSIFileInformation -Path "$MSIPath" -Property ProductVersion | Out-String).trimend() 1217 | $PL = (Get-MSIFileInformation -Path "$MSIPath" -Property ProductLanguage | Out-String).trimend() 1218 | 1219 | # Create a new MSI LOB app. 1220 | $mobileAppBody = GetMSIAppBody -displayName "$PN" -publisher "$publisher" -description "$description" -filename "$FileName" -identityVersion "$PV" -ProductCode "$PC" 1221 | 1222 | Write-Host 1223 | Write-Host "Creating application in Intune..." -ForegroundColor Yellow 1224 | $mobileApp = MakePostRequest "mobileApps" ($mobileAppBody | ConvertTo-Json); 1225 | 1226 | # Get the content version for the new app (this will always be 1 until the new app is committed). 1227 | Write-Host 1228 | Write-Host "Creating Content Version in the service for the application..." -ForegroundColor Yellow 1229 | $appId = $mobileApp.id; 1230 | $contentVersionUri = "mobileApps/$appId/$LOBType/contentVersions"; 1231 | $contentVersion = MakePostRequest $contentVersionUri "{}"; 1232 | 1233 | # Encrypt file and Get File Information 1234 | Write-Host 1235 | Write-Host "Ecrypting the file '$SourceFile'..." -ForegroundColor Yellow 1236 | $encryptionInfo = EncryptFile $sourceFile $tempFile; 1237 | $Size = (Get-Item "$sourceFile").Length 1238 | $EncrySize = (Get-Item "$tempFile").Length 1239 | 1240 | Write-Host 1241 | Write-Host "Creating the manifest file used to install the application on the device..." -ForegroundColor Yellow 1242 | 1243 | [xml]$manifestXML = '' 1244 | 1245 | $manifestXML.MobileMsiData.MsiUpgradeCode = "$PC" 1246 | 1247 | $manifestXML_Output = $manifestXML.OuterXml.ToString() 1248 | 1249 | $Bytes = [System.Text.Encoding]::ASCII.GetBytes($manifestXML_Output) 1250 | $EncodedText =[Convert]::ToBase64String($Bytes) 1251 | 1252 | # Create a new file for the app. 1253 | Write-Host 1254 | Write-Host "Creating a new file entry in Azure for the upload..." -ForegroundColor Yellow 1255 | $contentVersionId = $contentVersion.id; 1256 | $fileBody = GetAppFileBody "$FileName" $Size $EncrySize "$EncodedText"; 1257 | $filesUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files"; 1258 | $file = MakePostRequest $filesUri ($fileBody | ConvertTo-Json); 1259 | 1260 | # Wait for the service to process the new file request. 1261 | Write-Host 1262 | Write-Host "Waiting for the file entry URI to be created..." -ForegroundColor Yellow 1263 | $fileId = $file.id; 1264 | $fileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId"; 1265 | $file = WaitForFileProcessing $fileUri "AzureStorageUriRequest"; 1266 | 1267 | # Upload the content to Azure Storage. 1268 | Write-Host 1269 | Write-Host "Uploading file to Azure Storage..." -f Yellow 1270 | 1271 | $sasUri = $file.azureStorageUri; 1272 | UploadFileToAzureStorage $file.azureStorageUri $tempFile; 1273 | 1274 | # Commit the file. 1275 | Write-Host 1276 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 1277 | $commitFileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId/commit"; 1278 | MakePostRequest $commitFileUri ($encryptionInfo | ConvertTo-Json); 1279 | 1280 | # Wait for the service to process the commit file request. 1281 | Write-Host 1282 | Write-Host "Waiting for the service to process the commit file request..." -ForegroundColor Yellow 1283 | $file = WaitForFileProcessing $fileUri "CommitFile"; 1284 | 1285 | # Commit the app. 1286 | Write-Host 1287 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 1288 | $commitAppUri = "mobileApps/$appId"; 1289 | $commitAppBody = GetAppCommitBody $contentVersionId $LOBType; 1290 | MakePatchRequest $commitAppUri ($commitAppBody | ConvertTo-Json); 1291 | 1292 | Write-Host "Removing Temporary file '$tempFile'..." -f Gray 1293 | Remove-Item -Path "$tempFile" -Force 1294 | Write-Host 1295 | 1296 | Write-Host "Sleeping for $sleep seconds to allow patch completion..." -f Magenta 1297 | Start-Sleep $sleep 1298 | Write-Host 1299 | 1300 | } 1301 | 1302 | catch { 1303 | 1304 | Write-Host ""; 1305 | Write-Host -ForegroundColor Red "Aborting with exception: $($_.Exception.ToString())"; 1306 | 1307 | } 1308 | 1309 | } 1310 | 1311 | #################################################### 1312 | 1313 | #region Authentication 1314 | 1315 | write-host 1316 | 1317 | # Checking if authToken exists before running authentication 1318 | if($global:authToken){ 1319 | 1320 | # Setting DateTime to Universal time to work in all timezones 1321 | $DateTime = (Get-Date).ToUniversalTime() 1322 | 1323 | # If the authToken exists checking when it expires 1324 | $TokenExpires = ($authToken.ExpiresOn.datetime - $DateTime).Minutes 1325 | 1326 | if($TokenExpires -le 0){ 1327 | 1328 | write-host "Authentication Token expired" $TokenExpires "minutes ago" -ForegroundColor Yellow 1329 | write-host 1330 | 1331 | # Defining Azure AD tenant name, this is the name of your Azure Active Directory (do not use the verified domain name) 1332 | 1333 | if($User -eq $null -or $User -eq ""){ 1334 | 1335 | $User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication" 1336 | Write-Host 1337 | 1338 | } 1339 | 1340 | $global:authToken = Get-AuthToken -User $User 1341 | 1342 | } 1343 | } 1344 | 1345 | # Authentication doesn't exist, calling Get-AuthToken function 1346 | 1347 | else { 1348 | 1349 | if($User -eq $null -or $User -eq ""){ 1350 | 1351 | $User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication" 1352 | Write-Host 1353 | 1354 | } 1355 | 1356 | # Getting the authorization token 1357 | $global:authToken = Get-AuthToken -User $User 1358 | 1359 | } 1360 | 1361 | #endregion 1362 | 1363 | #################################################### 1364 | 1365 | # Path to Android SDK Location to find aapt.exe tool if you don't specify identityName or identityVersion 1366 | # Note: Don't specify direct location to build folder number, just to the build-tools folder as the script will find the latest SDK installed 1367 | $AndroidSDKLocation = "C:\AndroidSDK\build-tools" 1368 | 1369 | $baseUrl = "https://graph.microsoft.com/beta/deviceAppManagement/" 1370 | 1371 | $logRequestUris = $true; 1372 | $logHeaders = $false; 1373 | $logContent = $true; 1374 | 1375 | $sleep = 30 1376 | 1377 | #################################################### 1378 | 1379 | #### MSI Install microsoft Teams 64 bit 1380 | $output = "$PSScriptRoot\teams64bit.msi" 1381 | Start-BitsTransfer -Source http://aka.ms/teams64bitmsi -Destination $output 1382 | Upload-MSILob "$output" -publisher "Microsoft" -description "Microsoft Teams 64Bit" 1383 | 1384 | #### MSI Install microsoft Teams 32 bit 1385 | $output = "$PSScriptRoot\teams32bit.msi" 1386 | Start-BitsTransfer -Source http://aka.ms/teams32bitmsi -Destination $output 1387 | Upload-MSILob "$output" -publisher "Microsoft" -description "Microsoft Teams 32Bit" 1388 | 1389 | -------------------------------------------------------------------------------- /Application_LOB_Add - Google.ps1: -------------------------------------------------------------------------------- 1 | 2 | <# 3 | 4 | .COPYRIGHT 5 | Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. 6 | See LICENSE in the project root for license information. 7 | 8 | #> 9 | 10 | #################################################### 11 | 12 | function Get-AuthToken { 13 | 14 | <# 15 | .SYNOPSIS 16 | This function is used to authenticate with the Graph API REST interface 17 | .DESCRIPTION 18 | The function authenticate with the Graph API Interface with the tenant name 19 | .EXAMPLE 20 | Get-AuthToken 21 | Authenticates you with the Graph API interface 22 | .NOTES 23 | NAME: Get-AuthToken 24 | #> 25 | 26 | [cmdletbinding()] 27 | 28 | param 29 | ( 30 | [Parameter(Mandatory=$true)] 31 | $User 32 | ) 33 | 34 | $userUpn = New-Object "System.Net.Mail.MailAddress" -ArgumentList $User 35 | 36 | $tenant = $userUpn.Host 37 | 38 | Write-Host "Checking for AzureAD module..." 39 | 40 | $AadModule = Get-Module -Name "AzureAD" -ListAvailable 41 | 42 | if ($AadModule -eq $null) { 43 | 44 | Write-Host "AzureAD PowerShell module not found, looking for AzureADPreview" 45 | $AadModule = Get-Module -Name "AzureADPreview" -ListAvailable 46 | 47 | } 48 | 49 | if ($AadModule -eq $null) { 50 | write-host 51 | write-host "AzureAD Powershell module not installed..." -f Red 52 | write-host "Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt" -f Yellow 53 | write-host "Script can't continue..." -f Red 54 | write-host 55 | exit 56 | } 57 | 58 | # Getting path to ActiveDirectory Assemblies 59 | # If the module count is greater than 1 find the latest version 60 | 61 | if($AadModule.count -gt 1){ 62 | 63 | $Latest_Version = ($AadModule | select version | Sort-Object)[-1] 64 | 65 | $aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version } 66 | 67 | # Checking if there are multiple versions of the same module found 68 | 69 | if($AadModule.count -gt 1){ 70 | 71 | $aadModule = $AadModule | select -Unique 72 | 73 | } 74 | 75 | $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" 76 | $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll" 77 | 78 | } 79 | 80 | else { 81 | 82 | $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" 83 | $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll" 84 | 85 | } 86 | 87 | [System.Reflection.Assembly]::LoadFrom($adal) | Out-Null 88 | 89 | [System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null 90 | 91 | $clientId = "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" 92 | 93 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 94 | 95 | $resourceAppIdURI = "https://graph.microsoft.com" 96 | 97 | $authority = "https://login.microsoftonline.com/$Tenant" 98 | 99 | try { 100 | 101 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 102 | 103 | # https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx 104 | # Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession 105 | 106 | $platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto" 107 | 108 | $userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($User, "OptionalDisplayableId") 109 | 110 | $authResult = $authContext.AcquireTokenAsync($resourceAppIdURI,$clientId,$redirectUri,$platformParameters,$userId).Result 111 | 112 | # If the accesstoken is valid then create the authentication header 113 | 114 | if($authResult.AccessToken){ 115 | 116 | # Creating header for Authorization token 117 | 118 | $authHeader = @{ 119 | 'Content-Type'='application/json' 120 | 'Authorization'="Bearer " + $authResult.AccessToken 121 | 'ExpiresOn'=$authResult.ExpiresOn 122 | } 123 | 124 | return $authHeader 125 | 126 | } 127 | 128 | else { 129 | 130 | Write-Host 131 | Write-Host "Authorization Access Token is null, please re-run authentication..." -ForegroundColor Red 132 | Write-Host 133 | break 134 | 135 | } 136 | 137 | } 138 | 139 | catch { 140 | 141 | write-host $_.Exception.Message -f Red 142 | write-host $_.Exception.ItemName -f Red 143 | write-host 144 | break 145 | 146 | } 147 | 148 | } 149 |   150 | #################################################### 151 | 152 | function CloneObject($object){ 153 | 154 | $stream = New-Object IO.MemoryStream; 155 | $formatter = New-Object Runtime.Serialization.Formatters.Binary.BinaryFormatter; 156 | $formatter.Serialize($stream, $object); 157 | $stream.Position = 0; 158 | $formatter.Deserialize($stream); 159 | } 160 | 161 | #################################################### 162 | 163 | function WriteHeaders($authToken){ 164 | 165 | foreach ($header in $authToken.GetEnumerator()) 166 | { 167 | if ($header.Name.ToLower() -eq "authorization") 168 | { 169 | continue; 170 | } 171 | 172 | Write-Host -ForegroundColor Gray "$($header.Name): $($header.Value)"; 173 | } 174 | } 175 | 176 | #################################################### 177 | 178 | function MakeGetRequest($collectionPath){ 179 | 180 | $uri = "$baseUrl$collectionPath"; 181 | $request = "GET $uri"; 182 | 183 | if ($logRequestUris) { Write-Host $request; } 184 | if ($logHeaders) { WriteHeaders $authToken; } 185 | 186 | try 187 | { 188 | $response = Invoke-RestMethod $uri -Method Get -Headers $authToken; 189 | $response; 190 | } 191 | catch 192 | { 193 | Write-Host -ForegroundColor Red $request; 194 | Write-Host -ForegroundColor Red $_.Exception.Message; 195 | throw; 196 | } 197 | } 198 | 199 | #################################################### 200 | 201 | function MakePatchRequest($collectionPath, $body){ 202 | 203 | MakeRequest "PATCH" $collectionPath $body; 204 | 205 | } 206 | 207 | #################################################### 208 | 209 | function MakePostRequest($collectionPath, $body){ 210 | 211 | MakeRequest "POST" $collectionPath $body; 212 | 213 | } 214 | 215 | #################################################### 216 | 217 | function MakeRequest($verb, $collectionPath, $body){ 218 | 219 | $uri = "$baseUrl$collectionPath"; 220 | $request = "$verb $uri"; 221 | 222 | $clonedHeaders = CloneObject $authToken; 223 | $clonedHeaders["content-length"] = $body.Length; 224 | $clonedHeaders["content-type"] = "application/json"; 225 | 226 | if ($logRequestUris) { Write-Host $request; } 227 | if ($logHeaders) { WriteHeaders $clonedHeaders; } 228 | if ($logContent) { Write-Host -ForegroundColor Gray $body; } 229 | 230 | try 231 | { 232 | $response = Invoke-RestMethod $uri -Method $verb -Headers $clonedHeaders -Body $body; 233 | $response; 234 | } 235 | catch 236 | { 237 | Write-Host -ForegroundColor Red $request; 238 | Write-Host -ForegroundColor Red $_.Exception.Message; 239 | throw; 240 | } 241 | } 242 | 243 | #################################################### 244 | 245 | function UploadAzureStorageChunk($sasUri, $id, $body){ 246 | 247 | $uri = "$sasUri&comp=block&blockid=$id"; 248 | $request = "PUT $uri"; 249 | 250 | $iso = [System.Text.Encoding]::GetEncoding("iso-8859-1"); 251 | $encodedBody = $iso.GetString($body); 252 | $headers = @{ 253 | "x-ms-blob-type" = "BlockBlob" 254 | }; 255 | 256 | if ($logRequestUris) { Write-Host $request; } 257 | if ($logHeaders) { WriteHeaders $headers; } 258 | 259 | try 260 | { 261 | $response = Invoke-WebRequest $uri -Method Put -Headers $headers -Body $encodedBody; 262 | } 263 | catch 264 | { 265 | Write-Host -ForegroundColor Red $request; 266 | Write-Host -ForegroundColor Red $_.Exception.Message; 267 | throw; 268 | } 269 | 270 | } 271 | 272 | #################################################### 273 | 274 | function FinalizeAzureStorageUpload($sasUri, $ids){ 275 | 276 | $uri = "$sasUri&comp=blocklist"; 277 | $request = "PUT $uri"; 278 | 279 | $xml = ''; 280 | foreach ($id in $ids) 281 | { 282 | $xml += "$id"; 283 | } 284 | $xml += ''; 285 | 286 | if ($logRequestUris) { Write-Host $request; } 287 | if ($logContent) { Write-Host -ForegroundColor Gray $xml; } 288 | 289 | try 290 | { 291 | Invoke-RestMethod $uri -Method Put -Body $xml; 292 | } 293 | catch 294 | { 295 | Write-Host -ForegroundColor Red $request; 296 | Write-Host -ForegroundColor Red $_.Exception.Message; 297 | throw; 298 | } 299 | } 300 | 301 | #################################################### 302 | 303 | function UploadFileToAzureStorage($sasUri, $filepath){ 304 | 305 | # Chunk size = 1 MiB 306 | $chunkSizeInBytes = 1024 * 1024; 307 | 308 | # Read the whole file and find the total chunks. 309 | #[byte[]]$bytes = Get-Content $filepath -Encoding byte; 310 | # Using ReadAllBytes method as the Get-Content used alot of memory on the machine 311 | [byte[]]$bytes = [System.IO.File]::ReadAllBytes($filepath); 312 | $chunks = [Math]::Ceiling($bytes.Length / $chunkSizeInBytes); 313 | 314 | # Upload each chunk. 315 | $ids = @(); 316 | $cc = 1 317 | 318 | for ($chunk = 0; $chunk -lt $chunks; $chunk++) 319 | { 320 | $id = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($chunk.ToString("0000"))); 321 | $ids += $id; 322 | 323 | $start = $chunk * $chunkSizeInBytes; 324 | $end = [Math]::Min($start + $chunkSizeInBytes - 1, $bytes.Length - 1); 325 | $body = $bytes[$start..$end]; 326 | 327 | Write-Progress -Activity "Uploading File to Azure Storage" -status "Uploading chunk $cc of $chunks" ` 328 | -percentComplete ($cc / $chunks*100) 329 | $cc++ 330 | 331 | $uploadResponse = UploadAzureStorageChunk $sasUri $id $body; 332 | 333 | 334 | } 335 | 336 | Write-Progress -Completed -Activity "Uploading File to Azure Storage" 337 | 338 | Write-Host 339 | 340 | # Finalize the upload. 341 | $uploadResponse = FinalizeAzureStorageUpload $sasUri $ids; 342 | } 343 | 344 | #################################################### 345 | 346 | function GenerateKey{ 347 | 348 | try 349 | { 350 | $aes = [System.Security.Cryptography.Aes]::Create(); 351 | $aesProvider = New-Object System.Security.Cryptography.AesCryptoServiceProvider; 352 | $aesProvider.GenerateKey(); 353 | $aesProvider.Key; 354 | } 355 | finally 356 | { 357 | if ($aesProvider -ne $null) { $aesProvider.Dispose(); } 358 | if ($aes -ne $null) { $aes.Dispose(); } 359 | } 360 | } 361 | 362 | #################################################### 363 | 364 | function GenerateIV{ 365 | 366 | try 367 | { 368 | $aes = [System.Security.Cryptography.Aes]::Create(); 369 | $aes.IV; 370 | } 371 | finally 372 | { 373 | if ($aes -ne $null) { $aes.Dispose(); } 374 | } 375 | } 376 | 377 | #################################################### 378 | 379 | function EncryptFileWithIV($sourceFile, $targetFile, $encryptionKey, $hmacKey, $initializationVector){ 380 | 381 | $bufferBlockSize = 1024 * 4; 382 | $computedMac = $null; 383 | 384 | try 385 | { 386 | $aes = [System.Security.Cryptography.Aes]::Create(); 387 | $hmacSha256 = New-Object System.Security.Cryptography.HMACSHA256; 388 | $hmacSha256.Key = $hmacKey; 389 | $hmacLength = $hmacSha256.HashSize / 8; 390 | 391 | $buffer = New-Object byte[] $bufferBlockSize; 392 | $bytesRead = 0; 393 | 394 | $targetStream = [System.IO.File]::Open($targetFile, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::Read); 395 | $targetStream.Write($buffer, 0, $hmacLength + $initializationVector.Length); 396 | 397 | try 398 | { 399 | $encryptor = $aes.CreateEncryptor($encryptionKey, $initializationVector); 400 | $sourceStream = [System.IO.File]::Open($sourceFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read); 401 | $cryptoStream = New-Object System.Security.Cryptography.CryptoStream -ArgumentList @($targetStream, $encryptor, [System.Security.Cryptography.CryptoStreamMode]::Write); 402 | 403 | $targetStream = $null; 404 | while (($bytesRead = $sourceStream.Read($buffer, 0, $bufferBlockSize)) -gt 0) 405 | { 406 | $cryptoStream.Write($buffer, 0, $bytesRead); 407 | $cryptoStream.Flush(); 408 | } 409 | $cryptoStream.FlushFinalBlock(); 410 | } 411 | finally 412 | { 413 | if ($cryptoStream -ne $null) { $cryptoStream.Dispose(); } 414 | if ($sourceStream -ne $null) { $sourceStream.Dispose(); } 415 | if ($encryptor -ne $null) { $encryptor.Dispose(); } 416 | } 417 | 418 | try 419 | { 420 | $finalStream = [System.IO.File]::Open($targetFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::Read) 421 | 422 | $finalStream.Seek($hmacLength, [System.IO.SeekOrigin]::Begin) > $null; 423 | $finalStream.Write($initializationVector, 0, $initializationVector.Length); 424 | $finalStream.Seek($hmacLength, [System.IO.SeekOrigin]::Begin) > $null; 425 | 426 | $hmac = $hmacSha256.ComputeHash($finalStream); 427 | $computedMac = $hmac; 428 | 429 | $finalStream.Seek(0, [System.IO.SeekOrigin]::Begin) > $null; 430 | $finalStream.Write($hmac, 0, $hmac.Length); 431 | } 432 | finally 433 | { 434 | if ($finalStream -ne $null) { $finalStream.Dispose(); } 435 | } 436 | } 437 | finally 438 | { 439 | if ($targetStream -ne $null) { $targetStream.Dispose(); } 440 | if ($aes -ne $null) { $aes.Dispose(); } 441 | } 442 | 443 | $computedMac; 444 | } 445 | 446 | #################################################### 447 | 448 | function EncryptFile($sourceFile, $targetFile){ 449 | 450 | $encryptionKey = GenerateKey; 451 | $hmacKey = GenerateKey; 452 | $initializationVector = GenerateIV; 453 | 454 | # Create the encrypted target file and compute the HMAC value. 455 | $mac = EncryptFileWithIV $sourceFile $targetFile $encryptionKey $hmacKey $initializationVector; 456 | 457 | # Compute the SHA256 hash of the source file and convert the result to bytes. 458 | $fileDigest = (Get-FileHash $sourceFile -Algorithm SHA256).Hash; 459 | $fileDigestBytes = New-Object byte[] ($fileDigest.Length / 2); 460 | for ($i = 0; $i -lt $fileDigest.Length; $i += 2) 461 | { 462 | $fileDigestBytes[$i / 2] = [System.Convert]::ToByte($fileDigest.Substring($i, 2), 16); 463 | } 464 | 465 | # Return an object that will serialize correctly to the file commit Graph API. 466 | $encryptionInfo = @{}; 467 | $encryptionInfo.encryptionKey = [System.Convert]::ToBase64String($encryptionKey); 468 | $encryptionInfo.macKey = [System.Convert]::ToBase64String($hmacKey); 469 | $encryptionInfo.initializationVector = [System.Convert]::ToBase64String($initializationVector); 470 | $encryptionInfo.mac = [System.Convert]::ToBase64String($mac); 471 | $encryptionInfo.profileIdentifier = "ProfileVersion1"; 472 | $encryptionInfo.fileDigest = [System.Convert]::ToBase64String($fileDigestBytes); 473 | $encryptionInfo.fileDigestAlgorithm = "SHA256"; 474 | 475 | $fileEncryptionInfo = @{}; 476 | $fileEncryptionInfo.fileEncryptionInfo = $encryptionInfo; 477 | 478 | $fileEncryptionInfo; 479 | 480 | } 481 | 482 | #################################################### 483 | 484 | function WaitForFileProcessing($fileUri, $stage){ 485 | 486 | $attempts= 60; 487 | $waitTimeInSeconds = 1; 488 | 489 | $successState = "$($stage)Success"; 490 | $pendingState = "$($stage)Pending"; 491 | $failedState = "$($stage)Failed"; 492 | $timedOutState = "$($stage)TimedOut"; 493 | 494 | $file = $null; 495 | while ($attempts -gt 0) 496 | { 497 | $file = MakeGetRequest $fileUri; 498 | 499 | if ($file.uploadState -eq $successState) 500 | { 501 | break; 502 | } 503 | elseif ($file.uploadState -ne $pendingState) 504 | { 505 | throw "File upload state is not success: $($file.uploadState)"; 506 | } 507 | 508 | Start-Sleep $waitTimeInSeconds; 509 | $attempts--; 510 | } 511 | 512 | if ($file -eq $null) 513 | { 514 | throw "File request did not complete in the allotted time."; 515 | } 516 | 517 | $file; 518 | 519 | } 520 | 521 | #################################################### 522 | 523 | function GetAndroidAppBody($displayName, $publisher, $description, $filename, $identityName, $identityVersion, $versionName, $minimumSupportedOperatingSystem){ 524 | 525 | $body = @{ "@odata.type" = "#microsoft.graph.androidLOBApp" }; 526 | $body.categories = @(); 527 | $body.displayName = $displayName; 528 | $body.publisher = $publisher; 529 | $body.description = $description; 530 | $body.fileName = $filename; 531 | $body.identityName = $identityName; 532 | $body.identityVersion = $identityVersion; 533 | 534 | if ($minimumSupportedOperatingSystem -eq $null){ 535 | 536 | $body.minimumSupportedOperatingSystem = @{ "v4_4" = $true }; 537 | 538 | } 539 | 540 | else { 541 | 542 | $body.minimumSupportedOperatingSystem = $minimumSupportedOperatingSystem; 543 | 544 | } 545 | 546 | $body.informationUrl = $null; 547 | $body.isFeatured = $false; 548 | $body.privacyInformationUrl = $null; 549 | $body.developer = ""; 550 | $body.notes = ""; 551 | $body.owner = ""; 552 | $body.versionCode = $identityVersion; 553 | $body.versionName = $versionName; 554 | 555 | $body; 556 | } 557 | 558 | #################################################### 559 | 560 | function GetiOSAppBody($displayName, $publisher, $description, $filename, $bundleId, $identityVersion, $versionNumber, $expirationDateTime){ 561 | 562 | $body = @{ "@odata.type" = "#microsoft.graph.iosLOBApp" }; 563 | $body.applicableDeviceType = @{ "iPad" = $true; "iPhoneAndIPod" = $true } 564 | $body.categories = @(); 565 | $body.displayName = $displayName; 566 | $body.publisher = $publisher; 567 | $body.description = $description; 568 | $body.fileName = $filename; 569 | $body.bundleId = $bundleId; 570 | $body.identityVersion = $identityVersion; 571 | if ($minimumSupportedOperatingSystem -eq $null) 572 | { 573 | $body.minimumSupportedOperatingSystem = @{ "v9_0" = $true }; 574 | } 575 | else 576 | { 577 | $body.minimumSupportedOperatingSystem = $minimumSupportedOperatingSystem; 578 | } 579 | 580 | $body.informationUrl = $null; 581 | $body.isFeatured = $false; 582 | $body.privacyInformationUrl = $null; 583 | $body.developer = ""; 584 | $body.notes = ""; 585 | $body.owner = ""; 586 | $body.expirationDateTime = $expirationDateTime; 587 | $body.versionNumber = $versionNumber; 588 | 589 | $body; 590 | } 591 | 592 | #################################################### 593 | 594 | function GetMSIAppBody($displayName, $publisher, $description, $filename, $identityVersion, $ProductCode){ 595 | 596 | $body = @{ "@odata.type" = "#microsoft.graph.windowsMobileMSI" }; 597 | $body.displayName = $displayName; 598 | $body.publisher = $publisher; 599 | $body.description = $description; 600 | $body.fileName = $filename; 601 | $body.identityVersion = $identityVersion; 602 | $body.informationUrl = $null; 603 | $body.isFeatured = $false; 604 | $body.privacyInformationUrl = $null; 605 | $body.developer = ""; 606 | $body.notes = ""; 607 | $body.owner = ""; 608 | $body.productCode = "$ProductCode"; 609 | $body.productVersion = "$identityVersion"; 610 | 611 | $body; 612 | } 613 | 614 | #################################################### 615 | 616 | function GetAppFileBody($name, $size, $sizeEncrypted, $manifest){ 617 | 618 | $body = @{ "@odata.type" = "#microsoft.graph.mobileAppContentFile" }; 619 | $body.name = $name; 620 | $body.size = $size; 621 | $body.sizeEncrypted = $sizeEncrypted; 622 | $body.manifest = $manifest; 623 | 624 | $body; 625 | } 626 | 627 | #################################################### 628 | 629 | function GetAppCommitBody($contentVersionId, $LobType){ 630 | 631 | $body = @{ "@odata.type" = "#$LobType" }; 632 | $body.committedContentVersion = $contentVersionId; 633 | 634 | $body; 635 | 636 | } 637 | 638 | #################################################### 639 | 640 | Function Get-MSIFileInformation(){ 641 | 642 | # https://www.scconfigmgr.com/2014/08/22/how-to-get-msi-file-information-with-powershell/ 643 | 644 | param( 645 |     [parameter(Mandatory=$true)] 646 |     [ValidateNotNullOrEmpty()] 647 |     [System.IO.FileInfo]$Path, 648 |   649 |     [parameter(Mandatory=$true)] 650 |     [ValidateNotNullOrEmpty()] 651 |     [ValidateSet("ProductCode", "ProductVersion", "ProductName", "Manufacturer", "ProductLanguage", "FullVersion")] 652 |     [string]$Property 653 | ) 654 | Process { 655 | 656 |     try { 657 |         # Read property from MSI database 658 |         $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer 659 |         $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $WindowsInstaller, @($Path.FullName, 0)) 660 |         $Query = "SELECT Value FROM Property WHERE Property = '$($Property)'" 661 |         $View = $MSIDatabase.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $MSIDatabase, ($Query)) 662 |         $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null) 663 |         $Record = $View.GetType().InvokeMember("Fetch", "InvokeMethod", $null, $View, $null) 664 |         $Value = $Record.GetType().InvokeMember("StringData", "GetProperty", $null, $Record, 1) 665 |   666 |         # Commit database and close view 667 |         $MSIDatabase.GetType().InvokeMember("Commit", "InvokeMethod", $null, $MSIDatabase, $null) 668 |         $View.GetType().InvokeMember("Close", "InvokeMethod", $null, $View, $null)           669 |         $MSIDatabase = $null 670 |         $View = $null 671 |   672 |         # Return the value 673 |         return $Value 674 |     } 675 | 676 |     catch { 677 | 678 |      Write-Warning -Message $_.Exception.Message; 679 | break; 680 |      681 | } 682 | 683 | } 684 | 685 | End { 686 |      # Run garbage collection and release ComObject 687 |      [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WindowsInstaller) | Out-Null 688 |      [System.GC]::Collect() 689 | } 690 | 691 | } 692 | 693 | #################################################### 694 | 695 | Function Test-SourceFile(){ 696 | 697 | param 698 | ( 699 |     [parameter(Mandatory=$true)] 700 |     [ValidateNotNullOrEmpty()] 701 | $SourceFile 702 | ) 703 | 704 | try { 705 | 706 | if(!(test-path "$SourceFile")){ 707 | 708 | Write-Host "Source File '$sourceFile' doesn't exist..." -ForegroundColor Red 709 | throw 710 | 711 | } 712 | 713 | } 714 | 715 | catch { 716 | 717 | Write-Host -ForegroundColor Red $_.Exception.Message; 718 | Write-Host 719 | break; 720 | 721 | } 722 | 723 | } 724 | 725 | #################################################### 726 | 727 | Function Get-ApkInformation { 728 | 729 | <# 730 | .SYNOPSIS 731 | This function is used to get information about an Android APK file using the Android SDK - https://developer.android.com/studio/index.html 732 | .DESCRIPTION 733 | This function is used to get information about an Android APK file using the Android SDK - https://developer.android.com/studio/index.html 734 | .EXAMPLE 735 | Get-ApkInformation -sourceFile c:\source\application.apk 736 | Function will return two object, object[0] is the identityName and object[1] is the identityVersion 737 | .NOTES 738 | NAME: Get-ApkInformation 739 | #> 740 | 741 | [cmdletbinding()] 742 | 743 | param 744 | ( 745 | [Parameter(Mandatory=$true)] 746 | $sourceFile, 747 | [Parameter(Mandatory=$true)] 748 | $AndroidSDK 749 | ) 750 | 751 | if(!(test-path $AndroidSDK)){ 752 | 753 | Write-Host 754 | Write-Host "Android SDK isn't installed..." -ForegroundColor Red 755 | Write-Host "Please install Android Studio and install the SDK from https://developer.android.com/studio/index.html" 756 | Write-Host 757 | break 758 | 759 | } 760 | 761 | if(((gci $AndroidSDK | select name).Name).count -gt 1){ 762 | 763 | $BuildTools = ((gci $AndroidSDK | select name).Name | sort -Descending)[0] 764 | 765 | } 766 | 767 | else { 768 | 769 | $BuildTools = ((gci $AndroidSDK | select name).Name) 770 | 771 | } 772 | 773 | $aaptPath = "$AndroidSDK\$BuildTools" 774 | 775 | [ScriptBlock]$command = { 776 | 777 | cmd.exe /c "$aaptPath\aapt.exe" dump badging "$sourceFile" 778 | 779 | } 780 | 781 | $aaptRun = Invoke-Command -ScriptBlock $command 782 | 783 | $AndroidPackage = $aaptRun | ? { ($_).startswith("package") } 784 | 785 | $PackageInfo = $AndroidPackage.split(" ") 786 | 787 | $PackageInfo[1].Split("'")[1] 788 | $PackageInfo[2].Split("'")[1] 789 | $PackageInfo[3].Split("'")[1] 790 | 791 | if ($logContent) { Write-Host -ForegroundColor Gray $PackageInfo[1].Split("'")[1]; } 792 | if ($logContent) { Write-Host -ForegroundColor Gray $PackageInfo[2].Split("'")[1]; } 793 | if ($logContent) { Write-Host -ForegroundColor Gray $PackageInfo[3].Split("'")[1]; } 794 | 795 | } 796 | 797 | #################################################### 798 | 799 | function Upload-AndroidLob(){ 800 | 801 | <# 802 | .SYNOPSIS 803 | This function is used to upload an Android LOB Application to the Intune Service 804 | .DESCRIPTION 805 | This function is used to upload an Android LOB Application to the Intune Service 806 | .EXAMPLE 807 | Upload-AndroidLob -sourceFile "C:\Software\package.apk" -publisher "Publisher Name" -description "Description of Application" -identityName "com.package" -identityVersion "1" -versionName "10.1.1" 808 | This example uses all parameters required to add an Android Application into the Intune Service 809 | Upload-AndroidLob -sourceFile "C:\Software\package.apk" -publisher "Publisher Name" -description "Description of Application" 810 | This example uses the required parameters to add an Android Application into the Intune Service. This example will require the Android SDK to get identityName and identityVersion 811 | .NOTES 812 | NAME: Upload-AndroidLOB 813 | #> 814 | 815 | [cmdletbinding()] 816 | 817 | param 818 | ( 819 |     [parameter(Mandatory=$true,Position=1)] 820 |     [ValidateNotNullOrEmpty()] 821 | [string]$SourceFile, 822 | 823 |     [parameter(Mandatory=$false)] 824 | [string]$displayName, 825 | 826 | [parameter(Mandatory=$true,Position=2)] 827 |     [ValidateNotNullOrEmpty()] 828 | [string]$publisher, 829 | 830 | [parameter(Mandatory=$true,Position=3)] 831 |     [ValidateNotNullOrEmpty()] 832 | [string]$description, 833 | 834 | [parameter(Mandatory=$false)] 835 | [string]$identityName, 836 | 837 | [parameter(Mandatory=$false)] 838 | [string]$identityVersion, 839 | 840 | [parameter(Mandatory=$false)] 841 | [string]$versionName 842 | 843 | ) 844 | 845 | try 846 | { 847 | 848 | $LOBType = "microsoft.graph.androidLOBApp" 849 | 850 | Write-Host "Testing if SourceFile '$SourceFile' Path is valid..." -ForegroundColor Yellow 851 | Test-SourceFile "$SourceFile" 852 | 853 | if(!$identityName){ 854 | 855 | Write-Host 856 | Write-Host "Opening APK file to get identityName to pass to the service..." -ForegroundColor Yellow 857 | 858 | $APKInformation = Get-ApkInformation -AndroidSDK $AndroidSDKLocation -sourceFile "$SourceFile" 859 | 860 | $identityName = $APKInformation[0] 861 | 862 | } 863 | 864 | if(!$identityVersion){ 865 | 866 | Write-Host 867 | Write-Host "Opening APK file to get identityVersion to pass to the service..." -ForegroundColor Yellow 868 | 869 | $APKInformation = Get-ApkInformation -AndroidSDK $AndroidSDKLocation -sourceFile "$SourceFile" 870 | 871 | $identityVersion = $APKInformation[1] 872 | 873 | } 874 | 875 | if(!$versionName){ 876 | 877 | Write-Host 878 | Write-Host "Opening APK file to get versionName to pass to the service..." -ForegroundColor Yellow 879 | 880 | $APKInformation = Get-ApkInformation -AndroidSDK $AndroidSDKLocation -sourceFile "$SourceFile" 881 | 882 | $versionName = $APKInformation[2] 883 | 884 | } 885 | 886 | 887 | # Creating temp file name from Source File path 888 | $tempFile = [System.IO.Path]::GetDirectoryName("$SourceFile") + "\" + [System.IO.Path]::GetFileNameWithoutExtension("$SourceFile") + "_temp.bin" 889 | 890 | # Creating filename variable from Source File Path 891 | $filename = [System.IO.Path]::GetFileName("$SourceFile") 892 | 893 | if(!($displayName)){ 894 | 895 | $displayName = $filename 896 | 897 | } 898 | 899 | # Create a new Android LOB app. 900 | Write-Host 901 | Write-Host "Creating JSON data to pass to the service..." -ForegroundColor Yellow 902 | $mobileAppBody = GetAndroidAppBody "$displayName" "$Publisher" "$Description" "$filename" "$identityName" "$identityVersion" "$versionName"; 903 | 904 | Write-Host 905 | Write-Host "Creating application in Intune..." -ForegroundColor Yellow 906 | $mobileApp = MakePostRequest "mobileApps" ($mobileAppBody | ConvertTo-Json); 907 | 908 | # Get the content version for the new app (this will always be 1 until the new app is committed). 909 | Write-Host 910 | Write-Host "Creating Content Version in the service for the application..." -ForegroundColor Yellow 911 | $appId = $mobileApp.id; 912 | $contentVersionUri = "mobileApps/$appId/$LOBType/contentVersions"; 913 | $contentVersion = MakePostRequest $contentVersionUri "{}"; 914 | 915 | # Encrypt file and Get File Information 916 | Write-Host 917 | Write-Host "Ecrypting the file '$SourceFile'..." -ForegroundColor Yellow 918 | $encryptionInfo = EncryptFile "$sourceFile" "$tempFile"; 919 | $Size = (Get-Item "$sourceFile").Length 920 | $EncrySize = (Get-Item "$tempFile").Length 921 | 922 | Write-Host 923 | Write-Host "Creating the manifest file used to install the application on the device..." -ForegroundColor Yellow 924 | 925 | [xml]$manifestXML = 'com.leadapps.android.radio.ncp101.0.5.4A_Online_Radio_1.0.5.4.apk3' 926 | 927 | $manifestXML.AndroidManifestProperties.Package = "$identityName" # com.application.test 928 | $manifestXML.AndroidManifestProperties.PackageVersionCode = "$identityVersion" # 10 929 | $manifestXML.AndroidManifestProperties.PackageVersionName = "$identityVersion" # 1.0.5.4 930 | $manifestXML.AndroidManifestProperties.ApplicationName = "$filename" # name.apk 931 | 932 | $manifestXML_Output = $manifestXML.OuterXml.ToString() 933 | 934 | $Bytes = [System.Text.Encoding]::ASCII.GetBytes($manifestXML_Output) 935 | $EncodedText =[Convert]::ToBase64String($Bytes) 936 | 937 | # Create a new file for the app. 938 | Write-Host 939 | Write-Host "Creating a new file entry in Azure for the upload..." -ForegroundColor Yellow 940 | $contentVersionId = $contentVersion.id; 941 | $fileBody = GetAppFileBody "$filename" $Size $EncrySize "$EncodedText"; 942 | $filesUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files"; 943 | $file = MakePostRequest $filesUri ($fileBody | ConvertTo-Json); 944 | 945 | # Wait for the service to process the new file request. 946 | Write-Host 947 | Write-Host "Waiting for the file entry URI to be created..." -ForegroundColor Yellow 948 | $fileId = $file.id; 949 | $fileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId"; 950 | $file = WaitForFileProcessing $fileUri "AzureStorageUriRequest"; 951 | 952 | # Upload the content to Azure Storage. 953 | Write-Host 954 | Write-Host "Uploading file to Azure Storage URI..." -ForegroundColor Yellow 955 | 956 | $sasUri = $file.azureStorageUri; 957 | UploadFileToAzureStorage $file.azureStorageUri $tempFile; 958 | 959 | # Commit the file. 960 | Write-Host 961 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 962 | $commitFileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId/commit"; 963 | MakePostRequest $commitFileUri ($encryptionInfo | ConvertTo-Json); 964 | 965 | # Wait for the service to process the commit file request. 966 | Write-Host 967 | Write-Host "Waiting for the service to process the commit file request..." -ForegroundColor Yellow 968 | $file = WaitForFileProcessing $fileUri "CommitFile"; 969 | 970 | # Commit the app. 971 | Write-Host 972 | Write-Host "Committing the application to the Intune Service..." -ForegroundColor Yellow 973 | $commitAppUri = "mobileApps/$appId"; 974 | $commitAppBody = GetAppCommitBody $contentVersionId $LOBType; 975 | MakePatchRequest $commitAppUri ($commitAppBody | ConvertTo-Json); 976 | 977 | Write-Host "Removing Temporary file '$tempFile'..." -f Gray 978 | Remove-Item -Path "$tempFile" -Force 979 | Write-Host 980 | 981 | Write-Host "Sleeping for $sleep seconds to allow patch completion..." -f Magenta 982 | Start-Sleep $sleep 983 | Write-Host 984 | 985 | } 986 | catch 987 | { 988 | Write-Host ""; 989 | Write-Host -ForegroundColor Red "Aborting with exception: $($_.Exception.ToString())"; 990 | } 991 | } 992 | 993 | #################################################### 994 | 995 | function Upload-iOSLob(){ 996 | 997 | <# 998 | .SYNOPSIS 999 | This function is used to upload an iOS LOB Application to the Intune Service 1000 | .DESCRIPTION 1001 | This function is used to upload an iOS LOB Application to the Intune Service 1002 | .EXAMPLE 1003 | Upload-iOSLob -sourceFile "C:\Software\package.ipa" -displayName "package.ipa" -publisher "Publisher Name" -description "Description of Application" -bundleId "com.package" -identityVersion "1" -versionNumber "3.0.0" -expirationDateTime "2018-02-14T20:53:52Z" 1004 | This example uses all parameters required to add an iOS Application into the Intune Service 1005 | .NOTES 1006 | NAME: Upload-iOSLOB 1007 | #> 1008 | 1009 | [cmdletbinding()] 1010 | 1011 | param 1012 | ( 1013 |     [parameter(Mandatory=$true,Position=1)] 1014 |     [ValidateNotNullOrEmpty()] 1015 | [string]$SourceFile, 1016 | 1017 |     [parameter(Mandatory=$true,Position=2)] 1018 |     [ValidateNotNullOrEmpty()] 1019 | [string]$displayName, 1020 | 1021 | [parameter(Mandatory=$true,Position=3)] 1022 |     [ValidateNotNullOrEmpty()] 1023 | [string]$publisher, 1024 | 1025 | [parameter(Mandatory=$true,Position=4)] 1026 |     [ValidateNotNullOrEmpty()] 1027 | [string]$description, 1028 | 1029 | [parameter(Mandatory=$true,Position=5)] 1030 |     [ValidateNotNullOrEmpty()] 1031 | [string]$bundleId, 1032 | 1033 | [parameter(Mandatory=$true,Position=6)] 1034 |     [ValidateNotNullOrEmpty()] 1035 | [string]$identityVersion, 1036 | 1037 | [parameter(Mandatory=$true,Position=7)] 1038 |     [ValidateNotNullOrEmpty()] 1039 | [string]$versionNumber, 1040 | 1041 | [parameter(Mandatory=$true,Position=8)] 1042 |     [ValidateNotNullOrEmpty()] 1043 | [string]$expirationDateTime 1044 | ) 1045 | 1046 | try 1047 | { 1048 | 1049 | $LOBType = "microsoft.graph.iosLOBApp" 1050 | 1051 | Write-Host "Testing if SourceFile '$SourceFile' Path is valid..." -ForegroundColor Yellow 1052 | Test-SourceFile "$SourceFile" 1053 | 1054 | # Checking expirationdatetime of SourceFile to check if it can be uploaded 1055 | [datetimeoffset]$Expiration = $expirationDateTime 1056 | 1057 | $Date = get-date 1058 | 1059 | if($Expiration -lt $Date){ 1060 | 1061 | Write-Error "$SourceFile has expired Follow the guidelines provided by Apple to extend the expiration date, then try adding the app again" 1062 | throw 1063 | 1064 | } 1065 | 1066 | # Creating temp file name from Source File path 1067 | $tempFile = [System.IO.Path]::GetDirectoryName("$SourceFile") + "\" + [System.IO.Path]::GetFileNameWithoutExtension("$SourceFile") + "_temp.bin" 1068 | 1069 | # Creating filename variable from Source File Path 1070 | $filename = [System.IO.Path]::GetFileName("$SourceFile") 1071 | 1072 | # Create a new iOS LOB app. 1073 | Write-Host 1074 | Write-Host "Creating JSON data to pass to the service..." -ForegroundColor Yellow 1075 | $mobileAppBody = GetiOSAppBody "$displayName" "$Publisher" "$Description" "$filename" "$bundleId" "$identityVersion" "$versionNumber" "$expirationDateTime"; 1076 | 1077 | Write-Host 1078 | Write-Host "Creating application in Intune..." -ForegroundColor Yellow 1079 | 1080 | $mobileApp = MakePostRequest "mobileApps" ($mobileAppBody | ConvertTo-Json); 1081 | 1082 | # Get the content version for the new app (this will always be 1 until the new app is committed). 1083 | Write-Host 1084 | Write-Host "Creating Content Version in the service for the application..." -ForegroundColor Yellow 1085 | $appId = $mobileApp.id; 1086 | $contentVersionUri = "mobileApps/$appId/$LOBType/contentVersions"; 1087 | $contentVersion = MakePostRequest $contentVersionUri "{}"; 1088 | 1089 | # Encrypt file and Get File Information 1090 | Write-Host 1091 | Write-Host "Ecrypting the file '$SourceFile'..." -ForegroundColor Yellow 1092 | $encryptionInfo = EncryptFile $sourceFile $tempFile; 1093 | $Size = (Get-Item "$sourceFile").Length 1094 | $EncrySize = (Get-Item "$tempFile").Length 1095 | 1096 | Write-Host 1097 | Write-Host "Creating the manifest file used to install the application on the device..." -ForegroundColor Yellow 1098 | 1099 | [string]$manifestXML = 'itemsassetskindsoftware-packageurl{UrlPlaceHolder}metadataAppRestrictionPolicyTemplate http://management.microsoft.com/PolicyTemplates/AppRestrictions/iOS/v1AppRestrictionTechnologyWindows Intune Application Restrictions Technology for iOSIntuneMAMVersionCFBundleSupportedPlatformsiPhoneOSMinimumOSVersion9.0bundle-identifierbundleidbundle-versionbundleversionkindsoftwaresubtitleLaunchMeSubtitletitlebundletitle' 1100 | 1101 | $manifestXML = $manifestXML.replace("bundleid","$bundleId") 1102 | $manifestXML = $manifestXML.replace("bundleversion","$identityVersion") 1103 | $manifestXML = $manifestXML.replace("bundletitle","$displayName") 1104 | 1105 | $Bytes = [System.Text.Encoding]::ASCII.GetBytes($manifestXML) 1106 | $EncodedText =[Convert]::ToBase64String($Bytes) 1107 | 1108 | # Create a new file for the app. 1109 | Write-Host 1110 | Write-Host "Creating a new file entry in Azure for the upload..." -ForegroundColor Yellow 1111 | $contentVersionId = $contentVersion.id; 1112 | $fileBody = GetAppFileBody "$filename" $Size $EncrySize "$EncodedText"; 1113 | $filesUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files"; 1114 | $file = MakePostRequest $filesUri ($fileBody | ConvertTo-Json); 1115 | 1116 | # Wait for the service to process the new file request. 1117 | Write-Host 1118 | Write-Host "Waiting for the file entry URI to be created..." -ForegroundColor Yellow 1119 | $fileId = $file.id; 1120 | $fileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId"; 1121 | $file = WaitForFileProcessing $fileUri "AzureStorageUriRequest"; 1122 | 1123 | # Upload the content to Azure Storage. 1124 | Write-Host 1125 | Write-Host "Uploading file to Azure Storage..." -f Yellow 1126 | 1127 | $sasUri = $file.azureStorageUri; 1128 | UploadFileToAzureStorage $file.azureStorageUri $tempFile; 1129 | 1130 | # Commit the file. 1131 | Write-Host 1132 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 1133 | $commitFileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId/commit"; 1134 | MakePostRequest $commitFileUri ($encryptionInfo | ConvertTo-Json); 1135 | 1136 | # Wait for the service to process the commit file request. 1137 | Write-Host 1138 | Write-Host "Waiting for the service to process the commit file request..." -ForegroundColor Yellow 1139 | $file = WaitForFileProcessing $fileUri "CommitFile"; 1140 | 1141 | # Commit the app. 1142 | Write-Host 1143 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 1144 | $commitAppUri = "mobileApps/$appId"; 1145 | $commitAppBody = GetAppCommitBody $contentVersionId $LOBType; 1146 | MakePatchRequest $commitAppUri ($commitAppBody | ConvertTo-Json); 1147 | 1148 | Write-Host "Removing Temporary file '$tempFile'..." -f Gray 1149 | Remove-Item -Path "$tempFile" -Force 1150 | Write-Host 1151 | 1152 | Write-Host "Sleeping for $sleep seconds to allow patch completion..." -f Magenta 1153 | Start-Sleep $sleep 1154 | Write-Host 1155 | 1156 | } 1157 | catch 1158 | { 1159 | Write-Host ""; 1160 | Write-Host -ForegroundColor Red "Aborting with exception: $($_.Exception.ToString())"; 1161 | } 1162 | } 1163 | 1164 | #################################################### 1165 | 1166 | function Upload-MSILob(){ 1167 | 1168 | <# 1169 | .SYNOPSIS 1170 | This function is used to upload an MSI LOB Application to the Intune Service 1171 | .DESCRIPTION 1172 | This function is used to upload an MSI LOB Application to the Intune Service 1173 | .EXAMPLE 1174 | Upload-MSILob "C:\Software\Orca\Orca.Msi" -publisher "Microsoft" -description "Orca" 1175 | This example uses all parameters required to add an MSI Application into the Intune Service 1176 | .NOTES 1177 | NAME: Upload-MSILOB 1178 | #> 1179 | 1180 | [cmdletbinding()] 1181 | 1182 | param 1183 | ( 1184 |     [parameter(Mandatory=$true,Position=1)] 1185 |     [ValidateNotNullOrEmpty()] 1186 | [string]$SourceFile, 1187 | 1188 | [parameter(Mandatory=$true,Position=2)] 1189 |     [ValidateNotNullOrEmpty()] 1190 | [string]$publisher, 1191 | 1192 | [parameter(Mandatory=$true,Position=3)] 1193 |     [ValidateNotNullOrEmpty()] 1194 | [string]$description 1195 | ) 1196 | 1197 | try { 1198 | 1199 | $LOBType = "microsoft.graph.windowsMobileMSI" 1200 | 1201 | Write-Host "Testing if SourceFile '$SourceFile' Path is valid..." -ForegroundColor Yellow 1202 | Test-SourceFile "$SourceFile" 1203 | 1204 | $MSIPath = "$SourceFile" 1205 | 1206 | # Creating temp file name from Source File path 1207 | $tempFile = [System.IO.Path]::GetDirectoryName("$SourceFile") + "\" + [System.IO.Path]::GetFileNameWithoutExtension("$SourceFile") + "_temp.bin" 1208 | 1209 | Write-Host 1210 | Write-Host "Creating JSON data to pass to the service..." -ForegroundColor Yellow 1211 | 1212 | $FileName = [System.IO.Path]::GetFileName("$MSIPath") 1213 | 1214 | $PN = (Get-MSIFileInformation -Path "$MSIPath" -Property ProductName | Out-String).trimend() 1215 | $PC = (Get-MSIFileInformation -Path "$MSIPath" -Property ProductCode | Out-String).trimend() 1216 | $PV = (Get-MSIFileInformation -Path "$MSIPath" -Property ProductVersion | Out-String).trimend() 1217 | $PL = (Get-MSIFileInformation -Path "$MSIPath" -Property ProductLanguage | Out-String).trimend() 1218 | 1219 | # Create a new MSI LOB app. 1220 | $mobileAppBody = GetMSIAppBody -displayName "$PN" -publisher "$publisher" -description "$description" -filename "$FileName" -identityVersion "$PV" -ProductCode "$PC" 1221 | 1222 | Write-Host 1223 | Write-Host "Creating application in Intune..." -ForegroundColor Yellow 1224 | $mobileApp = MakePostRequest "mobileApps" ($mobileAppBody | ConvertTo-Json); 1225 | 1226 | # Get the content version for the new app (this will always be 1 until the new app is committed). 1227 | Write-Host 1228 | Write-Host "Creating Content Version in the service for the application..." -ForegroundColor Yellow 1229 | $appId = $mobileApp.id; 1230 | $contentVersionUri = "mobileApps/$appId/$LOBType/contentVersions"; 1231 | $contentVersion = MakePostRequest $contentVersionUri "{}"; 1232 | 1233 | # Encrypt file and Get File Information 1234 | Write-Host 1235 | Write-Host "Ecrypting the file '$SourceFile'..." -ForegroundColor Yellow 1236 | $encryptionInfo = EncryptFile $sourceFile $tempFile; 1237 | $Size = (Get-Item "$sourceFile").Length 1238 | $EncrySize = (Get-Item "$tempFile").Length 1239 | 1240 | Write-Host 1241 | Write-Host "Creating the manifest file used to install the application on the device..." -ForegroundColor Yellow 1242 | 1243 | [xml]$manifestXML = '' 1244 | 1245 | $manifestXML.MobileMsiData.MsiUpgradeCode = "$PC" 1246 | 1247 | $manifestXML_Output = $manifestXML.OuterXml.ToString() 1248 | 1249 | $Bytes = [System.Text.Encoding]::ASCII.GetBytes($manifestXML_Output) 1250 | $EncodedText =[Convert]::ToBase64String($Bytes) 1251 | 1252 | # Create a new file for the app. 1253 | Write-Host 1254 | Write-Host "Creating a new file entry in Azure for the upload..." -ForegroundColor Yellow 1255 | $contentVersionId = $contentVersion.id; 1256 | $fileBody = GetAppFileBody "$FileName" $Size $EncrySize "$EncodedText"; 1257 | $filesUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files"; 1258 | $file = MakePostRequest $filesUri ($fileBody | ConvertTo-Json); 1259 | 1260 | # Wait for the service to process the new file request. 1261 | Write-Host 1262 | Write-Host "Waiting for the file entry URI to be created..." -ForegroundColor Yellow 1263 | $fileId = $file.id; 1264 | $fileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId"; 1265 | $file = WaitForFileProcessing $fileUri "AzureStorageUriRequest"; 1266 | 1267 | # Upload the content to Azure Storage. 1268 | Write-Host 1269 | Write-Host "Uploading file to Azure Storage..." -f Yellow 1270 | 1271 | $sasUri = $file.azureStorageUri; 1272 | UploadFileToAzureStorage $file.azureStorageUri $tempFile; 1273 | 1274 | # Commit the file. 1275 | Write-Host 1276 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 1277 | $commitFileUri = "mobileApps/$appId/$LOBType/contentVersions/$contentVersionId/files/$fileId/commit"; 1278 | MakePostRequest $commitFileUri ($encryptionInfo | ConvertTo-Json); 1279 | 1280 | # Wait for the service to process the commit file request. 1281 | Write-Host 1282 | Write-Host "Waiting for the service to process the commit file request..." -ForegroundColor Yellow 1283 | $file = WaitForFileProcessing $fileUri "CommitFile"; 1284 | 1285 | # Commit the app. 1286 | Write-Host 1287 | Write-Host "Committing the file into Azure Storage..." -ForegroundColor Yellow 1288 | $commitAppUri = "mobileApps/$appId"; 1289 | $commitAppBody = GetAppCommitBody $contentVersionId $LOBType; 1290 | MakePatchRequest $commitAppUri ($commitAppBody | ConvertTo-Json); 1291 | 1292 | Write-Host "Removing Temporary file '$tempFile'..." -f Gray 1293 | Remove-Item -Path "$tempFile" -Force 1294 | Write-Host 1295 | 1296 | Write-Host "Sleeping for $sleep seconds to allow patch completion..." -f Magenta 1297 | Start-Sleep $sleep 1298 | Write-Host 1299 | 1300 | } 1301 | 1302 | catch { 1303 | 1304 | Write-Host ""; 1305 | Write-Host -ForegroundColor Red "Aborting with exception: $($_.Exception.ToString())"; 1306 | 1307 | } 1308 | 1309 | } 1310 | 1311 | #################################################### 1312 | 1313 | #region Authentication 1314 | 1315 | write-host 1316 | 1317 | # Checking if authToken exists before running authentication 1318 | if($global:authToken){ 1319 | 1320 | # Setting DateTime to Universal time to work in all timezones 1321 | $DateTime = (Get-Date).ToUniversalTime() 1322 | 1323 | # If the authToken exists checking when it expires 1324 | $TokenExpires = ($authToken.ExpiresOn.datetime - $DateTime).Minutes 1325 | 1326 | if($TokenExpires -le 0){ 1327 | 1328 | write-host "Authentication Token expired" $TokenExpires "minutes ago" -ForegroundColor Yellow 1329 | write-host 1330 | 1331 | # Defining Azure AD tenant name, this is the name of your Azure Active Directory (do not use the verified domain name) 1332 | 1333 | if($User -eq $null -or $User -eq ""){ 1334 | 1335 | $User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication" 1336 | Write-Host 1337 | 1338 | } 1339 | 1340 | $global:authToken = Get-AuthToken -User $User 1341 | 1342 | } 1343 | } 1344 | 1345 | # Authentication doesn't exist, calling Get-AuthToken function 1346 | 1347 | else { 1348 | 1349 | if($User -eq $null -or $User -eq ""){ 1350 | 1351 | $User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication" 1352 | Write-Host 1353 | 1354 | } 1355 | 1356 | # Getting the authorization token 1357 | $global:authToken = Get-AuthToken -User $User 1358 | 1359 | } 1360 | 1361 | #endregion 1362 | 1363 | #################################################### 1364 | 1365 | # Path to Android SDK Location to find aapt.exe tool if you don't specify identityName or identityVersion 1366 | # Note: Don't specify direct location to build folder number, just to the build-tools folder as the script will find the latest SDK installed 1367 | $AndroidSDKLocation = "C:\AndroidSDK\build-tools" 1368 | 1369 | $baseUrl = "https://graph.microsoft.com/beta/deviceAppManagement/" 1370 | 1371 | $logRequestUris = $true; 1372 | $logHeaders = $false; 1373 | $logContent = $true; 1374 | 1375 | $sleep = 30 1376 | 1377 | #################################################### 1378 | 1379 | #### MSI Install Google Chrome Enterprise x64 1380 | $output = "$PSScriptRoot\googlechromestandaloneenterprise64.msi" 1381 | Start-BitsTransfer -Source https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise64.msi -Destination $output 1382 | Upload-MSILob "$output" -publisher "Google" -description "Google Chrome Enterprise x64" 1383 | 1384 | #### MSI Install Google Chrome Enterprise x32 1385 | $output = "$PSScriptRoot\googlechromestandaloneenterprise.msi" 1386 | Start-BitsTransfer -Source https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise.msi -Destination $output 1387 | Upload-MSILob "$output" -publisher "Google" -description "Google Chrome Enterprise x32" --------------------------------------------------------------------------------