Updates project to add powershell module

This commit is contained in:
Ryan Newington
2023-02-04 09:38:01 +11:00
parent 843535a0ba
commit 4ad11d5a63
21 changed files with 1061 additions and 433 deletions
@@ -0,0 +1,24 @@
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
namespace Lithnet.CredentialProvider.RegistrationTool
{
internal static class AssemblyContextResourceLoader
{
private static readonly DependencyAssemblyLoadContext dependencyLoadContext = new DependencyAssemblyLoadContext();
public static Assembly LoadIntoAlc(Stream stream)
{
return dependencyLoadContext.LoadFromStream(stream);
}
private class DependencyAssemblyLoadContext : AssemblyLoadContext
{
protected override Assembly Load(AssemblyName assemblyName)
{
return null;
}
}
}
}
@@ -0,0 +1,23 @@
using System;
namespace Lithnet.CredentialProvider.RegistrationTool
{
public class CredentialProviderRegistrationData
{
public bool IsComRegistered { get; set; }
public bool IsCredentialProviderRegistered { get; set; }
public bool IsCredentalProviderEnabled { get; set; }
public string CredentialProviderName { get; set; }
public Guid Clsid { get; set; }
public string ProgId { get; set; }
public string DllPath { get; set; }
public DllType DllType { get; set; }
}
}
@@ -0,0 +1,443 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace Lithnet.CredentialProvider.RegistrationTool
{
public static class CredentialProviderRegistrationServices
{
public static bool IsManagedAssembly(string path)
{
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var peReader = new PEReader(fs))
{
if (!peReader.HasMetadata)
{
return false;
}
MetadataReader reader = peReader.GetMetadataReader();
return reader.IsAssembly;
}
}
}
public static IEnumerable<CredentialProviderRegistrationData> GetCredentalProviders()
{
var cpKeys = Registry.LocalMachine.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers");
foreach (var clsid in cpKeys.GetSubKeyNames())
{
if (Guid.TryParse(clsid, out Guid result))
{
yield return GetCredentialProvider(result);
}
}
}
public static CredentialProviderRegistrationData GetCredentialProvider(Type type)
{
var comGuid = GetComGuid(type);
return GetCredentialProvider(comGuid);
}
public static CredentialProviderRegistrationData GetCredentialProvider(string progId)
{
var clsid = GetClsidFromProgId(progId);
return GetCredentialProvider(clsid);
}
public static CredentialProviderRegistrationData GetCredentialProvider(Guid clsid)
{
CredentialProviderRegistrationData data = new CredentialProviderRegistrationData();
data.Clsid = clsid;
var clsidKey = Registry.ClassesRoot.OpenSubKey($@"CLSID\{clsid:B}");
if (clsidKey != null)
{
var inprocKey = clsidKey.OpenSubKey("InprocServer32");
data.IsComRegistered = inprocKey != null;
if (data.IsComRegistered)
{
var coreLib = inprocKey.GetValue(string.Empty) as string;
if (string.IsNullOrWhiteSpace(coreLib))
{
data.IsComRegistered = false;
}
else
{
if (string.Equals(coreLib, "mscoree.dll", StringComparison.OrdinalIgnoreCase))
{
data.DllType = DllType.NetFramework;
data.DllPath = inprocKey.GetValue("CodeBase") as string;
}
else if (coreLib.EndsWith(".comhost.dll", StringComparison.OrdinalIgnoreCase))
{
data.DllType = DllType.NetCore;
var i = coreLib.IndexOf(".comhost.dll", StringComparison.OrdinalIgnoreCase);
data.DllPath = coreLib.Substring(0, i) + ".dll";
}
else
{
data.DllType = DllType.Native;
data.DllPath = coreLib;
}
}
}
}
data.ProgId = Registry.ClassesRoot.OpenSubKey($@"CLSID\{clsid:B}\ProgId")?.GetValue(string.Empty) as string;
var cpkey = Registry.LocalMachine.OpenSubKey($@"Software\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{clsid:B}");
data.IsCredentialProviderRegistered = cpkey != null;
if (data.IsCredentialProviderRegistered)
{
int? disabled = cpkey.GetValue("Disabled", 0) as int?;
data.IsCredentalProviderEnabled = disabled == null || disabled == 0;
data.CredentialProviderName = cpkey.GetValue(string.Empty) as string;
}
return data;
}
public static void UnregisterCredentialProvider(Type type, bool unregisterCom)
{
DeleteCredentialProviderRegistration(type);
if (unregisterCom)
{
if (IsFrameworkType(type))
{
UnregisterFrameworkAssembly(type);
}
else
{
UnregisterNetCoreAssembly(type);
}
}
}
public static void UnregisterCredentialProvider(Guid clsid, bool unregisterCom)
{
DeleteCredentialProviderRegistration(clsid);
if (unregisterCom)
{
UnregisterClass(clsid);
}
}
public static void RegisterCredentialProvider(Type type)
{
CreateCredentialProviderRegistration(type);
if (IsFrameworkType(type))
{
RegisterFrameworkAssembly(type);
}
else
{
RegisterNetCoreAssembly(type);
}
}
public static void DisableCredentialProvider(Type type)
{
var comGuid = GetComGuid(type);
DisableCredentialProvider(comGuid);
}
public static void DisableCredentialProvider(Guid comGuid)
{
var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{comGuid:B}", true);
key?.SetValue("Disabled", 1);
}
public static void EnableCredentialProvider(string progId)
{
var clsid = GetClsidFromProgId(progId);
EnableCredentialProvider(clsid);
}
public static void DisableCredentialProvider(string progId)
{
var clsid = GetClsidFromProgId(progId);
DisableCredentialProvider(clsid);
}
public static void EnableCredentialProvider(Guid comGuid)
{
var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{comGuid:B}", true);
key?.SetValue("Disabled", 0);
}
public static void EnableCredentialProvider(Type type)
{
var comGuid = GetComGuid(type);
EnableCredentialProvider(comGuid);
}
private static void CreateCredentialProviderRegistration(Type t)
{
var comGuid = GetComGuid(t);
var typeName = GetTypeFullName(t);
var key = Registry.LocalMachine.CreateSubKey($@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{comGuid:B}", true);
key.SetValue(null, typeName);
}
private static void DeleteCredentialProviderRegistration(Type t)
{
var comGuid = GetComGuid(t);
DeleteCredentialProviderRegistration(comGuid);
}
private static void DeleteCredentialProviderRegistration(Guid clsid)
{
Registry.LocalMachine.DeleteSubKeyTree($@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{clsid:B}", false);
}
private static void RegisterNetCoreAssembly(Type t)
{
var comGuid = GetComGuid(t);
var typeName = GetTypeFullName(t);
var progId = GetComProgId(t);
var assemblyLocation = GetTypeAssemblyLocation(t);
var dir = Path.GetDirectoryName(assemblyLocation);
var assemblyFile = Path.GetFileNameWithoutExtension(assemblyLocation);
var comHostLocation = Path.Combine(dir, assemblyFile + ".comhost.dll");
var rootClsid = Registry.LocalMachine.CreateSubKey($@"Software\Classes\CLSID\{comGuid:B}", true);
rootClsid.SetValue(null, "CoreCLR COMHost Server");
var inprocKey = rootClsid.CreateSubKey("InprocServer32", true);
inprocKey.SetValue(null, comHostLocation);
inprocKey.SetValue("ThreadingModel", "Both");
var progIdKey = rootClsid.CreateSubKey("ProgId", true);
progIdKey.SetValue(null, progId);
var progIdRoot = Registry.LocalMachine.CreateSubKey($@"Software\Classes\{progId}", true);
progIdRoot.SetValue(null, typeName);
var progIdSubKey = progIdRoot.CreateSubKey("CLSID");
progIdSubKey.SetValue(null, comGuid.ToString("B"));
}
private static void UnregisterNetCoreAssembly(Type t)
{
var comGuid = GetComGuid(t);
var progId = GetComProgId(t);
UnregisterClass(comGuid, progId);
}
private static void UnregisterClass(Guid? clsid, string progId)
{
if (clsid != null)
{
Registry.LocalMachine.DeleteSubKeyTree($@"Software\Classes\CLSID\{clsid}", false);
}
if (!string.IsNullOrWhiteSpace(progId))
{
Registry.LocalMachine.DeleteSubKeyTree($@"Software\Classes\{progId}", false);
}
}
private static void RegisterFrameworkAssembly(Type t)
{
var comGuid = GetComGuid(t);
var typeName = GetTypeFullName(t);
var progId = GetComProgId(t);
var rootClsid = Registry.LocalMachine.CreateSubKey($@"Software\Classes\CLSID\{comGuid:B}", true);
rootClsid.SetValue(null, typeName);
rootClsid.CreateSubKey("Implemented Categories");
rootClsid.CreateSubKey(@"Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}");
var inprocKey = rootClsid.CreateSubKey("InprocServer32", true);
inprocKey.SetValue(null, "mscoree.dll");
inprocKey.SetValue("ThreadingModel", "Both");
inprocKey.SetValue("Class", typeName);
inprocKey.SetValue("RuntimeVersion", "v4.0.30319");
inprocKey.SetValue("Assembly", GetTypeAssemblyName(t));
inprocKey.SetValue("CodeBase", GetTypeAssemblyLocation(t));
var progIdKey = rootClsid.CreateSubKey("ProgId", true);
progIdKey.SetValue(null, progId);
var progIdRoot = Registry.LocalMachine.CreateSubKey($@"Software\Classes\{progId}", true);
progIdRoot.SetValue(null, typeName);
var progIdSubKey = progIdRoot.CreateSubKey("CLSID");
progIdSubKey.SetValue(null, comGuid.ToString("B"));
}
private static void UnregisterFrameworkAssembly(Type t)
{
var comGuid = GetComGuid(t);
var progId = GetComProgId(t);
UnregisterClass(comGuid, progId);
}
public static void UnregisterClass(Guid clsid)
{
string progid = null;
try
{
progid = GetProgIdFromClasid(clsid);
}
catch (NotFoundException) { }
UnregisterClass(clsid, progid);
}
public static void UnregisterClass(string progId)
{
Guid? clsid = null;
try
{
clsid = GetClsidFromProgId(progId);
}
catch (NotFoundException) { }
UnregisterClass(clsid, progId);
}
public static Guid GetClsidFromProgId(string progId)
{
var value = Registry.ClassesRoot.OpenSubKey($@"{progId}\CLSID")?.GetValue(string.Empty) as string;
if (string.IsNullOrWhiteSpace(value))
{
throw new ClsidNotFoundException($"The clsid for ProgId was not found {progId}");
}
return Guid.Parse(value);
}
public static string GetProgIdFromClasid(Guid clsid)
{
var value = Registry.ClassesRoot.OpenSubKey($@"CLSID\{clsid:B}\ProgId")?.GetValue(string.Empty) as string;
if (string.IsNullOrWhiteSpace(value))
{
throw new ProgIdNotFoundException($"The ProgId for clsid was not found {clsid}");
}
return value;
}
private static string GetTypeAssemblyLocation(Type type)
{
return type.Assembly.Location;
}
private static string GetTypeAssemblyName(Type type)
{
return type.Assembly.FullName;
}
private static string GetTypeClassName(Type type)
{
return type.Name;
}
private static string GetTypeFullName(Type type)
{
return type.FullName;
}
private static Guid GetComGuid(Type type)
{
var typeId = type.GetCustomAttributeValue("GuidAttribute");
if (typeId == null)
{
throw new ArgumentException($"The type {type.Name} does not have the Guid attribute present");
}
return new Guid(typeId);
}
private static string GetComProgId(Type type)
{
var typeId = type.GetCustomAttributeValue("ProgIdAttribute");
if (typeId == null)
{
throw new ArgumentException($"The type {type.Name} does not have the ProgId attribute present");
}
return typeId;
}
private static bool IsFrameworkType(Type type)
{
return IsFrameworkAssembly(type.Assembly);
}
private static bool IsFrameworkAssembly(Assembly assembly)
{
var framework = assembly.GetCustomAttributeValue("TargetFrameworkAttribute");
return framework.StartsWith(".NETFramework");
}
private static string GetCustomAttributeValue(this Type type, string attributeName)
{
var cads = type.GetCustomAttributesData();
foreach (CustomAttributeData cad in cads.Where(a => a.AttributeType.Name == attributeName))
{
return cad.ConstructorArguments.FirstOrDefault().Value as string;
}
return String.Empty;
}
private static string GetCustomAttributeValue(this Assembly assembly, string attributeName)
{
foreach (CustomAttributeData cad in assembly.GetCustomAttributesData().Where(a => a.AttributeType.Name == attributeName))
{
return cad.ConstructorArguments.FirstOrDefault().Value as string;
}
return String.Empty;
}
public static IEnumerable<Type> GetCredentialProviders(Assembly assembly)
{
return assembly.GetExportedTypes().Where(t => t.GetInterfaces().Any(ifn => ifn.Name == "ICredentialProvider") && !t.IsAbstract && !t.IsInterface);
}
public static Assembly LoadAssembly(string assemblyPath)
{
string assemblyBasePath = Path.GetDirectoryName(assemblyPath);
List<string> paths = new List<string>();
paths.AddRange(Directory.GetFiles(assemblyBasePath));
paths.Add(typeof(object).Assembly.Location);
// needs to be the .net fx or net core fx location
paths.AddRange(Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll"));
var resolver = new PathAssemblyResolver(paths);
MetadataLoadContext mlc = new MetadataLoadContext(resolver);
return mlc.LoadFromAssemblyPath(assemblyPath);
}
}
}
@@ -0,0 +1,45 @@
using System;
using System.Management.Automation;
namespace Lithnet.CredentialProvider.RegistrationTool
{
[Cmdlet(VerbsLifecycle.Disable, "CredentialProvider", DefaultParameterSetName = "DisableByFileName")]
public class DisableCredentialProviderCmdlet : PSCmdlet
{
[Parameter(ParameterSetName = "DisableByFileName")]
public string File { get; set; }
[Parameter(ParameterSetName = "DisableByClsid")]
public Guid Clsid { get; set; }
[Parameter(ParameterSetName = "DisableByProgId")]
public string ProgId { get; set; }
protected override void ProcessRecord()
{
if (this.ParameterSetName == "DisableByFileName")
{
if (!CredentialProviderRegistrationServices.IsManagedAssembly(this.File))
{
throw new System.Exception("This tool cannot disable managed assemblies by file name. You can disable native assemblies using the CLSID or ProgID");
}
var assembly = CredentialProviderRegistrationServices.LoadAssembly(this.File);
foreach (var type in CredentialProviderRegistrationServices.GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.DisableCredentialProvider(type);
this.WriteVerbose($"Disabled credential provider {type.FullName}");
}
}
else if (this.ParameterSetName == "DisableByClsid")
{
CredentialProviderRegistrationServices.DisableCredentialProvider(this.Clsid);
}
else if (this.ParameterSetName == "DisableByProgId")
{
var clsid = CredentialProviderRegistrationServices.GetClsidFromProgId(this.ProgId);
CredentialProviderRegistrationServices.DisableCredentialProvider(clsid);
}
}
}
}
@@ -0,0 +1,10 @@
namespace Lithnet.CredentialProvider.RegistrationTool
{
public enum DllType
{
Unknown,
NetFramework,
NetCore,
Native
}
}
@@ -0,0 +1,46 @@
using System;
using System.Management.Automation;
namespace Lithnet.CredentialProvider.RegistrationTool
{
[Cmdlet(VerbsLifecycle.Enable, "CredentialProvider", DefaultParameterSetName = "EnableByFileName")]
public class EnableCredentialProviderCmdlet : PSCmdlet
{
[Parameter(ParameterSetName = "EnableByFileName")]
public string File { get; set; }
[Parameter(ParameterSetName = "EnableByClsid")]
public Guid Clsid { get; set; }
[Parameter(ParameterSetName = "EnableByProgId")]
public string ProgId { get; set; }
protected override void ProcessRecord()
{
if (this.ParameterSetName == "EnableByFileName")
{
if (!CredentialProviderRegistrationServices.IsManagedAssembly(this.File))
{
throw new System.Exception("This tool cannot enable managed assemblies by file name. You can enable native assemblies using the CLSID or ProgID");
}
var assembly = CredentialProviderRegistrationServices.LoadAssembly(this.File);
foreach (var type in CredentialProviderRegistrationServices.GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.EnableCredentialProvider(type);
this.WriteVerbose($"Enabled credential provider {type.FullName}");
}
}
else if (this.ParameterSetName == "EnableByClsid")
{
CredentialProviderRegistrationServices.EnableCredentialProvider(this.Clsid);
}
else if (this.ParameterSetName == "EnableByProgId")
{
var clsid = CredentialProviderRegistrationServices.GetClsidFromProgId(this.ProgId);
CredentialProviderRegistrationServices.EnableCredentialProvider(clsid);
}
}
}
}
@@ -0,0 +1,19 @@
using System;
namespace Lithnet.CredentialProvider
{
public class ClsidNotFoundException : NotFoundException
{
public ClsidNotFoundException() : base()
{
}
public ClsidNotFoundException(string message) : base(message)
{
}
public ClsidNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
@@ -0,0 +1,19 @@
using System;
namespace Lithnet.CredentialProvider
{
public class NotFoundException : Exception
{
public NotFoundException() : base()
{
}
public NotFoundException(string message) : base(message)
{
}
public NotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
@@ -0,0 +1,19 @@
using System;
namespace Lithnet.CredentialProvider
{
public class ProgIdNotFoundException : NotFoundException
{
public ProgIdNotFoundException() : base()
{
}
public ProgIdNotFoundException(string message) : base(message)
{
}
public ProgIdNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
@@ -0,0 +1,48 @@
using System;
using System.Management.Automation;
namespace Lithnet.CredentialProvider.RegistrationTool
{
[Cmdlet(VerbsCommon.Get, "CredentialProvider", DefaultParameterSetName = "None")]
public class GetCredentialProviderCmdlet : PSCmdlet
{
[Parameter(ParameterSetName = "GetByFileName")]
public string File { get; set; }
[Parameter(ParameterSetName = "GetByClsid")]
public Guid Clsid { get; set; }
[Parameter(ParameterSetName = "GetByProgId")]
public string ProgId { get; set; }
protected override void ProcessRecord()
{
if (this.ParameterSetName == "None")
{
foreach (var item in CredentialProviderRegistrationServices.GetCredentalProviders())
{
this.WriteObject(item);
}
}
else if (this.ParameterSetName == "GetByFileName")
{
var assembly = CredentialProviderRegistrationServices.LoadAssembly(this.File);
foreach (var type in CredentialProviderRegistrationServices.GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.GetCredentialProvider(type);
this.WriteVerbose($"Got credential provider {type.FullName}");
}
}
else if (this.ParameterSetName == "GetByClsid")
{
CredentialProviderRegistrationServices.GetCredentialProvider(this.Clsid);
}
else if (this.ParameterSetName == "GetByProgId")
{
var clsid = CredentialProviderRegistrationServices.GetClsidFromProgId(this.ProgId);
CredentialProviderRegistrationServices.GetCredentialProvider(clsid);
}
}
}
}
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<Platform>AnyCPU</Platform>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<None Remove="Lithnet.CredentialProvider.Management.psd1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="6.0.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
<Content Include="Lithnet.CredentialProvider.Management.psd1">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Target Name="AfterResolveReferences2" AfterTargets="ResolveAssemblyReferences">
<ItemGroup>
<EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
<LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
</EmbeddedResource>
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" />
</ItemGroup>
</Target>
</Project>
@@ -0,0 +1,124 @@
@{
# Script module or binary module file associated with this manifest.
RootModule = 'Lithnet.CredentialProvider.Management.dll'
# Version number of this module.
ModuleVersion = '1.0.0'
# Supported PSEditions
CompatiblePSEditions = @('Desktop' ,'Core')
# ID used to uniquely identify this module
GUID = '7cbafd6a-cfe0-4380-b3f3-a161a9b96792'
# Author of this module
Author = 'Lithnet Pty Ltd'
# Company or vendor of this module
CompanyName = 'Lithnet Pty Ltd'
# Copyright statement for this module
Copyright = '(c) Lithnet Pty Ltd 2023. All rights reserved.'
# Description of the functionality provided by this module
Description = 'This module provides cmdlets fot the management of Windows Credential providers'
# Minimum version of the PowerShell engine required by this module
PowerShellVersion = '5.1'
# Name of the PowerShell host required by this module
# PowerShellHostName = ''
# Minimum version of the PowerShell host required by this module
# PowerShellHostVersion = ''
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
DotNetFrameworkVersion = '4.6.1'
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
ClrVersion = '4.0'
# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''
# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()
# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = @()
# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()
# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
# NestedModules = @()
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = @()
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @('Register-CredentialProvider', 'Unregister-CredentialProvider', 'Enable-CredentialProvider', 'Disable-CredentialProvider', 'Get-CredentialProvider')
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @()
# DSC resources to export from this module
# DscResourcesToExport = @()
# List of all modules packaged with this module
# ModuleList = @()
# List of all files packaged with this module
# FileList = @()
# 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 = @{
# Tags applied to this module. These help with module discovery in online galleries.
Tags = @("Windows" ,"PSEdition_Desktop", "PSEdition_Core")
# A URL to the license for this module.
LicenseUri = 'https://github.com/lithnet/windows-credential-provider/blob/main/LICENSE'
# A URL to the main website for this project.
ProjectUri = 'https://github.com/lithnet/windows-credential-provider'
# A URL to an icon representing this module.
# IconUri = ''
# ReleaseNotes of this module
ReleaseNotes = 'https://github.com/lithnet/windows-credential-provider'
# Prerelease string of this module
# Prerelease = ''
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
RequireLicenseAcceptance = $false
# External dependent modules of this module
# ExternalModuleDependencies = @()
} # End of PSData hashtable
} # End of PrivateData hashtable
# HelpInfo URI of this module
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
}
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management.Automation;
using System.Reflection;
using System.Runtime.Loader;
namespace Lithnet.CredentialProvider.RegistrationTool
{
public class ModuleInitializer : IModuleAssemblyInitializer, IModuleAssemblyCleanup
{
public static bool IsFullFramework => typeof(object).Assembly.FullName.StartsWith("mscorlib", StringComparison.OrdinalIgnoreCase);
private Dictionary<string, Assembly> assemblies = new Dictionary<string, Assembly>();
public void OnImport()
{
Trace.WriteLine($"Initializing PowerShell module loaded in {(IsFullFramework ? "netfx" : "netcore")}");
this.PreloadAssemblies();
this.HookResolvers();
}
public void OnRemove(PSModuleInfo psModuleInfo)
{
this.UnhookResolvers();
}
private void PreloadAssemblies()
{
var executingAssembly = Assembly.GetExecutingAssembly();
foreach (string resource in executingAssembly.GetManifestResourceNames().Where(n => n.EndsWith(".dll")))
{
using (var stream = executingAssembly.GetManifestResourceStream(resource))
{
if (stream == null)
{
continue;
}
try
{
Trace.WriteLine("Preloading assembly: " + resource);
if (IsFullFramework)
{
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
this.assemblies.Add(resource, Assembly.Load(bytes));
}
else
{
this.assemblies.Add(resource, AssemblyContextResourceLoader.LoadIntoAlc(stream));
}
}
catch (Exception ex)
{
Trace.TraceError("Failed to load: {0}\r\n", resource, ex.ToString());
}
}
}
}
private void HookResolvers()
{
AppDomain.CurrentDomain.AssemblyResolve += this.ResolveAssembly;
if (!IsFullFramework)
{
this.HookAssemblyLoadContextResolver();
}
}
private void UnhookResolvers()
{
AppDomain.CurrentDomain.AssemblyResolve -= this.ResolveAssembly;
if (!IsFullFramework)
{
this.UnhookAssemblyLoadContextResolver();
}
}
private void HookAssemblyLoadContextResolver()
{
AssemblyLoadContext.Default.Resolving += this.ResolveAssembly;
}
private void UnhookAssemblyLoadContextResolver()
{
AssemblyLoadContext.Default.Resolving += this.ResolveAssembly;
}
private Assembly ResolveAssembly(object s, ResolveEventArgs e)
{
var assemblyName = new AssemblyName(e.Name);
return this.ResolveAssemblyFromCache(assemblyName);
}
private Assembly ResolveAssembly(AssemblyLoadContext defaultAlc, AssemblyName assemblyName)
{
return this.ResolveAssemblyFromCache(assemblyName);
}
private Assembly ResolveAssemblyFromCache(AssemblyName assemblyName)
{
var path = string.Format("{0}.dll", assemblyName.Name);
if (this.assemblies.ContainsKey(path))
{
return this.assemblies[path];
}
return null;
}
}
}
@@ -0,0 +1,9 @@
{
"profiles": {
"Lithnet.CredentialProvider.RegistrationTool": {
"commandName": "Project",
"commandLineArgs": "--unregister \"D:\\dev\\git\\ryannewington\\CredProvider.NET\\CredProvider.NET\\bin\\Debug\\CredProvider.NET.dll\""
//"commandLineArgs": "--register \"D:\\dev\\git\\lithnet\\windows-credential-provider\\src\\samples\\Lithnet.CredentialProvider.Sample.net6.0.x64\\bin\\Debug\\net6.0-windows\\Lithnet.CredentialProvider.Sample.net6.0.x64.dll\""
}
}
}
@@ -0,0 +1,27 @@
using System.Management.Automation;
namespace Lithnet.CredentialProvider.RegistrationTool
{
[Cmdlet(VerbsLifecycle.Register, "CredentialProvider")]
public class RegisterCredentialProviderCmdlet : PSCmdlet
{
[Parameter]
public string File { get; set; }
protected override void ProcessRecord()
{
if (!CredentialProviderRegistrationServices.IsManagedAssembly(this.File))
{
throw new System.Exception("This tool can only register managed assemblies");
}
var assembly = CredentialProviderRegistrationServices.LoadAssembly(this.File);
foreach (var type in CredentialProviderRegistrationServices.GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.RegisterCredentialProvider(type);
this.WriteVerbose($"Registered credential provider {type.FullName}");
}
}
}
}
@@ -0,0 +1,59 @@
using System;
using System.Management.Automation;
namespace Lithnet.CredentialProvider.RegistrationTool
{
[Cmdlet(VerbsLifecycle.Unregister, "CredentialProvider", DefaultParameterSetName = "UnregisterByFileName")]
public class UnregisterCredentialProviderCmdlet : PSCmdlet
{
[Parameter(ParameterSetName = "UnregisterByFileName")]
public string File { get; set; }
[Parameter(ParameterSetName = "UnregisterByClsid")]
public Guid Clsid { get; set; }
[Parameter(ParameterSetName = "UnregisterByProgId")]
public string ProgId { get; set; }
[Parameter]
public SwitchParameter UnregisterCom { get; set; }
protected override void ProcessRecord()
{
if (this.ParameterSetName == "UnregisterByFileName")
{
if (!CredentialProviderRegistrationServices.IsManagedAssembly(this.File))
{
throw new Exception("This tool cannot unregister managed assemblies by file name. You can unregister native assemblies using the CLSID or ProgID");
}
var assembly = CredentialProviderRegistrationServices.LoadAssembly(this.File);
foreach (var type in CredentialProviderRegistrationServices.GetCredentialProviders(assembly))
{
CredentialProviderRegistrationServices.UnregisterCredentialProvider(type, this.GetSwitchValue(this.UnregisterCom, nameof(this.UnregisterCom)));
this.WriteVerbose($"Unregistered credential provider {type.FullName}");
}
}
else if (this.ParameterSetName == "UnregisterByClsid")
{
CredentialProviderRegistrationServices.UnregisterCredentialProvider(this.Clsid, this.GetSwitchValue(this.UnregisterCom, nameof(this.UnregisterCom)));
}
else if (this.ParameterSetName == "UnregisterByProgId")
{
var clsid = CredentialProviderRegistrationServices.GetClsidFromProgId(this.ProgId);
CredentialProviderRegistrationServices.UnregisterCredentialProvider(clsid, this.GetSwitchValue(this.UnregisterCom, nameof(this.UnregisterCom)));
}
}
protected bool GetSwitchValue(SwitchParameter parameter, string name)
{
if (this.MyInvocation.BoundParameters.ContainsKey(name))
{
return parameter.ToBool();
}
return false;
}
}
}