コード例 #1
0
        private async Task CreateBlobAsync(IntuneAppPackage package, MobileAppContentFile contentFile)
        {
            var blockCount = 0;
            var blockIds   = new List <string>();

            const int chunkSize = 5 * 1024 * 1024;

            package.Data.Seek(0, SeekOrigin.Begin);
            var lastBlockId = (Math.Ceiling((double)package.Data.Length / chunkSize) - 1).ToString("0000");

            foreach (var chunk in Chunk(package.Data, chunkSize, false))
            {
                var blockId = blockCount++.ToString("0000");
                logger.LogInformation($"Uploading block {blockId} of {lastBlockId} to {contentFile.AzureStorageUri}.");

                await using (var ms = new MemoryStream(chunk))
                {
                    await TryPutBlockAsync(contentFile, blockId, ms);
                }

                blockIds.Add(blockId);
            }

            await new CloudBlockBlob(new Uri(contentFile.AzureStorageUri)).PutBlockListAsync(blockIds);
        }
コード例 #2
0
        /// <inheritdoc />
        public async Task PublishAsync(IntuneAppPackage package)
        {
            logger.LogInformation($"Publishing Intune app package for {package.App.DisplayName}.");

            var app = await GetAppAsync(package.App);

            var sw = Stopwatch.StartNew();

            var requestBuilder = new MobileLobAppRequestBuilder(msGraphClient.DeviceAppManagement.MobileApps[app.Id]
                                                                .AppendSegmentToRequestUrl(app.ODataType.TrimStart('#')), msGraphClient);

            MobileAppContent content = null;

            // if content has never been committed, need to use last created content if one exists, otherwise an error is thrown
            if (app.CommittedContentVersion == null)
            {
                content = (await requestBuilder.ContentVersions.Request().OrderBy("id desc").GetAsync()).FirstOrDefault();
            }

            if (content == null)
            {
                content = await requestBuilder.ContentVersions.Request().AddAsync(new MobileAppContent());
            }
            else if ((await requestBuilder.ContentVersions[content.Id].Files.Request().Filter("isCommitted ne true").GetAsync()).Any())
            {
                // partially committed content - delete that content version
                await requestBuilder.ContentVersions[content.Id].Request().DeleteAsync();
            }

            // manifests are only supported if the app is a WindowsMobileMSI (not a Win32 app installing an msi)
            if (!(app is WindowsMobileMSI))
            {
                package.File.Manifest = null;
            }

            await CreateAppContentFileAsync(requestBuilder.ContentVersions[content.Id], package);

            MobileLobApp update = (MobileLobApp)Activator.CreateInstance(package.App.GetType());

            update.CommittedContentVersion = content.Id;
            await msGraphClient.DeviceAppManagement.MobileApps[app.Id].Request().UpdateAsync(update);

            logger.LogInformation($"Published Intune app package for {app.DisplayName} in {sw.ElapsedMilliseconds}ms.");
        }
コード例 #3
0
        private async Task CreateBlobAsync(IntuneAppPackage package, MobileAppContentFile contentFile, IMobileAppContentFileRequestBuilder contentFileRequestBuilder)
        {
            var blockCount = 0;
            var blockIds   = new List <string>();

            const int chunkSize = 25 * 1024 * 1024;

            package.Data.Seek(0, SeekOrigin.Begin);
            var lastBlockId = (Math.Ceiling((double)package.Data.Length / chunkSize) - 1).ToString("0000");
            var sw          = Stopwatch.StartNew();

            foreach (var chunk in Chunk(package.Data, chunkSize, false))
            {
                if (sw.ElapsedMilliseconds >= 450000)
                {
                    contentFile = await RenewStorageUri(contentFileRequestBuilder);

                    sw.Restart();
                }

                var blockId = blockCount++.ToString("0000");
                logger.LogInformation($"Uploading block {blockId} of {lastBlockId} to {contentFile.AzureStorageUri}.");

                await using (var ms = new MemoryStream(chunk))
                {
                    try
                    {
                        await TryPutBlockAsync(contentFile, blockId, ms);
                    }
                    catch (StorageException ex) when(ex.RequestInformation.HttpStatusCode == 403)
                    {
                        // normally the timer should account for renewing upload URIs, but the Intune APIs are fundamentally unstable and sometimes 403s will be encountered randomly
                        contentFile = await RenewStorageUri(contentFileRequestBuilder);

                        sw.Restart();
                        await TryPutBlockAsync(contentFile, blockId, ms);
                    }
                }

                blockIds.Add(blockId);
            }

            await new CloudBlockBlob(new Uri(contentFile.AzureStorageUri)).PutBlockListAsync(blockIds);
        }
コード例 #4
0
 private async Task <MobileAppContentFile> AddContentFileAsync(IMobileAppContentRequestBuilder requestBuilder, IntuneAppPackage package)
 {
     return(await requestBuilder.Files.Request()
            .WithMaxRetry(10)
            .WithRetryDelay(30)
            .WithShouldRetry((delay, count, r) => r.StatusCode == HttpStatusCode.NotFound)
            .AddAsync(package.File));
 }
コード例 #5
0
        private async Task CreateAppContentFileAsync(IMobileAppContentRequestBuilder requestBuilder, IntuneAppPackage package)
        {
            // add content file
            var contentFile = await AddContentFileAsync(requestBuilder, package);

            // waits for the desired status, refreshing the file along the way
            async Task WaitForStateAsync(MobileAppContentFileUploadState state)
            {
                logger.LogInformation($"Waiting for app content file to have a state of {state}.");

                // ReSharper disable AccessToModifiedClosure - intended

                var waitStopwatch = Stopwatch.StartNew();

                while (true)
                {
                    contentFile = await requestBuilder.Files[contentFile.Id].Request().GetAsync();

                    if (contentFile.UploadState == state)
                    {
                        logger.LogInformation($"Waited {waitStopwatch.ElapsedMilliseconds}ms for app content file to have a state of {state}.");
                        return;
                    }

                    var failedStates = new[]
                    {
                        MobileAppContentFileUploadState.AzureStorageUriRequestFailed,
                        MobileAppContentFileUploadState.AzureStorageUriRenewalFailed,
                        MobileAppContentFileUploadState.CommitFileFailed
                    };

                    if (failedStates.Contains(contentFile.UploadState.GetValueOrDefault()))
                    {
                        throw new InvalidOperationException($"{nameof(contentFile.UploadState)} is in a failed state of {contentFile.UploadState} - was waiting for {state}.");
                    }
                    const int waitTimeout  = 240000;
                    const int testInterval = 2000;
                    if (waitStopwatch.ElapsedMilliseconds > waitTimeout)
                    {
                        throw new InvalidOperationException($"Timed out waiting for {nameof(contentFile.UploadState)} of {state} - current state is {contentFile.UploadState}.");
                    }
                    await Task.Delay(testInterval);
                }
                // ReSharper restore AccessToModifiedClosure
            }

            // refetch until we can get the uri to upload to
            await WaitForStateAsync(MobileAppContentFileUploadState.AzureStorageUriRequestSuccess);

            var sw = Stopwatch.StartNew();

            await CreateBlobAsync(package, contentFile);

            logger.LogInformation($"Uploaded app content file in {sw.ElapsedMilliseconds}ms.");

            // commit
            await requestBuilder.Files[contentFile.Id].Commit(package.EncryptionInfo).Request().PostAsync();

            // refetch until has committed
            await WaitForStateAsync(MobileAppContentFileUploadState.CommitFileSuccess);
        }
コード例 #6
0
        private async Task CreateAppContentFileAsync(IMobileAppContentRequestBuilder requestBuilder, IntuneAppPackage package)
        {
            // add content file
            var contentFile = await AddContentFileAsync(requestBuilder, package);

            // refetch until we can get the uri to upload to
            contentFile = await WaitForStateAsync(requestBuilder.Files[contentFile.Id], MobileAppContentFileUploadState.AzureStorageUriRequestSuccess);

            var sw = Stopwatch.StartNew();

            await CreateBlobAsync(package, contentFile, requestBuilder.Files[contentFile.Id]);

            logger.LogInformation($"Uploaded app content file in {sw.ElapsedMilliseconds}ms.");

            // commit
            await requestBuilder.Files[contentFile.Id].Commit(package.EncryptionInfo).Request().PostAsync();

            // refetch until has committed
            await WaitForStateAsync(requestBuilder.Files[contentFile.Id], MobileAppContentFileUploadState.CommitFileSuccess);
        }