2015-04-07 21:05:52 +00:00
|
|
|
#
|
|
|
|
# win-setup - Prepare a Windows development environment for building Wireshark.
|
|
|
|
#
|
|
|
|
# Copyright 2015 Gerald Combs <gerald@wireshark.org>
|
|
|
|
#
|
|
|
|
# Wireshark - Network traffic analyzer
|
|
|
|
# By Gerald Combs <gerald@wireshark.org>
|
|
|
|
# Copyright 1998 Gerald Combs
|
|
|
|
#
|
2018-03-06 14:31:02 +00:00
|
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
2015-04-07 21:05:52 +00:00
|
|
|
|
|
|
|
#requires -version 2
|
|
|
|
|
|
|
|
# To do:
|
2021-12-04 19:29:33 +00:00
|
|
|
# - Use Expand-Archive instead of `cmake -E tar`? That requires PS >= 5.0
|
2015-04-07 21:05:52 +00:00
|
|
|
|
|
|
|
<#
|
|
|
|
.SYNOPSIS
|
|
|
|
Prepare a Windows development environment for building Wireshark.
|
|
|
|
|
|
|
|
.DESCRIPTION
|
|
|
|
This script downloads and extracts third-party libraries required to compile
|
|
|
|
Wireshark.
|
|
|
|
|
|
|
|
.PARAMETER Destination
|
|
|
|
Specifies the destination directory for the text files. The path must
|
|
|
|
contain the pattern "wireshark-*-libs".
|
|
|
|
|
|
|
|
.PARAMETER Platform
|
2022-05-13 18:22:39 +00:00
|
|
|
Target platform. Must be "win64".
|
2015-04-07 21:05:52 +00:00
|
|
|
|
2022-05-25 17:29:57 +00:00
|
|
|
.PARAMETER CMakeExecutable
|
|
|
|
Specifies the path to the CMake executable, which is used to extract archives.
|
|
|
|
|
2015-04-07 21:05:52 +00:00
|
|
|
.INPUTS
|
|
|
|
-Destination Destination directory.
|
|
|
|
-Platform Target platform.
|
2022-05-25 17:29:57 +00:00
|
|
|
-CMakeExecutable Path to CMake.
|
2015-04-07 21:05:52 +00:00
|
|
|
|
|
|
|
.OUTPUTS
|
|
|
|
A set of libraries required to compile Wireshark on Windows, along with
|
|
|
|
their compressed archives.
|
2022-05-22 16:09:27 +00:00
|
|
|
A manifest file (library-manifest.xml)
|
2015-04-07 21:05:52 +00:00
|
|
|
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> .\tools\win-setup.ps1 -Destination C:\wireshark-master-64-libs -Platform win64
|
|
|
|
#>
|
|
|
|
|
|
|
|
Param(
|
|
|
|
[Parameter(Mandatory=$true, Position=0)]
|
2021-09-20 13:34:01 +00:00
|
|
|
[ValidateScript({$_ -like "*[/\]wireshark-*-libs"})]
|
2015-04-07 21:05:52 +00:00
|
|
|
[String]
|
|
|
|
$Destination,
|
|
|
|
|
|
|
|
[Parameter(Mandatory=$true, Position=1)]
|
2022-05-13 18:22:39 +00:00
|
|
|
[ValidateSet("win64")]
|
2015-04-07 21:05:52 +00:00
|
|
|
[String]
|
2022-05-25 17:29:57 +00:00
|
|
|
$Platform,
|
|
|
|
|
|
|
|
[Parameter(Mandatory=$false, Position=3)]
|
|
|
|
[ValidateScript({$_ | Test-Path -Type leaf })]
|
|
|
|
[String]
|
|
|
|
$CMakeExecutable = "CMake"
|
2015-04-07 21:05:52 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# Variables
|
|
|
|
|
|
|
|
# We create and delete files and directories. Bail out at the first sign of
|
|
|
|
# trouble instead of trying to catch exceptions everywhere.
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
|
2018-08-04 09:05:27 +00:00
|
|
|
# Archive file / SHA256
|
2015-04-07 21:05:52 +00:00
|
|
|
$Win64Archives = @{
|
2022-05-22 16:09:27 +00:00
|
|
|
"AirPcap/AirPcap_Devpack_4_1_0_1622.zip" = "09d637f28a79b1d2ecb09f35436271a90c0f69bd0a1ee82b803abaaf63c18a69";
|
2022-07-29 19:38:18 +00:00
|
|
|
"bcg729/bcg729-1.0.4-win64ws.zip" = "9a095fda4c39860d96f0c568830faa6651cd17635f68e27aa6de46c689aa0ee2";
|
2022-05-22 16:09:27 +00:00
|
|
|
"brotli/brotli-1.0.9-1-win64ws.zip" = "3f8d24aec8668201994327ff8d8542fe507d1d468a500a1aec50d0415f695aab";
|
2022-07-27 20:51:20 +00:00
|
|
|
"c-ares/c-ares-1.18.1-1-win64ws.zip" = "61183970996150e2eb137dfa7f5842ffa6e0eec2819634d5bdadc84013f8411d";
|
2022-05-22 16:09:27 +00:00
|
|
|
"gnutls/gnutls-3.6.3-1-win64ws.zip" = "994ac2578e7b4ca01e589ab2598927d53f7370bc3ff679f3006b0e6bb7a06df4";
|
|
|
|
"krb5/krb5-1.17-1-win64ws.zip" = "1f4a7ab86ae331ea9e58c9776a60def81ae9fe622882b2e8da2ad6ce6f6fb1d8";
|
2022-08-20 00:23:14 +00:00
|
|
|
"libgcrypt/libgcrypt-1.10.1-2-win64ws.zip" = "61e1157f7623ef70e39ddf3aa6689ca581dc2ed14461515f149f83f11d0fb0a5";
|
2022-05-22 16:09:27 +00:00
|
|
|
"libilbc/libilbc-2.0.2-3-win64ws.zip" = "d7baeb98627c405bd7c3e41d6b07c4ea4f0f5db88436e566148320afd10cbb66";
|
|
|
|
"libmaxminddb/libmaxminddb-1.4.3-1-win64ws.zip" = "ee89944a19ab6e1c873bdecb9fc6205d317c41e6da6ec1d30bc892fddfd143da";
|
|
|
|
"libpcap/libpcap-1.10.1-1-win64ws.zip" = "59f8e0e90a3ab5671df561266ed2b02870a6f8f3a895b80c9db19fea9a12ffb2";
|
|
|
|
"libsmi/libsmi-svn-40773-win64ws.zip" = "571fcee71d741bf847c3247d4c2e1c42388ca6a9feebe08fc0d4ce053571d15d";
|
|
|
|
"libssh/libssh-0.9.5-win64ws.zip" = "3226fcb89969a77643bd2bca7a1ff6b5a79261b680a09a6bfedb3d40f7a187e3";
|
|
|
|
"lua/lua-5.2.4-unicode-win64-vc14.zip" = "e8968d2c7871ce1ea82cbd29ac1b3a2c59d3dec25e483c5e12de85df66f5d928";
|
|
|
|
"lz4/lz4-1.9.3-1-win64ws.zip" = "7129515893ffdc439f4ffe9673c4bc43f9042e910bb2607e68dde6b99a1ab058";
|
|
|
|
"minizip/minizip-1.2.11-4-win64ws.zip" = "dd6bf24e2d946465ad19aa4f8c38e0db91da6585887935de68011982cd6fb2cb";
|
2022-08-25 11:34:57 +00:00
|
|
|
"nghttp2/nghttp2-1.49.0-1-win64ws.zip" = "215919ec20be62101d4704ec2464bfb72c5677126c5245b92ba495a3d30642ca";
|
2022-05-22 16:09:27 +00:00
|
|
|
"opus/opus-1.3.1-3-win64ws.zip" = "1f7a55a6d2d7215dffa4a43bca8ca05024bd4ba1ac3d0d0c405fd38b09cc2205";
|
2022-07-27 20:51:20 +00:00
|
|
|
"pcre2/pcre2-10.40-1-win64ws.zip" = "17eee615990b23bc859a862c19f5ac10c61776587603bc452285abe073a0fad9";
|
2022-05-22 16:09:27 +00:00
|
|
|
"sbc/sbc-1.3-1-win64ws.zip" = "08cef6898c421277a6582ef3225d8820f74a037cbd5b6e673a4d8f4593ce80a1";
|
|
|
|
"snappy/snappy-1.1.9-1-win64ws.zip" = "fa907724be019bcc55d27ebe88257ba8898b5c38b719099b8164ac78600d81cc";
|
|
|
|
"spandsp/spandsp-0.0.6-2-win64ws.zip" = "2eb8278633037f60f44815ea1606486ab5dcdf3bddc500b20c9fe356856236b2";
|
2022-12-15 18:54:48 +00:00
|
|
|
"speexdsp/speexdsp-1.21.1-1-win64ws.zip" = "d36db62e64ffaee38d9f607bef07d3778d8957ad29757f3eba169eb135f1a4e5";
|
2022-07-26 22:43:49 +00:00
|
|
|
"vcpkg-export/vcpkg-export-20220726-1-win64ws.zip" = "b1eaa8124802532fa8d30789219906f90fb80908844e4458327b3f73995a44b0";
|
2022-05-22 16:09:27 +00:00
|
|
|
"WinSparkle/WinSparkle-0.5.7.zip" = "56d396ef0c4e8b0589ea74134e484376ca6459d972cd1ab1da6b9624d82e6d04";
|
2022-05-24 16:52:16 +00:00
|
|
|
"zstd/zstd-1.5.2-1-win64ws.zip" = "d920afe636951cfcf144824d9c075d1f2c13387f4739152fe185fd9c09fc58f2";
|
2015-04-07 21:05:52 +00:00
|
|
|
}
|
|
|
|
|
2018-08-04 09:05:27 +00:00
|
|
|
# Subdirectory to extract an archive to
|
|
|
|
$ArchivesSubDirectory = @{
|
2022-05-22 16:09:27 +00:00
|
|
|
"AirPcap/AirPcap_Devpack_4_1_0_1622.zip" = "AirPcap_Devpack_4_1_0_1622";
|
2015-04-07 21:05:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Plain file downloads
|
|
|
|
|
2018-08-04 09:05:27 +00:00
|
|
|
$Win64Files = @{
|
2022-08-25 12:59:35 +00:00
|
|
|
"Npcap/npcap-1.71.exe" = "5ccb61296c48e3f8cd20db738784bd7bf0daf8fce630f89892678b6dda4e533c";
|
2022-05-22 16:09:27 +00:00
|
|
|
"USBPcap/USBPcapSetup-1.5.4.0.exe" = "87a7edf9bbbcf07b5f4373d9a192a6770d2ff3add7aa1e276e82e38582ccb622";
|
2018-08-04 09:05:27 +00:00
|
|
|
}
|
2015-04-07 21:05:52 +00:00
|
|
|
|
|
|
|
$Archives = $Win64Archives;
|
|
|
|
$Files = $Win64Files;
|
2022-05-22 16:09:27 +00:00
|
|
|
$CurrentManifest = $Archives + $Files
|
2015-04-07 21:05:52 +00:00
|
|
|
|
|
|
|
$CleanupItems = @(
|
2017-07-26 21:23:12 +00:00
|
|
|
"bcg729-1.0.4-win??ws"
|
2020-12-07 21:14:27 +00:00
|
|
|
"brotli-1.0.*-win??ws"
|
2015-04-07 21:05:52 +00:00
|
|
|
"c-ares-1.9.1-1-win??ws"
|
2017-06-28 07:33:55 +00:00
|
|
|
"c-ares-1.1*-win??ws"
|
2018-12-15 17:45:53 +00:00
|
|
|
"gnutls-3.?.*-*-win??ws"
|
2019-02-08 18:06:49 +00:00
|
|
|
"krb5-*-win??ws"
|
2018-08-03 16:49:57 +00:00
|
|
|
"libgcrypt-*-win??ws"
|
2019-11-18 22:55:25 +00:00
|
|
|
"libilbc-2.0.2-3-win??ws"
|
2020-12-07 21:14:27 +00:00
|
|
|
"libmaxminddb-1.4.3-1-win??ws"
|
2020-12-14 19:01:10 +00:00
|
|
|
"libpcap-1.9.1-1-win??ws"
|
2015-04-07 21:05:52 +00:00
|
|
|
"libsmi-0.4.8"
|
|
|
|
"libsmi-svn-40773-win??ws"
|
2020-12-08 22:18:39 +00:00
|
|
|
"libssh-0.*-win??ws"
|
2017-04-04 21:23:59 +00:00
|
|
|
"libxml2-*-win??ws"
|
2016-10-17 19:04:49 +00:00
|
|
|
"lua5.1.4"
|
|
|
|
"lua5.2.?"
|
2018-12-28 11:49:33 +00:00
|
|
|
"lua5.2.?-win??"
|
2019-01-18 07:11:19 +00:00
|
|
|
"lua-5.?.?-unicode-win??-vc??"
|
2017-05-11 19:15:28 +00:00
|
|
|
"lz4-*-win??ws"
|
2018-03-07 21:10:31 +00:00
|
|
|
"MaxMindDB-1.3.2-win??ws"
|
2019-07-10 22:25:45 +00:00
|
|
|
"minizip-*-win??ws"
|
2016-08-26 13:18:29 +00:00
|
|
|
"nghttp2-*-win??ws"
|
2020-09-29 04:33:06 +00:00
|
|
|
"opus-1.3.1-?-win??ws"
|
2022-07-27 20:51:20 +00:00
|
|
|
"pcre2-*-win??ws"
|
2016-10-22 16:15:51 +00:00
|
|
|
"sbc-1.3-win??ws"
|
2020-12-07 21:14:27 +00:00
|
|
|
"snappy-1.1.*-win??ws"
|
2016-11-23 23:27:14 +00:00
|
|
|
"spandsp-0.0.6-win??ws"
|
2022-12-15 18:54:48 +00:00
|
|
|
"speexdsp-*-win??ws"
|
2015-04-07 21:05:52 +00:00
|
|
|
"user-guide"
|
2019-04-30 09:36:29 +00:00
|
|
|
"vcpkg-export-*-win??ws"
|
2019-08-12 21:57:45 +00:00
|
|
|
"zstd-*-win??ws"
|
2015-04-07 21:05:52 +00:00
|
|
|
"AirPcap_Devpack_4_1_0_1622"
|
|
|
|
"WinSparkle-0.3-44-g2c8d9d3-win??ws"
|
2016-12-08 17:41:47 +00:00
|
|
|
"WinSparkle-0.5.?"
|
2015-04-07 21:05:52 +00:00
|
|
|
"current-tag.txt"
|
2022-05-22 16:09:27 +00:00
|
|
|
"library-manifest.xml"
|
2015-04-07 21:05:52 +00:00
|
|
|
)
|
|
|
|
|
2022-05-22 16:09:27 +00:00
|
|
|
# The dev-libs site repository is at
|
|
|
|
# https://gitlab.com/wireshark/wireshark-development-libraries
|
|
|
|
[Uri] $DownloadPrefix = "https://dev-libs.wireshark.org/windows/packages"
|
2018-08-04 09:32:32 +00:00
|
|
|
$proxy = $null
|
2015-04-07 21:05:52 +00:00
|
|
|
|
|
|
|
# Functions
|
|
|
|
|
2022-05-22 16:09:27 +00:00
|
|
|
# Verifies the contents of a file against a SHA256 hash.
|
2018-08-04 09:05:27 +00:00
|
|
|
# Returns success (0) if the file exists and verifies.
|
|
|
|
# Returns error (1) if the file does not exist.
|
|
|
|
# Returns error (2) if the integrity check fails (an error is also printed).
|
|
|
|
function VerifyIntegrity($filename, $hash) {
|
|
|
|
# Use absolute path because PS and .NET may have different working directories.
|
|
|
|
$filepath = Convert-Path -Path $filename -ErrorAction SilentlyContinue
|
|
|
|
if (-not ($filepath)) {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
# may throw due to permission error, I/O error, etc.
|
|
|
|
try { $stream = [IO.File]::OpenRead($filepath) } catch { throw }
|
|
|
|
|
|
|
|
try {
|
|
|
|
$sha256 = New-Object Security.Cryptography.SHA256Managed
|
|
|
|
$binaryHash = $sha256.ComputeHash([IO.Stream]$stream)
|
|
|
|
$hexHash = ([System.BitConverter]::ToString($binaryHash) -Replace "-").ToLower()
|
|
|
|
$hash = $hash.ToLower()
|
|
|
|
if ($hexHash -ne $hash) {
|
2022-05-22 16:09:27 +00:00
|
|
|
Write-Warning "$($filename): computed file hash $hexHash did NOT match $hash"
|
2018-08-04 09:05:27 +00:00
|
|
|
return 2
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
} finally {
|
|
|
|
$stream.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Downloads a file and checks its integrity. If a corrupt file already exists,
|
2022-05-22 16:09:27 +00:00
|
|
|
# it is removed and re-downloaded. Succeeds only if the SHA256 hash matches.
|
|
|
|
function DownloadFile($fileName, $fileHash, [Uri] $fileUrl = $null) {
|
2015-04-28 19:04:34 +00:00
|
|
|
if ([string]::IsNullOrEmpty($fileUrl)) {
|
|
|
|
$fileUrl = "$DownloadPrefix/$fileName"
|
|
|
|
}
|
2022-05-22 16:09:27 +00:00
|
|
|
$destinationFile = "$Destination\" + [string](Split-Path -Leaf $fileName)
|
2018-08-04 09:05:27 +00:00
|
|
|
if (Test-Path $destinationFile -PathType 'Leaf') {
|
2022-05-22 16:09:27 +00:00
|
|
|
if ((VerifyIntegrity $destinationFile $fileHash) -ne 0) {
|
2018-08-04 09:05:27 +00:00
|
|
|
Write-Output "$fileName is corrupt, removing and retrying download."
|
|
|
|
Remove-Item $destinationFile
|
|
|
|
} else {
|
|
|
|
Write-Output "$fileName already there; not retrieving."
|
|
|
|
return
|
|
|
|
}
|
2015-04-07 21:05:52 +00:00
|
|
|
}
|
2015-04-17 09:25:26 +00:00
|
|
|
|
2018-08-04 09:32:32 +00:00
|
|
|
if (-not ($Script:proxy)) {
|
|
|
|
$Script:proxy = [System.Net.WebRequest]::GetSystemWebProxy()
|
|
|
|
$Script:proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
|
|
|
|
}
|
2015-04-17 09:25:26 +00:00
|
|
|
|
2015-04-07 21:05:52 +00:00
|
|
|
Write-Output "Downloading $fileUrl into $Destination"
|
|
|
|
$webClient = New-Object System.Net.WebClient
|
2018-08-04 09:32:32 +00:00
|
|
|
$webClient.proxy = $Script:proxy
|
2018-08-04 09:05:27 +00:00
|
|
|
$webClient.DownloadFile($fileUrl, "$destinationFile")
|
|
|
|
Write-Output "Verifying $destinationFile"
|
2022-05-22 16:09:27 +00:00
|
|
|
if ((VerifyIntegrity $destinationFile $fileHash) -ne 0) {
|
2018-08-04 09:05:27 +00:00
|
|
|
Write-Output "Download is corrupted, aborting!"
|
|
|
|
exit 1
|
|
|
|
}
|
2015-04-07 21:05:52 +00:00
|
|
|
}
|
|
|
|
|
2022-05-22 16:09:27 +00:00
|
|
|
function DownloadArchive($fileName, $fileHash, $subDir) {
|
|
|
|
DownloadFile $fileName $fileHash
|
|
|
|
$archiveFile = "$Destination\" + [string](Split-Path -Leaf $fileName)
|
2015-04-07 21:05:52 +00:00
|
|
|
$archiveDir = "$Destination\$subDir"
|
|
|
|
if ($subDir -and -not (Test-Path $archiveDir -PathType 'Container')) {
|
|
|
|
New-Item -ItemType Directory -Path $archiveDir > $null
|
|
|
|
}
|
2019-09-24 07:41:15 +00:00
|
|
|
|
2015-04-28 19:04:34 +00:00
|
|
|
$activity = "Extracting into $($archiveDir)"
|
2021-12-04 19:29:33 +00:00
|
|
|
Write-Progress -Activity "$activity" -Status "Extracting $archiveFile using CMake ..."
|
|
|
|
Push-Location "$archiveDir"
|
2022-05-25 17:29:57 +00:00
|
|
|
& "$CMakeExecutable" -E tar xf "$archiveFile" 2>&1 | Set-Variable -Name CMakeOut
|
2021-12-04 19:29:33 +00:00
|
|
|
$cmStatus = $LASTEXITCODE
|
|
|
|
Pop-Location
|
2015-04-07 21:05:52 +00:00
|
|
|
Write-Progress -Activity "$activity" -Status "Done" -Completed
|
2021-12-04 19:29:33 +00:00
|
|
|
if ($cmStatus -gt 0) {
|
|
|
|
Write-Output $CMakeOut
|
2015-04-28 19:04:34 +00:00
|
|
|
exit 1
|
|
|
|
}
|
2015-04-07 21:05:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# On with the show
|
|
|
|
|
|
|
|
# Make sure $Destination exists and do our work there.
|
|
|
|
if ( -not (Test-Path $Destination -PathType 'Container') ) {
|
|
|
|
New-Item -ItemType 'Container' "$Destination" > $null
|
|
|
|
}
|
|
|
|
|
|
|
|
# CMake's file TO_NATIVE_PATH passive-aggressively omits the drive letter.
|
|
|
|
Set-Location "$Destination"
|
|
|
|
$Destination = $(Get-Item -Path ".\")
|
|
|
|
Write-Output "Working in $Destination"
|
|
|
|
|
|
|
|
# Check our last known state
|
2022-05-22 16:09:27 +00:00
|
|
|
$destinationManifest = @{ "INVALID" = "INVALID" }
|
|
|
|
$manifestFile = "library-manifest.xml"
|
|
|
|
if ((Test-Path $manifestFile -PathType 'Leaf') -and -not ($Force)) {
|
|
|
|
$destinationManifest = Import-Clixml $manifestFile
|
|
|
|
}
|
|
|
|
|
|
|
|
function ManifestList($manifestHash) {
|
|
|
|
$manifestHash.keys | Sort | ForEach-Object { "$_ : $($manifestHash[$_])" }
|
2015-04-07 21:05:52 +00:00
|
|
|
}
|
|
|
|
|
2022-05-22 16:09:27 +00:00
|
|
|
if (Compare-Object -ReferenceObject (ManifestList($destinationManifest)) -DifferenceObject (ManifestList($CurrentManifest))) {
|
|
|
|
Write-Output "Current library manifest not found. Refreshing."
|
2015-04-07 21:05:52 +00:00
|
|
|
$activity = "Removing directories"
|
|
|
|
foreach ($oldItem in $CleanupItems) {
|
|
|
|
if (Test-Path $oldItem) {
|
|
|
|
Write-Progress -Activity "$activity" -Status "Removing $oldItem"
|
|
|
|
Remove-Item -force -recurse $oldItem
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Write-Progress -Activity "$activity" -Status "Done" -Completed
|
|
|
|
} else {
|
2022-05-22 16:09:27 +00:00
|
|
|
Write-Output "Current library manifest found. Skipping download."
|
2015-04-07 21:05:52 +00:00
|
|
|
exit 0
|
|
|
|
}
|
|
|
|
|
|
|
|
# Download files
|
2018-08-04 09:05:27 +00:00
|
|
|
foreach ($item in $Files.GetEnumerator() | Sort-Object -property key) {
|
|
|
|
DownloadFile $item.Name $item.Value
|
2015-04-07 21:05:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Download and extract archives
|
|
|
|
foreach ($item in $Archives.GetEnumerator() | Sort-Object -property key) {
|
2018-08-04 09:05:27 +00:00
|
|
|
$subDir = $ArchivesSubDirectory[$item.Name]
|
|
|
|
DownloadArchive $item.Name $item.Value $subDir
|
2015-04-07 21:05:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Save our last known state
|
2022-05-22 16:09:27 +00:00
|
|
|
$CurrentManifest | Export-Clixml -Path $manifestFile -Encoding utf8
|