diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt
index f063332bb8..67acd6b889 100644
--- a/.github/actions/spelling/expect.txt
+++ b/.github/actions/spelling/expect.txt
@@ -18,6 +18,7 @@ alreadyinstalled
AMap
Amd
amrutha
+amsi
ansistring
APARTMENTTHREADED
apfn
@@ -209,6 +210,8 @@ gwgso
gwgus
gwgv
Hackathon
+HAMSICONTEXT
+HAMSISESSION
hashtables
helplib
helplibrary
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
index 043eab3f5a..19ae2652ce 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -506,6 +506,9 @@
true
+
+ true
+
true
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
index a24784a802..13cbc13fb2 100644
--- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
+++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
@@ -633,6 +633,9 @@
TestData
+
+ TestData
+
TestData
diff --git a/src/AppInstallerCLITests/Archive.cpp b/src/AppInstallerCLITests/Archive.cpp
index 4d415761f1..238d640d87 100644
--- a/src/AppInstallerCLITests/Archive.cpp
+++ b/src/AppInstallerCLITests/Archive.cpp
@@ -1,34 +1,82 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-#include "pch.h"
-#include "TestCommon.h"
-#include
-
-using namespace AppInstaller::Archive;
-using namespace TestCommon;
-
-constexpr std::string_view s_ZipFile = "TestZip.zip";
-
-TEST_CASE("Extract_ZipArchive", "[archive]")
-{
- TestCommon::TempDirectory tempDirectory("TempDirectory");
- TestDataFile testZip(s_ZipFile);
-
- const auto& testZipPath = testZip.GetPath();
- const auto& tempDirectoryPath = tempDirectory.GetPath();
-
- HRESULT hr = TryExtractArchive(testZipPath, tempDirectoryPath);
-
- std::filesystem::path expectedPath = tempDirectoryPath / "test.txt";
- REQUIRE(SUCCEEDED(hr));
- REQUIRE(std::filesystem::exists(expectedPath));
-}
-
-TEST_CASE("Scan_ZipArchive", "[archive]")
-{
- TestDataFile testZip(s_ZipFile);
-
- const auto& testZipPath = testZip.GetPath();
- bool result = ScanZipFile(testZipPath);
- REQUIRE(result);
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "TestCommon.h"
+#include "WorkflowCommon.h"
+#include
+#include
+
+using namespace AppInstaller::Archive;
+using namespace AppInstaller::CLI::Workflow;
+using namespace AppInstaller::Settings;
+using namespace TestCommon;
+
+constexpr std::string_view s_ZipFile = "TestZip.zip";
+constexpr std::string_view s_TarGzFile = "TestTarGz.tar.gz";
+constexpr std::string_view s_Large7zFile = "TestLarge7z.7z";
+
+TEST_CASE("Extract_ZipArchive", "[archive]")
+{
+ TestCommon::TempDirectory tempDirectory("TempDirectory");
+ TestDataFile testZip(s_ZipFile);
+
+ const auto& testZipPath = testZip.GetPath();
+ const auto& tempDirectoryPath = tempDirectory.GetPath();
+
+ HRESULT hr = TryExtractArchive(testZipPath, tempDirectoryPath);
+
+ std::filesystem::path expectedPath = tempDirectoryPath / "test.txt";
+ REQUIRE(SUCCEEDED(hr));
+ REQUIRE(std::filesystem::exists(expectedPath));
+}
+
+TEST_CASE("Scan_ZipArchive", "[archive]")
+{
+ TestDataFile testZip(s_ZipFile);
+
+ const auto& testZipPath = testZip.GetPath();
+ bool result = ScanZipFile(testZipPath);
+ REQUIRE(result);
+}
+
+TEST_CASE("Extract_TarGzArchive", "[archive]")
+{
+ TestCommon::TempDirectory tempDirectory("TempDirectory");
+ TestDataFile testTarGz(s_TarGzFile);
+
+ TestCommon::TestUserSettings testSettings;
+ testSettings.Set(AppInstaller::Archive::ExtractionMethod::Tar);
+
+ const auto& testTarGzPath = testTarGz.GetPath();
+ const auto& tempDirectoryPath = tempDirectory.GetPath();
+
+ ShellExecuteExtractArchive(testTarGzPath, tempDirectoryPath);
+
+ std::ostringstream extractOutput;
+ TestContext context{ extractOutput, std::cin };
+ context << ShellExecuteExtractArchive(testTarGzPath, tempDirectoryPath);
+
+ std::filesystem::path expectedPath = tempDirectoryPath / "test.txt";
+ REQUIRE(SUCCEEDED(context.GetTerminationHR()));
+ REQUIRE(std::filesystem::exists(expectedPath));
+ INFO(extractOutput.str());
+}
+
+TEST_CASE("Scan_TarGzArchive", "[archive]")
+{
+ TestDataFile testTarGz(s_TarGzFile);
+
+ const auto& testTarGzPath = testTarGz.GetPath();
+ bool result = ScanZipFile(testTarGzPath);
+ REQUIRE(result);
+}
+
+//TEST_CASE("Scan_Large7zArchive", "[archive]")
+//{
+// TestDataFile testLarge7z(s_Large7zFile);
+//
+// const auto& testTarGzPath = testLarge7z.GetPath();
+// bool result = ScanZipFile(testTarGzPath);
+// REQUIRE(result);
+//}
+
diff --git a/src/AppInstallerCLITests/TestData/TestTarGz.tar.gz b/src/AppInstallerCLITests/TestData/TestTarGz.tar.gz
new file mode 100644
index 0000000000..0a127aac9b
Binary files /dev/null and b/src/AppInstallerCLITests/TestData/TestTarGz.tar.gz differ
diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj
index d57fcfc5e6..75676ded8f 100644
--- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj
+++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj
@@ -274,6 +274,21 @@
Windows
Windows
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
@@ -287,6 +302,9 @@
Windows
+
+ amsi.lib;%(AdditionalDependencies)
+
@@ -324,6 +342,18 @@
Windows
Windows
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
@@ -365,6 +395,18 @@
Windows
Windows
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
@@ -385,6 +427,12 @@
false
Windows
+
+ amsi.lib;%(AdditionalDependencies)
+
+
+ amsi.lib;%(AdditionalDependencies)
+
diff --git a/src/AppInstallerCommonCore/Archive.cpp b/src/AppInstallerCommonCore/Archive.cpp
index 95766519e9..af1a432d0d 100644
--- a/src/AppInstallerCommonCore/Archive.cpp
+++ b/src/AppInstallerCommonCore/Archive.cpp
@@ -1,79 +1,93 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-#include "pch.h"
-#include "Public/winget/Archive.h"
-
-// TODO: Move include statement to pch.h and resolve build errors
-#pragma warning( push )
-#pragma warning ( disable : 4189 4244 26451 )
-#include
-#pragma warning ( pop )
-
-namespace AppInstaller::Archive
-{
- using unique_pidlist_absolute = wil::unique_any;
- using unique_lpitemidlist = wil::unique_any;
-
- HRESULT TryExtractArchive(const std::filesystem::path& archivePath, const std::filesystem::path& destPath)
- {
- wil::com_ptr pFileOperation;
- RETURN_IF_FAILED(CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation)));
- RETURN_IF_FAILED(pFileOperation->SetOperationFlags(FOF_NO_UI));
-
- wil::com_ptr pShellItemTo;
- RETURN_IF_FAILED(SHCreateItemFromParsingName(destPath.c_str(), NULL, IID_PPV_ARGS(&pShellItemTo)));
-
- unique_pidlist_absolute pidlFull;
- RETURN_IF_FAILED(SHParseDisplayName(archivePath.c_str(), NULL, &pidlFull, 0, NULL));
-
- wil::com_ptr pArchiveShellFolder;
- RETURN_IF_FAILED(SHBindToObject(NULL, pidlFull.get(), NULL, IID_PPV_ARGS(&pArchiveShellFolder)));
-
- wil::com_ptr pEnumIdList;
- RETURN_IF_FAILED(pArchiveShellFolder->EnumObjects(nullptr, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnumIdList));
-
- unique_lpitemidlist pidlChild;
- ULONG nFetched;
- while (pEnumIdList->Next(1, wil::out_param_ptr(pidlChild), &nFetched) == S_OK && nFetched == 1)
- {
- wil::com_ptr pShellItemFrom;
- STRRET strFolderName;
- WCHAR szFolderName[MAX_PATH];
- RETURN_IF_FAILED(pArchiveShellFolder->GetDisplayNameOf(pidlChild.get(), SHGDN_INFOLDER | SHGDN_FORPARSING, &strFolderName));
- RETURN_IF_FAILED(StrRetToBuf(&strFolderName, pidlChild.get(), szFolderName, MAX_PATH));
- RETURN_IF_FAILED(SHCreateItemWithParent(pidlFull.get(), pArchiveShellFolder.get(), pidlChild.get(), IID_PPV_ARGS(&pShellItemFrom)));
- RETURN_IF_FAILED(pFileOperation->CopyItem(pShellItemFrom.get(), pShellItemTo.get(), NULL, NULL));
- }
-
- RETURN_IF_FAILED(pFileOperation->PerformOperations());
- return S_OK;
- }
-
-#ifndef AICLI_DISABLE_TEST_HOOKS
- static bool* s_ScanArchiveResult_TestHook_Override = nullptr;
-
- void TestHook_SetScanArchiveResult_Override(bool* status)
- {
- s_ScanArchiveResult_TestHook_Override = status;
- }
-#endif
-
- bool ScanZipFile(const std::filesystem::path& zipPath)
- {
-#ifndef AICLI_DISABLE_TEST_HOOKS
- if (s_ScanArchiveResult_TestHook_Override)
- {
- return *s_ScanArchiveResult_TestHook_Override;
- }
-#endif
-
- std::ifstream instream{ zipPath, std::ios::in | std::ios::binary };
- std::vector data{ { std::istreambuf_iterator{ instream } }, std::istreambuf_iterator{} };
-
- uint8_t* buffer = &data[0];
- uint64_t flag = 0;
- int scanResult = pure_zip(buffer, data.size(), flag);
-
- return scanResult == 0;
- }
-}
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "Public/winget/Archive.h"
+
+namespace AppInstaller::Archive
+{
+ using unique_pidlist_absolute = wil::unique_any;
+ using unique_lpitemidlist = wil::unique_any;
+
+ HRESULT TryExtractArchive(const std::filesystem::path& archivePath, const std::filesystem::path& destPath)
+ {
+ wil::com_ptr pFileOperation;
+ RETURN_IF_FAILED(CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation)));
+ RETURN_IF_FAILED(pFileOperation->SetOperationFlags(FOF_NO_UI));
+
+ wil::com_ptr pShellItemTo;
+ RETURN_IF_FAILED(SHCreateItemFromParsingName(destPath.c_str(), NULL, IID_PPV_ARGS(&pShellItemTo)));
+
+ unique_pidlist_absolute pidlFull;
+ RETURN_IF_FAILED(SHParseDisplayName(archivePath.c_str(), NULL, &pidlFull, 0, NULL));
+
+ wil::com_ptr pArchiveShellFolder;
+ RETURN_IF_FAILED(SHBindToObject(NULL, pidlFull.get(), NULL, IID_PPV_ARGS(&pArchiveShellFolder)));
+
+ wil::com_ptr pEnumIdList;
+ RETURN_IF_FAILED(pArchiveShellFolder->EnumObjects(nullptr, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnumIdList));
+
+ unique_lpitemidlist pidlChild;
+ ULONG nFetched;
+ while (pEnumIdList->Next(1, wil::out_param_ptr(pidlChild), &nFetched) == S_OK && nFetched == 1)
+ {
+ wil::com_ptr pShellItemFrom;
+ STRRET strFolderName;
+ WCHAR szFolderName[MAX_PATH];
+ RETURN_IF_FAILED(pArchiveShellFolder->GetDisplayNameOf(pidlChild.get(), SHGDN_INFOLDER | SHGDN_FORPARSING, &strFolderName));
+ RETURN_IF_FAILED(StrRetToBuf(&strFolderName, pidlChild.get(), szFolderName, MAX_PATH));
+ RETURN_IF_FAILED(SHCreateItemWithParent(pidlFull.get(), pArchiveShellFolder.get(), pidlChild.get(), IID_PPV_ARGS(&pShellItemFrom)));
+ RETURN_IF_FAILED(pFileOperation->CopyItem(pShellItemFrom.get(), pShellItemTo.get(), NULL, NULL));
+ }
+
+ RETURN_IF_FAILED(pFileOperation->PerformOperations());
+ return S_OK;
+ }
+
+#ifndef AICLI_DISABLE_TEST_HOOKS
+ static bool* s_ScanArchiveResult_TestHook_Override = nullptr;
+
+ void TestHook_SetScanArchiveResult_Override(bool* status)
+ {
+ s_ScanArchiveResult_TestHook_Override = status;
+ }
+#endif
+
+ bool ScanZipFile(const std::filesystem::path& zipPath)
+ {
+#ifndef AICLI_DISABLE_TEST_HOOKS
+ if (s_ScanArchiveResult_TestHook_Override)
+ {
+ return *s_ScanArchiveResult_TestHook_Override;
+ }
+#endif
+
+ HRESULT hr = S_OK;
+ HAMSICONTEXT amsiContext;
+ HAMSISESSION amsiSession;
+
+ hr = AmsiInitialize(L"WinGet", &amsiContext);
+ if (FAILED(hr))
+ {
+ return false;
+ }
+
+ hr = AmsiOpenSession(amsiContext, &amsiSession);
+ if (FAILED(hr))
+ {
+ AmsiUninitialize(amsiContext);
+ return false;
+ }
+
+ std::ifstream instream{ zipPath, std::ios::in | std::ios::binary };
+ std::vector data{ { std::istreambuf_iterator{ instream } }, std::istreambuf_iterator{} };
+
+ AMSI_RESULT result = AMSI_RESULT_CLEAN;
+ hr = AmsiScanBuffer(amsiContext, data.data(), static_cast(data.size()), zipPath.filename().c_str(), amsiSession, &result);
+
+ AmsiCloseSession(amsiContext, amsiSession);
+ AmsiUninitialize(amsiContext);
+
+ return SUCCEEDED(hr) && (result == AMSI_RESULT_CLEAN || result == AMSI_RESULT_NOT_DETECTED);
+ }
+}
+
diff --git a/src/AppInstallerCommonCore/pch.h b/src/AppInstallerCommonCore/pch.h
index 2825b5ff5c..e75482a35e 100644
--- a/src/AppInstallerCommonCore/pch.h
+++ b/src/AppInstallerCommonCore/pch.h
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include "TraceLogging.h"