commit 0c64cb8549d2239b3d813223a0365801dd32831f parent 531d2f1677717c5c4d59f407011e6390f8589506 Author: JohnMcPMS <johnmcp@microsoft.com> Date: Thu, 29 Jun 2023 11:27:14 -0700 Support for out of process configuration clients (#3363) The goal of this rather large change is to support out-of-process clients to configuration. This enables supported scenarios to not require shipping the entire PowerShell infrastructure, and instead leverage the one that is contained in our package. The interface changes are breaking, but minimal. The goal is to remove the necessity for a processor to need the configuration module itself, while creating a single entry point that can be used for OOP cases (and many in-proc cases as well). Diffstat:
154 files changed, 4047 insertions(+), 1072 deletions(-)
diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt @@ -2,6 +2,7 @@ abi ACCESSDENIED ACTIONDATA ACTIONSTART +activatable addfile addmanifest addpin diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt @@ -89,4 +89,5 @@ ^src/YamlCppLib/ # Because it doesn't handle argument -Words well ^tools/CorrelationTestbed/.*\.ps1$ +^tools/COMTrace/ComTrace.wprp$ ignore$ \ No newline at end of file diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt @@ -9,6 +9,7 @@ aicli AICLIC alreadyinstalled amrutha +ansistring APARTMENTTHREADED apfn apicontract @@ -62,6 +63,7 @@ certmgr certs cgi cinq +CLASSNOTREG CLIE cloudapp cls @@ -106,11 +108,13 @@ dvinns ecfr ecfrbrowse EFGH +EFile endregion EQU errmsg ESRB etest +etl execustom EXEHASH experimentalfeatures @@ -169,6 +173,7 @@ IFACEMETHODIMP IHelp iid IISOn +ilemode inet inproc installinprogress @@ -181,6 +186,7 @@ INTRESOURCE invalidparameter IPackage isable +IServer ishelp ISQ ISVs @@ -268,6 +274,7 @@ netlify NETSDK Newtonsoft NNS +NOAGGREGATION NOCRLF NOEXPAND NOLINKINFO @@ -288,6 +295,7 @@ nuffing objbase objidl ofile +ools osfhandle OPTOUT Outptr @@ -302,6 +310,7 @@ pcb PCCERT PCs pcwsz +PDWORD PEGI PFM pfn @@ -320,6 +329,7 @@ pri processthreads productcode PRODUCTICON +proxystub pscustomobject pseudocode PSHOST @@ -338,6 +348,7 @@ rebootrequiredtofinish redirector Redist REFIID +REGDB regexes REGSAM relativefilepath @@ -386,6 +397,7 @@ srs standalone startswith STARTUPINFOW +STDMETHODCALLTYPE STRRET stylecop subdir @@ -429,7 +441,9 @@ uninstallation uninstaller uninstallprevious uninstalls +Unk unknwn +Unknwnbase unparsable unvirtualized UParse @@ -444,6 +458,7 @@ VERSI VERSIE vns vsconfig +vstest webpages Webserver websites @@ -462,7 +477,10 @@ wingetdev wingetutil winreg winrtact +winstring withstarts +wpr +wprp wputenv wsl wsv diff --git a/azure-pipelines.yml b/azure-pipelines.yml @@ -133,7 +133,7 @@ jobs: inputs: targetType: 'inline' script: | - Add-AppxPackage AppInstallerCLIPackage_0.0.2.0_Test\Dependencies\$(buildPlatform)\Microsoft.VCLibs.$(buildPlatform).14.00.Desktop.appx + Get-ChildItem AppInstallerCLIPackage_0.0.2.0_Test\Dependencies\$(buildPlatform) -Filter *.appx | %{ Add-AppxPackage $_.FullName } workingDirectory: $(appxPackageDir) - task: VisualStudioTestPlatformInstaller@1 @@ -240,6 +240,13 @@ jobs: TargetFolder: '$(platformProgramFiles)\dotnet' Contents: Microsoft.Management.Deployment.winmd + - task: PowerShell@2 + displayName: Setup Local PS Repository + inputs: + filePath: 'src\AppInstallerCLIE2ETests\TestData\Configuration\Init-TestRepository.ps1' + arguments: '-Force' + pwsh: true + - template: templates/e2e-test.template.yml parameters: title: "E2E Tests Packaged" @@ -248,13 +255,13 @@ jobs: - template: templates/e2e-test.template.yml parameters: - title: "COM API E2E Tests (In-process)" + title: "Microsoft.Management.Deployment E2E Tests (In-process)" isPackaged: false filter: "TestCategory=InProcess" - template: templates/e2e-test.template.yml parameters: - title: "COM API E2E Tests (Out-of-process)" + title: "Microsoft.Management.Deployment E2E Tests (Out-of-process)" isPackaged: true filter: "TestCategory=OutOfProcess" @@ -272,6 +279,7 @@ jobs: TargetFolder: '$(Build.ArtifactStagingDirectory)\WinGetUtilInterop.UnitTests\' CleanTargetFolder: true OverWrite: true + condition: succeededOrFailed() - task: VSTest@2 displayName: 'Run tests: WinGetUtilInterop.UnitTests' @@ -282,16 +290,54 @@ jobs: codeCoverageEnabled: true platform: 'Any CPU' configuration: '$(BuildConfiguration)' + condition: succeededOrFailed() - task: VSTest@2 - displayName: 'Run tests: Microsoft.Management.Configuration.UnitTests' + displayName: 'Run tests: Microsoft.Management.Configuration.UnitTests (InProc)' inputs: + testRunTitle: Microsoft.Management.Configuration.UnitTests (InProc) testSelector: 'testAssemblies' testAssemblyVer2: '**\Microsoft.Management.Configuration.UnitTests.dll' searchFolder: '$(buildOutDir)\Microsoft.Management.Configuration.UnitTests' codeCoverageEnabled: true platform: '$(buildPlatform)' configuration: '$(BuildConfiguration)' + condition: succeededOrFailed() + + - task: CopyFiles@2 + displayName: 'Copy Microsoft.Management.Configuration.winmd' + inputs: + Contents: | + $(buildOutDir)\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd + TargetFolder: '$(buildOutDir)\Microsoft.Management.Configuration.UnitTests\net6.0-windows10.0.19041.0' + condition: succeededOrFailed() + + - task: PowerShell@2 + displayName: 'Copy Microsoft.Management.Configuration.OutOfProc.dll as Microsoft.Management.Configuration.dll' + inputs: + targetType: 'inline' + script: Copy-Item '$(buildOutDir)\Microsoft.Management.Configuration.OutOfProc\Microsoft.Management.Configuration.OutOfProc.dll' '$(buildOutDir)\Microsoft.Management.Configuration.UnitTests\net6.0-windows10.0.19041.0\Microsoft.Management.Configuration.dll' -Force + condition: succeededOrFailed() + + - task: PowerShell@2 + displayName: 'Register the Dev package for OOP configuration tests' + inputs: + targetType: 'inline' + script: Add-AppxPackage -Register $(packageLayoutDir)\AppxManifest.xml + condition: succeededOrFailed() + + - task: VSTest@2 + displayName: 'Run tests: Microsoft.Management.Configuration.UnitTests (OutOfProc)' + inputs: + testRunTitle: Microsoft.Management.Configuration.UnitTests (OutOfProc) + testSelector: 'testAssemblies' + testAssemblyVer2: '**\Microsoft.Management.Configuration.UnitTests.dll' + searchFolder: '$(buildOutDir)\Microsoft.Management.Configuration.UnitTests' + testFiltercriteria: 'Category=OutOfProc' + codeCoverageEnabled: true + platform: '$(buildPlatform)' + configuration: '$(BuildConfiguration)' + condition: succeededOrFailed() - task: CopyFiles@2 displayName: 'Copy Util to artifacts folder' @@ -307,27 +353,27 @@ jobs: inputs: SourceFolder: '$(buildOutDir)\PowerShell' TargetFolder: '$(artifactsDir)\PowerShell' - condition: always() + condition: succeededOrFailed() - task: CopyFiles@2 displayName: 'Copy Dev Package (Loose Files)' inputs: SourceFolder: '$(packageLayoutDir)' TargetFolder: '$(artifactsDir)\DevPackage' - condition: always() + condition: succeededOrFailed() - task: CopyFiles@2 displayName: 'Copy Dev Packages' inputs: SourceFolder: '$(appxPackageDir)' TargetFolder: '$(artifactsDir)\AppxPackages' - condition: always() + condition: succeededOrFailed() - task: PublishPipelineArtifact@1 displayName: Publish Pipeline Artifacts inputs: targetPath: '$(artifactsDir)' - condition: always() + condition: succeededOrFailed() - task: ComponentGovernanceComponentDetection@0 displayName: Component Governance diff --git a/src/AppInstallerCLI.sln b/src/AppInstallerCLI.sln @@ -14,6 +14,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppInstallerCLI", "AppInstallerCLI\AppInstallerCLI.vcxproj", "{5B6F90DF-FD19-4BAE-83D9-24DAD128E777}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppInstallerCLICore", "AppInstallerCLICore\AppInstallerCLICore.vcxproj", "{1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}" + ProjectSection(ProjectDependencies) = postProject + {71FA29AA-9035-468B-A11D-0F0B0F5D5AF4} = {71FA29AA-9035-468B-A11D-0F0B0F5D5AF4} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppInstallerCLITests", "AppInstallerCLITests\AppInstallerCLITests.vcxproj", "{89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}" ProjectSection(ProjectDependencies) = postProject @@ -167,6 +170,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.WinGet.Configurat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.WinGet.Configuration.Engine", "PowerShell\Microsoft.WinGet.Configuration.Engine\Microsoft.WinGet.Configuration.Engine.csproj", "{C54F80ED-B736-49B0-9BD3-662F57024D01}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Management.Configuration.OutOfProc", "Microsoft.Management.Configuration.OutOfProc\Microsoft.Management.Configuration.OutOfProc.vcxproj", "{2268D5AD-7F2A-485A-8C4B-C574497514C9}" + ProjectSection(ProjectDependencies) = postProject + {2B00D362-AC92-41F3-A8D2-5B1599BDCA01} = {2B00D362-AC92-41F3-A8D2-5B1599BDCA01} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -1127,6 +1135,36 @@ Global {C54F80ED-B736-49B0-9BD3-662F57024D01}.TestRelease|x64.Build.0 = Release|Any CPU {C54F80ED-B736-49B0-9BD3-662F57024D01}.TestRelease|x86.ActiveCfg = Release|Any CPU {C54F80ED-B736-49B0-9BD3-662F57024D01}.TestRelease|x86.Build.0 = Release|Any CPU + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Debug|ARM64.Build.0 = Debug|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Debug|x64.ActiveCfg = Debug|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Debug|x64.Build.0 = Debug|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Debug|x86.ActiveCfg = Debug|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Debug|x86.Build.0 = Debug|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Fuzzing|ARM64.ActiveCfg = ReleaseStatic|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Fuzzing|ARM64.Build.0 = ReleaseStatic|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Fuzzing|x64.ActiveCfg = ReleaseStatic|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Fuzzing|x64.Build.0 = ReleaseStatic|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Fuzzing|x86.ActiveCfg = Debug|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Fuzzing|x86.Build.0 = Debug|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.PowerShell|ARM64.ActiveCfg = ReleaseStatic|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.PowerShell|ARM64.Build.0 = ReleaseStatic|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.PowerShell|x64.ActiveCfg = ReleaseStatic|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.PowerShell|x64.Build.0 = ReleaseStatic|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.PowerShell|x86.ActiveCfg = Debug|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.PowerShell|x86.Build.0 = Debug|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Release|ARM64.ActiveCfg = Release|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Release|ARM64.Build.0 = Release|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Release|x64.ActiveCfg = Release|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Release|x64.Build.0 = Release|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Release|x86.ActiveCfg = Release|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.Release|x86.Build.0 = Release|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.TestRelease|ARM64.ActiveCfg = Release|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.TestRelease|ARM64.Build.0 = Release|ARM64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.TestRelease|x64.ActiveCfg = Release|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.TestRelease|x64.Build.0 = Release|x64 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.TestRelease|x86.ActiveCfg = Release|Win32 + {2268D5AD-7F2A-485A-8C4B-C574497514C9}.TestRelease|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj @@ -345,6 +345,7 @@ <ClInclude Include="Commands\ConfigureShowCommand.h" /> <ClInclude Include="Commands\ConfigureTestCommand.h" /> <ClInclude Include="Commands\ConfigureValidateCommand.h" /> + <ClInclude Include="Commands\DebugCommand.h" /> <ClInclude Include="Commands\ExperimentalCommand.h" /> <ClInclude Include="Commands\ExportCommand.h" /> <ClInclude Include="Commands\ImportCommand.h" /> @@ -363,9 +364,9 @@ <ClInclude Include="Commands\SettingsCommand.h" /> <ClInclude Include="CompletionData.h" /> <ClInclude Include="ConfigurationContext.h" /> - <ClInclude Include="ConfigurationSetProcessorFactoryRemoting.h" /> <ClInclude Include="ContextOrchestrator.h" /> <ClInclude Include="COMContext.h" /> + <ClInclude Include="Public\ConfigurationSetProcessorFactoryRemoting.h" /> <ClInclude Include="Workflows\ConfigurationFlow.h" /> <ClInclude Include="Workflows\DependenciesFlow.h" /> <ClInclude Include="ExecutionArgs.h" /> @@ -410,6 +411,7 @@ <ClCompile Include="Commands\ConfigureShowCommand.cpp" /> <ClCompile Include="Commands\ConfigureTestCommand.cpp" /> <ClCompile Include="Commands\ConfigureValidateCommand.cpp" /> + <ClCompile Include="Commands\DebugCommand.cpp" /> <ClCompile Include="Commands\ImportCommand.cpp" /> <ClCompile Include="Commands\PinCommand.cpp" /> <ClCompile Include="ConfigurationContext.cpp" /> @@ -486,6 +488,12 @@ <Project>{8bb94bb8-374f-4294-bca1-c7811514a6b7}</Project> </ProjectReference> </ItemGroup> + <ItemGroup> + <Reference Include="Microsoft.Management.Configuration.Processor"> + <HintPath>$(SolutionDir)\AnyCPU\$(Configuration)\Microsoft.Management.Configuration.Processor\net6.0-windows10.0.19041.0\win\Microsoft.Management.Configuration.Processor.winmd</HintPath> + <IsWinMDFile>true</IsWinMDFile> + </Reference> + </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.210204.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.210204.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> diff --git a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj.filters @@ -215,8 +215,11 @@ <ClInclude Include="Workflows\ConfigurationFlow.h"> <Filter>Workflows</Filter> </ClInclude> - <ClInclude Include="ConfigurationSetProcessorFactoryRemoting.h"> - <Filter>Workflows</Filter> + <ClInclude Include="Public\ConfigurationSetProcessorFactoryRemoting.h"> + <Filter>Public</Filter> + </ClInclude> + <ClInclude Include="Commands\DebugCommand.h"> + <Filter>Commands</Filter> </ClInclude> </ItemGroup> <ItemGroup> @@ -401,7 +404,10 @@ <Filter>Workflows</Filter> </ClCompile> <ClCompile Include="ConfigurationSetProcessorFactoryRemoting.cpp"> - <Filter>Workflows</Filter> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Commands\DebugCommand.cpp"> + <Filter>Commands</Filter> </ClCompile> </ItemGroup> <ItemGroup> diff --git a/src/AppInstallerCLICore/Commands/DebugCommand.cpp b/src/AppInstallerCLICore/Commands/DebugCommand.cpp @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" + +#if _DEBUG +#include "DebugCommand.h" +#include <winrt/Microsoft.Management.Configuration.h> + +namespace AppInstaller::CLI +{ + namespace + { + std::string MakeInterfaceNameAttribute(std::wstring_view name) + { + std::string result = Utility::ConvertToUTF8(name); + Utility::FindAndReplace(result, "<", "<"); + Utility::FindAndReplace(result, ">", ">"); + return result; + } + + std::string MakeIIDAttribute(const winrt::guid& guid) + { + std::string result; + wchar_t buffer[256]; + + if (StringFromGUID2(guid, buffer, ARRAYSIZE(buffer))) + { + result = AppInstaller::Utility::ConvertToUTF8(buffer); + result = result.substr(1, result.length() - 2); + } + else + { + result = "error"; + } + + return result; + } + + template <typename Interface> + void OutputProxyStubInterfaceRegistration(Execution::Context& context) + { + context.Reporter.Info() << "<Interface Name=\"" << MakeInterfaceNameAttribute(winrt::name_of<Interface>()) << "\" InterfaceId=\"" << MakeIIDAttribute(winrt::guid_of<Interface>()) << "\" />" << std::endl; + } + + template <typename Interface> + void OutputIIDMapping(Execution::Context& context) + { + context.Reporter.Info() << Utility::ConvertToUTF8(winrt::name_of<Interface>()) << " == " << winrt::guid_of<Interface>() << std::endl; + } + } + + std::vector<std::unique_ptr<Command>> DebugCommand::GetCommands() const + { + return InitializeFromMoveOnly<std::vector<std::unique_ptr<Command>>>({ + std::make_unique<DumpProxyStubRegistrationsCommand>(FullName()), + std::make_unique<DumpInterestingIIDsCommand>(FullName()), + }); + } + + Resource::LocString DebugCommand::ShortDescription() const + { + return Utility::LocIndString("Debug only dev commands"sv); + } + + Resource::LocString DebugCommand::LongDescription() const + { + return Utility::LocIndString("Commands that are useful in debugging and development."sv); + } + + void DebugCommand::ExecuteInternal(Execution::Context& context) const + { + OutputHelp(context.Reporter); + } + + Resource::LocString DumpProxyStubRegistrationsCommand::ShortDescription() const + { + return Utility::LocIndString("Dump proxy-stub registrations"sv); + } + + Resource::LocString DumpProxyStubRegistrationsCommand::LongDescription() const + { + return Utility::LocIndString("Dump proxy-stub registrations for WinRT interfaces to be place in the manifest."sv); + } + + void DumpProxyStubRegistrationsCommand::ExecuteInternal(Execution::Context& context) const + { + OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationConflict>>(context); + OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ApplyConfigurationUnitResult>>(context); + OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationConflictSetting>>(context); + OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationSet>>(context); + OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::ConfigurationUnit>>(context); + OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::GetConfigurationUnitDetailsResult>>(context); + OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::IConfigurationUnitSettingDetails>>(context); + OutputProxyStubInterfaceRegistration<winrt::Windows::Foundation::Collections::IIterable<winrt::Microsoft::Management::Configuration::TestConfigurationUnitResult>>(context); + + // TODO: Fix the layering inversion created by the COM deployment API (probably in order to operate winget.exe against the COM server). + // Then this code can just have a CppWinRT reference to the deployment API and spit out the interface registrations just like for configuration. + HMODULE module = nullptr; + if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCWSTR>(&MakeInterfaceNameAttribute), &module)) + { + return; + } + + // TODO: Have a PRIVATE export from WindowsPackageManager that returns a set of names and IIDs to include from the Deployment API surface + } + + Resource::LocString DumpInterestingIIDsCommand::ShortDescription() const + { + return Utility::LocIndString("Dump some IIDs"sv); + } + + Resource::LocString DumpInterestingIIDsCommand::LongDescription() const + { + return Utility::LocIndString("Dump some IIDs that might be useful."sv); + } + + void DumpInterestingIIDsCommand::ExecuteInternal(Execution::Context& context) const + { + OutputIIDMapping<winrt::Microsoft::Management::Configuration::IConfigurationStatics>(context); + } +} + +#endif diff --git a/src/AppInstallerCLICore/Commands/DebugCommand.h b/src/AppInstallerCLICore/Commands/DebugCommand.h @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "Command.h" + +#if _DEBUG + +namespace AppInstaller::CLI +{ + // Command that is only available with debug builds to aid development. + // Don't create localized strings for use here. + struct DebugCommand final : public Command + { + DebugCommand(std::string_view parent) : Command("debug", {}, parent, Visibility::Hidden) {} + + std::vector<std::unique_ptr<Command>> GetCommands() const override; + + Resource::LocString ShortDescription() const override; + Resource::LocString LongDescription() const override; + + protected: + void ExecuteInternal(Execution::Context& context) const override; + }; + + // Outputs the proxy stub registrations for the manifest. + struct DumpProxyStubRegistrationsCommand final : public Command + { + DumpProxyStubRegistrationsCommand(std::string_view parent) : Command("dump-proxystub-reg", {}, parent) {} + + Resource::LocString ShortDescription() const override; + Resource::LocString LongDescription() const override; + + protected: + void ExecuteInternal(Execution::Context& context) const override; + }; + + // Outputs some IIDs. + struct DumpInterestingIIDsCommand final : public Command + { + DumpInterestingIIDsCommand(std::string_view parent) : Command("dump-iids", {}, parent) {} + + Resource::LocString ShortDescription() const override; + Resource::LocString LongDescription() const override; + + protected: + void ExecuteInternal(Execution::Context& context) const override; + }; +} + +#endif diff --git a/src/AppInstallerCLICore/Commands/RootCommand.cpp b/src/AppInstallerCLICore/Commands/RootCommand.cpp @@ -21,6 +21,7 @@ #include "ImportCommand.h" #include "PinCommand.h" #include "ConfigureCommand.h" +#include "DebugCommand.h" #include "Resources.h" #include "TableOutput.h" @@ -175,6 +176,9 @@ namespace AppInstaller::CLI std::make_unique<ImportCommand>(FullName()), std::make_unique<PinCommand>(FullName()), std::make_unique<ConfigureCommand>(FullName()), +#if _DEBUG + std::make_unique<DebugCommand>(FullName()), +#endif }); } diff --git a/src/AppInstallerCLICore/ConfigurationSetProcessorFactoryRemoting.cpp b/src/AppInstallerCLICore/ConfigurationSetProcessorFactoryRemoting.cpp @@ -1,14 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #include "pch.h" -#include "ConfigurationSetProcessorFactoryRemoting.h" +#include "Public/ConfigurationSetProcessorFactoryRemoting.h" +#include <AppInstallerLanguageUtilities.h> #include <AppInstallerLogging.h> #include <AppInstallerRuntime.h> +#include <winget/ILifetimeWatcher.h> +#include <winrt/Microsoft.Management.Configuration.Processor.h> +#include <winrt/Microsoft.Management.Configuration.SetProcessorFactory.h> using namespace winrt::Windows::Foundation; using namespace winrt::Microsoft::Management::Configuration; -namespace AppInstaller::CLI::Workflow::ConfigurationRemoting +namespace AppInstaller::CLI::ConfigurationRemoting { namespace details { @@ -33,11 +37,14 @@ namespace AppInstaller::CLI::Workflow::ConfigurationRemoting namespace { + // The name of the directory containing additional modules. + constexpr std::wstring_view s_ExternalModulesName = L"ExternalModules"; + // The executable file name for the remote server process. constexpr std::wstring_view s_RemoteServerFileName = L"ConfigurationRemotingServer\\ConfigurationRemotingServer.exe"; // Represents a remote factory object that was created from a specific process. - struct RemoteFactory : winrt::implements<RemoteFactory, IConfigurationSetProcessorFactory> + struct RemoteFactory : winrt::implements<RemoteFactory, IConfigurationSetProcessorFactory, SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties, WinRT::ILifetimeWatcher>, WinRT::LifetimeWatcherBase { RemoteFactory() { @@ -63,13 +70,18 @@ namespace AppInstaller::CLI::Workflow::ConfigurationRemoting wil::unique_event initEvent; initEvent.create(wil::EventOptions::None, nullptr, &securityAttributes); - // Create the mutex that the remote process will wait on to keep the object alive. - m_completionMutex.create(nullptr, CREATE_MUTEX_INITIAL_OWNER, MUTEX_ALL_ACCESS, &securityAttributes); + // Create the event that the remote process will wait on to keep the object alive. + m_completionEvent.create(wil::EventOptions::None, nullptr, &securityAttributes); + auto completeEventIfFailureDuringConstruction = wil::scope_exit([&]() { m_completionEvent.SetEvent(); }); + + wil::unique_process_handle thisProcessHandle; + THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &thisProcessHandle, 0, TRUE, DUPLICATE_SAME_ACCESS)); // Arguments are: - // server.exe <mapped memory handle> <event handle> <mutex handle> + // server.exe <mapped memory handle> <event handle> <mutex handle> <parent process handle> std::wostringstream argumentsStream; - argumentsStream << s_RemoteServerFileName << L' ' << reinterpret_cast<INT_PTR>(memoryHandle.get()) << L' ' << reinterpret_cast<INT_PTR>(initEvent.get()) << L' ' << reinterpret_cast<INT_PTR>(m_completionMutex.get()); + argumentsStream << s_RemoteServerFileName << L' ' << reinterpret_cast<INT_PTR>(memoryHandle.get()) << L' ' << reinterpret_cast<INT_PTR>(initEvent.get()) + << L' ' << reinterpret_cast<INT_PTR>(m_completionEvent.get()) << L' ' << reinterpret_cast<INT_PTR>(thisProcessHandle.get()); std::wstring arguments = argumentsStream.str(); std::filesystem::path serverPath = Runtime::GetPathTo(Runtime::PathName::SelfPackageRoot); @@ -133,6 +145,24 @@ namespace AppInstaller::CLI::Workflow::ConfigurationRemoting THROW_IF_FAILED(CoUnmarshalInterface(stream.get(), winrt::guid_of<IConfigurationSetProcessorFactory>(), reinterpret_cast<void**>(&output))); AICLI_LOG(Config, Verbose, << "... configuration processing connection established."); m_remoteFactory = IConfigurationSetProcessorFactory{ output.detach(), winrt::take_ownership_from_abi }; + + // The additional modules path is a direct child directory to the package root + std::filesystem::path externalModules = Runtime::GetPathTo(Runtime::PathName::SelfPackageRoot) / s_ExternalModulesName; + THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), !std::filesystem::is_directory(externalModules)); + m_internalAdditionalModulePaths.emplace_back(externalModules.wstring()); + m_remoteAdditionalModulePaths = winrt::single_threaded_vector<winrt::hstring>(std::vector<winrt::hstring>{ m_internalAdditionalModulePaths }); + + auto properties = m_remoteFactory.as<Processor::IPowerShellConfigurationProcessorFactoryProperties>(); + AICLI_LOG(Config, Verbose, << "Applying built in additional module path: " << externalModules.u8string()); + properties.AdditionalModulePaths(m_remoteAdditionalModulePaths.GetView()); + properties.ProcessorType(Processor::PowerShellConfigurationProcessorType::Hosted); + + completeEventIfFailureDuringConstruction.release(); + } + + ~RemoteFactory() + { + m_completionEvent.SetEvent(); } IConfigurationSetProcessor CreateSetProcessor(const ConfigurationSet& configurationSet) @@ -140,7 +170,7 @@ namespace AppInstaller::CLI::Workflow::ConfigurationRemoting return m_remoteFactory.CreateSetProcessor(configurationSet); } - winrt::event_token Diagnostics(const EventHandler<DiagnosticInformation>& handler) + winrt::event_token Diagnostics(const EventHandler<IDiagnosticInformation>& handler) { return m_remoteFactory.Diagnostics(handler); } @@ -160,9 +190,62 @@ namespace AppInstaller::CLI::Workflow::ConfigurationRemoting m_remoteFactory.MinimumLevel(value); } + Collections::IVectorView<winrt::hstring> AdditionalModulePaths() const + { + return m_additionalModulePaths.GetView(); + } + + void AdditionalModulePaths(const Collections::IVectorView<winrt::hstring>& value) + { + // Extract all values from incoming view + std::vector<winrt::hstring> newModulePaths{ value.Size() }; + value.GetMany(0, newModulePaths); + + // Combine with our own values + std::vector<winrt::hstring> newRemotePaths{ newModulePaths }; + newRemotePaths.insert(newRemotePaths.end(), m_internalAdditionalModulePaths.begin(), m_internalAdditionalModulePaths.end()); + + // Apply the new combined paths and pass to remote factory + m_remoteAdditionalModulePaths = winrt::single_threaded_vector<winrt::hstring>(std::move(newRemotePaths)); + m_remoteFactory.as<Processor::IPowerShellConfigurationProcessorFactoryProperties>().AdditionalModulePaths(m_remoteAdditionalModulePaths.GetView()); + + // Store the updated module paths that we were given + m_additionalModulePaths = winrt::single_threaded_vector<winrt::hstring>(std::move(newModulePaths)); + } + + SetProcessorFactory::PwshConfigurationProcessorPolicy Policy() const + { + return Convert(m_remoteFactory.as<Processor::IPowerShellConfigurationProcessorFactoryProperties>().Policy()); + } + + void Policy(SetProcessorFactory::PwshConfigurationProcessorPolicy value) + { + m_remoteFactory.as<Processor::IPowerShellConfigurationProcessorFactoryProperties>().Policy(Convert(value)); + } + + HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher) + { + return WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher); + } + private: + static SetProcessorFactory::PwshConfigurationProcessorPolicy Convert(Processor::PowerShellConfigurationProcessorPolicy policy) + { + // We have used the same values intentionally; if that changes, update this. + return ToEnum<SetProcessorFactory::PwshConfigurationProcessorPolicy>(ToIntegral(policy)); + } + + static Processor::PowerShellConfigurationProcessorPolicy Convert(SetProcessorFactory::PwshConfigurationProcessorPolicy policy) + { + // We have used the same values intentionally; if that changes, update this. + return ToEnum<Processor::PowerShellConfigurationProcessorPolicy>(ToIntegral(policy)); + } + IConfigurationSetProcessorFactory m_remoteFactory; - wil::unique_mutex m_completionMutex; + wil::unique_event m_completionEvent; + Collections::IVector<winrt::hstring> m_additionalModulePaths{ winrt::single_threaded_vector<winrt::hstring>() }; + std::vector<winrt::hstring> m_internalAdditionalModulePaths; + Collections::IVector<winrt::hstring> m_remoteAdditionalModulePaths{ winrt::single_threaded_vector<winrt::hstring>() }; }; } @@ -172,9 +255,9 @@ namespace AppInstaller::CLI::Workflow::ConfigurationRemoting } } -HRESULT WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(HRESULT result, void* factory, uint64_t memoryHandleIntPtr, uint64_t initEventHandleIntPtr, uint64_t completionMutexHandleIntPtr) try +HRESULT WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(HRESULT result, void* factory, uint64_t memoryHandleIntPtr, uint64_t initEventHandleIntPtr, uint64_t completionMutexHandleIntPtr, uint64_t parentProcessIntPtr) try { - using namespace AppInstaller::CLI::Workflow::ConfigurationRemoting; + using namespace AppInstaller::CLI::ConfigurationRemoting; RETURN_HR_IF(E_POINTER, !memoryHandleIntPtr); @@ -209,9 +292,15 @@ HRESULT WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitializat wil::unique_event initEvent{ reinterpret_cast<HANDLE>(initEventHandleIntPtr) }; initEvent.SetEvent(); - // Wait until the caller releases the object - wil::unique_mutex completionMutex{ reinterpret_cast<HANDLE>(completionMutexHandleIntPtr) }; - std::ignore = completionMutex.acquire(); + // Wait until the caller releases the object (signalling the event) or the parent process exits + wil::unique_event completionEvent{ reinterpret_cast<HANDLE>(completionMutexHandleIntPtr) }; + wil::unique_process_handle parentProcess{ reinterpret_cast<HANDLE>(parentProcessIntPtr) }; + + HANDLE waitHandles[2]; + waitHandles[0] = completionEvent.get(); + waitHandles[1] = parentProcess.get(); + + std::ignore = WaitForMultipleObjects(ARRAYSIZE(waitHandles), waitHandles, FALSE, INFINITE); return S_OK; } diff --git a/src/AppInstallerCLICore/ConfigurationSetProcessorFactoryRemoting.h b/src/AppInstallerCLICore/ConfigurationSetProcessorFactoryRemoting.h @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include <Windows.h> -#include <winrt/Microsoft.Management.Configuration.h> - -namespace AppInstaller::CLI::Workflow::ConfigurationRemoting -{ - // Creates a factory in another process - winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory CreateOutOfProcessFactory(); -} - -// Export for use by the out of process factory server to report its initialization. -HRESULT WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(HRESULT result, void* factory, uint64_t memoryHandle, uint64_t initEventHandle, uint64_t completionMutexHandle); diff --git a/src/AppInstallerCLICore/Public/ConfigurationSetProcessorFactoryRemoting.h b/src/AppInstallerCLICore/Public/ConfigurationSetProcessorFactoryRemoting.h @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <Windows.h> +#include <winrt/Microsoft.Management.Configuration.h> + +namespace AppInstaller::CLI::ConfigurationRemoting +{ + // Creates a factory in another process + winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory CreateOutOfProcessFactory(); +} + +// Export for use by the out of process factory server to report its initialization. +HRESULT WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(HRESULT result, void* factory, uint64_t memoryHandle, uint64_t initEventHandle, uint64_t completionMutexHandle); diff --git a/src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp b/src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp @@ -3,7 +3,7 @@ #include "pch.h" #include "ConfigurationFlow.h" #include "PromptFlow.h" -#include "ConfigurationSetProcessorFactoryRemoting.h" +#include "Public/ConfigurationSetProcessorFactoryRemoting.h" #include <AppInstallerErrors.h> #include <winrt/Microsoft.Management.Configuration.h> #include <winget/SelfManagement.h> @@ -354,7 +354,7 @@ namespace AppInstaller::CLI::Workflow } } - void LogFailedGetConfigurationUnitDetails(const ConfigurationUnit& unit, const ConfigurationUnitResultInformation& resultInformation) + void LogFailedGetConfigurationUnitDetails(const ConfigurationUnit& unit, const IConfigurationUnitResultInformation& resultInformation) { if (FAILED(resultInformation.ResultCode())) { @@ -372,7 +372,7 @@ namespace AppInstaller::CLI::Workflow // TODO: We may need a detailed result code to enable the internal error to be exposed. // Additionally, some of the processor exceptions that generate these errors should be enlightened to produce better, localized descriptions. - UnitFailedMessageData GetUnitFailedData(const ConfigurationUnit& unit, const ConfigurationUnitResultInformation& resultInformation) + UnitFailedMessageData GetUnitFailedData(const ConfigurationUnit& unit, const IConfigurationUnitResultInformation& resultInformation) { int32_t resultCode = resultInformation.ResultCode(); @@ -405,7 +405,7 @@ namespace AppInstaller::CLI::Workflow return { Resource::String::ConfigurationUnitFailed(resultCode), true }; } - Utility::LocIndString GetUnitSkippedMessage(const ConfigurationUnitResultInformation& resultInformation) + Utility::LocIndString GetUnitSkippedMessage(const IConfigurationUnitResultInformation& resultInformation) { int32_t resultCode = resultInformation.ResultCode(); @@ -532,7 +532,7 @@ namespace AppInstaller::CLI::Workflow } private: - void HandleUnitProgress(const ConfigurationUnit& unit, ConfigurationUnitState state, const ConfigurationUnitResultInformation& resultInformation) + void HandleUnitProgress(const ConfigurationUnit& unit, ConfigurationUnitState state, const IConfigurationUnitResultInformation& resultInformation) { if (UnitHasPreviouslyCompleted(unit)) { @@ -670,7 +670,7 @@ namespace AppInstaller::CLI::Workflow processor.GenerateTelemetryEvents(!Settings::User().Get<Settings::Setting::TelemetryDisable>()); // Route the configuration diagnostics into the context's diagnostics logging - processor.Diagnostics([&context](const winrt::Windows::Foundation::IInspectable&, const DiagnosticInformation& diagnostics) + processor.Diagnostics([&context](const winrt::Windows::Foundation::IInspectable&, const IDiagnosticInformation& diagnostics) { context.GetThreadGlobals().GetDiagnosticLogger().Write(Logging::Channel::Config, ConvertLevel(diagnostics.Level()), Utility::ConvertToUTF8(diagnostics.Message())); }); diff --git a/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj b/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj @@ -49,6 +49,15 @@ </ItemGroup> <ItemGroup> + <None Remove="TestData\Configuration\ConfigServerUnexpectedExit.yml" /> + <None Remove="TestData\Configuration\Configure_TestRepo.yml" /> + <None Remove="TestData\Configuration\DependentResources_Failure.yml" /> + <None Remove="TestData\Configuration\IndependentResources_OneFailure.yml" /> + <None Remove="TestData\configuration\Init-TestRepository.ps1" /> + <None Remove="TestData\Configuration\ShowDetails_TestRepo.yml" /> + </ItemGroup> + + <ItemGroup> <Content Include="..\..\doc\admx\DesktopAppInstaller.admx" Link="TestData\DesktopAppInstaller.admx"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> diff --git a/src/AppInstallerCLIE2ETests/ConfigureCommand.cs b/src/AppInstallerCLIE2ETests/ConfigureCommand.cs @@ -0,0 +1,122 @@ +// ----------------------------------------------------------------------------- +// <copyright file="ConfigureCommand.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace AppInstallerCLIE2ETests +{ + using System.IO; + using NUnit.Framework; + + /// <summary> + /// `Configure` command tests. + /// </summary> + public class ConfigureCommand + { + private const string CommandAndAgreements = "configure --accept-configuration-agreements"; + + /// <summary> + /// Setup done once before all the tests here. + /// </summary> + [OneTimeSetUp] + public void OneTimeSetup() + { + WinGetSettingsHelper.ConfigureFeature("configuration", true); + this.DeleteTxtFiles(); + } + + /// <summary> + /// Teardown done once after all the tests here. + /// </summary> + [OneTimeTearDown] + public void OneTimeTeardown() + { + this.DeleteTxtFiles(); + } + + /// <summary> + /// Simple test to confirm that a resource without a module specified can be discovered in the PSGallery. + /// Intentionally has no settings to force a failure, but only after acquiring the module. + /// </summary> + [Test] + public void ConfigureFromGallery() + { + TestCommon.EnsureModuleState(Constants.GalleryTestModuleName, present: false); + + var result = TestCommon.RunAICLICommand(CommandAndAgreements, TestCommon.GetTestDataFile("Configuration\\PSGallery_NoModule_NoSettings.yml"), timeOut: 120000); + Assert.AreEqual(Constants.ErrorCode.CONFIG_ERROR_SET_APPLY_FAILED, result.ExitCode); + Assert.True(result.StdOut.Contains("The configuration unit failed while attempting to test the current system state.")); + } + + /// <summary> + /// Simple test to confirm that a resource with a module specified can be discovered in a local repository that doesn't support resource discovery. + /// </summary> + [Test] + public void ConfigureFromTestRepo() + { + TestCommon.EnsureModuleState(Constants.SimpleTestModuleName, present: false); + + var result = TestCommon.RunAICLICommand(CommandAndAgreements, TestCommon.GetTestDataFile("Configuration\\Configure_TestRepo.yml")); + Assert.AreEqual(0, result.ExitCode); + + // The configuration creates a file next to itself with the given contents + string targetFilePath = TestCommon.GetTestDataFile("Configuration\\Configure_TestRepo.txt"); + FileAssert.Exists(targetFilePath); + Assert.AreEqual("Contents!", System.IO.File.ReadAllText(targetFilePath)); + } + + /// <summary> + /// One resource fails, but the other is not dependent and should be executed. + /// </summary> + [Test] + public void IndependentResourceWithSingleFailure() + { + var result = TestCommon.RunAICLICommand(CommandAndAgreements, TestCommon.GetTestDataFile("Configuration\\IndependentResources_OneFailure.yml")); + Assert.AreEqual(Constants.ErrorCode.CONFIG_ERROR_SET_APPLY_FAILED, result.ExitCode); + + // The configuration creates a file next to itself with the given contents + string targetFilePath = TestCommon.GetTestDataFile("Configuration\\IndependentResources_OneFailure.txt"); + FileAssert.Exists(targetFilePath); + Assert.AreEqual("Contents!", System.IO.File.ReadAllText(targetFilePath)); + } + + /// <summary> + /// One resource fails, and the dependent resource should not be executed. + /// </summary> + [Test] + public void DependentResourceWithFailure() + { + var result = TestCommon.RunAICLICommand(CommandAndAgreements, TestCommon.GetTestDataFile("Configuration\\DependentResources_Failure.yml")); + Assert.AreEqual(Constants.ErrorCode.CONFIG_ERROR_SET_APPLY_FAILED, result.ExitCode); + + // The configuration creates a file next to itself with the given contents + string targetFilePath = TestCommon.GetTestDataFile("Configuration\\DependentResources_Failure.txt"); + FileAssert.DoesNotExist(targetFilePath); + } + + /// <summary> + /// The configuration server unexpectedly exits. Winget should continue to operate properly. + /// </summary> + [Ignore("The version of CppWinRT that we are currently using is old and causes an assert on this test. Once it is updated, remove this Ignore.")] + [Test] + public void ConfigServerUnexpectedExit() + { + var result = TestCommon.RunAICLICommand(CommandAndAgreements, TestCommon.GetTestDataFile("Configuration\\ConfigServerUnexpectedExit.yml")); + Assert.AreEqual(Constants.ErrorCode.CONFIG_ERROR_SET_APPLY_FAILED, result.ExitCode); + + // The configuration creates a file next to itself with the given contents + string targetFilePath = TestCommon.GetTestDataFile("Configuration\\ConfigServerUnexpectedExit.txt"); + FileAssert.DoesNotExist(targetFilePath); + } + + private void DeleteTxtFiles() + { + // Delete all .txt files in the test directory; they are placed there by the tests + foreach (string file in Directory.GetFiles(TestCommon.GetTestDataFile("Configuration"), "*.txt")) + { + File.Delete(file); + } + } + } +} diff --git a/src/AppInstallerCLIE2ETests/ConfigureShowCommand.cs b/src/AppInstallerCLIE2ETests/ConfigureShowCommand.cs @@ -11,7 +11,7 @@ namespace AppInstallerCLIE2ETests /// <summary> /// `Configure show` command tests. /// </summary> - public class ConfigureShowCommand : BaseCommand + public class ConfigureShowCommand { /// <summary> /// Setup done once before all the tests here. @@ -23,14 +23,42 @@ namespace AppInstallerCLIE2ETests } /// <summary> - /// Simple smoke test to ensure that showing details is working. + /// Simple test to confirm that a resource without a module specified can be discovered in the PSGallery. /// </summary> [Test] public void ShowDetailsFromGallery() { - var result = TestCommon.RunAICLICommand("configure show", TestCommon.GetTestDataFile("Configuration\\ShowDetails.yml")); - TestContext.Out.Write(result.StdOut); + TestCommon.EnsureModuleState(Constants.GalleryTestModuleName, present: false); + + var result = TestCommon.RunAICLICommand("configure show", $"{TestCommon.GetTestDataFile("Configuration\\PSGallery_NoModule_NoSettings.yml")} --verbose", timeOut: 120000); + Assert.AreEqual(0, result.ExitCode); + Assert.True(result.StdOut.Contains(Constants.PSGalleryName)); + } + + /// <summary> + /// Simple test to confirm that a resource with a module specified can be discovered in a local repository that doesn't support resource discovery. + /// </summary> + [Test] + public void ShowDetailsFromTestRepo() + { + TestCommon.EnsureModuleState(Constants.SimpleTestModuleName, present: false); + + var result = TestCommon.RunAICLICommand("configure show", $"{TestCommon.GetTestDataFile("Configuration\\ShowDetails_TestRepo.yml")} --verbose"); + Assert.AreEqual(0, result.ExitCode); + Assert.True(result.StdOut.Contains(Constants.TestRepoName)); + } + + /// <summary> + /// Simple test to confirm that a resource that is already locally available shows that way. + /// </summary> + [Test] + public void ShowDetailsFromLocal() + { + TestCommon.EnsureModuleState(Constants.SimpleTestModuleName, present: true, repository: Constants.TestRepoName); + + var result = TestCommon.RunAICLICommand("configure show", $"{TestCommon.GetTestDataFile("Configuration\\ShowDetails_TestRepo.yml")} --verbose"); Assert.AreEqual(0, result.ExitCode); + Assert.True(result.StdOut.Contains(Constants.LocalModuleDescriptor)); } } } diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs @@ -113,6 +113,13 @@ namespace AppInstallerCLIE2ETests public const string PortablePackageMachineRoot = "portablePackageMachineRoot"; public const string InstallBehaviorScope = "scope"; + // Configuration + public const string PSGalleryName = "PSGallery"; + public const string TestRepoName = "AppInstallerCLIE2ETestsRepo"; + public const string GalleryTestModuleName = "XmlContentDsc"; + public const string SimpleTestModuleName = "xE2ETestResource"; + public const string LocalModuleDescriptor = "[Local]"; + /// <summary> /// Error codes. /// </summary> @@ -259,6 +266,32 @@ namespace AppInstallerCLIE2ETests public const int INSTALLED_STATUS_FILE_NOT_FOUND = unchecked((int)0x8A150205); public const int INSTALLED_STATUS_FILE_FOUND_WITHOUT_HASH_CHECK = unchecked((int)0x0A150206); public const int INSTALLED_STATUS_FILE_ACCESS_ERROR = unchecked((int)0x8A150207); + + public const int CONFIG_ERROR_INVALID_CONFIGURATION_FILE = unchecked((int)0x8A15C001); + public const int CONFIG_ERROR_INVALID_YAML = unchecked((int)0x8A15C002); + public const int CONFIG_ERROR_INVALID_FIELD_TYPE = unchecked((int)0x8A15C003); + public const int CONFIG_ERROR_UNKNOWN_CONFIGURATION_FILE_VERSION = unchecked((int)0x8A15C004); + public const int CONFIG_ERROR_SET_APPLY_FAILED = unchecked((int)0x8A15C005); + public const int CONFIG_ERROR_DUPLICATE_IDENTIFIER = unchecked((int)0x8A15C006); + public const int CONFIG_ERROR_MISSING_DEPENDENCY = unchecked((int)0x8A15C007); + public const int CONFIG_ERROR_DEPENDENCY_UNSATISFIED = unchecked((int)0x8A15C008); + public const int CONFIG_ERROR_ASSERTION_FAILED = unchecked((int)0x8A15C009); + public const int CONFIG_ERROR_MANUALLY_SKIPPED = unchecked((int)0x8A15C00A); + public const int CONFIG_ERROR_WARNING_NOT_ACCEPTED = unchecked((int)0x8A15C00B); + public const int CONFIG_ERROR_SET_DEPENDENCY_CYCLE = unchecked((int)0x8A15C00C); + public const int CONFIG_ERROR_INVALID_FIELD_VALUE = unchecked((int)0x8A15C00D); + public const int CONFIG_ERROR_MISSING_FIELD = unchecked((int)0x8A15C00E); + + public const int CONFIG_ERROR_UNIT_NOT_INSTALLED = unchecked((int)0x8A15C101); + public const int CONFIG_ERROR_UNIT_NOT_FOUND_REPOSITORY = unchecked((int)0x8A15C102); + public const int CONFIG_ERROR_UNIT_MULTIPLE_MATCHES = unchecked((int)0x8A15C103); + public const int CONFIG_ERROR_UNIT_INVOKE_GET = unchecked((int)0x8A15C104); + public const int CONFIG_ERROR_UNIT_INVOKE_TEST = unchecked((int)0x8A15C105); + public const int CONFIG_ERROR_UNIT_INVOKE_SET = unchecked((int)0x8A15C106); + public const int CONFIG_ERROR_UNIT_MODULE_CONFLICT = unchecked((int)0x8A15C107); + public const int CONFIG_ERROR_UNIT_IMPORT_MODULE = unchecked((int)0x8A15C108); + public const int CONFIG_ERROR_UNIT_INVOKE_INVALID_RESULT = unchecked((int)0x8A15C109); + public const int CONFIG_ERROR_UNIT_SETTING_CONFIG_ROOT = unchecked((int)0x8A15C110); } #pragma warning restore SA1310 // Field names should not contain underscore diff --git a/src/AppInstallerCLIE2ETests/SetUpFixture.cs b/src/AppInstallerCLIE2ETests/SetUpFixture.cs @@ -20,6 +20,7 @@ namespace AppInstallerCLIE2ETests { private static bool shouldDisableDevModeOnExit = true; private static bool shouldRevertDefaultFileTypeRiskOnExit = true; + private static bool shouldDoAnyTeardown = true; private static string defaultFileTypes = string.Empty; /// <summary> @@ -28,6 +29,21 @@ namespace AppInstallerCLIE2ETests [OneTimeSetUp] public void Setup() { + if (TestContext.Parameters.Count == 0) + { + // If no parameters are provided, use defaults that work locally. + // This allows the user to assume responsibility for setup. + TestCommon.PackagedContext = true; + TestCommon.VerboseLogging = true; + TestCommon.AICLIPath = "WinGetDev.exe"; + TestCommon.StaticFileRootPath = Path.GetTempPath(); + TestCommon.SettingsJsonFilePath = WinGetSettingsHelper.GetUserSettingsPath(); + WinGetSettingsHelper.InitializeWingetSettings(); + shouldDoAnyTeardown = false; + + return; + } + // Read TestParameters and set runtime variables TestCommon.PackagedContext = TestContext.Parameters.Exists(Constants.PackagedContextParameter) && TestContext.Parameters.Get(Constants.PackagedContextParameter).Equals("true", StringComparison.OrdinalIgnoreCase); @@ -124,23 +140,26 @@ namespace AppInstallerCLIE2ETests [OneTimeTearDown] public void TearDown() { - if (shouldDisableDevModeOnExit) + if (shouldDoAnyTeardown) { - this.EnableDevMode(false); - } + if (shouldDisableDevModeOnExit) + { + this.EnableDevMode(false); + } - if (shouldRevertDefaultFileTypeRiskOnExit) - { - this.DecreaseFileTypeRisk(defaultFileTypes, true); - } + if (shouldRevertDefaultFileTypeRiskOnExit) + { + this.DecreaseFileTypeRisk(defaultFileTypes, true); + } - TestCommon.RunCommand("certutil.exe", $"-delstore \"TRUSTEDPEOPLE\" {Constants.AppInstallerTestCertThumbprint}"); + TestCommon.RunCommand("certutil.exe", $"-delstore \"TRUSTEDPEOPLE\" {Constants.AppInstallerTestCertThumbprint}"); - TestCommon.PublishE2ETestLogs(); + TestCommon.PublishE2ETestLogs(); - if (TestCommon.PackagedContext) - { - TestCommon.RemoveMsix(Constants.AICLIPackageName); + if (TestCommon.PackagedContext) + { + TestCommon.RemoveMsix(Constants.AICLIPackageName); + } } } diff --git a/src/AppInstallerCLIE2ETests/TestCommon.cs b/src/AppInstallerCLIE2ETests/TestCommon.cs @@ -771,6 +771,34 @@ namespace AppInstallerCLIE2ETests } /// <summary> + /// Ensures that a module is in the desired state. + /// </summary> + /// <param name="moduleName">The module.</param> + /// <param name="present">Whether the module is present or not.</param> + /// <param name="repository">The repository to get the module from if needed.</param> + public static void EnsureModuleState(string moduleName, bool present, string repository = null) + { + var result = RunCommandWithResult("pwsh", $"-Command \"Get-Module {moduleName} -ListAvailable\""); + bool isPresent = !string.IsNullOrWhiteSpace(result.StdOut); + + if (isPresent && !present) + { + RunCommand("pwsh", $"-Command \"Uninstall-Module {moduleName}\""); + } + else if (!isPresent && present) + { + if (string.IsNullOrEmpty(repository)) + { + RunCommand("pwsh", $"-Command \"Install-Module {moduleName} -Force\""); + } + else + { + RunCommand("pwsh", $"-Command \"Install-Module {moduleName} -Repository {repository} -Force\""); + } + } + } + + /// <summary> /// Run command result. /// </summary> public struct RunCommandResult diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/ConfigServerUnexpectedExit.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/ConfigServerUnexpectedExit.yml @@ -0,0 +1,17 @@ +properties: + configurationVersion: 0.2 + resources: + - resource: xE2ETestResource/E2ETestResourceCrash + id: first + directives: + repository: AppInstallerCLIE2ETestsRepo + settings: + key: Foo + - resource: xE2ETestResource/E2EFileResource + dependsOn: + - first + directives: + repository: AppInstallerCLIE2ETestsRepo + settings: + Path: ${WinGetConfigRoot}\ConfigServerUnexpectedExit.txt + Content: Contents! diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/Configure_TestRepo.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/Configure_TestRepo.yml @@ -0,0 +1,9 @@ +properties: + configurationVersion: 0.2 + resources: + - resource: xE2ETestResource/E2EFileResource + directives: + repository: AppInstallerCLIE2ETestsRepo + settings: + Path: ${WinGetConfigRoot}\Configure_TestRepo.txt + Content: Contents! diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/DependentResources_Failure.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/DependentResources_Failure.yml @@ -0,0 +1,17 @@ +properties: + configurationVersion: 0.2 + resources: + - resource: xE2ETestResource/E2ETestResourceThrows + id: first + directives: + repository: AppInstallerCLIE2ETestsRepo + settings: + key: Foo + - resource: xE2ETestResource/E2EFileResource + dependsOn: + - first + directives: + repository: AppInstallerCLIE2ETestsRepo + settings: + Path: ${WinGetConfigRoot}\DependentResources_Failure.txt + Content: Contents! diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/IndependentResources_OneFailure.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/IndependentResources_OneFailure.yml @@ -0,0 +1,14 @@ +properties: + configurationVersion: 0.2 + resources: + - resource: xE2ETestResource/E2ETestResourceThrows + directives: + repository: AppInstallerCLIE2ETestsRepo + settings: + key: Foo + - resource: xE2ETestResource/E2EFileResource + directives: + repository: AppInstallerCLIE2ETestsRepo + settings: + Path: ${WinGetConfigRoot}\IndependentResources_OneFailure.txt + Content: Contents! diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/Init-TestRepository.ps1 b/src/AppInstallerCLIE2ETests/TestData/Configuration/Init-TestRepository.ps1 @@ -0,0 +1,65 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +[CmdletBinding()] +param( + [string]$ModulesPath, + + [string]$RepositoryPath, + + [string]$RepositoryName, + + [switch]$Force +) + +if ([System.String]::IsNullOrEmpty($ModulesPath)) +{ + $ModulesPath = Join-Path $PSScriptRoot "Modules" +} + +if ([System.String]::IsNullOrEmpty($RepositoryPath)) +{ + $RepositoryPath = Join-Path ([System.IO.Path]::GetTempPath()) (New-Guid) +} + +if ([System.String]::IsNullOrEmpty($RepositoryName)) +{ + $RepositoryName = "AppInstallerCLIE2ETestsRepo" +} + +if ($Force) { + $null = New-Item -Path $RepositoryPath -ItemType Directory -Force +} else { + $null = New-Item -Path $RepositoryPath -ItemType Directory -ErrorAction Inquire +} + +$Local:existingRepository = Get-PSRepository -Name $RepositoryName -ErrorAction Ignore +if ($Local:existingRepository) +{ + if ($Force) + { + Unregister-PSRepository -Name $RepositoryName + } + else + { + throw "Repository named $RepositoryName is already registered. Use -Force to overwrite it." + } +} + +$null = Register-PSRepository -Name $RepositoryName -SourceLocation $RepositoryPath -ScriptSourceLocation $RepositoryPath + +$Local:allItems = Get-ChildItem $ModulesPath + +$Local:progressActivity = "Publishing modules to $RepositoryPath" +Write-Progress -Activity $Local:progressActivity + +[Int32]$Local:modulesPublished = 0 + +$Local:allItems | ForEach-Object -Process { + $Local:modulePath = $_.FullName + Write-Verbose "Publishing $Local:modulePath" + Publish-Module -Path $Local:modulePath -Repository $RepositoryName + $Local:modulesPublished += 1 + Write-Progress -Activity $Local:progressActivity -PercentComplete (($Local:modulesPublished * 100) / $Local:allItems.Count) +} + +Write-Progress -Activity $Local:progressActivity -Completed diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/Modules/xE2ETestResource/xE2ETestResource.psd1 b/src/AppInstallerCLIE2ETests/TestData/Configuration/Modules/xE2ETestResource/xE2ETestResource.psd1 @@ -0,0 +1,38 @@ +# +# Module manifest for module 'xE2ETestResource' +# + +@{ + +RootModule = 'xE2ETestResource.psm1' +ModuleVersion = '0.0.0.1' +GUID = 'a0be43e8-ac22-4244-8efc-7263dfa50b8c' +CompatiblePSEditions = 'Core' +Author = 'WinGet Dev Team' +CompanyName = 'Microsoft Corporation' +Copyright = '(c) Microsoft Corporation. All rights reserved.' +Description = 'PowerShell module with DSC resources for unit tests' +PowerShellVersion = '7.2' +FunctionsToExport = @() +CmdletsToExport = @() +DscResourcesToExport = @( + 'E2EFileResource' + 'E2ETestResource' + 'E2ETestResourceThrows' + 'E2ETestResourceError' + 'E2ETestResourceTypes' + 'E2ETestResourceCrash' +) +HelpInfoURI = 'https://www.contoso.com/help' + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + ProjectUri = 'https://github.com/microsoft/winget-cli' + IconUri = 'https://www.contoso.com/icons/icon.png' + } + +} + +} diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/Modules/xE2ETestResource/xE2ETestResource.psm1 b/src/AppInstallerCLIE2ETests/TestData/Configuration/Modules/xE2ETestResource/xE2ETestResource.psm1 @@ -0,0 +1,290 @@ +# E2E module with resources. + +enum Ensure +{ + Absent + Present +} + +# This resource just checks if a file is there or not with and if its with the specified content. +[DscResource()] +class E2EFileResource +{ + [DscProperty(Key)] + [string] $Path + + [DscProperty()] + [Ensure] $Ensure = [Ensure]::Present + + [DscProperty()] + [string] $Content = $null + + [E2EFileResource] Get() + { + if ([string]::IsNullOrEmpty($this.Path)) + { + throw + } + + $fileContent = $null + if (Test-Path -Path $this.Path -PathType Leaf) + { + $fileContent = Get-Content $this.Path -Raw + } + + $result = @{ + Path = $this.Path + Content = $fileContent + } + + return $result + } + + [bool] Test() + { + $get = $this.Get() + + if (Test-Path -Path $this.Path -PathType Leaf) + { + if ($this.Ensure -eq [Ensure]::Present) + { + return $this.Content -eq $get.Content + } + } + elseif ($this.Ensure -eq [Ensure]::Absent) + { + return $true + } + + return $false + } + + [void] Set() + { + if (-not $this.Test()) + { + if (Test-Path -Path $this.Path -PathType Leaf) + { + if ($this.Ensure -eq [Ensure]::Present) + { + Set-Content $this.Path $this.Content -NoNewline + } + else + { + Remove-Item $this.Path + } + } + else + { + if ($this.Ensure -eq [Ensure]::Present) + { + Set-Content $this.Path $this.Content -NoNewline + } + } + } + } +} + +[DscResource()] +class E2ETestResource +{ + [DscProperty(Key)] + [string] $key + + [DscProperty(Mandatory)] + [string] $secretCode + + [E2ETestResource] Get() + { + $result = @{ + key = "E2ETestResourceKey" + } + return $result + } + + [bool] Test() + { + return $this.secretCode -eq "4815162342" + } + + [void] Set() + { + if (-not $this.Test()) + { + $global:DSCMachineStatus = 1 + } + } +} + +[DscResource()] +class E2ETestResourceThrows +{ + [DscProperty(Key)] + [string] $key + + [E2ETestResourceThrows] Get() + { + $result = @{ + key = "E2ETestResourceThrowsKey" + } + throw "throws in Get" + return $result + } + + [bool] Test() + { + throw "throws in Test" + return $false + } + + [void] Set() + { + throw "throws in Set" + } +} + +[DscResource()] +class E2ETestResourceError +{ + [DscProperty(Key)] + [string] $key + + [E2ETestResourceError] Get() + { + $result = @{ + key = "E2ETestResourceErrorKey" + } + Write-Error "Error in Get" + return $result + } + + [bool] Test() + { + Write-Error "Error in Test" + return $true + } + + [void] Set() + { + Write-Error "Error in Set" + } +} + +[DscResource()] +class E2ETestResourceTypes +{ + [DscProperty(Key)] + [string] $key + + [DscProperty()] + [boolean] $boolProperty + + [DscProperty()] + [int] $intProperty; + + [DscProperty()] + [double] $doubleProperty; + + [DscProperty()] + [char] $charProperty; + + [DscProperty()] + [Hashtable] $hashtableProperty; + + [E2ETestResourceTypes] Get() + { + $result = @{ + key = "E2ETestResourceTypesKey" + boolProperty = $false + intProperty = 0 + doubleProperty = 0.0 + charProperty = 'z' + hashtableProperty = @{} + } + return $result + } + + [bool] Test() + { + # Because we can't get the error stream from a class based resource, I throw so is easier to know if + # there's something wrong. + if ($this.boolProperty -ne $true) + { + throw "Failed boolProperty" + } + + if ($this.intProperty -ne 3) + { + throw "Failed intProperty. Got $($this.intProperty)" + } + + if ($this.doubleProperty -ne -9.876) + { + throw "Failed doubleProperty Got $($this.doubleProperty)" + } + + if ($this.charProperty -ne 'f') + { + throw "Failed charProperty Got $($this.charProperty)" + } + + if ($this.hashtableProperty.ContainsKey("secretStringKey")) + { + if ($this.hashtableProperty["secretStringKey"] -ne "secretCode") + { + throw "Failed comparing value of `$hashtableProperty.secretStringKey Got $($this.hashtableProperty["secretStringKey"])" + } + } + else + { + throw "Failed finding secretStringKey in hashtableProperty" + } + + if ($this.hashtableProperty.ContainsKey("secretIntKey")) + { + if ($this.hashtableProperty["secretIntKey"] -ne 123456) + { + throw "Failed comparing value of `$hashtableProperty.secretIntKey Got $($this.hashtableProperty["secretIntKey"])" + } + } + else + { + throw "Failed finding secretIntKey in hashtableProperty" + } + + return $true + } + + [void] Set() + { + # no-op + } +} + +# This resource "crashes" the containing process (really it just exits) +[DscResource()] +class E2ETestResourceCrash +{ + [DscProperty(Key)] + [string] $key + + [E2ETestResourceCrash] Get() + { + $result = @{ + key = "E2ETestResourceCrashKey" + } + [System.Environment]::Exit(0) + return $result + } + + [bool] Test() + { + [System.Environment]::Exit(0) + return $true + } + + [void] Set() + { + [System.Environment]::Exit(0) + } +} diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/PSGallery_NoModule_NoSettings.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/PSGallery_NoModule_NoSettings.yml @@ -0,0 +1,6 @@ +properties: + configurationVersion: 0.1 + resources: + - resource: XmlFileContentResource + directives: + description: Set XML file contents diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/ShowDetails.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/ShowDetails.yml @@ -1,11 +0,0 @@ -properties: - configurationVersion: 0.1 - resources: - - resource: XmlFileContentResource - directives: - module: XmlContentDsc - description: Set XML file contents - - resource: SecureBoot - directives: - module: DellBIOSProvider - description: Set secure boot options- \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/ShowDetails_TestRepo.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/ShowDetails_TestRepo.yml @@ -0,0 +1,6 @@ +properties: + configurationVersion: 0.2 + resources: + - resource: xE2ETestResource/E2EFileResource + directives: + repository: AppInstallerCLIE2ETestsRepo diff --git a/src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj b/src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj @@ -63,6 +63,7 @@ </AppxManifest> </ItemGroup> <ItemGroup> + <None Include="Execute-AppxRecipe.ps1" /> <Content Include="Images\SplashScreen.scale-200.png" /> <Content Include="Images\LockScreenLogo.scale-200.png" /> <Content Include="Images\Square150x150Logo.scale-200.png" /> @@ -114,7 +115,6 @@ <WinGetAdditonalPackageFileRoot>$(SolutionDir)</WinGetAdditonalPackageFileRoot> <WinGetAdditonalPackageFileRoot Condition="!Exists('$(WinGetAdditonalPackageFileRoot)\$(PlatformTarget)\$(Configuration)\WindowsPackageManager\WindowsPackageManager.dll')">$(OutputPath)\..\..\..\..</WinGetAdditonalPackageFileRoot> </PropertyGroup> - <Message Importance="normal" Text="WinGetAdditonalPackageFileRoot = $(WinGetAdditonalPackageFileRoot)" /> <ItemGroup> <WinGetAdditionalPackageFile Include="$(WinGetAdditonalPackageFileRoot)\$(PlatformTarget)\$(Configuration)\WindowsPackageManager\WindowsPackageManager.dll"> @@ -144,21 +144,16 @@ <Recurse>true</Recurse> </WinGetAdditionalPackageFile> </ItemGroup> - <Error Condition="!Exists('%(WinGetAdditionalPackageFile.Identity)')" Text="%(WinGetAdditionalPackageFile.Identity) was not found" /> - <!-- Single (non-recursive) file items --> <Message Importance="normal" Condition="'%(WinGetAdditionalPackageFile.Recurse)'!='true' AND Exists('%(WinGetAdditionalPackageFile.Identity)')" Text="%(WinGetAdditionalPackageFile.Identity) -> %(WinGetAdditionalPackageFile.PackagePath)" /> - <ItemGroup> <AppxPackagePayload Condition="'%(WinGetAdditionalPackageFile.Recurse)'!='true'" Include="%(WinGetAdditionalPackageFile.Identity)" KeepDuplicates="false"> <TargetPath>%(WinGetAdditionalPackageFile.PackagePath)</TargetPath> </AppxPackagePayload> </ItemGroup> - <!-- Recursive file items --> <Message Importance="normal" Condition="'%(WinGetAdditionalPackageFile.Recurse)'=='true' AND Exists('%(WinGetAdditionalPackageFile.Identity)')" Text="%(WinGetAdditionalPackageFile.Identity) -> %(WinGetAdditionalPackageFile.PackagePath)\%(WinGetAdditionalPackageFile.RecursiveDir)%(WinGetAdditionalPackageFile.Filename)%(WinGetAdditionalPackageFile.Extension)" /> - <ItemGroup> <AppxPackagePayload Condition="'%(WinGetAdditionalPackageFile.Recurse)'=='true'" Include="%(WinGetAdditionalPackageFile.Identity)" KeepDuplicates="false"> <TargetPath>%(WinGetAdditionalPackageFile.PackagePath)\%(WinGetAdditionalPackageFile.RecursiveDir)%(WinGetAdditionalPackageFile.Filename)%(WinGetAdditionalPackageFile.Extension)</TargetPath> diff --git a/src/AppInstallerCLIPackage/Package.appxmanifest b/src/AppInstallerCLIPackage/Package.appxmanifest @@ -62,12 +62,36 @@ </com:Class> <com:Class Id ="AA2A5C04-1AD9-46C4-B74F-6B334AD7EB8C" DisplayName="UninstallOptions Server"> </com:Class> + <com:Class Id ="C9ED7917-66AB-4E31-A92A-F65F18EF7933" DisplayName="Configuration Statics Server"> + </com:Class> </com:ExeServer> </com:ComServer> </com:Extension> </Extensions> </Application> </Applications> + <Extensions> + <Extension Category="windows.activatableClass.proxyStub"> + <ProxyStub ClassId="00000355-0000-0000-C000-000000000046"> + <Path>Microsoft.Management.Configuration.winmd</Path> + <Interface Name="Windows.Foundation.Collections.IIterable`1<Microsoft.Management.Configuration.ConfigurationConflict>" InterfaceId="41A1F29F-518B-5776-BCF2-E42FC9DDE32A" /> + <Interface Name="Windows.Foundation.Collections.IIterable`1<Microsoft.Management.Configuration.ApplyConfigurationUnitResult>" InterfaceId="0E2334B9-8431-5A9D-B3AA-62D4FB5B5749" /> + <Interface Name="Windows.Foundation.Collections.IIterable`1<Microsoft.Management.Configuration.ConfigurationConflictSetting>" InterfaceId="EB1E5A3C-A444-5394-B7B3-F1593937E31E" /> + <Interface Name="Windows.Foundation.Collections.IIterable`1<Microsoft.Management.Configuration.ConfigurationSet>" InterfaceId="070C1D82-67BC-5F8E-BE2F-F0F66E70E2CE" /> + <Interface Name="Windows.Foundation.Collections.IIterable`1<Microsoft.Management.Configuration.ConfigurationUnit>" InterfaceId="DB35BA1B-3DE5-50B7-80CE-BE149DF0540C" /> + <Interface Name="Windows.Foundation.Collections.IIterable`1<Microsoft.Management.Configuration.GetConfigurationUnitDetailsResult>" InterfaceId="DCF7323D-3E1E-5B22-A331-C6A29CBB6D33" /> + <Interface Name="Windows.Foundation.Collections.IIterable`1<Microsoft.Management.Configuration.IConfigurationUnitSettingDetails>" InterfaceId="9901CFD7-A9E3-5D2A-A79C-72FE20513823" /> + <Interface Name="Windows.Foundation.Collections.IIterable`1<Microsoft.Management.Configuration.TestConfigurationUnitResult>" InterfaceId="73848262-86D4-5FFC-8353-8408C4E649DE" /> + </ProxyStub> + </Extension> + <!-- This entry forces the package registration to process the windows.activatableClass.proxyStub extension above. --> + <Extension Category="windows.activatableClass.inProcessServer"> + <InProcessServer> + <Path>WindowsPackageManager.dll</Path> + <ActivatableClass ActivatableClassId="Placeholder.Activatable.Class.Do.Not.Use" ThreadingModel="STA" /> + </InProcessServer> + </Extension> + </Extensions> <Capabilities> <rescap:Capability Name="runFullTrust" /> <rescap:Capability Name="packageManagement" /> diff --git a/src/AppInstallerCLITests/TestConfiguration.cpp b/src/AppInstallerCLITests/TestConfiguration.cpp @@ -21,7 +21,7 @@ namespace TestCommon } } - winrt::event_token TestConfigurationSetProcessorFactory::Diagnostics(const EventHandler<DiagnosticInformation>& handler) + winrt::event_token TestConfigurationSetProcessorFactory::Diagnostics(const EventHandler<IDiagnosticInformation>& handler) { return m_diagnostics.add(handler); } @@ -72,7 +72,7 @@ namespace TestCommon UnitValue(unit), DirectivesOverlayValue(directivesOverlay) {} - TestSettingsResult TestConfigurationUnitProcessor::TestSettings() + ITestSettingsResult TestConfigurationUnitProcessor::TestSettings() { if (TestSettingsFunc) { @@ -80,11 +80,11 @@ namespace TestCommon } else { - return TestSettingsResult{}; + return winrt::make<TestSettingsResultInstance>(); } } - GetSettingsResult TestConfigurationUnitProcessor::GetSettings() + IGetSettingsResult TestConfigurationUnitProcessor::GetSettings() { if (GetSettingsFunc) { @@ -92,11 +92,11 @@ namespace TestCommon } else { - return GetSettingsResult{}; + return winrt::make<GetSettingsResultInstance>(); } } - ApplySettingsResult TestConfigurationUnitProcessor::ApplySettings() + IApplySettingsResult TestConfigurationUnitProcessor::ApplySettings() { if (ApplySettingsFunc) { @@ -104,7 +104,7 @@ namespace TestCommon } else { - return ApplySettingsResult{}; + return winrt::make<ApplySettingsResultInstance>(); } } } diff --git a/src/AppInstallerCLITests/TestConfiguration.h b/src/AppInstallerCLITests/TestConfiguration.h @@ -13,7 +13,7 @@ namespace TestCommon { winrt::Microsoft::Management::Configuration::IConfigurationSetProcessor CreateSetProcessor(const winrt::Microsoft::Management::Configuration::ConfigurationSet& configurationSet); - winrt::event_token Diagnostics(const winrt::Windows::Foundation::EventHandler<winrt::Microsoft::Management::Configuration::DiagnosticInformation>& handler); + winrt::event_token Diagnostics(const winrt::Windows::Foundation::EventHandler<winrt::Microsoft::Management::Configuration::IDiagnosticInformation>& handler); void Diagnostics(const winrt::event_token& token) noexcept; winrt::Microsoft::Management::Configuration::DiagnosticLevel MinimumLevel(); @@ -22,7 +22,7 @@ namespace TestCommon std::function<winrt::Microsoft::Management::Configuration::IConfigurationSetProcessor(const winrt::Microsoft::Management::Configuration::ConfigurationSet&)> CreateSetProcessorFunc; private: - winrt::event<winrt::Windows::Foundation::EventHandler<winrt::Microsoft::Management::Configuration::DiagnosticInformation>> m_diagnostics; + winrt::event<winrt::Windows::Foundation::EventHandler<winrt::Microsoft::Management::Configuration::IDiagnosticInformation>> m_diagnostics; }; struct TestConfigurationSetProcessor : winrt::implements<TestConfigurationSetProcessor, winrt::Microsoft::Management::Configuration::IConfigurationSetProcessor> @@ -115,16 +115,61 @@ namespace TestCommon winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Windows::Foundation::IInspectable> DirectivesOverlayValue; winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Windows::Foundation::IInspectable> DirectivesOverlay() { return DirectivesOverlayValue; } - winrt::Microsoft::Management::Configuration::TestSettingsResult TestSettings(); + winrt::Microsoft::Management::Configuration::ITestSettingsResult TestSettings(); - std::function<winrt::Microsoft::Management::Configuration::TestSettingsResult()> TestSettingsFunc; + std::function<winrt::Microsoft::Management::Configuration::ITestSettingsResult()> TestSettingsFunc; - winrt::Microsoft::Management::Configuration::GetSettingsResult GetSettings(); + winrt::Microsoft::Management::Configuration::IGetSettingsResult GetSettings(); - std::function<winrt::Microsoft::Management::Configuration::GetSettingsResult()> GetSettingsFunc; + std::function<winrt::Microsoft::Management::Configuration::IGetSettingsResult()> GetSettingsFunc; - winrt::Microsoft::Management::Configuration::ApplySettingsResult ApplySettings(); + winrt::Microsoft::Management::Configuration::IApplySettingsResult ApplySettings(); - std::function<winrt::Microsoft::Management::Configuration::ApplySettingsResult()> ApplySettingsFunc; + std::function<winrt::Microsoft::Management::Configuration::IApplySettingsResult()> ApplySettingsFunc; + }; + + struct TestSettingsResultInstance : winrt::implements<TestSettingsResultInstance, winrt::Microsoft::Management::Configuration::ITestSettingsResult> + { + TestSettingsResultInstance() = default; + + winrt::Microsoft::Management::Configuration::ConfigurationTestResult TestResult() { return m_testResult; } + void TestResult(winrt::Microsoft::Management::Configuration::ConfigurationTestResult value) { m_testResult = value; } + + winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation ResultInformation() { return m_resultInformation; } + void ResultInformation(winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation value) { m_resultInformation = value; } + + private: + winrt::Microsoft::Management::Configuration::ConfigurationTestResult m_testResult = winrt::Microsoft::Management::Configuration::ConfigurationTestResult::Unknown; + winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation m_resultInformation; + }; + + struct ApplySettingsResultInstance : winrt::implements<ApplySettingsResultInstance, winrt::Microsoft::Management::Configuration::IApplySettingsResult> + { + ApplySettingsResultInstance() = default; + + bool RebootRequired() { return m_rebootRequired; } + void RebootRequired(bool value) { m_rebootRequired = value; } + + winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation ResultInformation() { return m_resultInformation; } + void ResultInformation(winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation value) { m_resultInformation = value; } + + private: + bool m_rebootRequired = false; + winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation m_resultInformation; + }; + + struct GetSettingsResultInstance : winrt::implements<GetSettingsResultInstance, winrt::Microsoft::Management::Configuration::IGetSettingsResult> + { + GetSettingsResultInstance() = default; + + winrt::Windows::Foundation::Collections::ValueSet Settings() { return m_settings; } + void Settings(winrt::Windows::Foundation::Collections::ValueSet value) { m_settings = value; } + + winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation ResultInformation() { return m_resultInformation; } + void ResultInformation(winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation value) { m_resultInformation = value; } + + private: + winrt::Windows::Foundation::Collections::ValueSet m_settings; + winrt::Microsoft::Management::Configuration::IConfigurationUnitResultInformation m_resultInformation; }; } diff --git a/src/AppInstallerSharedLib/AppInstallerSharedLib.vcxproj b/src/AppInstallerSharedLib/AppInstallerSharedLib.vcxproj @@ -399,10 +399,13 @@ <ClInclude Include="Public\Telemetry\MicrosoftTelemetry.h" /> <ClInclude Include="Public\Telemetry\WinEventLogLevels.h" /> <ClInclude Include="Public\winget\AsyncTokens.h" /> + <ClInclude Include="Public\winget\ConfigurationSetProcessorHandlers.h" /> + <ClInclude Include="Public\winget\ILifetimeWatcher.h" /> <ClInclude Include="Public\winget\JsonSchemaValidation.h" /> <ClInclude Include="Public\winget\LocIndependent.h" /> <ClInclude Include="Public\winget\Resources.h" /> <ClInclude Include="Public\winget\Runtime.h" /> + <ClInclude Include="Public\winget\Security.h" /> <ClInclude Include="Public\winget\SharedThreadGlobals.h" /> <ClInclude Include="Public\winget\Yaml.h" /> <ClInclude Include="YamlWrapper.h" /> @@ -418,6 +421,7 @@ <PrecompiledHeader>Create</PrecompiledHeader> </ClCompile> <ClCompile Include="Runtime.cpp" /> + <ClCompile Include="Security.cpp" /> <ClCompile Include="SHA256.cpp" /> <ClCompile Include="SharedThreadGlobals.cpp" /> <ClCompile Include="Versions.cpp" /> diff --git a/src/AppInstallerSharedLib/AppInstallerSharedLib.vcxproj.filters b/src/AppInstallerSharedLib/AppInstallerSharedLib.vcxproj.filters @@ -74,6 +74,15 @@ <ClInclude Include="Public\winget\AsyncTokens.h"> <Filter>Public\winget</Filter> </ClInclude> + <ClInclude Include="Public\winget\ConfigurationSetProcessorHandlers.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Public\winget\ILifetimeWatcher.h"> + <Filter>Public\winget</Filter> + </ClInclude> + <ClInclude Include="Public\winget\Security.h"> + <Filter>Public\winget</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="pch.cpp"> @@ -115,6 +124,9 @@ <ClCompile Include="Runtime.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="Security.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> diff --git a/src/AppInstallerSharedLib/Public/AppInstallerLogging.h b/src/AppInstallerSharedLib/Public/AppInstallerLogging.h @@ -188,4 +188,4 @@ namespace AppInstaller::Logging } std::ostream& operator<<(std::ostream& out, const std::chrono::system_clock::time_point& time); -std::ostream& operator<<(std::ostream& out, const GUID& time); +std::ostream& operator<<(std::ostream& out, const GUID& guid); diff --git a/src/AppInstallerSharedLib/Public/winget/ConfigurationSetProcessorHandlers.h b/src/AppInstallerSharedLib/Public/winget/ConfigurationSetProcessorHandlers.h @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <AppInstallerLogging.h> +#include <winrt/Windows.Foundation.h> +#include <memory> + +namespace AppInstaller::Configuration +{ + constexpr std::wstring_view PowerShellHandlerIdentifier = L"pwsh"; +} diff --git a/src/AppInstallerSharedLib/Public/winget/ILifetimeWatcher.h b/src/AppInstallerSharedLib/Public/winget/ILifetimeWatcher.h @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <Unknwn.h> +#include <winrt/Windows.Foundation.h> + +namespace AppInstaller::WinRT +{ + MIDL_INTERFACE("59b5623f-d03e-41f8-b400-89ee04ea02d7") + ILifetimeWatcher : public IUnknown + { + public: + // Due to the way the winrt types are set up, this watcher will not have AddRef called. + virtual /* [local] */ HRESULT STDMETHODCALLTYPE SetLifetimeWatcher( + IUnknown* watcher) = 0; + }; + + // Implements ILifetimeWatcher functionality. + struct LifetimeWatcherBase + { + HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher) + { + m_lifetimeWatcher = winrt::Windows::Foundation::IUnknown(watcher, winrt::take_ownership_from_abi); + return S_OK; + } + + void PropagateLifetimeWatcher(const winrt::Windows::Foundation::IUnknown& child) + { + if (m_lifetimeWatcher && child) + { + // Require that any call to this function is for an object that implements watching to prevent + // accidental assumptions about the child object and lifetime management. + auto watcher = child.as<ILifetimeWatcher>(); + + // Create a copy of the lifetime watcher (to add_ref), then detach and pass it to the child to own. + watcher->SetLifetimeWatcher(static_cast<IUnknown*>(winrt::detach_abi(winrt::Windows::Foundation::IUnknown{ m_lifetimeWatcher }))); + } + } + + private: + winrt::Windows::Foundation::IUnknown m_lifetimeWatcher; + }; +} diff --git a/src/AppInstallerSharedLib/Public/winget/Security.h b/src/AppInstallerSharedLib/Public/winget/Security.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <wil/resource.h> +#include <string> +#include <string_view> + +namespace AppInstaller::Security +{ + // A Windows integrity level. + enum class IntegrityLevel + { + Untrusted, + Low, + Medium, + MediumPlus, + High, + System, + ProtectedProcess, + }; + + // Gets the integrity level for the current effective token. + // Does not know how to determine MediumPlus, if that ever matters... + IntegrityLevel GetEffectiveIntegrityLevel(); + + // Determines if the current COM caller is the same user as the current process + // and is at least equal integrity level (higher will also be allowed). + bool IsCOMCallerSameUserAndIntegrityLevel(); + + // Gets the string representation of the given SID. + std::string ToString(PSID sid); +} diff --git a/src/AppInstallerSharedLib/Security.cpp b/src/AppInstallerSharedLib/Security.cpp @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "winget/Security.h" +#include "AppInstallerLogging.h" +#include "AppInstallerLanguageUtilities.h" + +namespace AppInstaller::Security +{ + namespace + { + bool IsSameAuthority(const SID_IDENTIFIER_AUTHORITY& a, const SID_IDENTIFIER_AUTHORITY& b) + { + for (size_t i = 0; i < ARRAYSIZE(a.Value); ++i) + { + if (a.Value[i] != b.Value[i]) + { + return false; + } + } + + return true; + } + + // Helper to impersonate the COM or RPC caller. + struct ImpersonateCOMorRPCCaller + { + static ImpersonateCOMorRPCCaller BeginImpersonation() + { + return {}; + } + + ~ImpersonateCOMorRPCCaller() + { + if (m_serverSecurity) + { + FAIL_FAST_IF_FAILED(m_serverSecurity->RevertToSelf()); + } + else + { + FAIL_FAST_IF(RpcRevertToSelf() != RPC_S_OK); + } + } + + private: + ImpersonateCOMorRPCCaller() + { + if (SUCCEEDED_LOG(CoGetCallContext(IID_IServerSecurity, m_serverSecurity.put_void()))) + { + THROW_IF_FAILED(m_serverSecurity->ImpersonateClient()); + } + else + { + RPC_STATUS status = RpcImpersonateClient(nullptr); + THROW_HR_IF(MAKE_HRESULT(SEVERITY_ERROR, FACILITY_RPC, status), status != RPC_S_OK); + } + } + + wil::com_ptr<IServerSecurity> m_serverSecurity; + }; + } + + IntegrityLevel GetEffectiveIntegrityLevel() + { + auto currentIntegrityLevel = wil::get_token_information<TOKEN_MANDATORY_LABEL>(); + PSID sid = currentIntegrityLevel->Label.Sid; + THROW_HR_IF(CO_E_INVALIDSID, !IsValidSid(sid)); + + auto identifierAuthority = GetSidIdentifierAuthority(sid); + THROW_HR_IF(E_UNEXPECTED, !IsSameAuthority(*identifierAuthority, SECURITY_MANDATORY_LABEL_AUTHORITY)); + + PUCHAR subAuthorityCount = GetSidSubAuthorityCount(sid); + THROW_HR_IF(E_UNEXPECTED, *subAuthorityCount != 1); + + PDWORD subAuthority = GetSidSubAuthority(sid, 0); + + switch (*subAuthority) + { + case SECURITY_MANDATORY_UNTRUSTED_RID: return IntegrityLevel::Untrusted; + case SECURITY_MANDATORY_LOW_RID: return IntegrityLevel::Low; + case SECURITY_MANDATORY_MEDIUM_RID: return IntegrityLevel::Medium; + case SECURITY_MANDATORY_HIGH_RID: return IntegrityLevel::High; + case SECURITY_MANDATORY_SYSTEM_RID: return IntegrityLevel::System; + case SECURITY_MANDATORY_PROTECTED_PROCESS_RID: return IntegrityLevel::ProtectedProcess; + } + + THROW_HR(E_UNEXPECTED); + } + + bool IsCOMCallerSameUserAndIntegrityLevel() + { + auto serverUser = wil::get_token_information<TOKEN_USER>(); + IntegrityLevel serverIntegrityLevel = GetEffectiveIntegrityLevel(); + + auto impersonation = ImpersonateCOMorRPCCaller::BeginImpersonation(); + + auto callingUser = wil::get_token_information<TOKEN_USER>(); + IntegrityLevel callingIntegrityLevel = GetEffectiveIntegrityLevel(); + + if (!EqualSid(serverUser->User.Sid, callingUser->User.Sid)) + { + AICLI_LOG(Core, Crit, << "Attempt to access by another user: " << ToString(callingUser->User.Sid)); + return false; + } + + if (ToIntegral(callingIntegrityLevel) < ToIntegral(serverIntegrityLevel)) + { + AICLI_LOG(Core, Crit, << "Attempt to access by a lower integrity process: " << callingIntegrityLevel << " < " << serverIntegrityLevel); + return false; + } + + return true; + } + + std::string ToString(PSID sid) + { + wil::unique_hlocal_ansistring result; + THROW_IF_WIN32_BOOL_FALSE(ConvertSidToStringSidA(sid, &result)); + return result.get(); + } +} diff --git a/src/AppInstallerSharedLib/pch.h b/src/AppInstallerSharedLib/pch.h @@ -6,6 +6,7 @@ #include <Windows.h> #include <appmodel.h> #include <icu.h> +#include <sddl.h> #define YAML_DECLARE_STATIC #include <yaml.h> diff --git a/src/ConfigurationRemotingServer/Program.cs b/src/ConfigurationRemotingServer/Program.cs @@ -17,31 +17,22 @@ namespace ConfigurationRemotingServer { ulong initEventHandle = ulong.Parse(args[1]); ulong completionEventHandle = ulong.Parse(args[2]); + ulong parentProcessHandle = ulong.Parse(args[3]); - // Assume that the additional modules path is a sibling directory to the one containing this binary - string assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidDataException(); - string rootDirectory = Path.GetDirectoryName(assemblyDirectory) ?? throw new InvalidDataException(); ; - string modulesPath = Path.Combine(rootDirectory, "ExternalModules"); + PowerShellConfigurationSetProcessorFactory factory = new PowerShellConfigurationSetProcessorFactory(); - ConfigurationProcessorFactoryProperties properties = new ConfigurationProcessorFactoryProperties(); - properties.AdditionalModulePaths = new List<string>() { modulesPath }; - - // This can be RemoteSigned eventually or keep it Unrestricted for dev builds. - properties.Policy = ConfigurationProcessorPolicy.Unrestricted; - - ConfigurationSetProcessorFactory factory = new ConfigurationSetProcessorFactory(ConfigurationProcessorType.Hosted, properties); IObjectReference factoryInterface = MarshalInterface<global::Microsoft.Management.Configuration.IConfigurationSetProcessorFactory>.CreateMarshaler(factory); - return WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(0, factoryInterface.ThisPtr, memoryHandle, initEventHandle, completionEventHandle); + return WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(0, factoryInterface.ThisPtr, memoryHandle, initEventHandle, completionEventHandle, parentProcessHandle); } catch(Exception ex) { - WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(ex.HResult, IntPtr.Zero, memoryHandle, 0, 0); + WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(ex.HResult, IntPtr.Zero, memoryHandle, 0, 0, 0); return ex.HResult; } } [DllImport("WindowsPackageManager.dll")] - private static extern int WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(int result, IntPtr factory, ulong memoryHandle, ulong initEventHandle, ulong completionMutexHandle); + private static extern int WindowsPackageManagerConfigurationCompleteOutOfProcessFactoryInitialization(int result, IntPtr factory, ulong memoryHandle, ulong initEventHandle, ulong completionMutexHandle, ulong parentProcessHandle); } } \ No newline at end of file diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Factory.cpp b/src/Microsoft.Management.Configuration.OutOfProc/Factory.cpp @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Factory.h" +#include <winrt/Microsoft.Management.Configuration.h> +#include <winget/Runtime.h> +#include <WinGetServerManualActivation_Client.h> + +namespace Microsoft::Management::Configuration::OutOfProc +{ + namespace + { + const CLSID& GetConfigurationStaticsCLSID() + { +#if USE_PROD_CLSIDS + static const CLSID CLSID_ConfigurationStatics = { 0x73d763b7,0x2937,0x432f,{0xa9,0x7a,0xd9,0x8a,0x4a,0x59,0x61,0x26} }; // 73D763B7-2937-432F-A97A-D98A4A596126 +#else + static const CLSID CLSID_ConfigurationStatics = { 0xc9ed7917,0x66ab,0x4e31,{0xa9,0x2a,0xf6,0x5f,0x18,0xef,0x79,0x33} }; // C9ED7917-66AB-4E31-A92A-F65F18EF7933 +#endif + + return CLSID_ConfigurationStatics; + } + + winrt::Microsoft::Management::Configuration::IConfigurationStatics CreateOOPStaticsObject() + { + bool isAdmin = AppInstaller::Runtime::IsRunningAsAdmin(); + + try + { + return winrt::create_instance<winrt::Microsoft::Management::Configuration::IConfigurationStatics>(GetConfigurationStaticsCLSID(), CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD); + } + catch (const winrt::hresult_error& hre) + { + // We only want to fall through to trying the manual activation if we are running as admin and couldn't find the registration. + if (!(isAdmin && hre.code() == REGDB_E_CLASSNOTREG)) + { + throw; + } + } + + winrt::com_ptr<::IUnknown> result; + THROW_IF_FAILED(WinGetServerManualActivation_CreateInstance(GetConfigurationStaticsCLSID(), winrt::guid_of<winrt::Microsoft::Management::Configuration::IConfigurationStatics>(), 0, result.put_void())); + return result.as<winrt::Microsoft::Management::Configuration::IConfigurationStatics>(); + } + } + + Factory::Factory() + { + IncrementRefCount(); + } + + Factory::~Factory() + { + DecrementRefCount(); + } + + bool Factory::HasReferences() + { + return s_referenceCount.load() != 0; + } + + void Factory::Terminate() + { + WinGetServerManualActivation_Terminate(); + } + + bool Factory::IsCLSID(const GUID& clsid) + { + if (clsid == GetConfigurationStaticsCLSID()) + { + return true; + } + + return false; + } + + bool Factory::IsCLSID(HSTRING clsid) + { + constexpr std::wstring_view s_ClassName = L"Microsoft.Management.Configuration.ConfigurationStaticFunctions"; + + UINT32 length = 0; + PCWSTR buffer = WindowsGetStringRawBuffer(clsid, &length); + + if (std::wstring_view{ buffer, length } == s_ClassName) + { + return true; + } + + return false; + } + + winrt::Windows::Foundation::IInspectable Factory::ActivateInstance() + { + return CreateOOPStaticsObject().as<winrt::Windows::Foundation::IInspectable>(); + } + + HRESULT STDMETHODCALLTYPE Factory::CreateInstance(::IUnknown* pUnkOuter, REFIID riid, void** ppvObject) try + { + RETURN_HR_IF(E_POINTER, !ppvObject); + *ppvObject = nullptr; + RETURN_HR_IF(CLASS_E_NOAGGREGATION, pUnkOuter != nullptr); + + return CreateOOPStaticsObject().as(riid, ppvObject); + } + CATCH_RETURN(); + + HRESULT STDMETHODCALLTYPE Factory::LockServer(BOOL fLock) + { + if (fLock) + { + IncrementRefCount(); + } + else + { + DecrementRefCount(); + } + + return S_OK; + } + + void Factory::IncrementRefCount() + { + ++s_referenceCount; + } + + void Factory::DecrementRefCount() + { + --s_referenceCount; + } + + std::atomic<int32_t> Factory::s_referenceCount = ATOMIC_VAR_INIT(0); +} diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Factory.h b/src/Microsoft.Management.Configuration.OutOfProc/Factory.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <hstring.h> +#include <inspectable.h> +#include <winrt/Windows.Foundation.h> +#include <atomic> + +namespace Microsoft::Management::Configuration::OutOfProc +{ + struct Factory : winrt::implements<Factory, winrt::Windows::Foundation::IActivationFactory, IClassFactory> + { + Factory(); + ~Factory(); + + // Returns true if the reference count is not 0; false if it is. + static bool HasReferences(); + + // Forcibly destroys any static objects. + static void Terminate(); + + // Determines if the given CLSID is the CLSID for the factory. + static bool IsCLSID(const GUID& clsid); + + // Determines if the given CLSID is the CLSID for the factory. + static bool IsCLSID(HSTRING clsid); + + // IActivationFactory + winrt::Windows::Foundation::IInspectable ActivateInstance(); + + // IClassFactory + HRESULT STDMETHODCALLTYPE CreateInstance(::IUnknown *pUnkOuter, REFIID riid, void **ppvObject); + HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock); + + private: + static void IncrementRefCount(); + static void DecrementRefCount(); + + static std::atomic<int32_t> s_referenceCount; + }; +} diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Microsoft.Management.Configuration.OutOfProc.vcxproj b/src/Microsoft.Management.Configuration.OutOfProc/Microsoft.Management.Configuration.OutOfProc.vcxproj @@ -0,0 +1,499 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.props')" /> + <PropertyGroup Label="Globals"> + <CppWinRTOptimized>true</CppWinRTOptimized> + <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> + <MinimalCoreWin>true</MinimalCoreWin> + <VCProjectVersion>15.0</VCProjectVersion> + <Keyword>Win32Proj</Keyword> + <RootNamespace>MicrosoftManagementConfigurationOutOfProc</RootNamespace> + <WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion> + <WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> + <CppWinRTGenerateWindowsMetadata>false</CppWinRTGenerateWindowsMetadata> + <ProjectGuid>{2268D5AD-7F2A-485A-8C4B-C574497514C9}</ProjectGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="ReleaseStatic|ARM"> + <Configuration>ReleaseStatic</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="ReleaseStatic|ARM64"> + <Configuration>ReleaseStatic</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="ReleaseStatic|Win32"> + <Configuration>ReleaseStatic</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="ReleaseStatic|x64"> + <Configuration>ReleaseStatic</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v140</PlatformToolset> + <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset> + <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset> + <PlatformToolset Condition="'$(VisualStudioVersion)' == '17.0'">v143</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> + <UseDebugLibraries>true</UseDebugLibraries> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='ReleaseStatic'" Label="Configuration"> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <SpectreMitigation>Spectre</SpectreMitigation> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'" Label="Configuration"> + <SpectreMitigation>Spectre</SpectreMitigation> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <SpectreMitigation>Spectre</SpectreMitigation> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'" Label="Configuration"> + <SpectreMitigation>Spectre</SpectreMitigation> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <SpectreMitigation>Spectre</SpectreMitigation> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'" Label="Configuration"> + <SpectreMitigation>Spectre</SpectreMitigation> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <SpectreMitigation>Spectre</SpectreMitigation> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'" Label="Configuration"> + <SpectreMitigation>Spectre</SpectreMitigation> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="PropertySheet.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>true</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>true</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>true</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)x86\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>true</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)x86\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>false</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)x86\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>false</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>false</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>false</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>false</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>false</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>false</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> + <RunCodeAnalysis>false</RunCodeAnalysis> + <CodeAnalysisRuleSet>..\CodeAnalysis.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile> + <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <WarningLevel>Level4</WarningLevel> + <AdditionalOptions>%(AdditionalOptions) /permissive- /bigobj /D _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING</AdditionalOptions> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</TreatWarningAsError> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">false</ControlFlowGuard> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">false</ControlFlowGuard> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ControlFlowGuard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpp17</LanguageStandard> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</SDLCheck> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</SDLCheck> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</SDLCheck> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</EnablePREfast> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</EnablePREfast> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</EnablePREfast> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">6001</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">6001</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6001</DisableSpecificWarnings> + </ClCompile> + <Link> + <GenerateWindowsMetadata>false</GenerateWindowsMetadata> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Windows</SubSystem> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Source.def</ModuleDefinitionFile> + <AdditionalDependencies Condition="'$(Configuration)'=='Debug'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;Advapi32.lib;winhttp.lib;onecoreuap.lib;msi.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</TreatWarningAsError> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ControlFlowGuard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">stdcpp17</LanguageStandard> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</SDLCheck> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnablePREfast> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">6001</DisableSpecificWarnings> + </ClCompile> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</TreatWarningAsError> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Guard</ControlFlowGuard> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Guard</ControlFlowGuard> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Guard</ControlFlowGuard> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Guard</ControlFlowGuard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">stdcpp17</LanguageStandard> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</SDLCheck> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</SDLCheck> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</SDLCheck> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</SDLCheck> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">false</EnablePREfast> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">false</EnablePREfast> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</EnablePREfast> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</EnablePREfast> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">6001</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">6001</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">6001</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6001</DisableSpecificWarnings> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateWindowsMetadata>false</GenerateWindowsMetadata> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Windows</SubSystem> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Source.def</ModuleDefinitionFile> + <AdditionalDependencies Condition="'$(Configuration)'=='Release'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;Advapi32.lib;winhttp.lib;onecoreuap.lib;msi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)</AdditionalOptions> + </Link> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='ReleaseStatic'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\WinGetServer;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">true</TreatWarningAsError> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">Guard</ControlFlowGuard> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">Guard</ControlFlowGuard> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">Guard</ControlFlowGuard> + <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">Guard</ControlFlowGuard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">stdcpp17</LanguageStandard> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">true</SDLCheck> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">true</SDLCheck> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">true</SDLCheck> + <SDLCheck Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">true</SDLCheck> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">false</EnablePREfast> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">false</EnablePREfast> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">false</EnablePREfast> + <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">false</EnablePREfast> + <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">MultiThreaded</RuntimeLibrary> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">6001</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">6001</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">6001</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">6001</DisableSpecificWarnings> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateWindowsMetadata>false</GenerateWindowsMetadata> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">Windows</SubSystem> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">Source.def</ModuleDefinitionFile> + <ModuleDefinitionFile Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">Source.def</ModuleDefinitionFile> + <AdditionalDependencies Condition="'$(Configuration)'=='ReleaseStatic'">wininet.lib;shell32.lib;winsqlite3.lib;shlwapi.lib;icuuc.lib;icuin.lib;urlmon.lib;Advapi32.lib;winhttp.lib;onecoreuap.lib;msi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)</AdditionalOptions> + </Link> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + <Manifest> + <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> + </Manifest> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="Factory.h" /> + <ClInclude Include="pch.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\WinGetServer\Utils.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">NotUsing</PrecompiledHeader> + </ClCompile> + <ClCompile Include="..\WinGetServer\WinGetServerManualActivation_Client.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">NotUsing</PrecompiledHeader> + </ClCompile> + <ClCompile Include="..\WinGetServer\WinGetServer_c.c"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">NotUsing</PrecompiledHeader> + </ClCompile> + <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="Factory.cpp" /> + <ClCompile Include="pch.cpp"> + <PrecompiledHeader>Create</PrecompiledHeader> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + <None Include="PropertySheet.props" /> + <None Include="Source.def" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\AppInstallerSharedLib\AppInstallerSharedLib.vcxproj"> + <Project>{f3f6e699-bc5d-4950-8a05-e49dd9eb0d51}</Project> + </ProjectReference> + <ProjectReference Include="..\Microsoft.Management.Configuration\Microsoft.Management.Configuration.vcxproj"> + <Project>{ca460806-5e41-4e97-9a3d-1d74b433b663}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.210204.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.210204.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.targets')" /> + </ImportGroup> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.210204.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.210204.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + </Target> +</Project>+ \ No newline at end of file diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Microsoft.Management.Configuration.OutOfProc.vcxproj.filters b/src/Microsoft.Management.Configuration.OutOfProc/Microsoft.Management.Configuration.OutOfProc.vcxproj.filters @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="WinGetServerManualActivation"> + <UniqueIdentifier>{6017fd94-3eb1-40bc-964f-5dd571077d3c}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pch.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Factory.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="dllmain.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pch.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Factory.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\WinGetServer\WinGetServer_c.c"> + <Filter>WinGetServerManualActivation</Filter> + </ClCompile> + <ClCompile Include="..\WinGetServer\WinGetServerManualActivation_Client.cpp"> + <Filter>WinGetServerManualActivation</Filter> + </ClCompile> + <ClCompile Include="..\WinGetServer\Utils.cpp"> + <Filter>WinGetServerManualActivation</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + <None Include="PropertySheet.props" /> + <None Include="Source.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> +</Project>+ \ No newline at end of file diff --git a/src/Microsoft.Management.Configuration.OutOfProc/PropertySheet.props b/src/Microsoft.Management.Configuration.OutOfProc/PropertySheet.props @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <PropertyGroup Label="UserMacros" /> + <!-- + To customize common C++/WinRT project properties: + * right-click the project node + * expand the Common Properties item + * select the C++/WinRT property page + + For more advanced scenarios, and complete documentation, please see: + https://github.com/Microsoft/xlang/tree/master/src/package/cppwinrt/nuget + --> + <PropertyGroup /> + <ItemDefinitionGroup /> +</Project>+ \ No newline at end of file diff --git a/src/Microsoft.Management.Configuration.OutOfProc/Source.def b/src/Microsoft.Management.Configuration.OutOfProc/Source.def @@ -0,0 +1,4 @@ +EXPORTS +DllCanUnloadNow PRIVATE +DllGetClassObject PRIVATE +DllGetActivationFactory PRIVATE diff --git a/src/Microsoft.Management.Configuration.OutOfProc/dllmain.cpp b/src/Microsoft.Management.Configuration.OutOfProc/dllmain.cpp @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Factory.h" +#include <hstring.h> + +using namespace Microsoft::Management::Configuration::OutOfProc; + +EXTERN_C BOOL WINAPI DllMain( + HMODULE /* hModule */, + DWORD reason, + LPVOID /* lpReserved */) +{ + switch (reason) + { + case DLL_PROCESS_DETACH: + Factory::Terminate(); + break; + } + + return TRUE; +} + +_Check_return_ +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv) try +{ + RETURN_HR_IF(E_POINTER, !ppv); + *ppv = nullptr; + + winrt::Windows::Foundation::IUnknown result; + + if (Factory::IsCLSID(rclsid)) + { + result = winrt::make<Factory>().as<winrt::Windows::Foundation::IUnknown>(); + } + + if (result) + { + return result.as(riid, ppv); + } + + return REGDB_E_CLASSNOTREG; +} +CATCH_RETURN(); + +__control_entrypoint(DllExport) +STDAPI DllCanUnloadNow() +{ + return Factory::HasReferences() ? S_FALSE : S_OK; +} + +STDAPI DllGetActivationFactory(HSTRING classId, void** factory) try +{ + RETURN_HR_IF(E_POINTER, !factory); + *factory = nullptr; + + winrt::Windows::Foundation::IUnknown result; + + if (Factory::IsCLSID(classId)) + { + result = winrt::make<Factory>().as<winrt::Windows::Foundation::IUnknown>(); + } + + if (result) + { + return result.as(winrt::guid_of<winrt::Windows::Foundation::IActivationFactory>(), factory); + } + + return REGDB_E_CLASSNOTREG; +} +CATCH_RETURN(); diff --git a/src/Microsoft.Management.Configuration.OutOfProc/packages.config b/src/Microsoft.Management.Configuration.OutOfProc/packages.config @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Microsoft.Windows.CppWinRT" version="2.0.210505.3" targetFramework="native" /> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.210204.1" targetFramework="native" /> +</packages>+ \ No newline at end of file diff --git a/src/Microsoft.Management.Configuration.OutOfProc/pch.cpp b/src/Microsoft.Management.Configuration.OutOfProc/pch.cpp @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" diff --git a/src/Microsoft.Management.Configuration.OutOfProc/pch.h b/src/Microsoft.Management.Configuration.OutOfProc/pch.h @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#include <Unknwnbase.h> +#include <inspectable.h> +#include <winstring.h> + +#include <wil/result_macros.h> +#include <winrt/Windows.Foundation.h> + +#include <atomic> +#include <string_view> diff --git a/src/Microsoft.Management.Configuration.Processor/Constants/PowerShellConstants.cs b/src/Microsoft.Management.Configuration.Processor/Constants/PowerShellConstants.cs @@ -43,6 +43,7 @@ namespace Microsoft.Management.Configuration.Processor.Constants public const string InstallModule = "Install-Module"; public const string InvokeDscResource = "Invoke-DscResource"; public const string SaveModule = "Save-Module"; + public const string FindModule = "Find-Module"; } internal static class Parameters diff --git a/src/Microsoft.Management.Configuration.Processor/Helpers/DiagnosticInformation.cs b/src/Microsoft.Management.Configuration.Processor/Helpers/DiagnosticInformation.cs @@ -0,0 +1,23 @@ +// ----------------------------------------------------------------------------- +// <copyright file="DiagnosticInformation.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor.Helpers +{ + using System; + using Microsoft.Management.Configuration; + + /// <summary> + /// Implements IDiagnosticInformation. + /// </summary> + internal sealed class DiagnosticInformation : IDiagnosticInformation + { + /// <inheritdoc/> + public DiagnosticLevel Level { get; internal set; } + + /// <inheritdoc/> + public string? Message { get; internal set; } + } +} diff --git a/src/Microsoft.Management.Configuration.Processor/Microsoft.Management.Configuration.Processor.csproj b/src/Microsoft.Management.Configuration.Processor/Microsoft.Management.Configuration.Processor.csproj @@ -17,6 +17,7 @@ <!-- Disable warning CS1591 for cswinrt auto-generated files and CS8785 for SourceGenerator compilation errors --> <NoWarn>1591,8785</NoWarn> <Configurations>Debug;Release;ReleaseStatic</Configurations> + <CsWinRTEnableLogging>true</CsWinRTEnableLogging> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)'=='Release'"> @@ -57,14 +58,16 @@ </ProjectReference> </ItemGroup> - <PropertyGroup> - <MicrosoftManagementConfigurationPath>$(OutputPath)..\..\..\x64\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd</MicrosoftManagementConfigurationPath> - <MicrosoftManagementConfigurationPath Condition="!Exists('$(MicrosoftManagementConfigurationPath)')">$(OutputPath)..\..\..\x86\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd</MicrosoftManagementConfigurationPath> - <MicrosoftManagementConfigurationPath Condition="!Exists('$(MicrosoftManagementConfigurationPath)')">$(OutputPath)..\..\..\arm64\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd</MicrosoftManagementConfigurationPath> - </PropertyGroup> - <Target Name="MicrosoftManagementConfigurationPathTarget" BeforeTargets="CsWinRTSetAuthoringWinMDs"> + <PropertyGroup> + <MicrosoftManagementConfigurationPath>$(SolutionDir)x64\$(Configuration)\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd</MicrosoftManagementConfigurationPath> + <MicrosoftManagementConfigurationPath Condition="!Exists('$(MicrosoftManagementConfigurationPath)')">$(SolutionDir)x86\$(Configuration)\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd</MicrosoftManagementConfigurationPath> + <MicrosoftManagementConfigurationPath Condition="!Exists('$(MicrosoftManagementConfigurationPath)')">$(SolutionDir)arm\$(Configuration)\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd</MicrosoftManagementConfigurationPath> + <MicrosoftManagementConfigurationPath Condition="!Exists('$(MicrosoftManagementConfigurationPath)')">$(SolutionDir)arm64\$(Configuration)\Microsoft.Management.Configuration\Microsoft.Management.Configuration.winmd</MicrosoftManagementConfigurationPath> + </PropertyGroup> + <Message Importance="normal" Text="Microsoft.Management.Configuration.winmd -> $(MicrosoftManagementConfigurationPath)" /> + <Error Condition="!Exists('$(MicrosoftManagementConfigurationPath)')" Text="Microsoft.Management.Configuration.winmd was not found" /> <ItemGroup Condition="Exists('$(MicrosoftManagementConfigurationPath)')"> <CsWinRTAuthoringWinMDs Include="$(MicrosoftManagementConfigurationPath)" /> </ItemGroup> diff --git a/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/HostedEnvironment.cs b/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/HostedEnvironment.cs @@ -30,7 +30,7 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces /// </summary> internal class HostedEnvironment : IProcessorEnvironment { - private readonly ConfigurationProcessorType type; + private readonly PowerShellConfigurationProcessorType type; /// <summary> /// Initializes a new instance of the <see cref="HostedEnvironment"/> class. @@ -38,7 +38,7 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces /// <param name="runspace">PowerShell Runspace.</param> /// <param name="type">Configuration processor type.</param> /// <param name="dscModule">IDscModule.</param> - public HostedEnvironment(Runspace runspace, ConfigurationProcessorType type, IDscModule dscModule) + public HostedEnvironment(Runspace runspace, PowerShellConfigurationProcessorType type, IDscModule dscModule) { this.Runspace = runspace; this.type = type; @@ -56,7 +56,7 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces /// <summary> /// Gets or initializes the set processor factory. /// </summary> - internal ConfigurationSetProcessorFactory? SetProcessorFactory { get; init; } + internal PowerShellConfigurationSetProcessorFactory? SetProcessorFactory { get; init; } /// <inheritdoc/> public void ValidateRunspace() @@ -261,6 +261,73 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces } /// <inheritdoc/> + public PSObject? FindModule(ConfigurationUnitInternal unitInternal) + { + // Don't use ModuleSpecification here. Each parameter is independent and + // we need version even if a module was not specified. + string? moduleName = unitInternal.GetDirective<string>(DirectiveConstants.Module); + + if (string.IsNullOrEmpty(moduleName)) + { + return null; + } + + var semanticVersion = unitInternal.GetSemanticVersion(); + var semanticMinVersion = unitInternal.GetSemanticMinVersion(); + var semanticMaxVersion = unitInternal.GetSemanticMaxVersion(); + string? repository = unitInternal.GetDirective<string>(DirectiveConstants.Repository); + + bool? allowPrerelease = unitInternal.GetDirective(DirectiveConstants.AllowPrerelease); + bool implicitAllowPrerelease = false; + + var parameters = new Dictionary<string, object>() + { + { Parameters.Name, moduleName }, + }; + + if (semanticVersion != null) + { + implicitAllowPrerelease |= semanticVersion.IsPrerelease; + parameters.Add(Parameters.RequiredVersion, semanticVersion.ToString()); + } + + if (semanticMinVersion != null) + { + implicitAllowPrerelease |= semanticMinVersion.IsPrerelease; + parameters.Add(Parameters.MinimumVersion, semanticMinVersion.ToString()); + } + + if (semanticMaxVersion != null) + { + implicitAllowPrerelease |= semanticMaxVersion.IsPrerelease; + parameters.Add(Parameters.MaximumVersion, semanticMaxVersion.ToString()); + } + + if (!string.IsNullOrEmpty(repository)) + { + parameters.Add(Parameters.Repository, repository); + } + + if (allowPrerelease.HasValue || implicitAllowPrerelease) + { + // If explicit allowPrerelease = false don't use implicit. + bool allow = allowPrerelease.HasValue ? allowPrerelease.Value : implicitAllowPrerelease; + parameters.Add(Parameters.AllowPrerelease, allow); + } + + using PowerShell pwsh = PowerShell.Create(this.Runspace); + + pwsh.AddCommand(Commands.FindModule) + .AddParameters(parameters); + + var result = pwsh.Invoke() + .FirstOrDefault(); + + this.OnDiagnostics(DiagnosticLevel.Verbose, pwsh); + return result; + } + + /// <inheritdoc/> public PSObject? FindDscResource(ConfigurationUnitInternal unitInternal) { var parameters = new Dictionary<string, object>() diff --git a/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/IProcessorEnvironment.cs b/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/IProcessorEnvironment.cs @@ -117,6 +117,13 @@ namespace Microsoft.Management.Configuration.Processor.ProcessorEnvironments PSObject? GetInstalledModule(ModuleSpecification moduleSpecification); /// <summary> + /// Calls Find-Module. + /// </summary> + /// <param name="unitInternal">Configuration unit internal.</param> + /// <returns>Module info, null if not found.</returns> + PSObject? FindModule(ConfigurationUnitInternal unitInternal); + + /// <summary> /// Calls Find-DscResource. /// </summary> /// <param name="unitInternal">Configuration unit internal.</param> diff --git a/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/ProcessorEnvironmentFactory.cs b/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/ProcessorEnvironmentFactory.cs @@ -19,13 +19,13 @@ namespace Microsoft.Management.Configuration.Processor.ProcessorEnvironments /// </summary> internal class ProcessorEnvironmentFactory { - private readonly ConfigurationProcessorType type; + private readonly PowerShellConfigurationProcessorType type; /// <summary> /// Initializes a new instance of the <see cref="ProcessorEnvironmentFactory"/> class. /// </summary> /// <param name="type">Configuration processor type.</param> - public ProcessorEnvironmentFactory(ConfigurationProcessorType type) + public ProcessorEnvironmentFactory(PowerShellConfigurationProcessorType type) { this.type = type; } @@ -37,8 +37,8 @@ namespace Microsoft.Management.Configuration.Processor.ProcessorEnvironments /// <param name="policy">Configuration processor policy.</param> /// <returns>IProcessorEnvironment.</returns> public IProcessorEnvironment CreateEnvironment( - ConfigurationSetProcessorFactory? setProcessorFactory, - ConfigurationProcessorPolicy policy) + PowerShellConfigurationSetProcessorFactory? setProcessorFactory, + PowerShellConfigurationProcessorPolicy policy) { IDscModule dscModule = new DscModuleV2(); ExecutionPolicy executionPolicy = this.GetExecutionPolicy(policy); @@ -58,8 +58,8 @@ namespace Microsoft.Management.Configuration.Processor.ProcessorEnvironments // just makes sense before the ConfigurationSetProcessor gets created. We could add a new IConfigurationSetProcessorProperties // Then in PowerShell it can be something like // Get-WinGetConfiguration | Add-WinGetConfigurationVariable -Name foo | Start-WinGetConfiguration - if (this.type == ConfigurationProcessorType.Hosted || - this.type == ConfigurationProcessorType.Default) + if (this.type == PowerShellConfigurationProcessorType.Hosted || + this.type == PowerShellConfigurationProcessorType.Default) { var initialSessionState = this.CreateInitialSessionState( executionPolicy, @@ -93,15 +93,15 @@ namespace Microsoft.Management.Configuration.Processor.ProcessorEnvironments return initialSessionState; } - private ExecutionPolicy GetExecutionPolicy(ConfigurationProcessorPolicy policy) + private ExecutionPolicy GetExecutionPolicy(PowerShellConfigurationProcessorPolicy policy) { return policy switch { - ConfigurationProcessorPolicy.Unrestricted => ExecutionPolicy.Unrestricted, - ConfigurationProcessorPolicy.RemoteSigned => ExecutionPolicy.RemoteSigned, - ConfigurationProcessorPolicy.AllSigned => ExecutionPolicy.AllSigned, - ConfigurationProcessorPolicy.Restricted => ExecutionPolicy.Restricted, - ConfigurationProcessorPolicy.Bypass => ExecutionPolicy.Bypass, + PowerShellConfigurationProcessorPolicy.Unrestricted => ExecutionPolicy.Unrestricted, + PowerShellConfigurationProcessorPolicy.RemoteSigned => ExecutionPolicy.RemoteSigned, + PowerShellConfigurationProcessorPolicy.AllSigned => ExecutionPolicy.AllSigned, + PowerShellConfigurationProcessorPolicy.Restricted => ExecutionPolicy.Restricted, + PowerShellConfigurationProcessorPolicy.Bypass => ExecutionPolicy.Bypass, _ => throw new InvalidOperationException(), }; } diff --git a/src/Microsoft.Management.Configuration.Processor/Public/ConfigurationProcessorFactoryProperties.cs b/src/Microsoft.Management.Configuration.Processor/Public/ConfigurationProcessorFactoryProperties.cs @@ -1,29 +0,0 @@ -// ----------------------------------------------------------------------------- -// <copyright file="ConfigurationProcessorFactoryProperties.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------------- - -namespace Microsoft.Management.Configuration.Processor -{ - using System.Collections.Generic; - - /// <summary> - /// Implementation of <see cref="IConfigurationProcessorFactoryProperties"/>. - /// </summary> - public sealed class ConfigurationProcessorFactoryProperties : IConfigurationProcessorFactoryProperties - { - /// <summary> - /// Initializes a new instance of the <see cref="ConfigurationProcessorFactoryProperties"/> class. - /// </summary> - public ConfigurationProcessorFactoryProperties() - { - } - - /// <inheritdoc/> - public IReadOnlyList<string>? AdditionalModulePaths { get; set; } - - /// <inheritdoc/> - public ConfigurationProcessorPolicy Policy { get; set; } = ConfigurationProcessorPolicy.Default; - } -} diff --git a/src/Microsoft.Management.Configuration.Processor/Public/ConfigurationProcessorPolicy.cs b/src/Microsoft.Management.Configuration.Processor/Public/ConfigurationProcessorPolicy.cs @@ -1,51 +0,0 @@ -// ----------------------------------------------------------------------------- -// <copyright file="ConfigurationProcessorPolicy.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------------- - -namespace Microsoft.Management.Configuration.Processor -{ - /// <summary> - /// Processor policy. - /// For Processor type Default and Hosted they mean the same as PowerShell ExecutionPolicy. - /// https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies. - /// </summary> - public enum ConfigurationProcessorPolicy - { - /// <summary> - /// Unrestricted. - /// </summary> - Unrestricted = 0, - - /// <summary> - /// RemoteSigned. - /// </summary> - RemoteSigned = 1, - - /// <summary> - /// AllSigned. - /// </summary> - AllSigned = 2, - - /// <summary> - /// Restricted. - /// </summary> - Restricted = 3, - - /// <summary> - /// Bypass. - /// </summary> - Bypass = 4, - - /// <summary> - /// Undefined. - /// </summary> - Undefined = 5, - - /// <summary> - /// Default. - /// </summary> - Default = Restricted, - } -} diff --git a/src/Microsoft.Management.Configuration.Processor/Public/ConfigurationProcessorType.cs b/src/Microsoft.Management.Configuration.Processor/Public/ConfigurationProcessorType.cs @@ -1,24 +0,0 @@ -// ----------------------------------------------------------------------------- -// <copyright file="ConfigurationProcessorType.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------------- - -namespace Microsoft.Management.Configuration.Processor -{ - /// <summary> - /// Configuration processor runspace type. - /// </summary> - public enum ConfigurationProcessorType - { - /// <summary> - /// Uses default runspace. Requires to be running in PowerShell. Uses current runspace. - /// </summary> - Default, - - /// <summary> - /// Creates a new runspace in a hosted environment. - /// </summary> - Hosted, - } -} diff --git a/src/Microsoft.Management.Configuration.Processor/Public/ConfigurationSetProcessorFactory.cs b/src/Microsoft.Management.Configuration.Processor/Public/ConfigurationSetProcessorFactory.cs @@ -1,150 +0,0 @@ -// ----------------------------------------------------------------------------- -// <copyright file="ConfigurationSetProcessorFactory.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------------- - -namespace Microsoft.Management.Configuration.Processor -{ - using System; - using System.Management.Automation; - using System.Text; - using Microsoft.Management.Configuration; - using Microsoft.Management.Configuration.Processor.ProcessorEnvironments; - using Microsoft.Management.Configuration.Processor.Set; - using static Microsoft.Management.Configuration.Processor.Constants.PowerShellConstants; - - /// <summary> - /// ConfigurationSetProcessorFactory implementation. - /// </summary> - public sealed class ConfigurationSetProcessorFactory : IConfigurationSetProcessorFactory - { - private readonly ConfigurationProcessorType type; - private readonly IConfigurationProcessorFactoryProperties? properties; - - /// <summary> - /// Initializes a new instance of the <see cref="ConfigurationSetProcessorFactory"/> class. - /// </summary> - /// <param name="type">Type.</param> - /// <param name="properties">Properties.</param> - public ConfigurationSetProcessorFactory(ConfigurationProcessorType type, IConfigurationProcessorFactoryProperties? properties) - { - this.type = type; - this.properties = properties; - } - - /// <summary> - /// Diagnostics event; useful for logging and/or verbose output. - /// </summary> - public event EventHandler<DiagnosticInformation>? Diagnostics; - - /// <summary> - /// Gets or sets the minimum diagnostic level to send. - /// </summary> - public DiagnosticLevel MinimumLevel { get; set; } = DiagnosticLevel.Informational; - - /// <summary> - /// Gets the configuration unit processor details for the given unit. - /// </summary> - /// <param name="set">Configuration Set.</param> - /// <returns>Configuration set processor.</returns> - public IConfigurationSetProcessor CreateSetProcessor(ConfigurationSet set) - { - try - { - this.OnDiagnostics(DiagnosticLevel.Verbose, $"Creating set processor for `{set.Name}`..."); - - var envFactory = new ProcessorEnvironmentFactory(this.type); - var processorEnvironment = envFactory.CreateEnvironment( - this, - this.properties?.Policy ?? ConfigurationProcessorPolicy.RemoteSigned); - - if (this.properties is not null) - { - var additionalPsModulePaths = this.properties.AdditionalModulePaths; - if (additionalPsModulePaths is not null) - { - processorEnvironment.PrependPSModulePaths(additionalPsModulePaths); - } - } - - this.OnDiagnostics(DiagnosticLevel.Verbose, $" Effective module path:\n{processorEnvironment.GetVariable<string>(Variables.PSModulePath)}"); - - processorEnvironment.ValidateRunspace(); - - this.OnDiagnostics(DiagnosticLevel.Verbose, "... done creating set processor."); - - return new ConfigurationSetProcessor(processorEnvironment, set) { SetProcessorFactory = this }; - } - catch (Exception ex) - { - this.OnDiagnostics(DiagnosticLevel.Error, ex.ToString()); - throw; - } - } - - /// <summary> - /// Sends diagnostics if appropriate. - /// </summary> - /// <param name="level">The level of this diagnostic message.</param> - /// <param name="message">The diagnostic message.</param> - internal void OnDiagnostics(DiagnosticLevel level, string message) - { - EventHandler<DiagnosticInformation>? diagnostics = this.Diagnostics; - if (diagnostics != null && level >= this.MinimumLevel) - { - this.InvokeDiagnostics(diagnostics, level, message); - } - } - - /// <summary> - /// Sends diagnostic if appropriate for PowerShell streams. - /// </summary> - /// <param name="level">The level of this diagnostic message.</param> - /// <param name="pwsh">The PowerShell object.</param> - internal void OnDiagnostics(DiagnosticLevel level, PowerShell pwsh) - { - EventHandler<DiagnosticInformation>? diagnostics = this.Diagnostics; - if (diagnostics != null && level >= this.MinimumLevel && pwsh.HadErrors) - { - var builder = new StringBuilder(); - - // There are the last commands ran by that PowerShell obj, not all in our session. - builder.Append("PowerShellCommands: "); - foreach (var c in pwsh.Commands.Commands) - { - builder.Append($"['{c.CommandText}'"); - if (c.Parameters.Count > 0) - { - builder.Append(" Parameters: "); - foreach (var p in c.Parameters) - { - builder.Append($"{p.Name} = '{p.Value}' "); - } - - builder.Append("]"); - } - - builder.AppendLine(); - } - - foreach (var error in pwsh.Streams.Error) - { - builder.AppendLine($"[WriteError] {error}"); - } - - this.InvokeDiagnostics(diagnostics, level, builder.ToString()); - } - } - - private void InvokeDiagnostics(EventHandler<DiagnosticInformation> diagnostics, DiagnosticLevel level, string message) - { - DiagnosticInformation information = new () - { - Level = level, - Message = message, - }; - diagnostics.Invoke(this, information); - } - } -}- \ No newline at end of file diff --git a/src/Microsoft.Management.Configuration.Processor/Public/IConfigurationProcessorFactoryProperties.cs b/src/Microsoft.Management.Configuration.Processor/Public/IConfigurationProcessorFactoryProperties.cs @@ -1,26 +0,0 @@ -// ----------------------------------------------------------------------------- -// <copyright file="IConfigurationProcessorFactoryProperties.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------------- - -namespace Microsoft.Management.Configuration.Processor -{ - using System.Collections.Generic; - - /// <summary> - /// Properties for the configuration processor factory. - /// </summary> - public interface IConfigurationProcessorFactoryProperties - { - /// <summary> - /// Gets or sets the additional module paths. - /// </summary> - IReadOnlyList<string>? AdditionalModulePaths { get; set; } - - /// <summary> - /// Gets or sets the configuration policy. - /// </summary> - ConfigurationProcessorPolicy Policy { get; set; } - } -} diff --git a/src/Microsoft.Management.Configuration.Processor/Public/IPowerShellConfigurationProcessorFactoryProperties.cs b/src/Microsoft.Management.Configuration.Processor/Public/IPowerShellConfigurationProcessorFactoryProperties.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------------- +// <copyright file="IPowerShellConfigurationProcessorFactoryProperties.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor +{ + using System.Collections.Generic; + using System.Runtime.InteropServices; + + /// <summary> + /// Properties for the configuration processor factory. + /// </summary> + public interface IPowerShellConfigurationProcessorFactoryProperties + { + /// <summary> + /// Gets or sets the processor type. + /// </summary> + PowerShellConfigurationProcessorType ProcessorType { get; set; } + + /// <summary> + /// Gets or sets the additional module paths. + /// </summary> + IReadOnlyList<string>? AdditionalModulePaths { get; set; } + + /// <summary> + /// Gets or sets the configuration policy. + /// </summary> + PowerShellConfigurationProcessorPolicy Policy { get; set; } + } +} diff --git a/src/Microsoft.Management.Configuration.Processor/Public/PowerShellConfigurationProcessorPolicy.cs b/src/Microsoft.Management.Configuration.Processor/Public/PowerShellConfigurationProcessorPolicy.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------------- +// <copyright file="PowerShellConfigurationProcessorPolicy.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor +{ + /// <summary> + /// Processor policy. + /// For Processor type Default and Hosted they mean the same as PowerShell ExecutionPolicy. + /// https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies. + /// </summary> + public enum PowerShellConfigurationProcessorPolicy + { + /// <summary> + /// Unrestricted. + /// </summary> + Unrestricted = 0, + + /// <summary> + /// RemoteSigned. + /// </summary> + RemoteSigned = 1, + + /// <summary> + /// AllSigned. + /// </summary> + AllSigned = 2, + + /// <summary> + /// Restricted. + /// </summary> + Restricted = 3, + + /// <summary> + /// Bypass. + /// </summary> + Bypass = 4, + + /// <summary> + /// Undefined. + /// </summary> + Undefined = 5, + + /// <summary> + /// Default. + /// </summary> + Default = RemoteSigned, + } +} diff --git a/src/Microsoft.Management.Configuration.Processor/Public/PowerShellConfigurationProcessorType.cs b/src/Microsoft.Management.Configuration.Processor/Public/PowerShellConfigurationProcessorType.cs @@ -0,0 +1,24 @@ +// ----------------------------------------------------------------------------- +// <copyright file="PowerShellConfigurationProcessorType.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor +{ + /// <summary> + /// Configuration processor runspace type. + /// </summary> + public enum PowerShellConfigurationProcessorType + { + /// <summary> + /// Uses default runspace. Requires to be running in PowerShell. Uses current runspace. + /// </summary> + Default, + + /// <summary> + /// Creates a new runspace in a hosted environment. + /// </summary> + Hosted, + } +} diff --git a/src/Microsoft.Management.Configuration.Processor/Public/PowerShellConfigurationSetProcessorFactory.cs b/src/Microsoft.Management.Configuration.Processor/Public/PowerShellConfigurationSetProcessorFactory.cs @@ -0,0 +1,155 @@ +// ----------------------------------------------------------------------------- +// <copyright file="PowerShellConfigurationSetProcessorFactory.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor +{ + using System; + using System.Collections.Generic; + using System.Management.Automation; + using System.Text; + using Microsoft.Management.Configuration; + using Microsoft.Management.Configuration.Processor.ProcessorEnvironments; + using Microsoft.Management.Configuration.Processor.Set; + using static Microsoft.Management.Configuration.Processor.Constants.PowerShellConstants; + + /// <summary> + /// ConfigurationSetProcessorFactory implementation. + /// </summary> + public sealed class PowerShellConfigurationSetProcessorFactory : IConfigurationSetProcessorFactory, IPowerShellConfigurationProcessorFactoryProperties + { + /// <summary> + /// Initializes a new instance of the <see cref="PowerShellConfigurationSetProcessorFactory"/> class. + /// </summary> + public PowerShellConfigurationSetProcessorFactory() + { + } + + /// <summary> + /// Diagnostics event; useful for logging and/or verbose output. + /// </summary> + public event EventHandler<IDiagnosticInformation>? Diagnostics; + + /// <summary> + /// Gets or sets the minimum diagnostic level to send. + /// </summary> + public DiagnosticLevel MinimumLevel { get; set; } = DiagnosticLevel.Informational; + + /// <summary> + /// Gets or sets the processor type. + /// </summary> + public PowerShellConfigurationProcessorType ProcessorType { get; set; } = PowerShellConfigurationProcessorType.Default; + + /// <summary> + /// Gets or sets the additional module paths. + /// </summary> + public IReadOnlyList<string>? AdditionalModulePaths { get; set; } + + /// <summary> + /// Gets or sets the configuration policy. + /// </summary> + public PowerShellConfigurationProcessorPolicy Policy { get; set; } = PowerShellConfigurationProcessorPolicy.Default; + + /// <summary> + /// Gets the configuration unit processor details for the given unit. + /// </summary> + /// <param name="set">Configuration Set.</param> + /// <returns>Configuration set processor.</returns> + public IConfigurationSetProcessor CreateSetProcessor(ConfigurationSet set) + { + try + { + this.OnDiagnostics(DiagnosticLevel.Verbose, $"Creating set processor for `{set.Name}`..."); + + var envFactory = new ProcessorEnvironmentFactory(this.ProcessorType); + var processorEnvironment = envFactory.CreateEnvironment( + this, + this.Policy); + + if (this.AdditionalModulePaths is not null) + { + processorEnvironment.PrependPSModulePaths(this.AdditionalModulePaths); + } + + this.OnDiagnostics(DiagnosticLevel.Verbose, $" Effective module path:\n{processorEnvironment.GetVariable<string>(Variables.PSModulePath)}"); + + processorEnvironment.ValidateRunspace(); + + this.OnDiagnostics(DiagnosticLevel.Verbose, "... done creating set processor."); + + return new ConfigurationSetProcessor(processorEnvironment, set) { SetProcessorFactory = this }; + } + catch (Exception ex) + { + this.OnDiagnostics(DiagnosticLevel.Error, ex.ToString()); + throw; + } + } + + /// <summary> + /// Sends diagnostics if appropriate. + /// </summary> + /// <param name="level">The level of this diagnostic message.</param> + /// <param name="message">The diagnostic message.</param> + internal void OnDiagnostics(DiagnosticLevel level, string message) + { + EventHandler<IDiagnosticInformation>? diagnostics = this.Diagnostics; + if (diagnostics != null && level >= this.MinimumLevel) + { + this.InvokeDiagnostics(diagnostics, level, message); + } + } + + /// <summary> + /// Sends diagnostic if appropriate for PowerShell streams. + /// </summary> + /// <param name="level">The level of this diagnostic message.</param> + /// <param name="pwsh">The PowerShell object.</param> + internal void OnDiagnostics(DiagnosticLevel level, PowerShell pwsh) + { + EventHandler<IDiagnosticInformation>? diagnostics = this.Diagnostics; + if (diagnostics != null && level >= this.MinimumLevel && pwsh.HadErrors) + { + var builder = new StringBuilder(); + + // There are the last commands ran by that PowerShell obj, not all in our session. + builder.Append("PowerShellCommands: "); + foreach (var c in pwsh.Commands.Commands) + { + builder.Append($"['{c.CommandText}'"); + if (c.Parameters.Count > 0) + { + builder.Append(" Parameters: "); + foreach (var p in c.Parameters) + { + builder.Append($"{p.Name} = '{p.Value}' "); + } + + builder.Append("]"); + } + + builder.AppendLine(); + } + + foreach (var error in pwsh.Streams.Error) + { + builder.AppendLine($"[WriteError] {error}"); + } + + this.InvokeDiagnostics(diagnostics, level, builder.ToString()); + } + } + + private void InvokeDiagnostics(EventHandler<IDiagnosticInformation> diagnostics, DiagnosticLevel level, string message) + { + Helpers.DiagnosticInformation information = new () + { + Level = level, + Message = message, + }; + diagnostics.Invoke(this, information); + } + } +}+ \ No newline at end of file diff --git a/src/Microsoft.Management.Configuration.Processor/Set/ConfigurationSetProcessor.cs b/src/Microsoft.Management.Configuration.Processor/Set/ConfigurationSetProcessor.cs @@ -10,6 +10,7 @@ namespace Microsoft.Management.Configuration.Processor.Set using System.Collections.Generic; using System.IO; using System.Management.Automation; + using Microsoft.Management.Configuration.Processor.Constants; using Microsoft.Management.Configuration.Processor.DscResourcesInfo; using Microsoft.Management.Configuration.Processor.Exceptions; using Microsoft.Management.Configuration.Processor.Helpers; @@ -38,7 +39,7 @@ namespace Microsoft.Management.Configuration.Processor.Set /// <summary> /// Gets or initializes the set processor factory. /// </summary> - internal ConfigurationSetProcessorFactory? SetProcessorFactory { get; init; } + internal PowerShellConfigurationSetProcessorFactory? SetProcessorFactory { get; init; } /// <summary> /// Gets the processor environment. @@ -94,7 +95,7 @@ namespace Microsoft.Management.Configuration.Processor.Set if (dscResourceInfo is not null) { return this.GetUnitProcessorDetailsLocal( - unit.UnitName, + dscResourceInfo.Name, dscResourceInfo, detailLevel == ConfigurationUnitDetailLevel.Load); } @@ -105,26 +106,25 @@ namespace Microsoft.Management.Configuration.Processor.Set return null; } - var getFindResource = this.ProcessorEnvironment.FindDscResource(unitInternal); - if (getFindResource is null) + var unitModuleInfo = this.FindUnitModule(unitInternal); + if (unitModuleInfo is null) { // Not found in catalog. return null; } - // Hopefully they will never change the properties name. If someone can explain to me - // why assign it Name to $_ in Find-DscResource turns into a string in PowerShell but - // into a PSObject here that would be nice... - dynamic findResource = getFindResource; - string findResourceName = findResource.Name.ToString(); + PSObject foundModule = unitModuleInfo.Value.Module; + string resourceName = unitModuleInfo.Value.ResourceName; + + dynamic foundModuleInfo = foundModule; if (detailLevel == ConfigurationUnitDetailLevel.Catalog) { return new ConfigurationUnitProcessorDetails( - findResourceName, + resourceName, null, null, - findResource.PSGetModuleInfo, + foundModule, null); } @@ -132,22 +132,22 @@ namespace Microsoft.Management.Configuration.Processor.Set { var tempSavePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempSavePath); - this.ProcessorEnvironment.SaveModule(getFindResource, tempSavePath); + this.ProcessorEnvironment.SaveModule(foundModule, tempSavePath); var moduleInfo = this.ProcessorEnvironment.GetAvailableModule( - Path.Combine(tempSavePath, findResource.PSGetModuleInfo.Name)); + Path.Combine(tempSavePath, foundModuleInfo.Name)); return new ConfigurationUnitProcessorDetails( - findResourceName, + resourceName, null, moduleInfo, - findResource.PSGetModuleInfo, + foundModule, this.GetCertificates(moduleInfo)); } if (detailLevel == ConfigurationUnitDetailLevel.Load) { - this.ProcessorEnvironment.InstallModule(getFindResource); + this.ProcessorEnvironment.InstallModule(foundModule); dscResourceInfo = this.ProcessorEnvironment.GetDscResource(unitInternal); @@ -156,10 +156,10 @@ namespace Microsoft.Management.Configuration.Processor.Set // Well, this is awkward. throw new InstallDscResourceException( unit.UnitName, - PowerShellHelpers.CreateModuleSpecification(findResource.ModuleName, findResource.Version)); + PowerShellHelpers.CreateModuleSpecification(foundModuleInfo.Name, foundModuleInfo.Version)); } - return this.GetUnitProcessorDetailsLocal(unit.UnitName, dscResourceInfo, true); + return this.GetUnitProcessorDetailsLocal(dscResourceInfo.Name, dscResourceInfo, true); } return null; @@ -171,6 +171,48 @@ namespace Microsoft.Management.Configuration.Processor.Set } } + /// <summary> + /// Finds the module and preferred resource name for processing the configuration unit. + /// </summary> + /// <param name="unitInternal">The internal configuration unit.</param> + /// <returns>A tuple containing the module info and preferred resource name, or null if not found.</returns> + private (PSObject Module, string ResourceName)? FindUnitModule(ConfigurationUnitInternal unitInternal) + { + PSObject? foundModule = null; + string resourceName = string.Empty; + + // If module has been specified, find it and assume that the resource will be within it. + // Do this first as we do not currently gain much from FindDscResource; if that changes then it can be the primary. + if (unitInternal.Module != null) + { + foundModule = this.ProcessorEnvironment.FindModule(unitInternal); + if (foundModule != null) + { + resourceName = unitInternal.Unit.UnitName; + } + } + else + { + dynamic? foundResource = this.ProcessorEnvironment.FindDscResource(unitInternal); + if (foundResource != null) + { + foundModule = foundResource.PSGetModuleInfo; + + // Hopefully they will never change the properties name. If someone can explain to me + // why assign it Name to $_ in Find-DscResource turns into a string in PowerShell but + // into a PSObject here that would be nice... + resourceName = foundResource.Name.ToString(); + } + } + + if (foundModule != null) + { + return (foundModule, resourceName); + } + + return null; + } + private DscResourceInfoInternal PrepareUnitForProcessing(ConfigurationUnitInternal unitInternal) { // Invoke-DscResource makes a call to Get-DscResource which looks at the entire PSModulePath @@ -185,14 +227,14 @@ namespace Microsoft.Management.Configuration.Processor.Set if (dscResourceInfo is null) { - var findDscResourceResult = this.ProcessorEnvironment.FindDscResource(unitInternal); + var findUnitModuleResult = this.FindUnitModule(unitInternal); - if (findDscResourceResult is null) + if (findUnitModuleResult is null) { throw new FindDscResourceNotFoundException(unitInternal.Unit.UnitName, unitInternal.Module); } - this.ProcessorEnvironment.InstallModule(findDscResourceResult); + this.ProcessorEnvironment.InstallModule(findUnitModuleResult.Value.Module); // Now we should find it. dscResourceInfo = this.ProcessorEnvironment.GetDscResource(unitInternal); diff --git a/src/Microsoft.Management.Configuration.Processor/Unit/ApplySettingsResult.cs b/src/Microsoft.Management.Configuration.Processor/Unit/ApplySettingsResult.cs @@ -0,0 +1,30 @@ +// ----------------------------------------------------------------------------- +// <copyright file="ApplySettingsResult.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor.Unit +{ + using Microsoft.Management.Configuration; + + /// <summary> + /// Implements IApplySettingsResult. + /// </summary> + internal sealed class ApplySettingsResult : IApplySettingsResult + { + /// <inheritdoc/> + public IConfigurationUnitResultInformation ResultInformation + { + get { return this.InternalResult; } + } + + /// <summary> + /// Gets the implementation object for ResultInformation. + /// </summary> + public ConfigurationUnitResultInformation InternalResult { get; } = new ConfigurationUnitResultInformation(); + + /// <inheritdoc/> + public bool RebootRequired { get; internal set; } + } +} diff --git a/src/Microsoft.Management.Configuration.Processor/Unit/ConfigurationUnitProcessor.cs b/src/Microsoft.Management.Configuration.Processor/Unit/ConfigurationUnitProcessor.cs @@ -48,14 +48,14 @@ namespace Microsoft.Management.Configuration.Processor.Unit /// <summary> /// Gets or initializes the set processor factory. /// </summary> - internal ConfigurationSetProcessorFactory? SetProcessorFactory { get; init; } + internal PowerShellConfigurationSetProcessorFactory? SetProcessorFactory { get; init; } /// <summary> /// Gets the current system state for the configuration unit. /// Calls Get on the DSC resource. /// </summary> - /// <returns>A <see cref="GetSettingsResult"/>.</returns> - public GetSettingsResult GetSettings() + /// <returns>A <see cref="IGetSettingsResult"/>.</returns> + public IGetSettingsResult GetSettings() { this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `Get` for resource: {this.unitResource.UnitInternal.ToIdentifyingString()}..."); @@ -70,7 +70,7 @@ namespace Microsoft.Management.Configuration.Processor.Unit } catch (Exception e) { - this.ExtractExceptionInformation(e, result.ResultInformation); + this.ExtractExceptionInformation(e, result.InternalResult); } this.OnDiagnostics(DiagnosticLevel.Verbose, $"... done invoking `Get`."); @@ -81,8 +81,8 @@ namespace Microsoft.Management.Configuration.Processor.Unit /// Determines if the system is already in the state described by the configuration unit. /// Calls Test on the DSC resource. /// </summary> - /// <returns>A <see cref="TestSettingsResult"/>.</returns> - public TestSettingsResult TestSettings() + /// <returns>A <see cref="ITestSettingsResult"/>.</returns> + public ITestSettingsResult TestSettings() { this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `Test` for resource: {this.unitResource.UnitInternal.ToIdentifyingString()}..."); @@ -105,7 +105,7 @@ namespace Microsoft.Management.Configuration.Processor.Unit } catch (Exception e) { - this.ExtractExceptionInformation(e, result.ResultInformation); + this.ExtractExceptionInformation(e, result.InternalResult); } this.OnDiagnostics(DiagnosticLevel.Verbose, $"... done invoking `Test`."); @@ -116,8 +116,8 @@ namespace Microsoft.Management.Configuration.Processor.Unit /// Applies the state described in the configuration unit. /// Calls Set in the DSC resource. /// </summary> - /// <returns>A <see cref="ApplySettingsResult"/>.</returns> - public ApplySettingsResult ApplySettings() + /// <returns>A <see cref="IApplySettingsResult"/>.</returns> + public IApplySettingsResult ApplySettings() { this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `Apply` for resource: {this.unitResource.UnitInternal.ToIdentifyingString()}..."); @@ -138,7 +138,7 @@ namespace Microsoft.Management.Configuration.Processor.Unit } catch (Exception e) { - this.ExtractExceptionInformation(e, result.ResultInformation); + this.ExtractExceptionInformation(e, result.InternalResult); } this.OnDiagnostics(DiagnosticLevel.Verbose, $"... done invoking `Apply`."); diff --git a/src/Microsoft.Management.Configuration.Processor/Unit/ConfigurationUnitProcessorDetails.cs b/src/Microsoft.Management.Configuration.Processor/Unit/ConfigurationUnitProcessorDetails.cs @@ -246,7 +246,18 @@ namespace Microsoft.Management.Configuration.Processor.Unit var moduleProperty = getModuleInfo.Properties[getModuleInfoProperty]; if (moduleProperty is not null) { - propertyInfo.SetValue(this, new DateTimeOffset((DateTime)moduleProperty.Value)); + DateTime propertyAsDateTime; + + try + { + propertyAsDateTime = (DateTime)moduleProperty.Value; + } + catch + { + return; + } + + propertyInfo.SetValue(this, new DateTimeOffset(propertyAsDateTime)); } } } diff --git a/src/Microsoft.Management.Configuration.Processor/Unit/ConfigurationUnitResultInformation.cs b/src/Microsoft.Management.Configuration.Processor/Unit/ConfigurationUnitResultInformation.cs @@ -0,0 +1,29 @@ +// ----------------------------------------------------------------------------- +// <copyright file="ConfigurationUnitResultInformation.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor.Unit +{ + using System; + using Microsoft.Management.Configuration; + + /// <summary> + /// Implements IConfigurationUnitResultInformation. + /// </summary> + internal sealed class ConfigurationUnitResultInformation : IConfigurationUnitResultInformation + { + /// <inheritdoc/> + public string? Description { get; internal set; } + + /// <inheritdoc/> + public string? Details { get; internal set; } + + /// <inheritdoc/> + public Exception? ResultCode { get; internal set; } + + /// <inheritdoc/> + public ConfigurationUnitResultSource ResultSource { get; internal set; } = ConfigurationUnitResultSource.None; + } +} diff --git a/src/Microsoft.Management.Configuration.Processor/Unit/GetSettingsResult.cs b/src/Microsoft.Management.Configuration.Processor/Unit/GetSettingsResult.cs @@ -0,0 +1,31 @@ +// ----------------------------------------------------------------------------- +// <copyright file="GetSettingsResult.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor.Unit +{ + using Microsoft.Management.Configuration; + using Windows.Foundation.Collections; + + /// <summary> + /// Implements IGetSettingsResult. + /// </summary> + internal sealed class GetSettingsResult : IGetSettingsResult + { + /// <inheritdoc/> + public IConfigurationUnitResultInformation ResultInformation + { + get { return this.InternalResult; } + } + + /// <summary> + /// Gets the implementation object for ResultInformation. + /// </summary> + public ConfigurationUnitResultInformation InternalResult { get; } = new ConfigurationUnitResultInformation(); + + /// <inheritdoc/> + public ValueSet? Settings { get; internal set; } + } +} diff --git a/src/Microsoft.Management.Configuration.Processor/Unit/TestSettingsResult.cs b/src/Microsoft.Management.Configuration.Processor/Unit/TestSettingsResult.cs @@ -0,0 +1,30 @@ +// ----------------------------------------------------------------------------- +// <copyright file="TestSettingsResult.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.Processor.Unit +{ + using Microsoft.Management.Configuration; + + /// <summary> + /// Implements ITestSettingsResult. + /// </summary> + internal sealed class TestSettingsResult : ITestSettingsResult + { + /// <inheritdoc/> + public IConfigurationUnitResultInformation ResultInformation + { + get { return this.InternalResult; } + } + + /// <summary> + /// Gets the implementation object for ResultInformation. + /// </summary> + public ConfigurationUnitResultInformation InternalResult { get; } = new ConfigurationUnitResultInformation(); + + /// <inheritdoc/> + public ConfigurationTestResult TestResult { get; internal set; } + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Fixtures/UnitTestFixture.cs b/src/Microsoft.Management.Configuration.UnitTests/Fixtures/UnitTestFixture.cs @@ -59,6 +59,8 @@ namespace Microsoft.Management.Configuration.UnitTests.Fixtures { throw new DirectoryNotFoundException(this.ExternalModulesPath); } + + this.ConfigurationStatics = new ConfigurationStaticFunctions(); } /// <summary> @@ -82,13 +84,18 @@ namespace Microsoft.Management.Configuration.UnitTests.Fixtures public string ExternalModulesPath { get; } /// <summary> + /// Gets the configuration statics object to use. + /// </summary> + public IConfigurationStatics ConfigurationStatics { get; private init; } + + /// <summary> /// Creates a runspace adding the test module path. /// </summary> /// <param name="validate">Validate runspace.</param> /// <returns>PowerShellRunspace.</returns> internal IProcessorEnvironment PrepareTestProcessorEnvironment(bool validate = false) { - var processorEnv = new ProcessorEnvironmentFactory(ConfigurationProcessorType.Hosted).CreateEnvironment(null, ConfigurationProcessorPolicy.Unrestricted); + var processorEnv = new ProcessorEnvironmentFactory(PowerShellConfigurationProcessorType.Hosted).CreateEnvironment(null, PowerShellConfigurationProcessorPolicy.Unrestricted); processorEnv.PrependPSModulePath(this.ExternalModulesPath); processorEnv.PrependPSModulePath(this.TestModulesPath); diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/ApplySettingsResultInstance.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/ApplySettingsResultInstance.cs @@ -0,0 +1,30 @@ +// ----------------------------------------------------------------------------- +// <copyright file="ApplySettingsResultInstance.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.UnitTests.Helpers +{ + using Microsoft.Management.Configuration; + + /// <summary> + /// Implements IApplySettingsResult. + /// </summary> + internal sealed class ApplySettingsResultInstance : IApplySettingsResult + { + /// <inheritdoc/> + public IConfigurationUnitResultInformation ResultInformation + { + get { return this.InternalResult; } + } + + /// <summary> + /// Gets the implementation object for ResultInformation. + /// </summary> + public TestConfigurationUnitResultInformation InternalResult { get; } = new TestConfigurationUnitResultInformation(); + + /// <inheritdoc/> + public bool RebootRequired { get; internal set; } + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/ConfigurationExtensions.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/ConfigurationExtensions.cs @@ -0,0 +1,36 @@ +// ----------------------------------------------------------------------------- +// <copyright file="ConfigurationExtensions.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.UnitTests.Helpers +{ + using System.Linq; + using System.Reflection; + + /// <summary> + /// Contains extension methods for configuration objects. + /// </summary> + internal static class ConfigurationExtensions + { + /// <summary> + /// Assigns the given properties to the configuration unit. + /// </summary> + /// <param name="unit">The unit to assign the properties of.</param> + /// <param name="properties">The properties to assign.</param> + /// <returns>The given ConfigurationUnit.</returns> + internal static ConfigurationUnit Assign(this ConfigurationUnit unit, object properties) + { + PropertyInfo[] unitProperties = typeof(ConfigurationUnit).GetProperties(); + + foreach (PropertyInfo property in properties.GetType().GetProperties()) + { + PropertyInfo matchingProperty = unitProperties.First(pi => pi.Name == property.Name); + matchingProperty.SetValue(unit, property.GetValue(properties)); + } + + return unit; + } + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/ConfigurationProcessorTestBase.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/ConfigurationProcessorTestBase.cs @@ -53,7 +53,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers /// <returns>The new <see cref="ConfigurationProcessor"/> object.</returns> protected ConfigurationProcessor CreateConfigurationProcessorWithDiagnostics(IConfigurationSetProcessorFactory? factory = null) { - ConfigurationProcessor result = new ConfigurationProcessor(factory); + ConfigurationProcessor result = this.Fixture.ConfigurationStatics.CreateConfigurationProcessor(factory); result.Diagnostics += this.EventSink.DiagnosticsHandler; result.MinimumLevel = DiagnosticLevel.Verbose; return result; @@ -81,6 +81,24 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers } /// <summary> + /// Creates a configuration unit via the configuration statics object. + /// </summary> + /// <returns>A new configuration unit.</returns> + protected ConfigurationUnit ConfigurationUnit() + { + return this.Fixture.ConfigurationStatics.CreateConfigurationUnit(); + } + + /// <summary> + /// Creates a configuration set via the configuration statics object. + /// </summary> + /// <returns>A new configuration set.</returns> + protected ConfigurationSet ConfigurationSet() + { + return this.Fixture.ConfigurationStatics.CreateConfigurationSet(); + } + + /// <summary> /// Verifies the summary event generated by a processing run. /// </summary> /// <param name="configurationSet">The configuration set.</param> @@ -94,8 +112,10 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers int[] runs = new int[3]; int[] failures = new int[3]; - foreach (ApplyConfigurationUnitResult unitResult in setResult.UnitResults) + var unitResults = setResult.UnitResults; + for (int i = 0; i < unitResults.Count; ++i) { + ApplyConfigurationUnitResult unitResult = unitResults[i]; SummaryCountByIntent(counts, runs, failures, unitResult.Unit.Intent, unitResult.ResultInformation); } @@ -125,7 +145,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers VerifySummaryCounts(summary, counts, runs, failures); } - private static void SummaryCountByIntent(int[] counts, int[] runs, int[] failures, ConfigurationUnitIntent intent, ConfigurationUnitResultInformation resultInformation) + private static void SummaryCountByIntent(int[] counts, int[] runs, int[] failures, ConfigurationUnitIntent intent, IConfigurationUnitResultInformation resultInformation) { int index = (int)intent; diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/Constants.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/Constants.cs @@ -0,0 +1,24 @@ +// ----------------------------------------------------------------------------- +// <copyright file="Constants.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.UnitTests.Helpers +{ + /// <summary> + /// Constants used by the tests. + /// </summary> + public class Constants + { + /// <summary> + /// The assembly name value used by xUnit traits. + /// </summary> + public const string AssemblyNameForTraits = "Microsoft.Management.Configuration.UnitTests"; + + /// <summary> + /// The namespace where xUnit traits will be defined. + /// </summary> + public const string NamespaceNameForTraits = "Microsoft.Management.Configuration.UnitTests.Helpers"; + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/DiagnosticsEventSink.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/DiagnosticsEventSink.cs @@ -40,7 +40,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers /// </summary> /// <param name="sender">The object sending the information.</param> /// <param name="e">The diagnostic information.</param> - public void DiagnosticsHandler(object? sender, DiagnosticInformation e) + public void DiagnosticsHandler(object? sender, IDiagnosticInformation e) { if (e.Message.Contains(TelemetryEvent.Preamble)) { diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/GetSettingsResultInstance.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/GetSettingsResultInstance.cs @@ -0,0 +1,31 @@ +// ----------------------------------------------------------------------------- +// <copyright file="GetSettingsResultInstance.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.UnitTests.Helpers +{ + using Microsoft.Management.Configuration; + using Windows.Foundation.Collections; + + /// <summary> + /// Implements IGetSettingsResult. + /// </summary> + internal sealed class GetSettingsResultInstance : IGetSettingsResult + { + /// <inheritdoc/> + public IConfigurationUnitResultInformation ResultInformation + { + get { return this.InternalResult; } + } + + /// <summary> + /// Gets the implementation object for ResultInformation. + /// </summary> + public TestConfigurationUnitResultInformation InternalResult { get; } = new TestConfigurationUnitResultInformation(); + + /// <inheritdoc/> + public ValueSet? Settings { get; internal set; } + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/OutOfProcAttribute.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/OutOfProcAttribute.cs @@ -0,0 +1,33 @@ +// ----------------------------------------------------------------------------- +// <copyright file="OutOfProcAttribute.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.UnitTests.Helpers +{ + using System; + using Xunit.Sdk; + + /// <summary> + /// Trait used to mark a test as being able to run against the out of proc server. + /// </summary> + [TraitDiscoverer(OutOfProcDiscoverer.TypeName, Constants.AssemblyNameForTraits)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] + public class OutOfProcAttribute : Attribute, ITraitAttribute + { + /// <summary> + /// Initializes a new instance of the <see cref="OutOfProcAttribute"/> class. + /// </summary> + public OutOfProcAttribute() + { + // To run the tests OOP, you need to replace Microsoft.Management.Configuration.dll with Microsoft.Management.Configuration.OutOfProc.dll (renamed to remove the OutOfProc). + // You will also need to copy over Microsoft.Management.Configuration.winmd as it is needed by COM. + // It can be easier to run the tests on the command line because any changes needing a recompile will overwrite the DLL update above. + // The test runner is located somewhere like this: + // C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\TestPlatform + // and the command line from there is: + // .\vstest.console.exe "<location of your repo>\src\x64\Debug\Microsoft.Management.Configuration.UnitTests\net6.0-windows10.0.19041.0\Microsoft.Management.Configuration.UnitTests.dll" --TestCaseFilter:Category=OutOfProc + } + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/OutOfProcDiscoverer.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/OutOfProcDiscoverer.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------------- +// <copyright file="OutOfProcDiscoverer.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.UnitTests.Helpers +{ + using System.Collections.Generic; + using Xunit.Abstractions; + using Xunit.Sdk; + + /// <summary> + /// Enables integration with xUnit trait system. + /// </summary> + public class OutOfProcDiscoverer : ITraitDiscoverer + { + /// <summary> + /// The type name for this discoverer. + /// </summary> + public const string TypeName = Constants.NamespaceNameForTraits + ".OutOfProcDiscoverer"; + + /// <summary> + /// Initializes a new instance of the <see cref="OutOfProcDiscoverer"/> class. + /// </summary> + public OutOfProcDiscoverer() + { + } + + /// <summary> + /// Gets the trait information for the OutOfProcAttribute. + /// </summary> + /// <param name="traitAttribute">The trait information.</param> + /// <returns>Trait name/value pairs.</returns> + public IEnumerable<KeyValuePair<string, string>> GetTraits(IAttributeInfo traitAttribute) + { + yield return new KeyValuePair<string, string>("Category", "OutOfProc"); + } + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestConfigurationProcessorFactory.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestConfigurationProcessorFactory.cs @@ -26,7 +26,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers /// Diagnostics event; useful for logging and/or verbose output. /// </summary> #pragma warning disable CS0067 // The event is never used - public event EventHandler<DiagnosticInformation>? Diagnostics; + public event EventHandler<IDiagnosticInformation>? Diagnostics; #pragma warning restore CS0067 // The event is never used /// <summary> diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestConfigurationUnitProcessor.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestConfigurationUnitProcessor.cs @@ -38,19 +38,19 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers /// The delegate for ApplySettings. /// </summary> /// <returns>The result.</returns> - internal delegate ApplySettingsResult ApplySettingsDelegateType(); + internal delegate IApplySettingsResult ApplySettingsDelegateType(); /// <summary> /// The delegate for GetSettings. /// </summary> /// <returns>The result.</returns> - internal delegate GetSettingsResult GetSettingsDelegateType(); + internal delegate IGetSettingsResult GetSettingsDelegateType(); /// <summary> /// The delegate for TestSettings. /// </summary> /// <returns>The result.</returns> - internal delegate TestSettingsResult TestSettingsDelegateType(); + internal delegate ITestSettingsResult TestSettingsDelegateType(); /// <summary> /// Gets or sets the directives overlay. @@ -96,7 +96,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers /// Calls the ApplySettingsDelegate if one is provided; returns success if not. /// </summary> /// <returns>The result.</returns> - public ApplySettingsResult ApplySettings() + public IApplySettingsResult ApplySettings() { ++this.ApplySettingsCalls; if (this.ApplySettingsDelegate != null) @@ -105,7 +105,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers } else { - return new ApplySettingsResult(); + return new ApplySettingsResultInstance(); } } @@ -113,7 +113,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers /// Calls the GetSettingsDelegate if one is provided; returns success if not (with no settings values). /// </summary> /// <returns>The result.</returns> - public GetSettingsResult GetSettings() + public IGetSettingsResult GetSettings() { ++this.GetSettingsCalls; if (this.GetSettingsDelegate != null) @@ -122,7 +122,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers } else { - return new GetSettingsResult(); + return new GetSettingsResultInstance(); } } @@ -130,7 +130,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers /// Calls the TestSettingsDelegate if one is provided; returns success if not (with a positive test result). /// </summary> /// <returns>The result.</returns> - public TestSettingsResult TestSettings() + public ITestSettingsResult TestSettings() { ++this.TestSettingsCalls; if (this.TestSettingsDelegate != null) @@ -139,7 +139,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers } else { - return new TestSettingsResult { TestResult = ConfigurationTestResult.Positive }; + return new TestSettingsResultInstance { TestResult = ConfigurationTestResult.Positive }; } } } diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestConfigurationUnitResultInformation.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestConfigurationUnitResultInformation.cs @@ -0,0 +1,37 @@ +// ----------------------------------------------------------------------------- +// <copyright file="TestConfigurationUnitResultInformation.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.UnitTests.Helpers +{ + using System; + using System.Collections.Generic; + + /// <summary> + /// A test implementation of IConfigurationSetProcessorFactory. + /// </summary> + internal class TestConfigurationUnitResultInformation : IConfigurationUnitResultInformation + { + /// <summary> + /// Gets or sets the description. + /// </summary> + public string Description { get; set; } = string.Empty; + + /// <summary> + /// Gets or sets the details. + /// </summary> + public string Details { get; set; } = string.Empty; + + /// <summary> + /// Gets or sets the result code. + /// </summary> + public Exception? ResultCode { get; set; } + + /// <summary> + /// Gets or sets the result source. + /// </summary> + public ConfigurationUnitResultSource ResultSource { get; set; } = ConfigurationUnitResultSource.None; + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestSettingsResultInstance.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestSettingsResultInstance.cs @@ -0,0 +1,30 @@ +// ----------------------------------------------------------------------------- +// <copyright file="TestSettingsResultInstance.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.Management.Configuration.UnitTests.Helpers +{ + using Microsoft.Management.Configuration; + + /// <summary> + /// Implements ITestSettingsResult. + /// </summary> + internal sealed class TestSettingsResultInstance : ITestSettingsResult + { + /// <inheritdoc/> + public IConfigurationUnitResultInformation ResultInformation + { + get { return this.InternalResult; } + } + + /// <summary> + /// Gets the implementation object for ResultInformation. + /// </summary> + public TestConfigurationUnitResultInformation InternalResult { get; } = new TestConfigurationUnitResultInformation(); + + /// <inheritdoc/> + public ConfigurationTestResult TestResult { get; internal set; } + } +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationDetailsTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationDetailsTests.cs @@ -77,7 +77,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests } else { - var unit = this.CreteConfigurationUnit(); + var unit = this.CreateConfigurationUnit(); var (dscResourceInfo, psModuleInfo) = this.GetResourceAndModuleInfo(unit); DscResourceInfoInternal? dscResourceInfoInput = null; @@ -174,7 +174,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests } } - private ConfigurationUnit CreteConfigurationUnit() + private ConfigurationUnit CreateConfigurationUnit() { var unit = new ConfigurationUnit(); unit.UnitName = "SimpleFileResource"; diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationProcessorApplyTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationProcessorApplyTests.cs @@ -25,6 +25,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests /// Unit tests for running test on the processor. /// </summary> [Collection("UnitTestCollection")] + [OutOfProc] public class ConfigurationProcessorApplyTests : ConfigurationProcessorTestBase { /// <summary> @@ -43,7 +44,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_SetProcessorError() { - ConfigurationSet configurationSet = new ConfigurationSet(); + ConfigurationSet configurationSet = this.ConfigurationSet(); TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); factory.Exceptions.Add(configurationSet, new FileNotFoundException()); @@ -61,10 +62,10 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_DuplicateIdentifiers() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnit1 = new ConfigurationUnit(); - ConfigurationUnit configurationUnit2 = new ConfigurationUnit(); - ConfigurationUnit configurationUnitDifferentIdentifier = new ConfigurationUnit(); + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnit1 = this.ConfigurationUnit(); + ConfigurationUnit configurationUnit2 = this.ConfigurationUnit(); + ConfigurationUnit configurationUnitDifferentIdentifier = this.ConfigurationUnit(); string sharedIdentifier = "SameIdentifier"; configurationUnit1.Identifier = sharedIdentifier; configurationUnit2.Identifier = sharedIdentifier; @@ -82,7 +83,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests foreach (var configurationUnit in new ConfigurationUnit[] { configurationUnit1, configurationUnit2 }) { - ApplyConfigurationUnitResult unitResult = result.UnitResults.First(x => x.Unit == configurationUnit); + ApplyConfigurationUnitResult? unitResult = result.UnitResults.First(x => x.Unit == configurationUnit); Assert.NotNull(unitResult); Assert.False(unitResult.PreviouslyInDesiredState); Assert.False(unitResult.RebootRequired); @@ -109,9 +110,9 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_MissingDependency() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnit = new ConfigurationUnit(); - ConfigurationUnit configurationUnitMissingDependency = new ConfigurationUnit(); + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnit = this.ConfigurationUnit(); + ConfigurationUnit configurationUnitMissingDependency = this.ConfigurationUnit(); configurationUnit.Identifier = "Identifier"; configurationUnitMissingDependency.Dependencies = new string[] { "Dependency" }; configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnit, configurationUnitMissingDependency }; @@ -152,10 +153,10 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_DependencyCycle() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnit1 = new ConfigurationUnit(); - ConfigurationUnit configurationUnit2 = new ConfigurationUnit(); - ConfigurationUnit configurationUnit3 = new ConfigurationUnit(); + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnit1 = this.ConfigurationUnit(); + ConfigurationUnit configurationUnit2 = this.ConfigurationUnit(); + ConfigurationUnit configurationUnit3 = this.ConfigurationUnit(); configurationUnit1.Identifier = "Identifier1"; configurationUnit2.Identifier = "Identifier2"; configurationUnit3.Identifier = "Identifier3"; @@ -194,10 +195,10 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_IntentRespected() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnitAssert = new ConfigurationUnit { Intent = ConfigurationUnitIntent.Assert }; - ConfigurationUnit configurationUnitInform = new ConfigurationUnit { Intent = ConfigurationUnitIntent.Inform }; - ConfigurationUnit configurationUnitApply = new ConfigurationUnit { Intent = ConfigurationUnitIntent.Apply }; + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnitAssert = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Assert }); + ConfigurationUnit configurationUnitInform = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Inform }); + ConfigurationUnit configurationUnitApply = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply }); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnitInform, configurationUnitApply, configurationUnitAssert }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); @@ -205,7 +206,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests TestConfigurationUnitProcessor unitProcessorAssert = setProcessor.CreateTestProcessor(configurationUnitAssert); TestConfigurationUnitProcessor unitProcessorInform = setProcessor.CreateTestProcessor(configurationUnitInform); TestConfigurationUnitProcessor unitProcessorApply = setProcessor.CreateTestProcessor(configurationUnitApply); - unitProcessorApply.TestSettingsDelegate = () => new TestSettingsResult { TestResult = ConfigurationTestResult.Negative }; + unitProcessorApply.TestSettingsDelegate = () => new TestSettingsResultInstance { TestResult = ConfigurationTestResult.Negative }; ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(factory); @@ -245,9 +246,9 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_AssertionFailure() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnitAssert = new ConfigurationUnit { Intent = ConfigurationUnitIntent.Assert }; - ConfigurationUnit configurationUnitApply = new ConfigurationUnit { Intent = ConfigurationUnitIntent.Apply }; + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnitAssert = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Assert }); + ConfigurationUnit configurationUnitApply = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply }); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnitApply, configurationUnitAssert }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); @@ -255,7 +256,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests TestConfigurationUnitProcessor unitProcessorAssert = setProcessor.CreateTestProcessor(configurationUnitAssert); unitProcessorAssert.TestSettingsDelegate = () => throw new NullReferenceException(); TestConfigurationUnitProcessor unitProcessorApply = setProcessor.CreateTestProcessor(configurationUnitApply); - unitProcessorApply.TestSettingsDelegate = () => new TestSettingsResult { TestResult = ConfigurationTestResult.Negative }; + unitProcessorApply.TestSettingsDelegate = () => new TestSettingsResultInstance { TestResult = ConfigurationTestResult.Negative }; ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(factory); @@ -292,17 +293,17 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_AssertionNegative() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnitAssert = new ConfigurationUnit { Intent = ConfigurationUnitIntent.Assert }; - ConfigurationUnit configurationUnitApply = new ConfigurationUnit { Intent = ConfigurationUnitIntent.Apply }; + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnitAssert = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Assert }); + ConfigurationUnit configurationUnitApply = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply }); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnitApply, configurationUnitAssert }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); TestConfigurationSetProcessor setProcessor = factory.CreateTestProcessor(configurationSet); TestConfigurationUnitProcessor unitProcessorAssert = setProcessor.CreateTestProcessor(configurationUnitAssert); - unitProcessorAssert.TestSettingsDelegate = () => new TestSettingsResult { TestResult = ConfigurationTestResult.Negative }; + unitProcessorAssert.TestSettingsDelegate = () => new TestSettingsResultInstance { TestResult = ConfigurationTestResult.Negative }; TestConfigurationUnitProcessor unitProcessorApply = setProcessor.CreateTestProcessor(configurationUnitApply); - unitProcessorApply.TestSettingsDelegate = () => new TestSettingsResult { TestResult = ConfigurationTestResult.Negative }; + unitProcessorApply.TestSettingsDelegate = () => new TestSettingsResultInstance { TestResult = ConfigurationTestResult.Negative }; ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(factory); @@ -332,14 +333,14 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_UnitAlreadyInCorrectState() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnit = new ConfigurationUnit { Intent = ConfigurationUnitIntent.Apply }; + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnit = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply }); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnit }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); TestConfigurationSetProcessor setProcessor = factory.CreateTestProcessor(configurationSet); TestConfigurationUnitProcessor unitProcessor = setProcessor.CreateTestProcessor(configurationUnit); - unitProcessor.TestSettingsDelegate = () => new TestSettingsResult { TestResult = ConfigurationTestResult.Positive }; + unitProcessor.TestSettingsDelegate = () => new TestSettingsResultInstance { TestResult = ConfigurationTestResult.Positive }; ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(factory); @@ -365,15 +366,15 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ApplySet_Progress() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit assert1 = new ConfigurationUnit() { Intent = ConfigurationUnitIntent.Assert, Identifier = "Assert1" }; - ConfigurationUnit assert2 = new ConfigurationUnit() { Intent = ConfigurationUnitIntent.Assert, Identifier = "Assert2", Dependencies = new string[] { assert1.Identifier } }; - ConfigurationUnit inform1 = new ConfigurationUnit() { Intent = ConfigurationUnitIntent.Inform, Identifier = "Inform1" }; - ConfigurationUnit apply1 = new ConfigurationUnit() { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply1" }; - ConfigurationUnit apply2 = new ConfigurationUnit() { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply2" }; - ConfigurationUnit apply3 = new ConfigurationUnit() { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply3", Dependencies = new string[] { apply1.Identifier, apply2.Identifier } }; - ConfigurationUnit apply4 = new ConfigurationUnit() { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply4", ShouldApply = false }; - ConfigurationUnit apply5 = new ConfigurationUnit() { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply5", Dependencies = new string[] { apply4.Identifier } }; + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit assert1 = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Assert, Identifier = "Assert1" }); + ConfigurationUnit assert2 = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Assert, Identifier = "Assert2", Dependencies = new string[] { assert1.Identifier } }); + ConfigurationUnit inform1 = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Inform, Identifier = "Inform1" }); + ConfigurationUnit apply1 = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply1" }); + ConfigurationUnit apply2 = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply2" }); + ConfigurationUnit apply3 = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply3", Dependencies = new string[] { apply1.Identifier, apply2.Identifier } }); + ConfigurationUnit apply4 = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply4", ShouldApply = false }); + ConfigurationUnit apply5 = this.ConfigurationUnit().Assign(new { Intent = ConfigurationUnitIntent.Apply, Identifier = "Apply5", Dependencies = new string[] { apply4.Identifier } }); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { assert2, assert1, inform1, apply1, apply3, apply4, apply2, apply5 }; ManualResetEvent startProcessing = new ManualResetEvent(false); diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationProcessorFactoryTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationProcessorFactoryTests.cs @@ -11,6 +11,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests using Microsoft.Management.Configuration.Processor.Set; using Microsoft.Management.Configuration.UnitTests.Fixtures; using Moq; + using WinRT; using Xunit; using Xunit.Abstractions; using static Microsoft.Management.Configuration.Processor.Constants.PowerShellConstants; @@ -41,9 +42,10 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void CreateSetProcessor_Test() { - var configurationProcessorFactory = new ConfigurationSetProcessorFactory( - ConfigurationProcessorType.Hosted, - null); + var configurationProcessorFactory = new PowerShellConfigurationSetProcessorFactory(); + + var properties = configurationProcessorFactory.As<IPowerShellConfigurationProcessorFactoryProperties>(); + properties.ProcessorType = PowerShellConfigurationProcessorType.Hosted; var configurationSet = new ConfigurationSet(); @@ -56,22 +58,20 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests } /// <summary> - /// CreateSetProcessor test. + /// AdditionalModulePaths test. /// </summary> [Fact] public void CreateSetProcessor_Properties_PsModulePath() { - var configurationProcessorFactoryPropertiesMock = new Mock<IConfigurationProcessorFactoryProperties>(); - configurationProcessorFactoryPropertiesMock.Setup(c => c.AdditionalModulePaths) - .Returns(new List<string> + var configurationProcessorFactory = new PowerShellConfigurationSetProcessorFactory(); + + var properties = configurationProcessorFactory.As<IPowerShellConfigurationProcessorFactoryProperties>(); + properties.ProcessorType = PowerShellConfigurationProcessorType.Hosted; + properties.AdditionalModulePaths = new List<string> { "ThisIsOnePath", "ThisIsAnotherPath", - }); - - var configurationProcessorFactory = new ConfigurationSetProcessorFactory( - ConfigurationProcessorType.Hosted, - configurationProcessorFactoryPropertiesMock.Object); + }; var configurationSet = new ConfigurationSet(); @@ -81,8 +81,6 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests var processorSet = configurationProcessorSet as ConfigurationSetProcessor; Assert.NotNull(processorSet); - configurationProcessorFactoryPropertiesMock.Verify(); - var modulePath = processorSet.ProcessorEnvironment.GetVariable<string>(Variables.PSModulePath); Assert.StartsWith("ThisIsOnePath;ThisIsAnotherPath", modulePath); } diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationProcessorTelemetryTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationProcessorTelemetryTests.cs @@ -203,9 +203,10 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests if (getFails) { - this.GetResult = new GetSettingsResult(); - this.GetResult.ResultInformation.ResultCode = new NullReferenceException(); - this.GetResult.ResultInformation.ResultSource = ConfigurationUnitResultSource.UnitProcessing; + var getResult = new GetSettingsResultInstance(); + getResult.InternalResult.ResultCode = new NullReferenceException(); + getResult.InternalResult.ResultSource = ConfigurationUnitResultSource.UnitProcessing; + this.GetResult = getResult; this.UnitProcessor.GetSettingsDelegate = () => this.GetResult; } } @@ -216,7 +217,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests public TestConfigurationUnitProcessor UnitProcessor { get; set; } - public GetSettingsResult? GetResult { get; set; } + public IGetSettingsResult? GetResult { get; set; } public TestConfigurationUnitProcessorDetails? UnitDetails { get; set; } diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationProcessorTestTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationProcessorTestTests.cs @@ -24,6 +24,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests /// Unit tests for running test on the processor. /// </summary> [Collection("UnitTestCollection")] + [OutOfProc] public class ConfigurationProcessorTestTests : ConfigurationProcessorTestBase { /// <summary> @@ -42,7 +43,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void TestSet_SetProcessorError() { - ConfigurationSet configurationSet = new ConfigurationSet(); + ConfigurationSet configurationSet = this.ConfigurationSet(); TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); factory.Exceptions.Add(configurationSet, new FileNotFoundException()); @@ -60,9 +61,9 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void TestSet_UnitProcessorCreationError() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnitThrows = new ConfigurationUnit(); - ConfigurationUnit configurationUnitWorks = new ConfigurationUnit(); + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnitThrows = this.ConfigurationUnit(); + ConfigurationUnit configurationUnitWorks = this.ConfigurationUnit(); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnitThrows, configurationUnitWorks }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); @@ -102,9 +103,9 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void TestSet_UnitProcessorExecutionError() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnitThrows = new ConfigurationUnit(); - ConfigurationUnit configurationUnitWorks = new ConfigurationUnit(); + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnitThrows = this.ConfigurationUnit(); + ConfigurationUnit configurationUnitWorks = this.ConfigurationUnit(); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnitWorks, configurationUnitThrows }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); @@ -145,19 +146,19 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void TestSet_UnitProcessorResultError() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnitThrows = new ConfigurationUnit(); - ConfigurationUnit configurationUnitWorks = new ConfigurationUnit(); + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnitThrows = this.ConfigurationUnit(); + ConfigurationUnit configurationUnitWorks = this.ConfigurationUnit(); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnitWorks, configurationUnitThrows }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); TestConfigurationSetProcessor setProcessor = factory.CreateTestProcessor(configurationSet); TestConfigurationUnitProcessor unitProcessor = setProcessor.CreateTestProcessor(configurationUnitThrows); - TestSettingsResult testResult = new TestSettingsResult(); + TestSettingsResultInstance testResult = new TestSettingsResultInstance(); testResult.TestResult = ConfigurationTestResult.Failed; - testResult.ResultInformation.ResultCode = new NullReferenceException(); - testResult.ResultInformation.Description = "Failed again"; - testResult.ResultInformation.ResultSource = ConfigurationUnitResultSource.UnitProcessing; + testResult.InternalResult.ResultCode = new NullReferenceException(); + testResult.InternalResult.Description = "Failed again"; + testResult.InternalResult.ResultSource = ConfigurationUnitResultSource.UnitProcessing; unitProcessor.TestSettingsDelegate = () => testResult; ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(factory); @@ -222,27 +223,27 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests /// <param name="overallResult">The expected overall test result.</param> private void RunTestSetTestForResultTypes(ConfigurationTestResult[] resultTypes, ConfigurationTestResult overallResult) { - ConfigurationSet configurationSet = new ConfigurationSet(); + ConfigurationSet configurationSet = this.ConfigurationSet(); ConfigurationUnit[] configurationUnits = new ConfigurationUnit[resultTypes.Length]; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); TestConfigurationSetProcessor setProcessor = factory.CreateTestProcessor(configurationSet); - TestSettingsResult positiveResult = new TestSettingsResult(); + TestSettingsResultInstance positiveResult = new TestSettingsResultInstance(); positiveResult.TestResult = ConfigurationTestResult.Positive; - TestSettingsResult negativeResult = new TestSettingsResult(); + TestSettingsResultInstance negativeResult = new TestSettingsResultInstance(); negativeResult.TestResult = ConfigurationTestResult.Negative; - TestSettingsResult failedResult = new TestSettingsResult(); + TestSettingsResultInstance failedResult = new TestSettingsResultInstance(); failedResult.TestResult = ConfigurationTestResult.Failed; - failedResult.ResultInformation.ResultCode = new NullReferenceException(); - failedResult.ResultInformation.Description = "Failed again"; - failedResult.ResultInformation.ResultSource = ConfigurationUnitResultSource.UnitProcessing; + failedResult.InternalResult.ResultCode = new NullReferenceException(); + failedResult.InternalResult.Description = "Failed again"; + failedResult.InternalResult.ResultSource = ConfigurationUnitResultSource.UnitProcessing; for (int i = 0; i < resultTypes.Length; ++i) { - configurationUnits[i] = new ConfigurationUnit(); + configurationUnits[i] = this.ConfigurationUnit(); configurationUnits[i].UnitName = $"Unit {i}"; TestConfigurationUnitProcessor unitProcessor = setProcessor.CreateTestProcessor(configurationUnits[i]); diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationSetAuthoringTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationSetAuthoringTests.cs @@ -8,6 +8,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests { using System; using Microsoft.Management.Configuration.UnitTests.Fixtures; + using Microsoft.Management.Configuration.UnitTests.Helpers; using Microsoft.VisualBasic; using Xunit; using Xunit.Abstractions; @@ -16,20 +17,17 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests /// Unit tests for configuration set authoring (creating objects). /// </summary> [Collection("UnitTestCollection")] - public class ConfigurationSetAuthoringTests + [OutOfProc] + public class ConfigurationSetAuthoringTests : ConfigurationProcessorTestBase { - private readonly UnitTestFixture fixture; - private readonly ITestOutputHelper log; - /// <summary> /// Initializes a new instance of the <see cref="ConfigurationSetAuthoringTests"/> class. /// </summary> /// <param name="fixture">Unit test fixture.</param> /// <param name="log">Log helper.</param> public ConfigurationSetAuthoringTests(UnitTestFixture fixture, ITestOutputHelper log) + : base(fixture, log) { - this.fixture = fixture; - this.log = log; } /// <summary> @@ -42,7 +40,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests string testOrigin = "Test Origin"; string testPath = "TestPath.ext"; - ConfigurationSet testSet = new ConfigurationSet(); + ConfigurationSet testSet = this.ConfigurationSet(); testSet.Name = testName; Assert.Equal(testName, testSet.Name); @@ -55,7 +53,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests Assert.Equal(ConfigurationSetState.Unknown, testSet.State); Assert.Empty(testSet.ConfigurationUnits); - testSet.ConfigurationUnits = new ConfigurationUnit[] { new ConfigurationUnit() }; + testSet.ConfigurationUnits = new ConfigurationUnit[] { this.ConfigurationUnit() }; Assert.Equal(1, testSet.ConfigurationUnits.Count); Assert.NotEqual(string.Empty, testSet.SchemaVersion); @@ -71,7 +69,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests string testIdentifier = "Test Identifier"; ConfigurationUnitIntent testIntent = ConfigurationUnitIntent.Assert; - ConfigurationUnit testUnit = new ConfigurationUnit(); + ConfigurationUnit testUnit = this.ConfigurationUnit(); testUnit.UnitName = testName; Assert.Equal(testName, testUnit.UnitName); @@ -107,7 +105,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void ConfigurationSetSerializeNotImplemented() { - Assert.Throws<NotImplementedException>(() => new ConfigurationSet().Serialize(null)); + Assert.Throws<NotImplementedException>(() => this.ConfigurationSet().Serialize(null)); } } } diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationSetProcessorTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationSetProcessorTests.cs @@ -163,7 +163,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests PSObject findDscResourceResult = new PSObject(processorEnvMock); processorEnvMock.Setup( - m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => c.Unit.UnitName == resourceName))) + m => m.FindModule(It.Is<ConfigurationUnitInternal>(c => c.Unit.UnitName == resourceName))) .Returns(findDscResourceResult) .Verifiable(); @@ -193,6 +193,51 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests /// Tests Creating a unit processor by downloading the resource. /// </summary> [Fact] + public void CreateUnitProcessor_InstallResource_WithoutModule() + { + string resourceName = "SimpleFileResource"; + Version version = new Version("0.0.0.1"); + + DscResourceInfoInternal? nullResource = null; + DscResourceInfoInternal dscResourceInfo = new DscResourceInfoInternal(resourceName, null, version); + var processorEnvMock = new Mock<IProcessorEnvironment>(); + processorEnvMock.SetupSequence( + m => m.GetDscResource(It.Is<ConfigurationUnitInternal>(c => c.Unit.UnitName == resourceName))) + .Returns(nullResource) + .Returns(dscResourceInfo); + + PSObject findDscResourceResult = this.CreateFindResourceInfo(); + processorEnvMock.Setup( + m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => c.Unit.UnitName == resourceName))) + .Returns(findDscResourceResult) + .Verifiable(); + + PSObject moduleInfo = ((dynamic)findDscResourceResult).PSGetModuleInfo; + processorEnvMock.Setup( + m => m.InstallModule(moduleInfo)) + .Verifiable(); + + var configurationSetProcessor = new ConfigurationSetProcessor( + processorEnvMock.Object, + new ConfigurationSet()); + + var unit = new ConfigurationUnit + { + UnitName = resourceName, + }; + unit.Directives.Add("version", version.ToString()); + + var unitProcessor = configurationSetProcessor.CreateUnitProcessor(unit, null); + Assert.NotNull(unitProcessor); + Assert.Equal(unit.UnitName, unitProcessor.Unit.UnitName); + + processorEnvMock.Verify(); + } + + /// <summary> + /// Tests Creating a unit processor by downloading the resource. + /// </summary> + [Fact] public void CreateUnitProcessor_InstallResource_NotFoundAfterInstall() { string resourceName = "xResourceName"; @@ -208,7 +253,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests PSObject findDscResourceResult = new PSObject(processorEnvMock); processorEnvMock.Setup( - m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => c.Unit.UnitName == resourceName))) + m => m.FindModule(It.Is<ConfigurationUnitInternal>(c => c.Unit.UnitName == resourceName))) .Returns(findDscResourceResult) .Verifiable(); @@ -252,7 +297,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests PSObject? findDscResourceResult = null; processorEnvMock.Setup( - m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => c.Unit.UnitName == resourceName))) + m => m.FindModule(It.Is<ConfigurationUnitInternal>(c => c.Unit.UnitName == resourceName))) .Returns(findDscResourceResult) .Verifiable(); @@ -458,7 +503,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests .Returns(nullDscResourceInfo) .Verifiable(); processorEnvMock.Setup( - m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) + m => m.FindModule(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) .Returns(nullPsModuleInfo) .Verifiable(); @@ -491,7 +536,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests .Returns(nullDscResourceInfo) .Verifiable(); processorEnvMock.Setup( - m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) + m => m.FindModule(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) .Returns(getFindResourceInfo) .Verifiable(); @@ -518,7 +563,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests var unit = this.CreteConfigurationUnit(); DscResourceInfoInternal? nullDscResourceInfo = null; var (_, psModuleInfo) = this.GetResourceAndModuleInfo(unit); - var getFindResourceInfo = this.CreateFindResourceInfo(); + var getFindModuleInfo = this.CreateGetModuleInfo(); var processorEnvMock = new Mock<IProcessorEnvironment>(); processorEnvMock.Setup( @@ -526,11 +571,11 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests .Returns(nullDscResourceInfo) .Verifiable(); processorEnvMock.Setup( - m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) - .Returns(getFindResourceInfo) + m => m.FindModule(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) + .Returns(getFindModuleInfo) .Verifiable(); processorEnvMock.Setup( - m => m.SaveModule(getFindResourceInfo, It.IsAny<string>())) + m => m.SaveModule(getFindModuleInfo, It.IsAny<string>())) .Verifiable(); processorEnvMock.Setup( m => m.GetAvailableModule(It.Is<string>(s => s.EndsWith("xSimpleTestResource")))) @@ -574,7 +619,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests .Returns(nullDscResourceInfo) .Verifiable(); processorEnvMock.Setup( - m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) + m => m.FindModule(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) .Returns(getFindResourceInfo) .Verifiable(); processorEnvMock.Setup( @@ -612,7 +657,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests .Returns(nullDscResourceInfo) .Returns(dscResourceInfo); processorEnvMock.Setup( - m => m.FindDscResource(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) + m => m.FindModule(It.Is<ConfigurationUnitInternal>(c => unit.UnitName == unit.UnitName))) .Returns(getFindResourceInfo) .Verifiable(); processorEnvMock.Setup( diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/OpenConfigurationSetTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/OpenConfigurationSetTests.cs @@ -19,6 +19,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests /// Unit tests for parsing configuration sets from streams. /// </summary> [Collection("UnitTestCollection")] + [OutOfProc] public class OpenConfigurationSetTests : ConfigurationProcessorTestBase { /// <summary> diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ProcessorGetTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ProcessorGetTests.cs @@ -18,6 +18,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests /// Unit tests for getting details on processors. /// </summary> [Collection("UnitTestCollection")] + [OutOfProc] public class ProcessorGetTests : ConfigurationProcessorTestBase { /// <summary> @@ -36,7 +37,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void GetUnitDetailsError() { - ConfigurationUnit configurationUnitThrows = new ConfigurationUnit(); + ConfigurationUnit configurationUnitThrows = this.ConfigurationUnit(); TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); factory.NullProcessor = new TestConfigurationSetProcessor(null); @@ -53,7 +54,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void GetUnitDetailsSuccess() { - ConfigurationUnit configurationUnit = new ConfigurationUnit(); + ConfigurationUnit configurationUnit = this.ConfigurationUnit(); TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(factory); @@ -69,9 +70,9 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void GetSetDetailsError() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnitWorks = new ConfigurationUnit(); - ConfigurationUnit configurationUnitThrows = new ConfigurationUnit(); + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnitWorks = this.ConfigurationUnit(); + ConfigurationUnit configurationUnitThrows = this.ConfigurationUnit(); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnitWorks, configurationUnitThrows }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); @@ -101,9 +102,9 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void GetSetDetailsSuccess() { - ConfigurationSet configurationSet = new ConfigurationSet(); - ConfigurationUnit configurationUnit1 = new ConfigurationUnit(); - ConfigurationUnit configurationUnit2 = new ConfigurationUnit(); + ConfigurationSet configurationSet = this.ConfigurationSet(); + ConfigurationUnit configurationUnit1 = this.ConfigurationUnit(); + ConfigurationUnit configurationUnit2 = this.ConfigurationUnit(); configurationSet.ConfigurationUnits = new ConfigurationUnit[] { configurationUnit1, configurationUnit2 }; TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); @@ -121,7 +122,7 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void GetSettings_ProcessorSettingsError() { - ConfigurationUnit configurationUnit = new ConfigurationUnit(); + ConfigurationUnit configurationUnit = this.ConfigurationUnit(); TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); factory.NullProcessor = new TestConfigurationSetProcessor(null); @@ -145,14 +146,14 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void GetSettings_ProcessorSettingsFailedResult() { - ConfigurationUnit configurationUnit = new ConfigurationUnit(); + ConfigurationUnit configurationUnit = this.ConfigurationUnit(); TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); factory.NullProcessor = new TestConfigurationSetProcessor(null); TestConfigurationUnitProcessor unitProcessor = factory.NullProcessor.CreateTestProcessor(configurationUnit); - GetSettingsResult getSettingsResult = new GetSettingsResult(); - getSettingsResult.ResultInformation.ResultCode = new InvalidDataException(); - getSettingsResult.ResultInformation.Description = "We fail because we must"; + GetSettingsResultInstance getSettingsResult = new GetSettingsResultInstance(); + getSettingsResult.InternalResult.ResultCode = new InvalidDataException(); + getSettingsResult.InternalResult.Description = "We fail because we must"; unitProcessor.GetSettingsDelegate = () => getSettingsResult; ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(factory); @@ -172,12 +173,12 @@ namespace Microsoft.Management.Configuration.UnitTests.Tests [Fact] public void GetSettings_ProcessorSettingsSuccess() { - ConfigurationUnit configurationUnit = new ConfigurationUnit(); + ConfigurationUnit configurationUnit = this.ConfigurationUnit(); TestConfigurationProcessorFactory factory = new TestConfigurationProcessorFactory(); factory.NullProcessor = new TestConfigurationSetProcessor(null); TestConfigurationUnitProcessor unitProcessor = factory.NullProcessor.CreateTestProcessor(configurationUnit); - GetSettingsResult getSettingsResult = new GetSettingsResult(); + GetSettingsResultInstance getSettingsResult = new GetSettingsResultInstance(); getSettingsResult.Settings = new Windows.Foundation.Collections.ValueSet(); getSettingsResult.Settings.Add("key", "value"); unitProcessor.GetSettingsDelegate = () => getSettingsResult; diff --git a/src/Microsoft.Management.Configuration/ApplyConfigurationUnitResult.cpp b/src/Microsoft.Management.Configuration/ApplyConfigurationUnitResult.cpp @@ -47,12 +47,12 @@ namespace winrt::Microsoft::Management::Configuration::implementation m_rebootRequired = value; } - Configuration::ConfigurationUnitResultInformation ApplyConfigurationUnitResult::ResultInformation() + IConfigurationUnitResultInformation ApplyConfigurationUnitResult::ResultInformation() { return m_resultInformation; } - void ApplyConfigurationUnitResult::ResultInformation(ConfigurationUnitResultInformation value) + void ApplyConfigurationUnitResult::ResultInformation(IConfigurationUnitResultInformation value) { m_resultInformation = std::move(value); } diff --git a/src/Microsoft.Management.Configuration/ApplyConfigurationUnitResult.h b/src/Microsoft.Management.Configuration/ApplyConfigurationUnitResult.h @@ -9,7 +9,6 @@ namespace winrt::Microsoft::Management::Configuration::implementation struct ApplyConfigurationUnitResult : ApplyConfigurationUnitResultT<ApplyConfigurationUnitResult> { using ConfigurationUnit = Configuration::ConfigurationUnit; - using ConfigurationUnitResultInformation = Configuration::ConfigurationUnitResultInformation; ApplyConfigurationUnitResult() = default; @@ -18,14 +17,14 @@ namespace winrt::Microsoft::Management::Configuration::implementation void State(ConfigurationUnitState value); void PreviouslyInDesiredState(bool value); void RebootRequired(bool value); - void ResultInformation(ConfigurationUnitResultInformation value); + void ResultInformation(IConfigurationUnitResultInformation value); #endif ConfigurationUnit Unit(); ConfigurationUnitState State() const; bool PreviouslyInDesiredState() const; bool RebootRequired() const; - ConfigurationUnitResultInformation ResultInformation(); + IConfigurationUnitResultInformation ResultInformation(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: @@ -33,7 +32,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation std::atomic<ConfigurationUnitState> m_state = ConfigurationUnitState::Pending; bool m_previouslyInDesiredState = false; bool m_rebootRequired = false; - ConfigurationUnitResultInformation m_resultInformation = nullptr; + IConfigurationUnitResultInformation m_resultInformation; #endif }; } diff --git a/src/Microsoft.Management.Configuration/ApplySettingsResult.cpp b/src/Microsoft.Management.Configuration/ApplySettingsResult.cpp @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "ApplySettingsResult.h" -#include "ApplySettingsResult.g.cpp" -#include "ConfigurationUnitResultInformation.h" - -namespace winrt::Microsoft::Management::Configuration::implementation -{ - ApplySettingsResult::ApplySettingsResult() : - m_resultInformation(*make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>()) - { - } - - bool ApplySettingsResult::RebootRequired() const - { - return m_rebootRequired; - } - - void ApplySettingsResult::RebootRequired(bool value) - { - m_rebootRequired = value; - } - - Configuration::ConfigurationUnitResultInformation ApplySettingsResult::ResultInformation() - { - return m_resultInformation; - } -} diff --git a/src/Microsoft.Management.Configuration/ApplySettingsResult.h b/src/Microsoft.Management.Configuration/ApplySettingsResult.h @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include "ApplySettingsResult.g.h" - -namespace winrt::Microsoft::Management::Configuration::implementation -{ - struct ApplySettingsResult : ApplySettingsResultT<ApplySettingsResult> - { - ApplySettingsResult(); - - bool RebootRequired() const; - void RebootRequired(bool value); - - Configuration::ConfigurationUnitResultInformation ResultInformation(); - - private: - bool m_rebootRequired = false; - Configuration::ConfigurationUnitResultInformation m_resultInformation; - }; -} - -namespace winrt::Microsoft::Management::Configuration::factory_implementation -{ - struct ApplySettingsResult : ApplySettingsResultT<ApplySettingsResult, implementation::ApplySettingsResult> - { - }; -} diff --git a/src/Microsoft.Management.Configuration/ConfigurationProcessor.cpp b/src/Microsoft.Management.Configuration/ConfigurationProcessor.cpp @@ -6,7 +6,7 @@ #include "ConfigurationSet.h" #include "OpenConfigurationSetResult.h" #include "ConfigurationSetParser.h" -#include "DiagnosticInformation.h" +#include "DiagnosticInformationInstance.h" #include "ApplyConfigurationSetResult.h" #include "ConfigurationSetApplyProcessor.h" #include "TestConfigurationSetResult.h" @@ -106,24 +106,20 @@ namespace winrt::Microsoft::Management::Configuration::implementation } } - ConfigurationProcessor::ConfigurationProcessor(const IConfigurationSetProcessorFactory& factory) : m_factory(factory) + ConfigurationProcessor::ConfigurationProcessor() { AppInstaller::Logging::DiagnosticLogger& logger = m_threadGlobals.GetDiagnosticLogger(); logger.EnableChannel(AppInstaller::Logging::Channel::All); logger.SetLevel(AppInstaller::Logging::Level::Verbose); logger.AddLogger(std::make_unique<ConfigurationProcessorDiagnosticsLogger>(*this)); + } - if (m_factory) - { - m_factoryDiagnosticsEventRevoker = m_factory.Diagnostics(winrt::auto_revoke, - [this](const IInspectable&, const DiagnosticInformation& information) - { - m_diagnostics(*this, information); - }); - } + ConfigurationProcessor::ConfigurationProcessor(const IConfigurationSetProcessorFactory& factory) : ConfigurationProcessor() + { + ConfigurationSetProcessorFactory(factory); } - event_token ConfigurationProcessor::Diagnostics(const Windows::Foundation::EventHandler<DiagnosticInformation>& handler) + event_token ConfigurationProcessor::Diagnostics(const Windows::Foundation::EventHandler<IDiagnosticInformation>& handler) { static AttachWilFailureCallback s_callbackAttach; return m_diagnostics.add(handler); @@ -263,6 +259,8 @@ namespace winrt::Microsoft::Management::Configuration::implementation } configurationSet->SchemaVersion(parser->GetSchemaVersion()); + PropagateLifetimeWatcher(configurationSet.as<Windows::Foundation::IUnknown>()); + result->Initialize(*configurationSet); } catch (const wil::ResultException& resultException) @@ -464,7 +462,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation { try { - TestSettingsResult settingsResult = unitProcessor.TestSettings(); + ITestSettingsResult settingsResult = unitProcessor.TestSettings(); testResult->TestResult(settingsResult.TestResult()); testResult->ResultInformation(settingsResult.ResultInformation()); } @@ -556,7 +554,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation { try { - GetSettingsResult settingsResult = unitProcessor.GetSettings(); + IGetSettingsResult settingsResult = unitProcessor.GetSettings(); result->Settings(settingsResult.Settings()); result->ResultInformation(settingsResult.ResultInformation()); } @@ -571,11 +569,30 @@ namespace winrt::Microsoft::Management::Configuration::implementation return *result; } + HRESULT STDMETHODCALLTYPE ConfigurationProcessor::SetLifetimeWatcher(IUnknown* watcher) + { + return AppInstaller::WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher); + } + + void ConfigurationProcessor::ConfigurationSetProcessorFactory(const IConfigurationSetProcessorFactory& value) + { + m_factory = value; + + if (m_factory) + { + m_factoryDiagnosticsEventRevoker = m_factory.Diagnostics(winrt::auto_revoke, + [this](const IInspectable&, const IDiagnosticInformation& information) + { + m_diagnostics(*this, information); + }); + } + } + void ConfigurationProcessor::Diagnostics(DiagnosticLevel level, std::string_view message) { if (level >= m_minimumLevel) { - auto diagnostics = make_self<wil::details::module_count_wrapper<implementation::DiagnosticInformation>>(); + auto diagnostics = make_self<wil::details::module_count_wrapper<implementation::DiagnosticInformationInstance>>(); diagnostics->Initialize(level, AppInstaller::Utility::ConvertToUTF16(message)); m_diagnostics(*this, *diagnostics); } diff --git a/src/Microsoft.Management.Configuration/ConfigurationProcessor.h b/src/Microsoft.Management.Configuration/ConfigurationProcessor.h @@ -7,18 +7,18 @@ #include <winrt/Windows.Storage.Streams.h> #include "ConfigThreadGlobals.h" #include <winget/AsyncTokens.h> +#include <winget/ILifetimeWatcher.h> #include <string_view> #include <functional> namespace winrt::Microsoft::Management::Configuration::implementation { - struct ConfigurationProcessor : ConfigurationProcessorT<ConfigurationProcessor> + struct ConfigurationProcessor : ConfigurationProcessorT<ConfigurationProcessor, AppInstaller::WinRT::ILifetimeWatcher>, AppInstaller::WinRT::LifetimeWatcherBase { using ConfigurationSet = Configuration::ConfigurationSet; using ConfigurationSetChangeData = Configuration::ConfigurationSetChangeData; using ConfigurationUnit = Configuration::ConfigurationUnit; - using DiagnosticInformation = Configuration::DiagnosticInformation; using ApplyConfigurationSetResult = Configuration::ApplyConfigurationSetResult; using TestConfigurationSetResult = Configuration::TestConfigurationSetResult; using TestConfigurationUnitResult = Configuration::TestConfigurationUnitResult; @@ -26,9 +26,13 @@ namespace winrt::Microsoft::Management::Configuration::implementation using GetConfigurationSetDetailsResult = Configuration::GetConfigurationSetDetailsResult; using GetConfigurationUnitDetailsResult = Configuration::GetConfigurationUnitDetailsResult; +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + ConfigurationProcessor(); +#endif + ConfigurationProcessor(const IConfigurationSetProcessorFactory& factory); - event_token Diagnostics(const Windows::Foundation::EventHandler<DiagnosticInformation>& handler); + event_token Diagnostics(const Windows::Foundation::EventHandler<IDiagnosticInformation>& handler); void Diagnostics(const event_token& token) noexcept; DiagnosticLevel MinimumLevel(); @@ -74,7 +78,11 @@ namespace winrt::Microsoft::Management::Configuration::implementation GetConfigurationUnitSettingsResult GetUnitSettings(const ConfigurationUnit& unit); Windows::Foundation::IAsyncOperation<GetConfigurationUnitSettingsResult> GetUnitSettingsAsync(const ConfigurationUnit& unit); + HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher); + #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + void ConfigurationSetProcessorFactory(const IConfigurationSetProcessorFactory& value); + // Sends diagnostics objects to the event. void Diagnostics(DiagnosticLevel level, std::string_view message); @@ -98,7 +106,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation GetConfigurationUnitSettingsResult GetUnitSettingsImpl(const ConfigurationUnit& unit, AppInstaller::WinRT::AsyncCancellation cancellation = {}); IConfigurationSetProcessorFactory m_factory = nullptr; - event<Windows::Foundation::EventHandler<DiagnosticInformation>> m_diagnostics; + event<Windows::Foundation::EventHandler<IDiagnosticInformation>> m_diagnostics; event<Windows::Foundation::TypedEventHandler<ConfigurationSet, ConfigurationChangeData>> m_configurationChange; ConfigThreadGlobals m_threadGlobals; IConfigurationSetProcessorFactory::Diagnostics_revoker m_factoryDiagnosticsEventRevoker; diff --git a/src/Microsoft.Management.Configuration/ConfigurationSet.cpp b/src/Microsoft.Management.Configuration/ConfigurationSet.cpp @@ -133,4 +133,9 @@ namespace winrt::Microsoft::Management::Configuration::implementation { THROW_HR(E_NOTIMPL); } + + HRESULT STDMETHODCALLTYPE ConfigurationSet::SetLifetimeWatcher(IUnknown* watcher) + { + return AppInstaller::WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher); + } } diff --git a/src/Microsoft.Management.Configuration/ConfigurationSet.h b/src/Microsoft.Management.Configuration/ConfigurationSet.h @@ -3,13 +3,14 @@ #pragma once #include "ConfigurationSet.g.h" #include "MutableFlag.h" +#include <winget/ILifetimeWatcher.h> #include <winrt/Windows.Foundation.h> #include <winrt/Windows.Foundation.Collections.h> #include <vector> namespace winrt::Microsoft::Management::Configuration::implementation { - struct ConfigurationSet : ConfigurationSetT<ConfigurationSet> + struct ConfigurationSet : ConfigurationSetT<ConfigurationSet, AppInstaller::WinRT::ILifetimeWatcher>, AppInstaller::WinRT::LifetimeWatcherBase { using WinRT_Self = ::winrt::Microsoft::Management::Configuration::ConfigurationSet; using ConfigurationUnit = ::winrt::Microsoft::Management::Configuration::ConfigurationUnit; @@ -51,6 +52,8 @@ namespace winrt::Microsoft::Management::Configuration::implementation void Remove(); + HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher); + #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: hstring m_name; diff --git a/src/Microsoft.Management.Configuration/ConfigurationSetApplyProcessor.cpp b/src/Microsoft.Management.Configuration/ConfigurationSetApplyProcessor.cpp @@ -395,7 +395,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation case ConfigurationUnitIntent::Assert: { action = TelemetryTraceLogger::TestAction; - TestSettingsResult settingsResult = unitProcessor.TestSettings(); + ITestSettingsResult settingsResult = unitProcessor.TestSettings(); if (settingsResult.TestResult() == ConfigurationTestResult::Positive) { @@ -420,7 +420,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation { // Force the processor to retrieve the settings action = TelemetryTraceLogger::GetAction; - GetSettingsResult settingsResult = unitProcessor.GetSettings(); + IGetSettingsResult settingsResult = unitProcessor.GetSettings(); if (SUCCEEDED(settingsResult.ResultInformation().ResultCode())) { result = true; @@ -435,7 +435,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation case ConfigurationUnitIntent::Apply: { action = TelemetryTraceLogger::TestAction; - TestSettingsResult testSettingsResult = unitProcessor.TestSettings(); + ITestSettingsResult testSettingsResult = unitProcessor.TestSettings(); if (testSettingsResult.TestResult() == ConfigurationTestResult::Positive) { @@ -448,7 +448,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation m_progress.ThrowIfCancelled(); action = TelemetryTraceLogger::ApplyAction; - ApplySettingsResult applySettingsResult = unitProcessor.ApplySettings(); + IApplySettingsResult applySettingsResult = unitProcessor.ApplySettings(); if (SUCCEEDED(applySettingsResult.ResultInformation().ResultCode())) { unitInfo.Result->RebootRequired(applySettingsResult.RebootRequired()); diff --git a/src/Microsoft.Management.Configuration/ConfigurationSetApplyProcessor.h b/src/Microsoft.Management.Configuration/ConfigurationSetApplyProcessor.h @@ -21,7 +21,6 @@ namespace winrt::Microsoft::Management::Configuration::implementation using ApplyConfigurationSetResult = Configuration::ApplyConfigurationSetResult; using ConfigurationSet = Configuration::ConfigurationSet; using ConfigurationUnit = Configuration::ConfigurationUnit; - using ConfigurationUnitResultInformation = Configuration::ConfigurationUnitResultInformation; using ConfigurationSetChangeData = Configuration::ConfigurationSetChangeData; using result_type = decltype(make_self<wil::details::module_count_wrapper<implementation::ApplyConfigurationSetResult>>()); diff --git a/src/Microsoft.Management.Configuration/ConfigurationSetChangeData.cpp b/src/Microsoft.Management.Configuration/ConfigurationSetChangeData.cpp @@ -13,7 +13,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation return *result; } - Configuration::ConfigurationSetChangeData ConfigurationSetChangeData::Create(ConfigurationUnitState state, ConfigurationUnitResultInformation resultInformation, ConfigurationUnit unit) + Configuration::ConfigurationSetChangeData ConfigurationSetChangeData::Create(ConfigurationUnitState state, IConfigurationUnitResultInformation resultInformation, ConfigurationUnit unit) { auto result = make_self<wil::details::module_count_wrapper<implementation::ConfigurationSetChangeData>>(); result->Initialize(state, resultInformation, unit); @@ -26,7 +26,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation m_setState = state; } - void ConfigurationSetChangeData::Initialize(ConfigurationUnitState state, ConfigurationUnitResultInformation resultInformation, ConfigurationUnit unit) + void ConfigurationSetChangeData::Initialize(ConfigurationUnitState state, IConfigurationUnitResultInformation resultInformation, ConfigurationUnit unit) { m_change = ConfigurationSetChangeEventType::UnitStateChanged; m_setState = ConfigurationSetState::InProgress; @@ -50,7 +50,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation return m_unitState; } - ConfigurationUnitResultInformation ConfigurationSetChangeData::ResultInformation() + IConfigurationUnitResultInformation ConfigurationSetChangeData::ResultInformation() { return m_resultInformation; } diff --git a/src/Microsoft.Management.Configuration/ConfigurationSetChangeData.h b/src/Microsoft.Management.Configuration/ConfigurationSetChangeData.h @@ -2,28 +2,28 @@ // Licensed under the MIT License. #pragma once #include "ConfigurationSetChangeData.g.h" +#include "ConfigurationUnitResultInformation.h" namespace winrt::Microsoft::Management::Configuration::implementation { struct ConfigurationSetChangeData : ConfigurationSetChangeDataT<ConfigurationSetChangeData> { using ConfigurationUnit = Configuration::ConfigurationUnit; - using ConfigurationUnitResultInformation = Configuration::ConfigurationUnitResultInformation; ConfigurationSetChangeData() = default; #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) static Configuration::ConfigurationSetChangeData Create(ConfigurationSetState state); - static Configuration::ConfigurationSetChangeData Create(ConfigurationUnitState state, ConfigurationUnitResultInformation resultInformation, ConfigurationUnit unit); + static Configuration::ConfigurationSetChangeData Create(ConfigurationUnitState state, IConfigurationUnitResultInformation resultInformation, ConfigurationUnit unit); void Initialize(ConfigurationSetState state); - void Initialize(ConfigurationUnitState state, ConfigurationUnitResultInformation resultInformation, ConfigurationUnit unit); + void Initialize(ConfigurationUnitState state, IConfigurationUnitResultInformation resultInformation, ConfigurationUnit unit); #endif ConfigurationSetChangeEventType Change(); ConfigurationSetState SetState(); ConfigurationUnitState UnitState(); - ConfigurationUnitResultInformation ResultInformation(); + IConfigurationUnitResultInformation ResultInformation(); ConfigurationUnit Unit(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) @@ -31,7 +31,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation ConfigurationSetChangeEventType m_change = ConfigurationSetChangeEventType::Unknown; ConfigurationSetState m_setState = ConfigurationSetState::Unknown; ConfigurationUnitState m_unitState = ConfigurationUnitState::Unknown; - ConfigurationUnitResultInformation m_resultInformation = nullptr; + IConfigurationUnitResultInformation m_resultInformation; ConfigurationUnit m_unit = nullptr; #endif }; diff --git a/src/Microsoft.Management.Configuration/ConfigurationStaticFunctions.cpp b/src/Microsoft.Management.Configuration/ConfigurationStaticFunctions.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "ConfigurationStaticFunctions.h" +#include "ConfigurationStaticFunctions.g.cpp" +#include "ConfigurationUnit.h" +#include "ConfigurationSet.h" +#include "ConfigurationProcessor.h" +#include <AppInstallerStrings.h> +#include <winget/ConfigurationSetProcessorHandlers.h> + +namespace winrt::Microsoft::Management::Configuration::implementation +{ + Configuration::ConfigurationUnit ConfigurationStaticFunctions::CreateConfigurationUnit() + { + return *make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnit>>(); + } + + Configuration::ConfigurationSet ConfigurationStaticFunctions::CreateConfigurationSet() + { + return *make_self<wil::details::module_count_wrapper<implementation::ConfigurationSet>>(); + } + + Windows::Foundation::IAsyncOperation<IConfigurationSetProcessorFactory> ConfigurationStaticFunctions::CreateConfigurationSetProcessorFactoryAsync(hstring const& handler) + { + std::wstring lowerHandler = AppInstaller::Utility::ToLower(handler); + + if (lowerHandler == AppInstaller::Configuration::PowerShellHandlerIdentifier) + { + THROW_HR(E_NOTIMPL); + } + + AICLI_LOG(Config, Error, << "Unknown handler in CreateConfigurationSetProcessorFactory: " << AppInstaller::Utility::ConvertToUTF8(handler)); + THROW_HR(E_NOT_SET); + } + + Configuration::ConfigurationProcessor ConfigurationStaticFunctions::CreateConfigurationProcessor(IConfigurationSetProcessorFactory const& factory) + { + auto result = make_self<wil::details::module_count_wrapper<implementation::ConfigurationProcessor>>(); + result->ConfigurationSetProcessorFactory(factory); + return *result; + } +} diff --git a/src/Microsoft.Management.Configuration/ConfigurationStaticFunctions.h b/src/Microsoft.Management.Configuration/ConfigurationStaticFunctions.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "ConfigurationStaticFunctions.g.h" + +namespace winrt::Microsoft::Management::Configuration::implementation +{ + struct ConfigurationStaticFunctions : ConfigurationStaticFunctionsT<ConfigurationStaticFunctions> + { + ConfigurationStaticFunctions() = default; + + Configuration::ConfigurationUnit CreateConfigurationUnit(); + Configuration::ConfigurationSet CreateConfigurationSet(); + Windows::Foundation::IAsyncOperation<IConfigurationSetProcessorFactory> CreateConfigurationSetProcessorFactoryAsync(hstring const& handler); + Configuration::ConfigurationProcessor CreateConfigurationProcessor(IConfigurationSetProcessorFactory const& factory); + }; +} +namespace winrt::Microsoft::Management::Configuration::factory_implementation +{ + struct ConfigurationStaticFunctions : ConfigurationStaticFunctionsT<ConfigurationStaticFunctions, implementation::ConfigurationStaticFunctions> + { + }; +} diff --git a/src/Microsoft.Management.Configuration/ConfigurationUnit.cpp b/src/Microsoft.Management.Configuration/ConfigurationUnit.cpp @@ -102,7 +102,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation return ConfigurationUnitState::Unknown; } - ConfigurationUnitResultInformation ConfigurationUnit::ResultInformation() + IConfigurationUnitResultInformation ConfigurationUnit::ResultInformation() { return nullptr; } @@ -127,4 +127,9 @@ namespace winrt::Microsoft::Management::Configuration::implementation THROW_HR_IF(E_INVALIDARG, !ConfigurationSetParser::IsRecognizedSchemaVersion(value)); m_schemaVersion = value; } + + HRESULT STDMETHODCALLTYPE ConfigurationUnit::SetLifetimeWatcher(IUnknown* watcher) + { + return AppInstaller::WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher); + } } diff --git a/src/Microsoft.Management.Configuration/ConfigurationUnit.h b/src/Microsoft.Management.Configuration/ConfigurationUnit.h @@ -3,15 +3,14 @@ #pragma once #include "ConfigurationUnit.g.h" #include "MutableFlag.h" +#include <winget/ILifetimeWatcher.h> #include <winrt/Windows.Foundation.Collections.h> #include <vector> namespace winrt::Microsoft::Management::Configuration::implementation { - struct ConfigurationUnit : ConfigurationUnitT<ConfigurationUnit> + struct ConfigurationUnit : ConfigurationUnitT<ConfigurationUnit, AppInstaller::WinRT::ILifetimeWatcher>, AppInstaller::WinRT::LifetimeWatcherBase { - using ConfigurationUnitResultInformation = Configuration::ConfigurationUnitResultInformation; - ConfigurationUnit(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) @@ -40,7 +39,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation ConfigurationUnitState State(); - ConfigurationUnitResultInformation ResultInformation(); + IConfigurationUnitResultInformation ResultInformation(); bool ShouldApply(); void ShouldApply(bool value); @@ -48,6 +47,8 @@ namespace winrt::Microsoft::Management::Configuration::implementation hstring SchemaVersion(); void SchemaVersion(const hstring& value); + HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher); + #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) void Dependencies(std::vector<hstring>&& value); void Details(IConfigurationUnitProcessorDetails&& details); diff --git a/src/Microsoft.Management.Configuration/ConfigurationUnitResultInformation.cpp b/src/Microsoft.Management.Configuration/ConfigurationUnitResultInformation.cpp @@ -2,7 +2,6 @@ // Licensed under the MIT License. #include "pch.h" #include "ConfigurationUnitResultInformation.h" -#include "ConfigurationUnitResultInformation.g.cpp" #include "AppInstallerErrors.h" namespace winrt::Microsoft::Management::Configuration::implementation @@ -26,7 +25,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation } } - void ConfigurationUnitResultInformation::Initialize(const Configuration::ConfigurationUnitResultInformation& other) + void ConfigurationUnitResultInformation::Initialize(const Configuration::IConfigurationUnitResultInformation& other) { m_resultCode = other.ResultCode(); m_description = other.Description(); diff --git a/src/Microsoft.Management.Configuration/ConfigurationUnitResultInformation.h b/src/Microsoft.Management.Configuration/ConfigurationUnitResultInformation.h @@ -1,16 +1,16 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma once -#include "ConfigurationUnitResultInformation.g.h" +#include "winrt/Microsoft.Management.Configuration.h" namespace winrt::Microsoft::Management::Configuration::implementation { - struct ConfigurationUnitResultInformation : ConfigurationUnitResultInformationT<ConfigurationUnitResultInformation> + struct ConfigurationUnitResultInformation : winrt::implements<ConfigurationUnitResultInformation, IConfigurationUnitResultInformation> { ConfigurationUnitResultInformation() = default; #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) - void Initialize(const Configuration::ConfigurationUnitResultInformation& other); + void Initialize(const Configuration::IConfigurationUnitResultInformation& other); void Initialize(hresult resultCode, std::wstring_view description); void Initialize(hresult resultCode, hstring description); void Initialize(hresult resultCode, ConfigurationUnitResultSource resultSource); diff --git a/src/Microsoft.Management.Configuration/DiagnosticInformation.cpp b/src/Microsoft.Management.Configuration/DiagnosticInformation.cpp @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "DiagnosticInformation.h" -#include "DiagnosticInformation.g.cpp" - -namespace winrt::Microsoft::Management::Configuration::implementation -{ - void DiagnosticInformation::Initialize(DiagnosticLevel level, std::wstring_view message) - { - m_level = level; - m_message = message; - } - - DiagnosticLevel DiagnosticInformation::Level() - { - return m_level; - } - - void DiagnosticInformation::Level(DiagnosticLevel value) - { - m_level = value; - } - - hstring DiagnosticInformation::Message() - { - return m_message; - } - - void DiagnosticInformation::Message(const hstring& value) - { - m_message = value; - } -} diff --git a/src/Microsoft.Management.Configuration/DiagnosticInformation.h b/src/Microsoft.Management.Configuration/DiagnosticInformation.h @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include "DiagnosticInformation.g.h" - -namespace winrt::Microsoft::Management::Configuration::implementation -{ - struct DiagnosticInformation : DiagnosticInformationT<DiagnosticInformation> - { - DiagnosticInformation() = default; - -#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) - void Initialize(DiagnosticLevel level, std::wstring_view message); -#endif - - DiagnosticLevel Level(); - void Level(DiagnosticLevel value); - - hstring Message(); - void Message(const hstring& value); - -#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) - private: - DiagnosticLevel m_level = DiagnosticLevel::Verbose; - hstring m_message; -#endif - }; -} - -namespace winrt::Microsoft::Management::Configuration::factory_implementation -{ - struct DiagnosticInformation : DiagnosticInformationT<DiagnosticInformation, implementation::DiagnosticInformation> - { - }; -} diff --git a/src/Microsoft.Management.Configuration/DiagnosticInformationInstance.cpp b/src/Microsoft.Management.Configuration/DiagnosticInformationInstance.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "DiagnosticInformationInstance.h" + +namespace winrt::Microsoft::Management::Configuration::implementation +{ + void DiagnosticInformationInstance::Initialize(DiagnosticLevel level, std::wstring_view message) + { + m_level = level; + m_message = message; + } + + DiagnosticLevel DiagnosticInformationInstance::Level() + { + return m_level; + } + + void DiagnosticInformationInstance::Level(DiagnosticLevel value) + { + m_level = value; + } + + hstring DiagnosticInformationInstance::Message() + { + return m_message; + } + + void DiagnosticInformationInstance::Message(const hstring& value) + { + m_message = value; + } +} diff --git a/src/Microsoft.Management.Configuration/DiagnosticInformationInstance.h b/src/Microsoft.Management.Configuration/DiagnosticInformationInstance.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "winrt/Microsoft.Management.Configuration.h" + +namespace winrt::Microsoft::Management::Configuration::implementation +{ + struct DiagnosticInformationInstance : winrt::implements<DiagnosticInformationInstance, IDiagnosticInformation> + { + DiagnosticInformationInstance() = default; + + void Initialize(DiagnosticLevel level, std::wstring_view message); + + DiagnosticLevel Level(); + void Level(DiagnosticLevel value); + + hstring Message(); + void Message(const hstring& value); + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + private: + DiagnosticLevel m_level = DiagnosticLevel::Verbose; + hstring m_message; +#endif + }; +} diff --git a/src/Microsoft.Management.Configuration/GetConfigurationUnitDetailsResult.cpp b/src/Microsoft.Management.Configuration/GetConfigurationUnitDetailsResult.cpp @@ -11,7 +11,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation m_unit = std::move(value); } - void GetConfigurationUnitDetailsResult::ResultInformation(ConfigurationUnitResultInformation value) + void GetConfigurationUnitDetailsResult::ResultInformation(IConfigurationUnitResultInformation value) { m_resultInformation = std::move(value); } @@ -21,7 +21,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation return m_unit; } - ConfigurationUnitResultInformation GetConfigurationUnitDetailsResult::ResultInformation() + IConfigurationUnitResultInformation GetConfigurationUnitDetailsResult::ResultInformation() { return m_resultInformation; } diff --git a/src/Microsoft.Management.Configuration/GetConfigurationUnitDetailsResult.h b/src/Microsoft.Management.Configuration/GetConfigurationUnitDetailsResult.h @@ -8,22 +8,21 @@ namespace winrt::Microsoft::Management::Configuration::implementation struct GetConfigurationUnitDetailsResult : GetConfigurationUnitDetailsResultT<GetConfigurationUnitDetailsResult> { using ConfigurationUnit = Configuration::ConfigurationUnit; - using ConfigurationUnitResultInformation = Configuration::ConfigurationUnitResultInformation; GetConfigurationUnitDetailsResult() = default; #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) void Unit(ConfigurationUnit value); - void ResultInformation(ConfigurationUnitResultInformation value); + void ResultInformation(IConfigurationUnitResultInformation value); #endif ConfigurationUnit Unit(); - ConfigurationUnitResultInformation ResultInformation(); + IConfigurationUnitResultInformation ResultInformation(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: ConfigurationUnit m_unit = nullptr; - ConfigurationUnitResultInformation m_resultInformation = nullptr; + IConfigurationUnitResultInformation m_resultInformation; #endif }; } diff --git a/src/Microsoft.Management.Configuration/GetConfigurationUnitSettingsResult.cpp b/src/Microsoft.Management.Configuration/GetConfigurationUnitSettingsResult.cpp @@ -12,12 +12,12 @@ namespace winrt::Microsoft::Management::Configuration::implementation { } - void GetConfigurationUnitSettingsResult::ResultInformation(const ConfigurationUnitResultInformation& resultInformation) + void GetConfigurationUnitSettingsResult::ResultInformation(const IConfigurationUnitResultInformation& resultInformation) { m_resultInformation = resultInformation; } - Configuration::ConfigurationUnitResultInformation GetConfigurationUnitSettingsResult::ResultInformation() const + IConfigurationUnitResultInformation GetConfigurationUnitSettingsResult::ResultInformation() const { return m_resultInformation; } diff --git a/src/Microsoft.Management.Configuration/GetConfigurationUnitSettingsResult.h b/src/Microsoft.Management.Configuration/GetConfigurationUnitSettingsResult.h @@ -8,21 +8,19 @@ namespace winrt::Microsoft::Management::Configuration::implementation { struct GetConfigurationUnitSettingsResult : GetConfigurationUnitSettingsResultT<GetConfigurationUnitSettingsResult> { - using ConfigurationUnitResultInformation = Configuration::ConfigurationUnitResultInformation; - GetConfigurationUnitSettingsResult(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) - void ResultInformation(const ConfigurationUnitResultInformation& resultInformation); + void ResultInformation(const IConfigurationUnitResultInformation& resultInformation); void Settings(Windows::Foundation::Collections::ValueSet&& value); #endif - ConfigurationUnitResultInformation ResultInformation() const; + IConfigurationUnitResultInformation ResultInformation() const; Windows::Foundation::Collections::ValueSet Settings(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: - ConfigurationUnitResultInformation m_resultInformation; + IConfigurationUnitResultInformation m_resultInformation; Windows::Foundation::Collections::ValueSet m_settings; #endif }; diff --git a/src/Microsoft.Management.Configuration/GetSettingsResult.cpp b/src/Microsoft.Management.Configuration/GetSettingsResult.cpp @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "GetSettingsResult.h" -#include "GetSettingsResult.g.cpp" -#include "ConfigurationUnitResultInformation.h" - -namespace winrt::Microsoft::Management::Configuration::implementation -{ - GetSettingsResult::GetSettingsResult() : - m_resultInformation(*make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>()) - { - } - - Windows::Foundation::Collections::ValueSet GetSettingsResult::Settings() - { - return m_settings; - } - - void GetSettingsResult::Settings(Windows::Foundation::Collections::ValueSet value) - { - m_settings = std::move(value); - } - - Configuration::ConfigurationUnitResultInformation GetSettingsResult::ResultInformation() - { - return m_resultInformation; - } -} diff --git a/src/Microsoft.Management.Configuration/GetSettingsResult.h b/src/Microsoft.Management.Configuration/GetSettingsResult.h @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include "GetSettingsResult.g.h" -#include "winrt/Windows.Foundation.Collections.h" - -namespace winrt::Microsoft::Management::Configuration::implementation -{ - struct GetSettingsResult : GetSettingsResultT<GetSettingsResult> - { - GetSettingsResult(); - - Windows::Foundation::Collections::ValueSet Settings(); - void Settings(Windows::Foundation::Collections::ValueSet value); - - Configuration::ConfigurationUnitResultInformation ResultInformation(); - - private: - Windows::Foundation::Collections::ValueSet m_settings = nullptr; - Configuration::ConfigurationUnitResultInformation m_resultInformation; - }; -} -namespace winrt::Microsoft::Management::Configuration::factory_implementation -{ - struct GetSettingsResult : GetSettingsResultT<GetSettingsResult, implementation::GetSettingsResult> - { - }; -} diff --git a/src/Microsoft.Management.Configuration/Microsoft.Management.Configuration.idl b/src/Microsoft.Management.Configuration/Microsoft.Management.Configuration.idl @@ -72,19 +72,19 @@ namespace Microsoft.Management.Configuration // Information on a result for a single unit of configuration. [contract(Microsoft.Management.Configuration.Contract, 1)] - runtimeclass ConfigurationUnitResultInformation + interface IConfigurationUnitResultInformation { // The error code of the failure. - HRESULT ResultCode; + HRESULT ResultCode{ get; }; // The short description of the failure. - String Description; + String Description{ get; }; // A more detailed error message appropriate for diagnosing the root cause of an error. - String Details; + String Details{ get; }; // The source of the result. - ConfigurationUnitResultSource ResultSource; + ConfigurationUnitResultSource ResultSource{ get; }; } // Provides information for a specific configuration unit setting. @@ -208,7 +208,7 @@ namespace Microsoft.Management.Configuration ConfigurationUnitState State{ get; }; // Contains information on the result of the latest attempt to apply the configuration unit. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; // Allows for control over whether this unit should be applied when the set containing it is applied. Boolean ShouldApply; @@ -243,7 +243,7 @@ namespace Microsoft.Management.Configuration ConfigurationUnitState UnitState{ get; }; // Contains information on the result of the attempt to apply the configuration unit. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; // The configuration unit whose state changed. ConfigurationUnit Unit{ get; }; @@ -300,15 +300,13 @@ namespace Microsoft.Management.Configuration // The result of applying the settings with an IConfigurationUnitProcessor. [contract(Microsoft.Management.Configuration.Contract, 1)] - runtimeclass ApplySettingsResult + interface IApplySettingsResult { - ApplySettingsResult(); - // Indicates whether a reboot is required after the settings were applied. - Boolean RebootRequired; + Boolean RebootRequired{ get; }; // The result of applying the configuration unit. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; } // Informs the caller of the result of running a Test. @@ -329,30 +327,26 @@ namespace Microsoft.Management.Configuration // The result of testing the settings with an IConfigurationUnitProcessor. [contract(Microsoft.Management.Configuration.Contract, 1)] - runtimeclass TestSettingsResult + interface ITestSettingsResult { - TestSettingsResult(); - // The result (if any) of running Test on the configuration unit. - ConfigurationTestResult TestResult; + ConfigurationTestResult TestResult{ get; }; // The result of testing the configuration unit. // This is not the response for the test, but rather contains information about the actual attempt to run the test. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; } // The result of getting the settings with an IConfigurationUnitProcessor. [contract(Microsoft.Management.Configuration.Contract, 1)] - runtimeclass GetSettingsResult + interface IGetSettingsResult { - GetSettingsResult(); - // The current state of the system for the configuration unit. - Windows.Foundation.Collections.ValueSet Settings; + Windows.Foundation.Collections.ValueSet Settings{ get; }; // The result of getting the configuration unit settings. // This is not the response for the retrieval, but rather contains information about the actual attempt to retrieve the settings. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; } // Provides access to a specific configuration unit within the runtime. @@ -366,13 +360,13 @@ namespace Microsoft.Management.Configuration Windows.Foundation.Collections.IMapView<String, Object> DirectivesOverlay{ get; }; // Determines if the system is already in the state described by the configuration unit. - TestSettingsResult TestSettings(); + ITestSettingsResult TestSettings(); // Gets the current system state for the configuration unit. - GetSettingsResult GetSettings(); + IGetSettingsResult GetSettings(); // Applies the state described in the configuration unit. - ApplySettingsResult ApplySettings(); + IApplySettingsResult ApplySettings(); } // Controls the lifetime of operations for a single configuration set. @@ -401,15 +395,13 @@ namespace Microsoft.Management.Configuration // Enables diagnostic information from the configuration system to be inspected/stored by callers. [contract(Microsoft.Management.Configuration.Contract, 1)] - runtimeclass DiagnosticInformation + interface IDiagnosticInformation { - DiagnosticInformation(); - // Indicates the importance of the diagnostic information. - DiagnosticLevel Level; + DiagnosticLevel Level{ get; }; // The diagnostic message. - String Message; + String Message{ get; }; } // Allows different runtimes to provide specialized handling of configuration processing. @@ -420,7 +412,7 @@ namespace Microsoft.Management.Configuration IConfigurationSetProcessor CreateSetProcessor(ConfigurationSet configurationSet); // Diagnostics event; useful for logging and/or verbose output. - event Windows.Foundation.EventHandler<DiagnosticInformation> Diagnostics; + event Windows.Foundation.EventHandler<IDiagnosticInformation> Diagnostics; // Indicates the minimum importance desired for diagnostics. DiagnosticLevel MinimumLevel; @@ -535,7 +527,7 @@ namespace Microsoft.Management.Configuration ConfigurationUnit Unit{ get; }; // The result of getting the configuration unit details. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; } // The result of getting the configuration set details. @@ -573,7 +565,7 @@ namespace Microsoft.Management.Configuration Boolean RebootRequired{ get; }; // The result of applying the configuration unit. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; } // The result of applying the settings for a configuration set. @@ -596,7 +588,7 @@ namespace Microsoft.Management.Configuration // The result of testing the configuration unit. // This is not the response for the test, but rather contains information about the actual attempt to run the test. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; // The result (if any) of running Test on the configuration unit. ConfigurationTestResult TestResult{ get; }; @@ -623,7 +615,7 @@ namespace Microsoft.Management.Configuration { // The result of getting the configuration unit settings. // This is not the response for the retrieval, but rather contains information about the actual attempt to retrieve the settings. - ConfigurationUnitResultInformation ResultInformation{ get; }; + IConfigurationUnitResultInformation ResultInformation{ get; }; // The current state of the system for the configuration unit. Windows.Foundation.Collections.ValueSet Settings { get; }; @@ -636,7 +628,7 @@ namespace Microsoft.Management.Configuration ConfigurationProcessor(IConfigurationSetProcessorFactory factory); // Diagnostics event; useful for logging and/or verbose output. - event Windows.Foundation.EventHandler<DiagnosticInformation> Diagnostics; + event Windows.Foundation.EventHandler<IDiagnosticInformation> Diagnostics; // Indicates the minimum importance desired for diagnostics. DiagnosticLevel MinimumLevel; @@ -688,9 +680,36 @@ namespace Microsoft.Management.Configuration Windows.Foundation.IAsyncOperation<GetConfigurationUnitSettingsResult> GetUnitSettingsAsync(ConfigurationUnit unit); } + // Top level entry point for configuration, enabling easier usage in out-of-process scenarios. + [contract(Microsoft.Management.Configuration.Contract, 1)] + interface IConfigurationStatics + { + // Creates an empty configuration unit. + ConfigurationUnit CreateConfigurationUnit(); + + // Creates an empty configuration unit. + ConfigurationSet CreateConfigurationSet(); + + // Creates a processor factory for the given handler. + Windows.Foundation.IAsyncOperation<IConfigurationSetProcessorFactory> CreateConfigurationSetProcessorFactoryAsync(String handler); + + // Creates a processor from the given factory. + ConfigurationProcessor CreateConfigurationProcessor(IConfigurationSetProcessorFactory factory); + } + + // Top level entry point for configuration, enabling easier usage in out-of-process scenarios. + [contract(Microsoft.Management.Configuration.Contract, 1)] + runtimeclass ConfigurationStaticFunctions : [default]IConfigurationStatics + { + ConfigurationStaticFunctions(); + } + /// Force midl3 to generate vector marshalling info. declare { + // Due to the way that metadata (WinMD) based marshalling works, in order for any of these to be IIterable<T>, they need to be + // included in the manifest of the package. Update the DumpProxyStubRegistrationsCommand to add any new types to make it easier + // to iterate over these collections, especially in C#. interface Windows.Foundation.Collections.IVector<ConfigurationConflict>; interface Windows.Foundation.Collections.IVector<ConfigurationSet>; interface Windows.Foundation.Collections.IVectorView<ApplyConfigurationUnitResult>; @@ -701,4 +720,32 @@ namespace Microsoft.Management.Configuration interface Windows.Foundation.Collections.IVectorView<IConfigurationUnitSettingDetails>; interface Windows.Foundation.Collections.IVectorView<TestConfigurationUnitResult>; } + + // Provides a way to centralize the distribution of interfaces relevant to specific implementations of IConfigurationSetProcessorFactory. + namespace SetProcessorFactory + { + // The same as PowerShell ExecutionPolicy: + // https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies + enum PwshConfigurationProcessorPolicy + { + Unrestricted = 0, + RemoteSigned = 1, + AllSigned = 2, + Restricted = 3, + Bypass = 4, + Undefined = 5, + Default = RemoteSigned, + }; + + // The properties provided by the "pwsh" processor factory. + interface IPwshConfigurationSetProcessorFactoryProperties + { + // The module paths to add to the processor. + // This will be in addition to any paths added by the processor and those inherent to PowerShell. + Windows.Foundation.Collections.IVectorView<String> AdditionalModulePaths; + + // The execution policy to apply; must be set before taking actions with the processor. + PwshConfigurationProcessorPolicy Policy; + }; + } } diff --git a/src/Microsoft.Management.Configuration/Microsoft.Management.Configuration.vcxproj b/src/Microsoft.Management.Configuration/Microsoft.Management.Configuration.vcxproj @@ -194,7 +194,6 @@ <ItemGroup> <ClInclude Include="ApplyConfigurationSetResult.h" /> <ClInclude Include="ApplyConfigurationUnitResult.h" /> - <ClInclude Include="ApplySettingsResult.h" /> <ClInclude Include="ConfigThreadGlobals.h" /> <ClInclude Include="ConfigurationChangeData.h" /> <ClInclude Include="ConfigurationConflict.h" /> @@ -207,14 +206,14 @@ <ClInclude Include="ConfigurationSetParserError.h" /> <ClInclude Include="ConfigurationSetParser_0_1.h" /> <ClInclude Include="ConfigurationSetParser_0_2.h" /> + <ClInclude Include="ConfigurationStaticFunctions.h" /> <ClInclude Include="ConfigurationUnit.h" /> <ClInclude Include="ConfigurationUnitResultInformation.h" /> - <ClInclude Include="DiagnosticInformation.h" /> + <ClInclude Include="DiagnosticInformationInstance.h" /> <ClInclude Include="ExceptionResultHelpers.h" /> <ClInclude Include="GetConfigurationSetDetailsResult.h" /> <ClInclude Include="GetConfigurationUnitDetailsResult.h" /> <ClInclude Include="GetConfigurationUnitSettingsResult.h" /> - <ClInclude Include="GetSettingsResult.h" /> <ClInclude Include="MutableFlag.h" /> <ClInclude Include="OpenConfigurationSetResult.h" /> <ClInclude Include="pch.h" /> @@ -222,12 +221,10 @@ <ClInclude Include="Telemetry\TraceLogging.h" /> <ClInclude Include="TestConfigurationSetResult.h" /> <ClInclude Include="TestConfigurationUnitResult.h" /> - <ClInclude Include="TestSettingsResult.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="ApplyConfigurationSetResult.cpp" /> <ClCompile Include="ApplyConfigurationUnitResult.cpp" /> - <ClCompile Include="ApplySettingsResult.cpp" /> <ClCompile Include="ConfigThreadGlobals.cpp" /> <ClCompile Include="ConfigurationChangeData.cpp" /> <ClCompile Include="ConfigurationConflict.cpp" /> @@ -239,13 +236,13 @@ <ClCompile Include="ConfigurationSetParser.cpp" /> <ClCompile Include="ConfigurationSetParser_0_1.cpp" /> <ClCompile Include="ConfigurationSetParser_0_2.cpp" /> + <ClCompile Include="ConfigurationStaticFunctions.cpp" /> <ClCompile Include="ConfigurationUnit.cpp" /> <ClCompile Include="ConfigurationUnitResultInformation.cpp" /> - <ClCompile Include="DiagnosticInformation.cpp" /> + <ClCompile Include="DiagnosticInformationInstance.cpp" /> <ClCompile Include="GetConfigurationSetDetailsResult.cpp" /> <ClCompile Include="GetConfigurationUnitDetailsResult.cpp" /> <ClCompile Include="GetConfigurationUnitSettingsResult.cpp" /> - <ClCompile Include="GetSettingsResult.cpp" /> <ClCompile Include="MutableFlag.cpp" /> <ClCompile Include="OpenConfigurationSetResult.cpp" /> <ClCompile Include="pch.cpp"> @@ -256,7 +253,6 @@ <ClCompile Include="Telemetry\TraceLogging.cpp" /> <ClCompile Include="TestConfigurationSetResult.cpp" /> <ClCompile Include="TestConfigurationUnitResult.cpp" /> - <ClCompile Include="TestSettingsResult.cpp" /> </ItemGroup> <ItemGroup> <None Include="Microsoft_Management_Configuration.def" /> diff --git a/src/Microsoft.Management.Configuration/Microsoft.Management.Configuration.vcxproj.filters b/src/Microsoft.Management.Configuration/Microsoft.Management.Configuration.vcxproj.filters @@ -27,12 +27,6 @@ <ClCompile Include="ConfigurationUnit.cpp"> <Filter>API Source</Filter> </ClCompile> - <ClCompile Include="ConfigurationUnitResultInformation.cpp"> - <Filter>API Source</Filter> - </ClCompile> - <ClCompile Include="DiagnosticInformation.cpp"> - <Filter>API Source</Filter> - </ClCompile> <ClCompile Include="GetConfigurationUnitSettingsResult.cpp"> <Filter>API Source</Filter> </ClCompile> @@ -63,15 +57,6 @@ <ClCompile Include="ConfigurationSetApplyProcessor.cpp"> <Filter>Internals</Filter> </ClCompile> - <ClCompile Include="ApplySettingsResult.cpp"> - <Filter>API Source</Filter> - </ClCompile> - <ClCompile Include="GetSettingsResult.cpp"> - <Filter>API Source</Filter> - </ClCompile> - <ClCompile Include="TestSettingsResult.cpp"> - <Filter>API Source</Filter> - </ClCompile> <ClCompile Include="GetConfigurationUnitDetailsResult.cpp"> <Filter>API Source</Filter> </ClCompile> @@ -87,6 +72,15 @@ <ClCompile Include="ConfigurationSetParser_0_2.cpp"> <Filter>Parser</Filter> </ClCompile> + <ClCompile Include="ConfigurationUnitResultInformation.cpp"> + <Filter>Internals</Filter> + </ClCompile> + <ClCompile Include="ConfigurationStaticFunctions.cpp"> + <Filter>API Source</Filter> + </ClCompile> + <ClCompile Include="DiagnosticInformationInstance.cpp"> + <Filter>Internals</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="pch.h" /> @@ -114,12 +108,6 @@ <ClInclude Include="ConfigurationUnit.h"> <Filter>API Headers</Filter> </ClInclude> - <ClInclude Include="ConfigurationUnitResultInformation.h"> - <Filter>API Headers</Filter> - </ClInclude> - <ClInclude Include="DiagnosticInformation.h"> - <Filter>API Headers</Filter> - </ClInclude> <ClInclude Include="GetConfigurationUnitSettingsResult.h"> <Filter>API Headers</Filter> </ClInclude> @@ -156,15 +144,6 @@ <ClInclude Include="ExceptionResultHelpers.h"> <Filter>Internals</Filter> </ClInclude> - <ClInclude Include="ApplySettingsResult.h"> - <Filter>API Headers</Filter> - </ClInclude> - <ClInclude Include="GetSettingsResult.h"> - <Filter>API Headers</Filter> - </ClInclude> - <ClInclude Include="TestSettingsResult.h"> - <Filter>API Headers</Filter> - </ClInclude> <ClInclude Include="GetConfigurationUnitDetailsResult.h"> <Filter>API Headers</Filter> </ClInclude> @@ -180,6 +159,15 @@ <ClInclude Include="ConfigurationSetParser_0_2.h"> <Filter>Parser</Filter> </ClInclude> + <ClInclude Include="ConfigurationUnitResultInformation.h"> + <Filter>Internals</Filter> + </ClInclude> + <ClInclude Include="ConfigurationStaticFunctions.h"> + <Filter>API Headers</Filter> + </ClInclude> + <ClInclude Include="DiagnosticInformationInstance.h"> + <Filter>Internals</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <Midl Include="Microsoft.Management.Configuration.idl" /> diff --git a/src/Microsoft.Management.Configuration/Telemetry/Telemetry.cpp b/src/Microsoft.Management.Configuration/Telemetry/Telemetry.cpp @@ -100,7 +100,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation return GetPriority(first) < GetPriority(second); } - void ProcessUnitResult(const Configuration::ConfigurationUnit unit, Configuration::ConfigurationUnitResultInformation resultInformation, ConfigRunSummaryData& result) + void ProcessUnitResult(const Configuration::ConfigurationUnit unit, const IConfigurationUnitResultInformation& resultInformation, ConfigRunSummaryData& result) { hresult resultCode = resultInformation.ResultCode(); if (FAILED(resultCode)) @@ -254,7 +254,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation const Configuration::ConfigurationUnit& unit, ConfigurationUnitIntent runIntent, std::string_view action, - const Configuration::ConfigurationUnitResultInformation& resultInformation) const noexcept try + const IConfigurationUnitResultInformation& resultInformation) const noexcept try { // We only want to send telemetry for failures of publicly available units. if (!IsTelemetryEnabled() || SUCCEEDED(static_cast<int32_t>(resultInformation.ResultCode()))) diff --git a/src/Microsoft.Management.Configuration/Telemetry/Telemetry.h b/src/Microsoft.Management.Configuration/Telemetry/Telemetry.h @@ -70,7 +70,7 @@ namespace winrt::Microsoft::Management::Configuration::implementation const Configuration::ConfigurationUnit& unit, ConfigurationUnitIntent runIntent, std::string_view action, - const Configuration::ConfigurationUnitResultInformation& resultInformation) const noexcept; + const IConfigurationUnitResultInformation& resultInformation) const noexcept; // The summary information for a specific unit intent. struct ProcessingSummaryForIntent diff --git a/src/Microsoft.Management.Configuration/TestConfigurationUnitResult.cpp b/src/Microsoft.Management.Configuration/TestConfigurationUnitResult.cpp @@ -6,30 +6,30 @@ namespace winrt::Microsoft::Management::Configuration::implementation { - void TestConfigurationUnitResult::Initialize(ConfigurationUnit unit, ConfigurationUnitResultInformation resultInformation) - { - m_unit = unit; - m_resultInformation = resultInformation; - } + void TestConfigurationUnitResult::Initialize(ConfigurationUnit unit, IConfigurationUnitResultInformation resultInformation) + { + m_unit = unit; + m_resultInformation = resultInformation; + } + + ConfigurationUnit TestConfigurationUnitResult::Unit() + { + return m_unit; + } - ConfigurationUnit TestConfigurationUnitResult::Unit() - { - return m_unit; - } + IConfigurationUnitResultInformation TestConfigurationUnitResult::ResultInformation() + { + return m_resultInformation; + } - ConfigurationUnitResultInformation TestConfigurationUnitResult::ResultInformation() - { - return m_resultInformation; - } - - void TestConfigurationUnitResult::ResultInformation(const ConfigurationUnitResultInformation& value) - { - m_resultInformation = value; - } + void TestConfigurationUnitResult::ResultInformation(const IConfigurationUnitResultInformation& value) + { + m_resultInformation = value; + } - ConfigurationTestResult TestConfigurationUnitResult::TestResult() - { - return m_testResult; + ConfigurationTestResult TestConfigurationUnitResult::TestResult() + { + return m_testResult; } void TestConfigurationUnitResult::TestResult(ConfigurationTestResult value) diff --git a/src/Microsoft.Management.Configuration/TestConfigurationUnitResult.h b/src/Microsoft.Management.Configuration/TestConfigurationUnitResult.h @@ -8,24 +8,23 @@ namespace winrt::Microsoft::Management::Configuration::implementation struct TestConfigurationUnitResult : TestConfigurationUnitResultT<TestConfigurationUnitResult> { using ConfigurationUnit = Configuration::ConfigurationUnit; - using ConfigurationUnitResultInformation = Configuration::ConfigurationUnitResultInformation; TestConfigurationUnitResult() = default; #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) - void Initialize(ConfigurationUnit unit, ConfigurationUnitResultInformation resultInformation); - void ResultInformation(const ConfigurationUnitResultInformation& value); + void Initialize(ConfigurationUnit unit, IConfigurationUnitResultInformation resultInformation); + void ResultInformation(const IConfigurationUnitResultInformation& value); void TestResult(ConfigurationTestResult value); #endif ConfigurationUnit Unit(); - ConfigurationUnitResultInformation ResultInformation(); + IConfigurationUnitResultInformation ResultInformation(); ConfigurationTestResult TestResult(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: ConfigurationUnit m_unit = nullptr; - ConfigurationUnitResultInformation m_resultInformation = nullptr; + IConfigurationUnitResultInformation m_resultInformation; ConfigurationTestResult m_testResult = ConfigurationTestResult::Unknown; #endif }; diff --git a/src/Microsoft.Management.Configuration/TestSettingsResult.cpp b/src/Microsoft.Management.Configuration/TestSettingsResult.cpp @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "TestSettingsResult.h" -#include "TestSettingsResult.g.cpp" -#include "ConfigurationUnitResultInformation.h" - -namespace winrt::Microsoft::Management::Configuration::implementation -{ - TestSettingsResult::TestSettingsResult() : - m_resultInformation(*make_self<wil::details::module_count_wrapper<implementation::ConfigurationUnitResultInformation>>()) - { - } - - ConfigurationTestResult TestSettingsResult::TestResult() - { - return m_testResult; - } - - void TestSettingsResult::TestResult(ConfigurationTestResult const& value) - { - m_testResult = value; - } - - Configuration::ConfigurationUnitResultInformation TestSettingsResult::ResultInformation() - { - return m_resultInformation; - } -} diff --git a/src/Microsoft.Management.Configuration/TestSettingsResult.h b/src/Microsoft.Management.Configuration/TestSettingsResult.h @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include "TestSettingsResult.g.h" - -namespace winrt::Microsoft::Management::Configuration::implementation -{ - struct TestSettingsResult : TestSettingsResultT<TestSettingsResult> - { - TestSettingsResult(); - - ConfigurationTestResult TestResult(); - void TestResult(ConfigurationTestResult const& value); - - Configuration::ConfigurationUnitResultInformation ResultInformation(); - - private: - ConfigurationTestResult m_testResult = ConfigurationTestResult::Unknown; - Configuration::ConfigurationUnitResultInformation m_resultInformation; - }; -} - -namespace winrt::Microsoft::Management::Configuration::factory_implementation -{ - struct TestSettingsResult : TestSettingsResultT<TestSettingsResult, implementation::TestSettingsResult> - { - }; -} diff --git a/src/Microsoft.Management.Deployment/Helpers.h b/src/Microsoft.Management.Deployment/Helpers.h @@ -1,34 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma once -#include <AppInstallerErrors.h> -#include <winget/GroupPolicy.h> -#include <wil\cppwinrt_wrl.h> +#include "Public/CoCreatableMicrosoftManagementDeploymentClass.h" namespace winrt::Microsoft::Management::Deployment::implementation { void SetComCallerName(std::string name); std::string GetComCallerName(std::string defaultNameIfNotSet); - // Enable custom code to run before creating any object through the factory. - // Currently that means requiring the overall WinGet policy to be enabled. - template <typename TCppWinRTClass> - class wrl_factory_for_winrt_com_class : public ::wil::wrl_factory_for_winrt_com_class<TCppWinRTClass> - { - public: - IFACEMETHODIMP CreateInstance(_In_opt_::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void** object) noexcept try - { - *object = nullptr; - RETURN_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::WinGet)); - - return ::wil::wrl_factory_for_winrt_com_class<TCppWinRTClass>::CreateInstance(unknownOuter, riid, object); - } - CATCH_RETURN() - }; - -#define CoCreatableMicrosoftManagementDeploymentClass(className) \ - CoCreatableClassWithFactory(className, ::winrt::Microsoft::Management::Deployment::implementation::wrl_factory_for_winrt_com_class<className>) - enum class Capability { PackageManagement, diff --git a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj @@ -198,6 +198,7 @@ <ClInclude Include="PackageVersionId.h" /> <ClInclude Include="PackageVersionInfo.h" /> <ClInclude Include="pch.h" /> + <ClInclude Include="Public\CoCreatableMicrosoftManagementDeploymentClass.h" /> <ClInclude Include="Public\ComClsids.h" /> <ClInclude Include="SourceAgreement.h" /> <ClInclude Include="UninstallOptions.h" /> diff --git a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters @@ -68,6 +68,9 @@ <ClInclude Include="CatalogPackageMetadata.h" /> <ClInclude Include="SourceAgreement.h" /> <ClInclude Include="Icon.h" /> + <ClInclude Include="Public\CoCreatableMicrosoftManagementDeploymentClass.h"> + <Filter>Public</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <Midl Include="PackageManager.idl" /> diff --git a/src/Microsoft.Management.Deployment/Public/CoCreatableMicrosoftManagementDeploymentClass.h b/src/Microsoft.Management.Deployment/Public/CoCreatableMicrosoftManagementDeploymentClass.h @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <AppInstallerErrors.h> +#include <winget/GroupPolicy.h> +#include <wil\cppwinrt_wrl.h> + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + // Enable custom code to run before creating any object through the factory. + // Currently that means requiring the overall WinGet policy to be enabled. + template <typename TCppWinRTClass> + class wrl_factory_for_winrt_com_class : public ::wil::wrl_factory_for_winrt_com_class<TCppWinRTClass> + { + public: + IFACEMETHODIMP CreateInstance(_In_opt_::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void** object) noexcept try + { + *object = nullptr; + RETURN_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::WinGet)); + + return ::wil::wrl_factory_for_winrt_com_class<TCppWinRTClass>::CreateInstance(unknownOuter, riid, object); + } + CATCH_RETURN() + }; + +#define CoCreatableMicrosoftManagementDeploymentClass(className) \ + CoCreatableClassWithFactory(className, ::winrt::Microsoft::Management::Deployment::implementation::wrl_factory_for_winrt_com_class<className>) +} diff --git a/src/Microsoft.Management.Deployment/Public/ComClsids.h b/src/Microsoft.Management.Deployment/Public/ComClsids.h @@ -11,6 +11,7 @@ #define WINGET_OUTOFPROC_COM_CLSID_InstallOptions "1095F097-EB96-453B-B4E6-1613637F3B14" #define WINGET_OUTOFPROC_COM_CLSID_UninstallOptions "E1D9A11E-9F85-4D87-9C17-2B93143ADB8D" #define WINGET_OUTOFPROC_COM_CLSID_PackageMatchFilter "D02C9DAF-99DC-429C-B503-4E504E4AB000" +#define WINGET_OUTOFPROC_COM_CLSID_ConfigurationStaticFunctions "73D763B7-2937-432F-A97A-D98A4A596126" #else #define WINGET_OUTOFPROC_COM_CLSID_PackageManager "74CB3139-B7C5-4B9E-9388-E6616DEA288C" #define WINGET_OUTOFPROC_COM_CLSID_FindPackagesOptions "1BD8FF3A-EC50-4F69-AEEE-DF4C9D3BAA96" @@ -18,6 +19,7 @@ #define WINGET_OUTOFPROC_COM_CLSID_InstallOptions "44FE0580-62F7-44D4-9E91-AA9614AB3E86" #define WINGET_OUTOFPROC_COM_CLSID_UninstallOptions "AA2A5C04-1AD9-46C4-B74F-6B334AD7EB8C" #define WINGET_OUTOFPROC_COM_CLSID_PackageMatchFilter "3F85B9F4-487A-4C48-9035-2903F8A6D9E8" +#define WINGET_OUTOFPROC_COM_CLSID_ConfigurationStaticFunctions "C9ED7917-66AB-4E31-A92A-F65F18EF7933" #endif // Clsids only used in in-proc invocation diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Commands/ConfigurationCommand.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Commands/ConfigurationCommand.cs @@ -19,6 +19,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands using Microsoft.WinGet.Configuration.Engine.Resources; using Windows.Storage; using Windows.Storage.Streams; + using WinRT; /// <summary> /// Class that deals configuration commands. @@ -233,11 +234,11 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands { this.Write(StreamType.Information, Resources.ConfigurationInitializing); - var properties = new ConfigurationProcessorFactoryProperties(); - properties.Policy = this.GetConfigurationProcessorPolicy(executionPolicy); + var factory = new PowerShellConfigurationSetProcessorFactory(); - var factory = new ConfigurationSetProcessorFactory( - ConfigurationProcessorType.Default, properties); + var properties = factory.As<IPowerShellConfigurationProcessorFactoryProperties>(); + properties.Policy = this.GetConfigurationProcessorPolicy(executionPolicy); + properties.ProcessorType = PowerShellConfigurationProcessorType.Default; return new PSConfigurationProcessor(factory, this, canUseTelemetry); } @@ -381,7 +382,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands return psConfigurationSet; } - private void LogFailedGetConfigurationUnitDetails(ConfigurationUnit unit, ConfigurationUnitResultInformation resultInformation) + private void LogFailedGetConfigurationUnitDetails(ConfigurationUnit unit, IConfigurationUnitResultInformation resultInformation) { if (resultInformation.ResultCode != null) { @@ -394,15 +395,15 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands } } - private ConfigurationProcessorPolicy GetConfigurationProcessorPolicy(ExecutionPolicy policy) + private PowerShellConfigurationProcessorPolicy GetConfigurationProcessorPolicy(ExecutionPolicy policy) { return policy switch { - ExecutionPolicy.Unrestricted => ConfigurationProcessorPolicy.Unrestricted, - ExecutionPolicy.RemoteSigned => ConfigurationProcessorPolicy.RemoteSigned, - ExecutionPolicy.AllSigned => ConfigurationProcessorPolicy.AllSigned, - ExecutionPolicy.Restricted => ConfigurationProcessorPolicy.Restricted, - ExecutionPolicy.Bypass => ConfigurationProcessorPolicy.Bypass, + ExecutionPolicy.Unrestricted => PowerShellConfigurationProcessorPolicy.Unrestricted, + ExecutionPolicy.RemoteSigned => PowerShellConfigurationProcessorPolicy.RemoteSigned, + ExecutionPolicy.AllSigned => PowerShellConfigurationProcessorPolicy.AllSigned, + ExecutionPolicy.Restricted => PowerShellConfigurationProcessorPolicy.Restricted, + ExecutionPolicy.Bypass => PowerShellConfigurationProcessorPolicy.Bypass, _ => throw new InvalidOperationException(), }; } diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Helpers/ApplyConfigurationSetProgressOutput.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Helpers/ApplyConfigurationSetProgressOutput.cs @@ -109,7 +109,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers this.cmd.CompleteProgress(this.activityId, this.activity, this.completeMessage); } - private void HandleUnitProgress(ConfigurationUnit unit, ConfigurationUnitState state, ConfigurationUnitResultInformation resultInformation) + private void HandleUnitProgress(ConfigurationUnit unit, ConfigurationUnitState state, IConfigurationUnitResultInformation resultInformation) { if (this.unitsCompleted.Contains(unit.InstanceIdentifier)) { @@ -198,7 +198,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers } } - private (string message, bool showDescription) GetUnitFailedMessage(ConfigurationUnit unit, ConfigurationUnitResultInformation resultInformation) + private (string message, bool showDescription) GetUnitFailedMessage(ConfigurationUnit unit, IConfigurationUnitResultInformation resultInformation) { if (resultInformation.ResultCode == null) { @@ -251,7 +251,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers return (string.Format(Resources.ConfigurationUnitFailed, resultCode), true); } - private string GetUnitSkippedMessage(ConfigurationUnitResultInformation resultInformation) + private string GetUnitSkippedMessage(IConfigurationUnitResultInformation resultInformation) { if (resultInformation.ResultCode == null) { diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Helpers/GetConfigurationSetDetailsProgressOutput.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Helpers/GetConfigurationSetDetailsProgressOutput.cs @@ -91,7 +91,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers this.cmd.CompleteProgress(this.activityId, this.activity, this.completeMessage); } - private void LogFailedGetConfigurationUnitDetails(ConfigurationUnit unit, ConfigurationUnitResultInformation resultInformation) + private void LogFailedGetConfigurationUnitDetails(ConfigurationUnit unit, IConfigurationUnitResultInformation resultInformation) { if (resultInformation.ResultCode != null) { diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSConfigurationProcessor.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSConfigurationProcessor.cs @@ -61,7 +61,7 @@ namespace Microsoft.WinGet.Configuration.Engine.PSObjects } } - private void LogConfigurationDiagnostics(DiagnosticInformation diagnosticInformation) + private void LogConfigurationDiagnostics(IDiagnosticInformation diagnosticInformation) { try { diff --git a/src/WinGetServer/WinGetServer.vcxproj b/src/WinGetServer/WinGetServer.vcxproj @@ -161,6 +161,7 @@ </ClCompile> <ClCompile Include="WinGetServer_s.c" /> <ClCompile Include="WinMain.cpp" /> + <ClInclude Include="WinGetServerManualActivation_Client.h" /> <ResourceCompile Include="WinGetServer.rc" /> <Manifest Include="WinGetServer.exe.manifest" /> <None Include="packages.config" /> diff --git a/src/WinGetServer/WinGetServer.vcxproj.filters b/src/WinGetServer/WinGetServer.vcxproj.filters @@ -21,6 +21,9 @@ <ClInclude Include="Utils.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="WinGetServerManualActivation_Client.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="WinMain.cpp"> diff --git a/src/WinGetServer/WinGetServerManualActivation_Client.cpp b/src/WinGetServer/WinGetServerManualActivation_Client.cpp @@ -154,4 +154,10 @@ extern "C" HRESULT WinGetServerManualActivation_CreateInstance(REFCLSID rclsid, } return result; -}- \ No newline at end of file +} + +extern "C" HRESULT WinGetServerManualActivation_Terminate() +{ + RpcBindingFree(&WinGetServerManualActivation_IfHandle); + return S_OK; +} diff --git a/src/WinGetServer/WinGetServerManualActivation_Client.h b/src/WinGetServer/WinGetServerManualActivation_Client.h @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <Windows.h> + +extern "C" HRESULT WinGetServerManualActivation_CreateInstance(REFCLSID rclsid, REFIID riid, UINT32 flags, void** out); + +extern "C" HRESULT WinGetServerManualActivation_Terminate(); diff --git a/src/WinGetServer/WinMain.cpp b/src/WinGetServer/WinMain.cpp @@ -135,8 +135,11 @@ int __stdcall wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR cmdLine, // Register all the CoCreatableClassWrlCreatorMapInclude classes RETURN_IF_FAILED(WindowsPackageManagerServerModuleRegister()); + // Manual reset event to notify the client that the server is available. + wil::unique_event manualResetEvent; + if (manualActivation) - { + { HANDLE hMutex = NULL; hMutex = CreateMutex(NULL, FALSE, TEXT("WinGetServerMutex")); RETURN_LAST_ERROR_IF_NULL(hMutex); @@ -148,20 +151,22 @@ int __stdcall wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR cmdLine, } RETURN_IF_FAILED(WindowsPackageManagerServerInitializeRPCServer()); - } - // Manual reset event to notify the client that the server is available. - wil::unique_event manualResetEvent; - if (!manualResetEvent.try_create(wil::EventOptions::ManualReset, L"WinGetServerStartEvent")) - { - manualResetEvent.open(L"WinGetServerStartEvent"); - } + if (!manualResetEvent.try_create(wil::EventOptions::ManualReset, L"WinGetServerStartEvent")) + { + manualResetEvent.open(L"WinGetServerStartEvent"); + } - manualResetEvent.SetEvent(); + manualResetEvent.SetEvent(); + } _comServerExitEvent.wait(); - manualResetEvent.reset(); + if (manualResetEvent) + { + manualResetEvent.reset(); + } + RETURN_IF_FAILED(WindowsPackageManagerServerModuleUnregister()); } CATCH_RETURN() diff --git a/src/WindowsPackageManager/ConfigurationStaticFunctions.cpp b/src/WindowsPackageManager/ConfigurationStaticFunctions.cpp @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License +#include <Unknwn.h> +#include <wil\cppwinrt_wrl.h> +#include <winrt/Microsoft.Management.Configuration.h> +#include <ComClsids.h> +#include <AppInstallerErrors.h> +#include <AppInstallerStrings.h> +#include <winget/ConfigurationSetProcessorHandlers.h> +#include <ConfigurationSetProcessorFactoryRemoting.h> +#include <winget/ILifetimeWatcher.h> +#include <winget/GroupPolicy.h> +#include <winget/Security.h> + +namespace ConfigurationShim +{ + CLSID CLSID_ConfigurationObjectLifetimeWatcher = { 0x89a8f1d4,0x1e24,0x46a4,{0x9f,0x6c,0x65,0x78,0xb0,0x47,0xf2,0xf7} }; + + struct + DECLSPEC_UUID("89a8f1d4-1e24-46a4-9f6c-6578b047f2f7") + ConfigurationObjectLifetimeWatcher : winrt::implements<ConfigurationObjectLifetimeWatcher, IUnknown> + { + }; + + struct + DECLSPEC_UUID(WINGET_OUTOFPROC_COM_CLSID_ConfigurationStaticFunctions) + ConfigurationStaticFunctionsShim : winrt::implements<ConfigurationStaticFunctionsShim, winrt::Microsoft::Management::Configuration::IConfigurationStatics> + { + ConfigurationStaticFunctionsShim() = default; + + winrt::Microsoft::Management::Configuration::ConfigurationUnit CreateConfigurationUnit() + { + auto result = m_statics.CreateConfigurationUnit(); + result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); + return result; + } + + winrt::Microsoft::Management::Configuration::ConfigurationSet CreateConfigurationSet() + { + auto result = m_statics.CreateConfigurationSet(); + result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); + return result; + } + + winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory> CreateConfigurationSetProcessorFactoryAsync(winrt::hstring const& handler) + { + std::wstring lowerHandler = AppInstaller::Utility::ToLower(handler); + + co_await winrt::resume_background(); + + winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory result; + + if (lowerHandler == AppInstaller::Configuration::PowerShellHandlerIdentifier) + { + result = AppInstaller::CLI::ConfigurationRemoting::CreateOutOfProcessFactory(); + } + + if (result) + { + // Objects returned here *must* implement ILifetimeWatcher for now. + // If we create OOP objects implemented elsewhere in the future, decide then how to exempt those while still ensuring we + // don't accidentally create a lifetime bug by basing it solely off the QI result. + result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); + co_return result; + } + + AICLI_LOG(Config, Error, << "Unknown handler in CreateConfigurationSetProcessorFactory: " << AppInstaller::Utility::ConvertToUTF8(handler)); + THROW_HR(E_NOT_SET); + } + + winrt::Microsoft::Management::Configuration::ConfigurationProcessor CreateConfigurationProcessor(winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory const& factory) + { + auto result = m_statics.CreateConfigurationProcessor(factory); + result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); + return result; + } + + private: + // Returns a lifetime watcher object that is currently *unowned*. + IUnknown* CreateLifetimeWatcher() + { + ::Microsoft::WRL::ComPtr<IClassFactory> factory; + THROW_IF_FAILED(::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::OutOfProc>::GetModule().GetClassObject(CLSID_ConfigurationObjectLifetimeWatcher, IID_PPV_ARGS(&factory))); + winrt::com_ptr<IUnknown> out; + THROW_IF_FAILED(factory->CreateInstance(nullptr, __uuidof(IUnknown), out.put_void())); + return out.detach(); + } + + winrt::Microsoft::Management::Configuration::ConfigurationStaticFunctions m_statics; + }; + + // Enable custom code to run before creating any object through the factory. + template <typename TCppWinRTClass> + class ConfigurationFactory : public ::wil::wrl_factory_for_winrt_com_class<TCppWinRTClass> + { + public: + IFACEMETHODIMP CreateInstance(_In_opt_::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void** object) noexcept try + { + *object = nullptr; + // TODO: Review of policies for configuration + RETURN_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::WinGet)); + // TODO: Review of security for configuration OOP + RETURN_HR_IF(E_ACCESSDENIED, !::AppInstaller::Security::IsCOMCallerSameUserAndIntegrityLevel()); + + return ::wil::wrl_factory_for_winrt_com_class<TCppWinRTClass>::CreateInstance(unknownOuter, riid, object); + } + CATCH_RETURN() + }; + +#define CoCreatableMicrosoftManagementConfigurationClass(className) \ + CoCreatableClassWithFactory(className, ::ConfigurationShim::ConfigurationFactory<className>) + + // Disable 6388 as it seems to be falsely warning +#pragma warning(push) +#pragma warning(disable : 6388) + CoCreatableCppWinRtClass(ConfigurationObjectLifetimeWatcher); + CoCreatableMicrosoftManagementConfigurationClass(ConfigurationStaticFunctionsShim); +#pragma warning(pop) +} diff --git a/src/WindowsPackageManager/WindowsPackageManager.vcxproj b/src/WindowsPackageManager/WindowsPackageManager.vcxproj @@ -227,9 +227,9 @@ <ClCompile> <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</TreatWarningAsError> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</TreatWarningAsError> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</TreatWarningAsError> @@ -245,6 +245,9 @@ <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</EnablePREfast> <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</EnablePREfast> <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</EnablePREfast> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">4324</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">4324</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4324</DisableSpecificWarnings> </ClCompile> <Link> <GenerateWindowsMetadata>false</GenerateWindowsMetadata> @@ -271,12 +274,13 @@ <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'"> <ClCompile> <PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</TreatWarningAsError> <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ControlFlowGuard> <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">stdcpp17</LanguageStandard> <SDLCheck Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</SDLCheck> <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnablePREfast> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4324</DisableSpecificWarnings> </ClCompile> <Manifest> <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> @@ -288,10 +292,10 @@ <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</TreatWarningAsError> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</TreatWarningAsError> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</TreatWarningAsError> @@ -312,6 +316,10 @@ <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">false</EnablePREfast> <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</EnablePREfast> <EnablePREfast Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</EnablePREfast> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">4324</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">4324</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4324</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4324</DisableSpecificWarnings> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -350,10 +358,10 @@ <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">$(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\AppInstallerSharedLib\Public;$(ProjectDir)..\JsonCppLib;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">true</TreatWarningAsError> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">true</TreatWarningAsError> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">true</TreatWarningAsError> @@ -378,6 +386,10 @@ <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">MultiThreaded</RuntimeLibrary> <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">MultiThreaded</RuntimeLibrary> <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">MultiThreaded</RuntimeLibrary> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM'">4324</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|ARM64'">4324</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|Win32'">4324</DisableSpecificWarnings> + <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='ReleaseStatic|x64'">4324</DisableSpecificWarnings> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -414,6 +426,7 @@ <ClInclude Include="WindowsPackageManager.h" /> </ItemGroup> <ItemGroup> + <ClCompile Include="ConfigurationStaticFunctions.cpp" /> <ClCompile Include="main.cpp" /> <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> </ItemGroup> @@ -438,6 +451,9 @@ <ProjectReference Include="..\JsonCppLib\JsonCppLib.vcxproj"> <Project>{82b39fda-e86b-4713-a873-9d56de00247a}</Project> </ProjectReference> + <ProjectReference Include="..\Microsoft.Management.Configuration\Microsoft.Management.Configuration.vcxproj"> + <Project>{ca460806-5e41-4e97-9a3d-1d74b433b663}</Project> + </ProjectReference> <ProjectReference Include="..\Microsoft.Management.Deployment\Microsoft.Management.Deployment.vcxproj"> <Project>{1cc41a9a-ae66-459d-9210-1e572dd7be69}</Project> </ProjectReference> diff --git a/src/WindowsPackageManager/WindowsPackageManager.vcxproj.filters b/src/WindowsPackageManager/WindowsPackageManager.vcxproj.filters @@ -26,6 +26,9 @@ <ClCompile Include="$(GeneratedFilesDir)module.g.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="ConfigurationStaticFunctions.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> diff --git a/src/WindowsPackageManager/main.cpp b/src/WindowsPackageManager/main.cpp @@ -26,6 +26,9 @@ CoCreatableClassWrlCreatorMapInclude(UninstallOptions); CoCreatableClassWrlCreatorMapInclude(PackageMatchFilter); CoCreatableClassWrlCreatorMapInclude(PackageManagerSettings); +// Shim for configuration static functions +CoCreatableClassWrlCreatorMapInclude(ConfigurationStaticFunctionsShim); + extern "C" { int WINDOWS_PACKAGE_MANAGER_API_CALLING_CONVENTION WindowsPackageManagerCLIMain(int argc, wchar_t const** argv) try diff --git a/templates/e2e-test.template.yml b/templates/e2e-test.template.yml @@ -5,35 +5,50 @@ parameters: type: boolean - name: filter type: string +- name: comTrace + type: boolean + default: false steps: -- task: VSTest@2 - displayName: Run ${{ parameters.title }} - inputs: - testRunTitle: ${{ parameters.title }} - testSelector: 'testAssemblies' - testAssemblyVer2: '$(buildOutDir)\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' - testFiltercriteria: ${{ parameters.filter }} - runSettingsFile: '$(buildOutDir)\AppInstallerCLIE2ETests\Test.runsettings' - ${{ if eq(parameters.isPackaged, true) }}: - overrideTestrunParameters: '-PackagedContext true - -AICLIPackagePath $(packageLayoutDir) - -AICLIPath AppInstallerCLI\winget.exe - -LooseFileRegistration true - -InvokeCommandInDesktopPackage true - -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex - -MsiTestInstallerPath $(System.DefaultWorkingDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTestMsiInstaller.msi - -MsixTestInstallerPath $(Build.ArtifactStagingDirectory)\AppInstallerTestMsixInstaller.msix - -ExeTestInstallerPath $(buildOutDir)\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe - -PackageCertificatePath $(AppInstallerTest.secureFilePath) - -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client\Microsoft.WinGet.Client.psd1' - ${{ else }}: - overrideTestrunParameters: '-PackagedContext false - -AICLIPath $(packageLayoutDir)\AppInstallerCLI\winget.exe - -InvokeCommandInDesktopPackage false - -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex - -MsiTestInstallerPath $(System.DefaultWorkingDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTestMsiInstaller.msi - -MsixTestInstallerPath $(Build.ArtifactStagingDirectory)\AppInstallerTestMsixInstaller.msix - -ExeTestInstallerPath $(buildOutDir)\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe - -PackageCertificatePath $(AppInstallerTest.secureFilePath) - -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client\Microsoft.WinGet.Client.psd1' + - task: CmdLine@2 + displayName: Start COM trace for ${{ parameters.title }} + condition: and(succeededOrFailed(), ${{ parameters.comTrace }}) + inputs: + script: 'wpr -start $(Build.SourcesDirectory)\tools\COMTrace\ComTrace.wprp -filemode' + + - task: VSTest@2 + displayName: Run ${{ parameters.title }} + inputs: + testRunTitle: ${{ parameters.title }} + testSelector: 'testAssemblies' + testAssemblyVer2: '$(buildOutDir)\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' + testFiltercriteria: ${{ parameters.filter }} + runSettingsFile: '$(buildOutDir)\AppInstallerCLIE2ETests\Test.runsettings' + ${{ if eq(parameters.isPackaged, true) }}: + overrideTestrunParameters: '-PackagedContext true + -AICLIPackagePath $(packageLayoutDir) + -AICLIPath AppInstallerCLI\winget.exe + -LooseFileRegistration true + -InvokeCommandInDesktopPackage true + -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex + -MsiTestInstallerPath $(System.DefaultWorkingDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTestMsiInstaller.msi + -MsixTestInstallerPath $(Build.ArtifactStagingDirectory)\AppInstallerTestMsixInstaller.msix + -ExeTestInstallerPath $(buildOutDir)\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe + -PackageCertificatePath $(AppInstallerTest.secureFilePath) + -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client\Microsoft.WinGet.Client.psd1' + ${{ else }}: + overrideTestrunParameters: '-PackagedContext false + -AICLIPath $(packageLayoutDir)\AppInstallerCLI\winget.exe + -InvokeCommandInDesktopPackage false + -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex + -MsiTestInstallerPath $(System.DefaultWorkingDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTestMsiInstaller.msi + -MsixTestInstallerPath $(Build.ArtifactStagingDirectory)\AppInstallerTestMsixInstaller.msix + -ExeTestInstallerPath $(buildOutDir)\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe + -PackageCertificatePath $(AppInstallerTest.secureFilePath) + -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client\Microsoft.WinGet.Client.psd1' + + - task: CmdLine@2 + displayName: Complete COM trace for ${{ parameters.title }} + condition: and(succeededOrFailed(), ${{ parameters.comTrace }}) + inputs: + script: 'wpr -stop "$(artifactsDir)\ComTrace - ${{ parameters.title }}.etl"' diff --git a/tools/COMTrace/ComTrace.wprp b/tools/COMTrace/ComTrace.wprp @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<WindowsPerformanceRecorder Version="1.0" Author="Microsoft Corporation" Copyright="Microsoft Corporation" Company="Microsoft Corporation"> + <Profiles> + <SystemCollector Id="SystemCollector" Name="NT Kernel Logger"> + <BufferSize Value="1024"/> + <Buffers Value="32"/> + </SystemCollector> + + <EventCollector Id="EventCollector_MicrosoftWindowsCOMTrace" Name="MicrosoftWindowsCOMTraceCollector"> + <BufferSize Value="64" /> + <Buffers Value="4" /> + </EventCollector> + + <SystemProvider Id="SystemProviderVerbose"> + <Keywords> + <Keyword Value="ProcessThread"/> + </Keywords> + </SystemProvider> + + <EventProvider Id="EventProvider_MicrosoftWindowsComTraceLog" Name="1AFF6089-E863-4D36-BDFD-3581F07440BE" NonPagedMemory="true" EventKey="true"> + </EventProvider> + <EventProvider Id="EventProvider_MicrosoftWindowsComBaseWpp" Name="bda92ae8-9f11-4d49-ba1d-a4c2abca692e" NonPagedMemory="true" EventKey="true"> + <Keywords> + <Keyword Value="0x3"/> + </Keywords> + </EventProvider> + <EventProvider Id="EventProvider_MicrosoftWindowsDcomScmWpp" Name="9474a749-a98d-4f52-9f45-5b20247e4f01" NonPagedMemory="true" EventKey="true"> + <Keywords> + <Keyword Value="0x3"/> + </Keywords> + </EventProvider> + + <Profile Id="MicrosoftWindowsCOMTrace.Verbose.File" Name="MicrosoftWindowsCOMTrace" Description="Microsoft-Windows-COMTrace" LoggingMode="File" DetailLevel="Verbose"> + <Collectors> + <SystemCollectorId Value="SystemCollector"> + <SystemProviderId Value="SystemProviderVerbose"/> + </SystemCollectorId> + <EventCollectorId Value="EventCollector_MicrosoftWindowsCOMTrace"> + <EventProviders> + <EventProviderId Value="EventProvider_MicrosoftWindowsComTraceLog" /> + <EventProviderId Value="EventProvider_MicrosoftWindowsComBaseWpp" /> + <EventProviderId Value="EventProvider_MicrosoftWindowsDcomScmWpp" /> + </EventProviders> + </EventCollectorId> + </Collectors> + </Profile> + + </Profiles> +</WindowsPerformanceRecorder>