YAML ファイルを使用した CI/CD パイプラインの構成

次の表は、ビルド パイプラインを設定するために定義できるさまざまな MSBuild 引数を示しています。

MSBuild 引数 説明
AppxPackageDir $(Build.ArtifactStagingDirectory)\AppxPackages 生成された成果物を格納するフォルダーを定義します。
AppxBundlePlatforms $(Build.BuildPlatform) バンドルに含めるプラットフォームを定義できます。
AppxBundle 常に表示する 指定されているプラットフォームの .msix/.appx ファイルを含む .msixbundle/.appxbundle が作成されます。
UapAppxPackageBuildMode StoreUpload サイドローディング用の .msixupload/.appxupload ファイルと _Test フォルダーが生成されます。
UapAppxPackageBuildMode CI .msixupload/.appxupload ファイルのみが生成されます。
UapAppxPackageBuildMode SideloadOnly サイドローディング用の _Test フォルダーのみが生成されます。
AppxPackageSigningEnabled true パッケージの署名を有効にします。
PackageCertificateThumbprint 証明書の拇印 この値は、署名証明書の拇印と一致しているか、空の文字列である必要があります
PackageCertificateKeyFile パス 使用する証明書へのパス。 これは、セキュア ファイルのメタデータから取得されます。
PackageCertificatePassword Password 証明書の秘密キーのパスワード。 パスワードを Azure Key Vault に保存し、パスワードを変数グループにリンクすることをお勧めします。 この引数に変数を渡すことができます。

Visual Studio のウィザードで MSBuild コマンド ラインを使用して行うのと同じ方法でパッケージ プロジェクトをビルドする前に、Package.appxmanifest ファイル内のパッケージ要素のバージョン属性を編集することで、ビルド プロセスで、生成されている MSIX パッケージのバージョンを管理することができます。 Azure Pipelines では、すべてのビルドに対してインクリメントされるカウンター変数の設定用に式を使用したり、.NET で System.Xml.Linq.XDocument クラスを使用して属性の値を変更する PowerShell スクリプトを使用することでこれを実現できます。

MSIX ビルド パイプラインを定義するサンプル YAML ファイル

pool: 
  vmImage: windows-2019
  
variables:
  buildPlatform: 'x86'
  buildConfiguration: 'release'
  major: 1
  minor: 0
  build: 0
  revision: $[counter('rev', 0)]
  
steps:
- powershell: |
     # Update appxmanifest. This must be done before the build.
     [xml]$manifest= get-content ".\Msix\Package.appxmanifest"
     $manifest.Package.Identity.Version = "$(major).$(minor).$(build).$(revision)"    
     $manifest.save("Msix/Package.appxmanifest")
  displayName: 'Version Package Manifest'
  
- task: MSBuild@1
  inputs:
    solution: Msix/Msix.wapproj
    platform: $(buildPlatform)
    configuration: $(buildConfiguration)
    msbuildArguments: '/p:OutputPath=NonPackagedApp
     /p:UapAppxPackageBuildMode=SideLoadOnly  /p:AppxBundle=Never /p:AppxPackageOutput=$(Build.ArtifactStagingDirectory)\MsixDesktopApp.msix /p:AppxPackageSigningEnabled=false'
  displayName: 'Package the App'
  
- task: DownloadSecureFile@1
  inputs:
    secureFile: 'certificate.pfx'
  displayName: 'Download Secure PFX File'
  
- script: '"C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\signtool"
    sign /fd SHA256 /f $(Agent.TempDirectory)/certificate.pfx /p secret $(
    Build.ArtifactStagingDirectory)/MsixDesktopApp.msix'
  displayName: 'Sign MSIX Package'
  
- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: drop'

YAMl ファイルで定義されているさまざまなビルド タスクの内訳を次に示します。

パッケージ生成プロパティの構成

次の定義では、ビルド コンポーネントのディレクトリとプラットフォームを設定し、バンドルをビルドするかどうかを定義します。

/p:AppxPackageDir="$(Build.ArtifactStagingDirectory)\AppxPackages\"
/p:UapAppxPackageBuildMode=SideLoadOnly
/p:AppxBundlePlatforms="$(Build.BuildPlatform)"
/p:AppxBundle=Never

パッケージ署名の構成

MSIX (または APPX) パッケージに署名するには、パイプラインで署名証明書を取得する必要があります。 これを行うには、VSBuild タスクの前に DownloadSecureFile タスクを追加します。 これにより、signingCert 経由で署名証明書にアクセスできるようになります。

- task: DownloadSecureFile@1
  name: signingCert
  displayName: 'Download CA certificate'
  inputs:
    secureFile: '[Your_Pfx].pfx'

次に、署名証明書を参照するように MSBuild タスクを更新します。

- task: MSBuild@1
  inputs:
    platform: 'x86'
    solution: '$(solution)'
    configuration: '$(buildConfiguration)'
    msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" 
                  /p:AppxPackageDir="$(appxPackageDir)" 
                  /p:AppxBundle=Never 
                  p:UapAppxPackageBuildMode=SideLoadOnly 
                  /p:AppxPackageSigningEnabled=true
                  /p:PackageCertificateThumbprint="" 
                  /p:PackageCertificateKeyFile="$(signingCert.secureFilePath)"'

Note

PackageCertificateThumbprint 引数は、予防措置として、意図的に空の文字列に設定されます。 拇印がプロジェクトで設定されていても、署名証明書と一致しない場合、ビルドは失敗し、次のエラーが表示されます。Certificate does not match supplied signing thumbprint

パラメーターの確認

$() 構文で定義されたパラメーターは、ビルド定義で定義される変数で、他のビルド システムでは変更されます。

すべての定義済みの変数を表示するには、「定義済みのビルド変数」をご覧ください。

ビルド成果物の発行タスクを構成する

既定の MSIX パイプラインでは、生成された成果物は保存されません。 発行機能を YAML 定義に追加するには、次のタスクを追加します。

- task: CopyFiles@2
  displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
  inputs:
    SourceFolder: '$(system.defaultworkingdirectory)'
    Contents: '**\bin\$(BuildConfiguration)\**'
    TargetFolder: '$(build.artifactstagingdirectory)'

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: drop'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'

生成された成果物は、ビルド結果ページの [成果物] オプションで確認できます。

ストア以外での配布用の AppInstaller ファイル

Microsoft Store の外部でアプリケーションを配布している場合は、パッケージのインストールと更新プログラムに AppInstaller ファイルを利用できます。

\server\foo 上で更新されたファイルを検索する .appinstaller ファイル

<?xml version="1.0" encoding="utf-8"?>
<AppInstaller xmlns="http://schemas.microsoft.com/appx/appinstaller/2018"
              Version="1.0.0.0"
              Uri="\\server\foo\MsixDesktopApp.appinstaller">
  <MainPackage Name="MyCompany.MySampleApp"
               Publisher="CN=MyCompany, O=MyCompany, L=Stockholm, S=N/A, C=Sweden"
               Version="1.0.0.0"
               Uri="\\server\foo\MsixDesktopApp.msix"
               ProcessorArchitecture="x86"/>
  <UpdateSettings>
    <OnLaunch HoursBetweenUpdateChecks="0" />
  </UpdateSettings>
</AppInstaller>

UpdateSettings 要素は、更新プログラムを確認するタイミングと、ユーザーに更新を強制するかどうかをシステムに指示するために使用されます。 Windows 10 の各バージョンでサポートされている名前空間を含む完全なスキーマ参照は、bit.ly/2TGWnCR にあるドキュメントに記載されています。

.appinstaller ファイルをパッケージ プロジェクトに追加し、その [パッケージアクション] プロパティを [コンテンツ] に、[出力ディレクトリにコピー] プロパティを [新しい場合はコピーする] に設定すると、別の PowerShell タスクを YAML ファイルに追加できます。このタスクは、ルートのバージョン属性と MainPackage 要素を更新し、更新されたファイルをステージング ディレクトリに保存します。

- powershell: |
  [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
  $doc = [System.Xml.Linq.XDocument]::Load(
    "$(Build.SourcesDirectory)/Msix/Package.appinstaller")
  $version = "$(major).$(minor).$(build).$(revision)"
  $doc.Root.Attribute("Version").Value = $version;
  $xName =
    [System.Xml.Linq.XName]
      "{http://schemas.microsoft.com/appx/appinstaller/2018}MainPackage"
  $doc.Root.Element($xName).Attribute("Version").Value = $version;
  $doc.Save("$(Build.ArtifactStagingDirectory)/MsixDesktopApp.appinstaller")
displayName: 'Version App Installer File'

次に、.appinstaller ファイルをエンド ユーザーに配布し、.msix ファイルではなく、このファイルをダブルクリックしてパッケージ アプリをインストールできるようにします。

継続的なデプロイ

アプリ インストーラー ファイル自体は、コンパイルされていない XML ファイルであり、必要に応じてビルド後に編集できます。 これにより、複数の環境にソフトウェアをデプロイする場合や、ビルド パイプラインをリリース プロセスから分離する場合に、簡単に使用できるようになります。

"空のジョブ" テンプレートを使用して Azure Portal でリリース パイプラインを作成し、デプロイする成果物のソースとして最近設定したビルド パイプラインを使用する場合、.appinstaller ファイル内の 2 つの Uri 属性の値が、アプリが発行される場所を反映するために動的に変更されるように、PowerShell タスクをリリース ステージに追加することができます。

.appinstaller ファイルの Uri を変更するリリース パイプライン タスク

- powershell: |
  [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
  $fileShare = "\\filesharestorageccount.file.core.windows.net\myfileshare\"
  $localFilePath =
    "$(System.DefaultWorkingDirectory)\_MsixDesktopApp\drop\MsixDesktopApp.appinstaller"
  $doc = [System.Xml.Linq.XDocument]::Load("$localFilePath")
  $doc.Root.Attribute("Uri").Value = [string]::Format('{0}{1}', $fileShare,
    'MsixDesktopApp.appinstaller')
  $xName =
    [System.Xml.Linq.XName]"{http://schemas.microsoft.com/appx/appinstaller/2018}MainPackage"
  $doc.Root.Element($xName).Attribute("Uri").Value = [string]::Format('{0}{1}',
    $fileShare, 'MsixDesktopApp.appx')
  $doc.Save("$localFilePath")
displayName: 'Modify URIs in App Installer File'

上のタスクでは、URI は Azure ファイル共有の UNC パスに設定されています。 これは、アプリをインストールおよび更新するときに、OS が MSIX パッケージを検索する場所であるため、リリース パイプラインに別のコマンドライン スクリプトも追加しています。このスクリプトは、最初にクラウド内のファイル共有をビルド エージェント上のローカルの Z:\ ドライブにマップしてから、xcopy コマンドを使用して、.appinstaller ファイルと msix ファイルをそこにコピーします。

- script: |
  net use Z: \\filesharestorageccount.file.core.windows.net\myfileshare
    /u:AZURE\filesharestorageccount
    3PTYC+ociHIwNgCnyg7zsWoKBxRmkEc4Aew4FMzbpUl/
    dydo/3HVnl71XPe0uWxQcLddEUuq0fN8Ltcpc0LYeg==
  xcopy $(System.DefaultWorkingDirectory)\_MsixDesktopApp\drop Z:\ /Y
  displayName: 'Publish App Installer File and MSIX package'

独自のオンプレミスの Azure DevOps Server をホストしている場合は、自身の内部ネットワーク共有にファイルを発行することはもちろん可能です。

Web サーバーに発行することを選択した場合は、YAML ファイルでいくつか追加の引数を指定することで、バージョン管理された .appinstaller ファイルと、ダウンロード リンクとパッケージ アプリに関するいくつかの情報を含む HTML ページを生成するよう MSBuild に指示できます。

- task: MSBuild@1
  inputs:
    solution: Msix/Msix.wapproj
    platform: $(buildPlatform)
    configuration: $(buildConfiguration)
    msbuildArguments: '/p:OutputPath=NonPackagedApp /p:UapAppxPackageBuildMode=SideLoadOnly  /p:AppxBundle=Never /p:GenerateAppInstallerFile=True
/p:AppInstallerUri=http://yourwebsite.com/packages/ /p:AppInstallerCheckForUpdateFrequency=OnApplicationRun /p:AppInstallerUpdateFrequency=1 /p:AppxPackageDir=$(Build.ArtifactStagingDirectory)/'
  displayName: 'Package the App'

生成された HTML ファイルには、ブラウザーに依存しない ms-appinstaller プロトコル アクティブ化スキームのプレフィックスが付いたハイパーリンクが含まれています。

<a href="ms-appinstaller:?source=
  http://yourwebsite.com/packages/Msix_x86.appinstaller ">Install App</a>

ドロップ フォルダーの内容をイントラネットまたはその他の Web サイトに発行するリリース パイプラインを設定し、Web サーバーがバイト範囲要求をサポートしていて、適切に構成されている場合、エンド ユーザーは、最初に MSIX パッケージをダウンロードしなくても、このリンクを使用してアプリを直接インストールすることができます。