Improve powershell startup time (#8341)
Major changes are as follows: - Avoid `SecuritySupport.IsProductBinary` and unnecessary AMSI/suspicious code scan at startup time - Update `CompiledScriptBlockData.IsProductCode` to avoid unnecessary calls to `IsProductBinary`, which attempts to retrieve catalog signature of the target file. - Update `PerformSecurityChecks` to skip AMSI and suspicious code scan for the `.psd1` file that contains a safe `HashtableAst` only. - Use customized `ReadOnlyBag` instead of `ImmutableHashSet` so that we can avoid loading the `System.Collections.Immutable.dll` completely. - Replace `SHA1` with `CRC32` when generating module analysis cache file name - This remove the loading of `System.Security.Cryptography.Algorithms.dll` at startup - Move `ConvertFrom-SddlString` to C# to remove the `Utility.psm1` file. - Crossgen `Microsoft.ApplicationInsights.dll` and enable tiered compilation - Even pwsh with crossgen assemblies spends a lot time in jitting at the startup, about `191.6ms` comparing with `24.7ms` for Windows PowerShell. - Jitting `Microsoft.ApplicationInsights.dll` takes about `51.6ms`. - By crossgen `Microsoft.ApplicationInsights.dll` and enable tiered compilation, the jitting time drops to about `98.9ms`.
This commit is contained in:
parent
2a469b7d0f
commit
a11810bf33
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -24,6 +24,9 @@ dotnet-uninstall-debian-packages.sh
|
|||
# Visual Studio IDE directory
|
||||
.vs/
|
||||
|
||||
# VSCode directories that are not at the repository root
|
||||
/**/.vscode/
|
||||
|
||||
# Project Rider IDE files
|
||||
.idea.powershell/
|
||||
|
||||
|
|
|
@ -1641,9 +1641,6 @@
|
|||
<Component Id="cmp2DF9FE0BD560EB7DC8489A259330C2C6" Guid="{1C027D01-228F-4878-8E05-A6EC7602253B}">
|
||||
<File Id="fil70CD54BF55F5335B82B2BED64BDB246D" KeyPath="yes" Source="$(env.ProductSourcePath)\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" />
|
||||
</Component>
|
||||
<Component Id="cmpA4E56A46B68CE37D7731DB1F96458D10" Guid="{B7F5384B-6F82-4839-ADA2-5C1C2A5FBEAE}">
|
||||
<File Id="fil2471B9979A48B7FA2E1E46E597EB337A" KeyPath="yes" Source="$(env.ProductSourcePath)\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psm1" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="dirAB5880051B03D55D6C333CF1F67C7F76" Name="PSDesiredStateConfiguration">
|
||||
<Component Id="cmp9723892C7119DFDFD3A6FAE8027B053F" Guid="{C3A2E60E-7F0F-44D0-B54E-2E4B73CE7602}">
|
||||
|
@ -2733,7 +2730,6 @@
|
|||
<ComponentRef Id="cmpB924CBBD7AE45EF70866F140D8E133E9" />
|
||||
<ComponentRef Id="cmpDC2EF4541FA5A2E63F36A8CD6C5FA51B" />
|
||||
<ComponentRef Id="cmp2DF9FE0BD560EB7DC8489A259330C2C6" />
|
||||
<ComponentRef Id="cmpA4E56A46B68CE37D7731DB1F96458D10" />
|
||||
<ComponentRef Id="cmp9723892C7119DFDFD3A6FAE8027B053F" />
|
||||
<ComponentRef Id="cmp6DAFD01CAA3A4C67185922F445EDE495" />
|
||||
<ComponentRef Id="cmp4AF592F1EDC8794BF4A3CCC2DCB717DB" />
|
||||
|
|
|
@ -2193,6 +2193,7 @@ function Start-CrossGen {
|
|||
"System.IO.Pipes.dll"
|
||||
"System.Diagnostics.FileVersionInfo.dll"
|
||||
"System.Collections.Specialized.dll"
|
||||
"Microsoft.ApplicationInsights.dll"
|
||||
)
|
||||
|
||||
# Common PowerShell libraries to crossgen
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
|
||||
<PackageReference Include="System.Threading.AccessControl" Version="4.5.0" />
|
||||
<PackageReference Include="NJsonSchema" Version="9.12.6" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#if !UNIX
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a SDDL string into an object-based representation of a security descriptor.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsData.ConvertFrom, "SddlString", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=623636", RemotingCapability = RemotingCapability.None)]
|
||||
[OutputType(typeof(SecurityDescriptorInfo))]
|
||||
public sealed class ConvertFromSddlStringCommand : PSCmdlet
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets and sets the string representing the security descriptor in SDDL syntax.
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)]
|
||||
public string Sddl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets type of rights that this SDDL string represents.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public AccessRightTypeNames Type
|
||||
{
|
||||
get { return _type; }
|
||||
set
|
||||
{
|
||||
_isTypeSet = true;
|
||||
_type = value;
|
||||
}
|
||||
}
|
||||
private AccessRightTypeNames _type;
|
||||
private bool _isTypeSet = false;
|
||||
|
||||
private string ConvertToNTAccount(SecurityIdentifier securityIdentifier)
|
||||
{
|
||||
try
|
||||
{
|
||||
return securityIdentifier?.Translate(typeof(NTAccount)).Value;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> GetApplicableAccessRights(int accessMask, AccessRightTypeNames? typeName)
|
||||
{
|
||||
List<Type> typesToExamine = new List<Type>();
|
||||
List<string> foundAccessRightNames = new List<string>();
|
||||
HashSet<int> foundAccessRightValues = new HashSet<int>();
|
||||
|
||||
if (typeName != null)
|
||||
{
|
||||
typesToExamine.Add(GetRealAccessRightType(typeName.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (AccessRightTypeNames member in Enum.GetValues(typeof(AccessRightTypeNames)))
|
||||
{
|
||||
typesToExamine.Add(GetRealAccessRightType(member));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Type accessRightType in typesToExamine)
|
||||
{
|
||||
foreach (string memberName in Enum.GetNames(accessRightType))
|
||||
{
|
||||
int memberValue = (int)Enum.Parse(accessRightType, memberName);
|
||||
if (!foundAccessRightValues.Contains(memberValue))
|
||||
{
|
||||
foundAccessRightValues.Add(memberValue);
|
||||
if ((accessMask & memberValue) == memberValue)
|
||||
{
|
||||
foundAccessRightNames.Add(memberName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foundAccessRightNames.Sort(StringComparer.OrdinalIgnoreCase);
|
||||
return foundAccessRightNames;
|
||||
}
|
||||
|
||||
private Type GetRealAccessRightType(AccessRightTypeNames typeName)
|
||||
{
|
||||
switch (typeName)
|
||||
{
|
||||
case AccessRightTypeNames.FileSystemRights:
|
||||
return typeof(FileSystemRights);
|
||||
case AccessRightTypeNames.RegistryRights:
|
||||
return typeof(RegistryRights);
|
||||
case AccessRightTypeNames.ActiveDirectoryRights:
|
||||
return typeof(System.DirectoryServices.ActiveDirectoryRights);
|
||||
case AccessRightTypeNames.MutexRights:
|
||||
return typeof(MutexRights);
|
||||
case AccessRightTypeNames.SemaphoreRights:
|
||||
return typeof(SemaphoreRights);
|
||||
case AccessRightTypeNames.EventWaitHandleRights:
|
||||
return typeof(EventWaitHandleRights);
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private string[] ConvertAccessControlListToStrings(CommonAcl acl, AccessRightTypeNames? typeName)
|
||||
{
|
||||
if (acl == null || acl.Count == 0)
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
List<string> aceStringList = new List<string>(acl.Count);
|
||||
foreach (CommonAce ace in acl)
|
||||
{
|
||||
StringBuilder aceString = new StringBuilder();
|
||||
string ntAccount = ConvertToNTAccount(ace.SecurityIdentifier);
|
||||
aceString.Append($"{ntAccount}: {ace.AceQualifier}");
|
||||
|
||||
if (ace.AceFlags != AceFlags.None)
|
||||
{
|
||||
aceString.Append($" {ace.AceFlags}");
|
||||
}
|
||||
|
||||
List<string> accessRightList = GetApplicableAccessRights(ace.AccessMask, typeName);
|
||||
if (accessRightList.Count > 0)
|
||||
{
|
||||
string accessRights = String.Join(", ", accessRightList);
|
||||
aceString.Append($" ({accessRights})");
|
||||
}
|
||||
aceStringList.Add(aceString.ToString());
|
||||
}
|
||||
|
||||
return aceStringList.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ProcessRecord method.
|
||||
/// </summary>
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
CommonSecurityDescriptor rawSecurityDescriptor = null;
|
||||
try
|
||||
{
|
||||
rawSecurityDescriptor = new CommonSecurityDescriptor(isContainer: false, isDS: false, Sddl);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var ioe = PSTraceSource.NewInvalidOperationException(e, UtilityCommonStrings.InvalidSDDL, e.Message);
|
||||
ThrowTerminatingError(new ErrorRecord(ioe, "InvalidSDDL", ErrorCategory.InvalidArgument, Sddl));
|
||||
}
|
||||
|
||||
string owner = ConvertToNTAccount(rawSecurityDescriptor.Owner);
|
||||
string group = ConvertToNTAccount(rawSecurityDescriptor.Group);
|
||||
|
||||
AccessRightTypeNames? typeToUse = _isTypeSet ? _type : (AccessRightTypeNames?) null;
|
||||
string[] discretionaryAcl = ConvertAccessControlListToStrings(rawSecurityDescriptor.DiscretionaryAcl, typeToUse);
|
||||
string[] systemAcl = ConvertAccessControlListToStrings(rawSecurityDescriptor.SystemAcl, typeToUse);
|
||||
|
||||
var outObj = new SecurityDescriptorInfo(owner, group, discretionaryAcl, systemAcl, rawSecurityDescriptor);
|
||||
WriteObject(outObj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AccessRight type names.
|
||||
/// </summary>
|
||||
public enum AccessRightTypeNames
|
||||
{
|
||||
/// <summary>
|
||||
/// FileSystemRights.
|
||||
/// </summary>
|
||||
FileSystemRights,
|
||||
|
||||
/// <summary>
|
||||
/// RegistryRights.
|
||||
/// </summary>
|
||||
RegistryRights,
|
||||
|
||||
/// <summary>
|
||||
/// ActiveDirectoryRights.
|
||||
/// </summary>
|
||||
ActiveDirectoryRights,
|
||||
|
||||
/// <summary>
|
||||
/// MutexRights.
|
||||
/// </summary>
|
||||
MutexRights,
|
||||
|
||||
/// <summary>
|
||||
/// SemaphoreRights.
|
||||
/// </summary>
|
||||
SemaphoreRights,
|
||||
|
||||
// We have 'CryptoKeyRights' in the list for Windows PowerShell, but that type is not available in .NET Core.
|
||||
// CryptoKeyRights,
|
||||
|
||||
/// <summary>
|
||||
/// EventWaitHandleRights.
|
||||
/// </summary>
|
||||
EventWaitHandleRights
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Representation of a security descriptor.
|
||||
/// </summary>
|
||||
public sealed class SecurityDescriptorInfo
|
||||
{
|
||||
internal SecurityDescriptorInfo(
|
||||
string owner,
|
||||
string group,
|
||||
string[] discretionaryAcl,
|
||||
string[] systemAcl,
|
||||
CommonSecurityDescriptor rawDescriptor)
|
||||
{
|
||||
Owner = owner;
|
||||
Group = group;
|
||||
DiscretionaryAcl = discretionaryAcl;
|
||||
SystemAcl = systemAcl;
|
||||
RawDescriptor = rawDescriptor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EventWaitHandle rights.
|
||||
/// </summary>
|
||||
public readonly string Owner;
|
||||
|
||||
/// <summary>
|
||||
/// EventWaitHandle rights.
|
||||
/// </summary>
|
||||
public readonly string Group;
|
||||
|
||||
/// <summary>
|
||||
/// EventWaitHandle rights.
|
||||
/// </summary>
|
||||
public readonly string[] DiscretionaryAcl;
|
||||
|
||||
/// <summary>
|
||||
/// EventWaitHandle rights.
|
||||
/// </summary>
|
||||
public readonly string[] SystemAcl;
|
||||
|
||||
/// <summary>
|
||||
/// EventWaitHandle rights.
|
||||
/// </summary>
|
||||
public readonly CommonSecurityDescriptor RawDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -19,7 +19,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
{
|
||||
/// <summary>
|
||||
/// Path parameter.
|
||||
/// The paths of the files to calculate a hashs.
|
||||
/// The paths of the files to calculate hash values.
|
||||
/// Resolved wildcards.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
|
@ -266,7 +266,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
catch
|
||||
{
|
||||
// Seems it will never throw! Remove?
|
||||
Exception exc = new NotSupportedException(UtilityResources.AlgorithmTypeNotSupported);
|
||||
Exception exc = new NotSupportedException(UtilityCommonStrings.AlgorithmTypeNotSupported);
|
||||
ThrowTerminatingError(new ErrorRecord(exc, "AlgorithmTypeNotSupported", ErrorCategory.NotImplemented, null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
{
|
||||
var errorId = "PathNotFound";
|
||||
var errorCategory = ErrorCategory.InvalidArgument;
|
||||
var errorMessage = string.Format(UtilityResources.PathDoesNotExist, path);
|
||||
var errorMessage = string.Format(UtilityCommonStrings.PathDoesNotExist, path);
|
||||
var exception = new ArgumentException(errorMessage);
|
||||
var errorRecord = new ErrorRecord(exception, errorId, errorCategory, path);
|
||||
WriteError(errorRecord);
|
||||
|
@ -88,7 +88,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
private void WriteInvalidDataFileError(string resolvedPath, string errorId)
|
||||
{
|
||||
var errorCategory = ErrorCategory.InvalidData;
|
||||
var errorMessage = string.Format(UtilityResources.CouldNotParseAsPowerShellDataFile, resolvedPath);
|
||||
var errorMessage = string.Format(UtilityCommonStrings.CouldNotParseAsPowerShellDataFile, resolvedPath);
|
||||
var exception = new InvalidOperationException(errorMessage);
|
||||
var errorRecord = new ErrorRecord(exception, errorId, errorCategory, resolvedPath);
|
||||
WriteError(errorRecord);
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace Microsoft.PowerShell.Commands
|
|||
/// <summary>
|
||||
/// Utility class to contain resources for the Microsoft.PowerShell.Utility module.
|
||||
/// </summary>
|
||||
[Obsolete("This class is obsolete", true)]
|
||||
public static class UtilityResources
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -171,7 +171,7 @@
|
|||
<data name="CouldNotParseAsPowerShellDataFile" xml:space="preserve">
|
||||
<value>The file '{0}' could not be parsed as a PowerShell Data File.</value>
|
||||
</data>
|
||||
<data name="TypeNotSupported" xml:space="preserve">
|
||||
<value>'{0}' is not supported in this system.</value>
|
||||
<data name="InvalidSDDL" xml:space="preserve">
|
||||
<value>Cannot construct a security descriptor from the given SDDL due to the following error: {0}</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||
<PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.5.1" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="4.5.0" />
|
||||
<PackageReference Include="System.Threading.AccessControl" Version="4.5.0" />
|
||||
<!-- the following package(s) are from https://github.com/dotnet/wcf -->
|
||||
<PackageReference Include="System.ServiceModel.Duplex" Version="4.5.3" />
|
||||
<PackageReference Include="System.ServiceModel.Http" Version="4.5.3" />
|
||||
|
|
|
@ -1,176 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
## Converts a SDDL string into an object-based representation of a security
|
||||
## descriptor
|
||||
function ConvertFrom-SddlString
|
||||
{
|
||||
[CmdletBinding(HelpUri = "https://go.microsoft.com/fwlink/?LinkId=623636")]
|
||||
param(
|
||||
## The string representing the security descriptor in SDDL syntax
|
||||
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
|
||||
[String] $Sddl,
|
||||
|
||||
## The type of rights that this SDDL string represents, if any.
|
||||
[Parameter()]
|
||||
[ValidateSet(
|
||||
"FileSystemRights", "RegistryRights", "ActiveDirectoryRights",
|
||||
"MutexRights", "SemaphoreRights", "CryptoKeyRights",
|
||||
"EventWaitHandleRights")]
|
||||
$Type
|
||||
)
|
||||
|
||||
Begin
|
||||
{
|
||||
# On CoreCLR CryptoKeyRights and ActiveDirectoryRights are not supported.
|
||||
if ($PSEdition -eq "Core" -and ($Type -eq "CryptoKeyRights" -or $Type -eq "ActiveDirectoryRights"))
|
||||
{
|
||||
$errorId = "TypeNotSupported"
|
||||
$errorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument
|
||||
$errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::TypeNotSupported -f $Type
|
||||
$exception = [System.ArgumentException]::New($errorMessage)
|
||||
$errorRecord = [System.Management.Automation.ErrorRecord]::New($exception, $errorId, $errorCategory, $null)
|
||||
$PSCmdlet.ThrowTerminatingError($errorRecord)
|
||||
}
|
||||
|
||||
## Translates a SID into a NT Account
|
||||
function ConvertTo-NtAccount
|
||||
{
|
||||
param($Sid)
|
||||
|
||||
if($Sid)
|
||||
{
|
||||
$securityIdentifier = [System.Security.Principal.SecurityIdentifier] $Sid
|
||||
|
||||
try
|
||||
{
|
||||
$ntAccount = $securityIdentifier.Translate([System.Security.Principal.NTAccount]).ToString()
|
||||
}
|
||||
catch{}
|
||||
|
||||
$ntAccount
|
||||
}
|
||||
}
|
||||
|
||||
## Gets the access rights that apply to an access mask, preferring right types
|
||||
## of 'Type' if specified.
|
||||
function Get-AccessRights
|
||||
{
|
||||
param($AccessMask, $Type)
|
||||
|
||||
if ($PSEdition -eq "Core")
|
||||
{
|
||||
## All the types of access rights understood by .NET Core
|
||||
$rightTypes = [Ordered] @{
|
||||
"FileSystemRights" = [System.Security.AccessControl.FileSystemRights]
|
||||
"RegistryRights" = [System.Security.AccessControl.RegistryRights]
|
||||
"MutexRights" = [System.Security.AccessControl.MutexRights]
|
||||
"SemaphoreRights" = [System.Security.AccessControl.SemaphoreRights]
|
||||
"EventWaitHandleRights" = [System.Security.AccessControl.EventWaitHandleRights]
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
## All the types of access rights understood by .NET
|
||||
$rightTypes = [Ordered] @{
|
||||
"FileSystemRights" = [System.Security.AccessControl.FileSystemRights]
|
||||
"RegistryRights" = [System.Security.AccessControl.RegistryRights]
|
||||
"ActiveDirectoryRights" = [System.DirectoryServices.ActiveDirectoryRights]
|
||||
"MutexRights" = [System.Security.AccessControl.MutexRights]
|
||||
"SemaphoreRights" = [System.Security.AccessControl.SemaphoreRights]
|
||||
"CryptoKeyRights" = [System.Security.AccessControl.CryptoKeyRights]
|
||||
"EventWaitHandleRights" = [System.Security.AccessControl.EventWaitHandleRights]
|
||||
}
|
||||
}
|
||||
$typesToExamine = $rightTypes.Values
|
||||
|
||||
## If they know the access mask represents a certain type, prefer its names
|
||||
## (i.e.: CreateLink for the registry over CreateDirectories for the filesystem)
|
||||
if($Type)
|
||||
{
|
||||
$typesToExamine = @($rightTypes[$Type]) + $typesToExamine
|
||||
}
|
||||
|
||||
|
||||
## Stores the access types we've found that apply
|
||||
$foundAccess = @()
|
||||
|
||||
## Store the access types we've already seen, so that we don't report access
|
||||
## flags that are essentially duplicate. Many of the access values in the different
|
||||
## enumerations have the same value but with different names.
|
||||
$foundValues = @{}
|
||||
|
||||
## Go through the entries in the different right types, and see if they apply to the
|
||||
## provided access mask. If they do, then add that to the result.
|
||||
foreach($rightType in $typesToExamine)
|
||||
{
|
||||
foreach($accessFlag in [Enum]::GetNames($rightType))
|
||||
{
|
||||
$longKeyValue = [long] $rightType::$accessFlag
|
||||
if(-not $foundValues.ContainsKey($longKeyValue))
|
||||
{
|
||||
$foundValues[$longKeyValue] = $true
|
||||
if(($AccessMask -band $longKeyValue) -eq ($longKeyValue))
|
||||
{
|
||||
$foundAccess += $accessFlag
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$foundAccess | Sort-Object
|
||||
}
|
||||
|
||||
## Converts an ACE into a string representation
|
||||
function ConvertTo-AceString
|
||||
{
|
||||
param(
|
||||
[Parameter(ValueFromPipeline)]
|
||||
$Ace,
|
||||
$Type
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
foreach($aceEntry in $Ace)
|
||||
{
|
||||
$AceString = (ConvertTo-NtAccount $aceEntry.SecurityIdentifier) + ": " + $aceEntry.AceQualifier
|
||||
if($aceEntry.AceFlags -ne "None")
|
||||
{
|
||||
$AceString += " " + $aceEntry.AceFlags
|
||||
}
|
||||
|
||||
if($aceEntry.AccessMask)
|
||||
{
|
||||
$foundAccess = Get-AccessRights $aceEntry.AccessMask $Type
|
||||
|
||||
if($foundAccess)
|
||||
{
|
||||
$AceString += " ({0})" -f ($foundAccess -join ", ")
|
||||
}
|
||||
}
|
||||
|
||||
$AceString
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process
|
||||
{
|
||||
$rawSecurityDescriptor = [Security.AccessControl.CommonSecurityDescriptor]::new($false,$false,$Sddl)
|
||||
|
||||
$owner = ConvertTo-NtAccount $rawSecurityDescriptor.Owner
|
||||
$group = ConvertTo-NtAccount $rawSecurityDescriptor.Group
|
||||
$discretionaryAcl = ConvertTo-AceString $rawSecurityDescriptor.DiscretionaryAcl $Type
|
||||
$systemAcl = ConvertTo-AceString $rawSecurityDescriptor.SystemAcl $Type
|
||||
|
||||
[PSCustomObject] @{
|
||||
Owner = $owner
|
||||
Group = $group
|
||||
DiscretionaryAcl = @($discretionaryAcl)
|
||||
SystemAcl = @($systemAcl)
|
||||
RawDescriptor = $rawSecurityDescriptor
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +1,34 @@
|
|||
@{
|
||||
GUID="1DA87E53-152B-403E-98DC-74D7B4D63D59"
|
||||
Author="PowerShell"
|
||||
CompanyName="Microsoft Corporation"
|
||||
Copyright="Copyright (c) Microsoft Corporation. All rights reserved."
|
||||
ModuleVersion="6.1.0.0"
|
||||
GUID = "1DA87E53-152B-403E-98DC-74D7B4D63D59"
|
||||
Author = "PowerShell"
|
||||
CompanyName = "Microsoft Corporation"
|
||||
Copyright = "Copyright (c) Microsoft Corporation. All rights reserved."
|
||||
ModuleVersion = "6.1.0.0"
|
||||
CompatiblePSEditions = @("Core")
|
||||
PowerShellVersion="3.0"
|
||||
CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide",
|
||||
"Out-File", "Out-String", "Get-FormatData", "Export-FormatData", "ConvertFrom-Json", "ConvertTo-Json",
|
||||
"Invoke-RestMethod", "Invoke-WebRequest", "Register-ObjectEvent", "Register-EngineEvent",
|
||||
"Wait-Event", "Get-Event", "Remove-Event", "Get-EventSubscriber", "Unregister-Event", "New-Guid",
|
||||
"New-Event", "Add-Member", "Add-Type", "Compare-Object", "ConvertTo-Html", "ConvertFrom-StringData",
|
||||
"Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression",
|
||||
"Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture",
|
||||
"Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData",
|
||||
"Join-String", "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date",
|
||||
"Start-Sleep", "Tee-Object", "Measure-Command", "Update-TypeData", "Update-FormatData",
|
||||
"Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object",
|
||||
"Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable",
|
||||
"Clear-Variable", "Export-Clixml", "Import-Clixml", "Import-PowerShellDataFile", "ConvertTo-Xml", "Select-Xml", "Write-Debug",
|
||||
"Write-Verbose", "Write-Warning", "Write-Error", "Write-Information", "Write-Output", "Set-PSBreakpoint",
|
||||
"Get-PSBreakpoint", "Remove-PSBreakpoint", "Enable-PSBreakpoint", "Disable-PSBreakpoint", "Get-PSCallStack",
|
||||
"Send-MailMessage", "Get-TraceSource", "Set-TraceSource", "Trace-Command", "Get-FileHash",
|
||||
"Get-Runspace", "Debug-Runspace", "Enable-RunspaceDebug", "Disable-RunspaceDebug",
|
||||
"Get-RunspaceDebug", "Wait-Debugger" , "Get-Uptime", "New-TemporaryFile", "Get-Verb", "Format-Hex",
|
||||
"Test-Json", "Remove-Alias", "ConvertFrom-Markdown", "Show-Markdown", "Set-MarkdownOption", "Get-MarkdownOption"
|
||||
FunctionsToExport= "Import-PowerShellDataFile"
|
||||
AliasesToExport= "fhx"
|
||||
NestedModules="Microsoft.PowerShell.Commands.Utility.dll","Microsoft.PowerShell.Utility.psm1"
|
||||
PowerShellVersion = "3.0"
|
||||
CmdletsToExport = @(
|
||||
'Export-Alias', 'Get-Alias', 'Import-Alias', 'New-Alias', 'Remove-Alias', 'Set-Alias', 'Export-Clixml',
|
||||
'Import-Clixml', 'Measure-Command', 'Trace-Command', 'ConvertFrom-Csv', 'ConvertTo-Csv', 'Export-Csv',
|
||||
'Import-Csv', 'Get-Culture', 'Format-Custom', 'Get-Date', 'Set-Date', 'Write-Debug', 'Wait-Debugger',
|
||||
'Register-EngineEvent', 'Write-Error', 'Get-Event', 'New-Event', 'Remove-Event', 'Unregister-Event',
|
||||
'Wait-Event', 'Get-EventSubscriber', 'Invoke-Expression', 'Out-File', 'Get-FileHash', 'Export-FormatData',
|
||||
'Get-FormatData', 'Update-FormatData', 'New-Guid', 'Format-Hex', 'Get-Host', 'Read-Host', 'Write-Host',
|
||||
'ConvertTo-Html', 'Write-Information', 'ConvertFrom-Json', 'ConvertTo-Json', 'Test-Json', 'Format-List',
|
||||
'Import-LocalizedData', 'Send-MailMessage', 'ConvertFrom-Markdown', 'Show-Markdown', 'Get-MarkdownOption',
|
||||
'Set-MarkdownOption', 'Add-Member', 'Get-Member', 'Compare-Object', 'Group-Object', 'Measure-Object',
|
||||
'New-Object', 'Select-Object', 'Sort-Object', 'Tee-Object', 'Register-ObjectEvent', 'Write-Output',
|
||||
'Import-PowerShellDataFile', 'Write-Progress', 'Disable-PSBreakpoint', 'Enable-PSBreakpoint',
|
||||
'Get-PSBreakpoint', 'Remove-PSBreakpoint', 'Set-PSBreakpoint', 'Get-PSCallStack', 'Export-PSSession',
|
||||
'Import-PSSession', 'Get-Random', 'Invoke-RestMethod', 'Debug-Runspace', 'Get-Runspace',
|
||||
'Disable-RunspaceDebug', 'Enable-RunspaceDebug', 'Get-RunspaceDebug', 'Start-Sleep', 'Join-String',
|
||||
'Out-String', 'Select-String', 'ConvertFrom-StringData', 'Format-Table', 'New-TemporaryFile', 'New-TimeSpan',
|
||||
'Get-TraceSource', 'Set-TraceSource', 'Add-Type', 'Get-TypeData', 'Remove-TypeData', 'Update-TypeData',
|
||||
'Get-UICulture', 'Get-Unique', 'Get-Uptime', 'Clear-Variable', 'Get-Variable', 'New-Variable',
|
||||
'Remove-Variable', 'Set-Variable', 'Get-Verb', 'Write-Verbose', 'Write-Warning', 'Invoke-WebRequest',
|
||||
'Format-Wide', 'ConvertTo-Xml', 'Select-Xml'
|
||||
)
|
||||
FunctionsToExport = @()
|
||||
AliasesToExport = @('fhx')
|
||||
NestedModules = @("Microsoft.PowerShell.Commands.Utility.dll")
|
||||
HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855960'
|
||||
}
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
@{
|
||||
GUID="1DA87E53-152B-403E-98DC-74D7B4D63D59"
|
||||
Author="PowerShell"
|
||||
CompanyName="Microsoft Corporation"
|
||||
Copyright="Copyright (c) Microsoft Corporation. All rights reserved."
|
||||
ModuleVersion="6.1.0.0"
|
||||
GUID = "1DA87E53-152B-403E-98DC-74D7B4D63D59"
|
||||
Author = "PowerShell"
|
||||
CompanyName = "Microsoft Corporation"
|
||||
Copyright = "Copyright (c) Microsoft Corporation. All rights reserved."
|
||||
ModuleVersion = "6.1.0.0"
|
||||
CompatiblePSEditions = @("Core")
|
||||
PowerShellVersion="3.0"
|
||||
CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide",
|
||||
"Out-File", "Out-String", "Get-FormatData", "Export-FormatData", "ConvertFrom-Json", "ConvertTo-Json",
|
||||
"Invoke-RestMethod", "Invoke-WebRequest", "Register-ObjectEvent", "Register-EngineEvent",
|
||||
"Wait-Event", "Get-Event", "Remove-Event", "Get-EventSubscriber", "Unregister-Event", "New-Guid",
|
||||
"New-Event", "Add-Member", "Add-Type", "Compare-Object", "ConvertTo-Html", "ConvertFrom-StringData",
|
||||
"Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression",
|
||||
"Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture",
|
||||
"Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData",
|
||||
"Join-String", "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date",
|
||||
"Start-Sleep", "Tee-Object", "Measure-Command", "Update-TypeData", "Update-FormatData",
|
||||
"Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object",
|
||||
"Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable",
|
||||
"Clear-Variable", "Export-Clixml", "Import-Clixml", "Import-PowerShellDataFile","ConvertTo-Xml", "Select-Xml", "Write-Debug",
|
||||
"Write-Verbose", "Write-Warning", "Write-Error", "Write-Information", "Write-Output", "Set-PSBreakpoint",
|
||||
"Get-PSBreakpoint", "Remove-PSBreakpoint", "New-TemporaryFile", "Enable-PSBreakpoint", "Disable-PSBreakpoint", "Get-PSCallStack",
|
||||
"Send-MailMessage", "Get-TraceSource", "Set-TraceSource", "Trace-Command", "Get-FileHash",
|
||||
"Unblock-File", "Get-Runspace", "Debug-Runspace", "Enable-RunspaceDebug", "Disable-RunspaceDebug",
|
||||
"Get-RunspaceDebug", "Wait-Debugger" , "Get-Uptime", "Get-Verb", "Format-Hex",
|
||||
"Test-Json", "Remove-Alias", "ConvertFrom-Markdown", "Show-Markdown", "Set-MarkdownOption", "Get-MarkdownOption"
|
||||
FunctionsToExport= "ConvertFrom-SddlString"
|
||||
AliasesToExport= "fhx"
|
||||
NestedModules="Microsoft.PowerShell.Commands.Utility.dll","Microsoft.PowerShell.Utility.psm1"
|
||||
PowerShellVersion = "3.0"
|
||||
CmdletsToExport = @(
|
||||
'Export-Alias', 'Get-Alias', 'Import-Alias', 'New-Alias', 'Remove-Alias', 'Set-Alias', 'Export-Clixml', 'Import-Clixml',
|
||||
'Measure-Command', 'Trace-Command', 'ConvertFrom-Csv', 'ConvertTo-Csv', 'Export-Csv', 'Import-Csv', 'Get-Culture',
|
||||
'Format-Custom', 'Get-Date', 'Set-Date', 'Write-Debug', 'Wait-Debugger', 'Register-EngineEvent', 'Write-Error',
|
||||
'Get-Event', 'New-Event', 'Remove-Event', 'Unregister-Event', 'Wait-Event', 'Get-EventSubscriber', 'Invoke-Expression',
|
||||
'Out-File', 'Unblock-File', 'Get-FileHash', 'Export-FormatData', 'Get-FormatData', 'Update-FormatData', 'New-Guid',
|
||||
'Format-Hex', 'Get-Host', 'Read-Host', 'Write-Host', 'ConvertTo-Html', 'Write-Information', 'ConvertFrom-Json',
|
||||
'ConvertTo-Json', 'Test-Json', 'Format-List', 'Import-LocalizedData', 'Send-MailMessage', 'ConvertFrom-Markdown',
|
||||
'Show-Markdown', 'Get-MarkdownOption', 'Set-MarkdownOption', 'Add-Member', 'Get-Member', 'Compare-Object', 'Group-Object',
|
||||
'Measure-Object', 'New-Object', 'Select-Object', 'Sort-Object', 'Tee-Object', 'Register-ObjectEvent', 'Write-Output',
|
||||
'Import-PowerShellDataFile', 'Write-Progress', 'Disable-PSBreakpoint', 'Enable-PSBreakpoint', 'Get-PSBreakpoint',
|
||||
'Remove-PSBreakpoint', 'Set-PSBreakpoint', 'Get-PSCallStack', 'Export-PSSession', 'Import-PSSession', 'Get-Random',
|
||||
'Invoke-RestMethod', 'Debug-Runspace', 'Get-Runspace', 'Disable-RunspaceDebug', 'Enable-RunspaceDebug',
|
||||
'Get-RunspaceDebug', 'ConvertFrom-SddlString', 'Start-Sleep', 'Join-String', 'Out-String', 'Select-String',
|
||||
'ConvertFrom-StringData', 'Format-Table', 'New-TemporaryFile', 'New-TimeSpan', 'Get-TraceSource', 'Set-TraceSource',
|
||||
'Add-Type', 'Get-TypeData', 'Remove-TypeData', 'Update-TypeData', 'Get-UICulture', 'Get-Unique', 'Get-Uptime',
|
||||
'Clear-Variable', 'Get-Variable', 'New-Variable', 'Remove-Variable', 'Set-Variable', 'Get-Verb', 'Write-Verbose',
|
||||
'Write-Warning', 'Invoke-WebRequest', 'Format-Wide', 'ConvertTo-Xml', 'Select-Xml'
|
||||
)
|
||||
FunctionsToExport = @()
|
||||
AliasesToExport = @('fhx')
|
||||
NestedModules = @("Microsoft.PowerShell.Commands.Utility.dll")
|
||||
HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855960'
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<AssemblyName>resgen</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<RuntimeIdentifiers>win7-x86;win7-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Management.Automation.Configuration;
|
||||
|
@ -73,7 +73,7 @@ namespace System.Management.Automation
|
|||
/// <summary>
|
||||
/// Experimental feature names that are enabled in the config file.
|
||||
/// </summary>
|
||||
internal static readonly ImmutableHashSet<string> EnabledExperimentalFeatureNames;
|
||||
internal static readonly ReadOnlyBag<string> EnabledExperimentalFeatureNames;
|
||||
|
||||
/// <summary>
|
||||
/// Type initializer. Initialize the engine experimental feature list.
|
||||
|
@ -99,7 +99,7 @@ namespace System.Management.Automation
|
|||
var engineExpFeatureMap = engineFeatures.ToDictionary(f => f.Name, StringComparer.OrdinalIgnoreCase);
|
||||
EngineExperimentalFeatureMap = new ReadOnlyDictionary<string, ExperimentalFeature>(engineExpFeatureMap);
|
||||
|
||||
// Initialize the immutable hashset 'EnabledExperimentalFeatureNames'.
|
||||
// Initialize the readonly hashset 'EnabledExperimentalFeatureNames'.
|
||||
// The initialization of 'EnabledExperimentalFeatureNames' is deliberately made in the type initializer so that:
|
||||
// 1. 'EnabledExperimentalFeatureNames' can be declared as readonly;
|
||||
// 2. No need to deal with initialization from multiple threads;
|
||||
|
@ -119,11 +119,11 @@ namespace System.Management.Automation
|
|||
/// <summary>
|
||||
/// Process the array of enabled feature names retrieved from configuration.
|
||||
/// Ignore invalid feature names and unavailable engine feature names, and
|
||||
/// return an ImmutableHashSet of the valid enabled feature names.
|
||||
/// return an ReadOnlyBag of the valid enabled feature names.
|
||||
/// </summary>
|
||||
private static ImmutableHashSet<string> ProcessEnabledFeatures(string[] enabledFeatures)
|
||||
private static ReadOnlyBag<string> ProcessEnabledFeatures(string[] enabledFeatures)
|
||||
{
|
||||
if (enabledFeatures.Length == 0) { return ImmutableHashSet<string>.Empty; }
|
||||
if (enabledFeatures.Length == 0) { return ReadOnlyBag<string>.Empty; }
|
||||
|
||||
var list = new List<string>(enabledFeatures.Length);
|
||||
foreach (string name in enabledFeatures)
|
||||
|
@ -151,7 +151,7 @@ namespace System.Management.Automation
|
|||
LogError(PSEventId.ExperimentalFeature_InvalidName, name, message);
|
||||
}
|
||||
}
|
||||
return ImmutableHashSet.CreateRange(StringComparer.OrdinalIgnoreCase, list);
|
||||
return new ReadOnlyBag<string>(new HashSet<string>(list, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -41,15 +41,13 @@ namespace System.Management.Automation.Runspaces
|
|||
// * have high disk cost
|
||||
|
||||
// We shouldn't create too many tasks.
|
||||
|
||||
// This task takes awhile, so it gets it's own task
|
||||
#if !UNIX
|
||||
// Amsi initialize can be a little slow
|
||||
Task.Run(() =>
|
||||
{
|
||||
// Building the catalog is expensive, so force that to happen early on a background thread, and do so
|
||||
// on a file we are very likely to read anyway.
|
||||
var pshome = Utils.DefaultPowerShellAppBase;
|
||||
var unused = SecuritySupport.IsProductBinary(Path.Combine(pshome, "Modules", "Microsoft.PowerShell.Utility", "Microsoft.PowerShell.Utility.psm1"));
|
||||
AmsiUtils.WinScanContent(content: string.Empty, sourceMetadata: string.Empty, warmUp: true);
|
||||
});
|
||||
#endif
|
||||
|
||||
// One other task for other stuff that's faster, but still a little slow.
|
||||
Task.Run(() =>
|
||||
|
@ -58,12 +56,6 @@ namespace System.Management.Automation.Runspaces
|
|||
// happen early on a background thread.
|
||||
var unused0 = RunspaceInit.OutputEncodingDescription;
|
||||
|
||||
// Amsi initialize can also be a little slow
|
||||
if (Platform.IsWindows)
|
||||
{
|
||||
AmsiUtils.Init();
|
||||
}
|
||||
|
||||
// This will init some tables and could load some assemblies.
|
||||
var unused1 = TypeAccelerators.builtinTypeAccelerators;
|
||||
|
||||
|
@ -2390,9 +2382,6 @@ namespace System.Management.Automation.Runspaces
|
|||
// Setting the module to null fixes that.
|
||||
initializedRunspace.ExecutionContext.EngineSessionState.Module = null;
|
||||
|
||||
// Set the SessionStateDrive here since we have all the provider information at this point
|
||||
SetSessionStateDrive(initializedRunspace.ExecutionContext, true);
|
||||
|
||||
Exception moduleImportException = ProcessImportModule(initializedRunspace, ModuleSpecificationsToImport, string.Empty, publicCommands, unresolvedCmdsToExpose);
|
||||
if (moduleImportException != null)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,6 @@ using System.IO;
|
|||
using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Language;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -1071,45 +1070,37 @@ namespace System.Management.Automation
|
|||
}
|
||||
|
||||
string cacheFileName = "ModuleAnalysisCache";
|
||||
|
||||
// When multiple copies of pwsh are on the system, they should use their own copy of the cache.
|
||||
// Append hash of `$PSHOME` to cacheFileName.
|
||||
byte[] hashBytes;
|
||||
using (var sha1 = SHA1.Create())
|
||||
string hashString = CRC32Hash.ComputeHash(Utils.DefaultPowerShellAppBase);
|
||||
cacheFileName = string.Format(CultureInfo.InvariantCulture, "{0}-{1}", cacheFileName, hashString);
|
||||
|
||||
if (ExperimentalFeature.EnabledExperimentalFeatureNames.Count > 0)
|
||||
{
|
||||
hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(Utils.DefaultPowerShellAppBase));
|
||||
|
||||
string hashString = BitConverter.ToString(hashBytes, startIndex: 0, length: 4).Replace("-", string.Empty);
|
||||
cacheFileName = string.Format(CultureInfo.InvariantCulture, "{0}-{1}", cacheFileName, hashString);
|
||||
|
||||
if (ExperimentalFeature.EnabledExperimentalFeatureNames.Count > 0)
|
||||
// If any experimental features are enabled, we cannot use the default cache file because those
|
||||
// features may expose commands that are not available in a regular powershell session, and we
|
||||
// should not cache those commands in the default cache file because that will result in wrong
|
||||
// auto-completion suggestions when the default cache file is used in another powershell session.
|
||||
//
|
||||
// Here we will generate a cache file name that represent the combination of enabled feature names.
|
||||
// We first convert enabled feature names to lower case, then we sort the feature names, and then
|
||||
// compute an CRC32 hash from the sorted feature names. We will use the CRC32 hash to generate the
|
||||
// cache file name.
|
||||
int index = 0;
|
||||
string[] featureNames = new string[ExperimentalFeature.EnabledExperimentalFeatureNames.Count];
|
||||
foreach (string featureName in ExperimentalFeature.EnabledExperimentalFeatureNames)
|
||||
{
|
||||
// If any experimental features are enabled, we cannot use the default cache file because those
|
||||
// features may expose commands that are not available in a regular powershell session, and we
|
||||
// should not cache those commands in the default cache file because that will result in wrong
|
||||
// auto-completion suggestions when the default cache file is used in another powershell session.
|
||||
//
|
||||
// Here we will generate a cache file name that represent the combination of enabled feature names.
|
||||
// We first convert enabled feature names to lower case, then we sort the feature names, and then
|
||||
// compute an SHA1 hash from the sorted feature names. We will use a short SHA name (first 8 chars)
|
||||
// to generate the cache file name.
|
||||
int index = 0;
|
||||
string[] featureNames = new string[ExperimentalFeature.EnabledExperimentalFeatureNames.Count];
|
||||
foreach (string featureName in ExperimentalFeature.EnabledExperimentalFeatureNames)
|
||||
{
|
||||
featureNames[index++] = featureName.ToLowerInvariant();
|
||||
}
|
||||
|
||||
Array.Sort(featureNames);
|
||||
string allNames = string.Join(Environment.NewLine, featureNames);
|
||||
|
||||
// Use SHA1 because it's faster.
|
||||
// It's very unlikely to get collision from hashing the combinations of enabled features names.
|
||||
hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(allNames));
|
||||
|
||||
// Use the first 8 characters of the hash string for a short SHA.
|
||||
hashString = BitConverter.ToString(hashBytes, startIndex: 0, length: 4).Replace("-", string.Empty);
|
||||
cacheFileName = string.Format(CultureInfo.InvariantCulture, "{0}-{1}", cacheFileName, hashString);
|
||||
featureNames[index++] = featureName.ToLowerInvariant();
|
||||
}
|
||||
|
||||
Array.Sort(featureNames);
|
||||
string allNames = string.Join(Environment.NewLine, featureNames);
|
||||
|
||||
// Use CRC32 because it's faster.
|
||||
// It's very unlikely to get collision from hashing the combinations of enabled features names.
|
||||
hashString = CRC32Hash.ComputeHash(allNames);
|
||||
cacheFileName = string.Format(CultureInfo.InvariantCulture, "{0}-{1}", cacheFileName, hashString);
|
||||
}
|
||||
|
||||
#if UNIX
|
||||
|
|
|
@ -3201,11 +3201,10 @@ namespace System.Management.Automation.Runspaces
|
|||
return;
|
||||
}
|
||||
|
||||
PSMemberInfoInternalCollection<PSMemberInfo> typeMembers = null;
|
||||
if (typeData.Members.Count > 0)
|
||||
{
|
||||
PSMemberInfoInternalCollection<PSMemberInfo> typeMembers
|
||||
= _extendedMembers.GetOrAdd(typeName, k => new PSMemberInfoInternalCollection<PSMemberInfo>());
|
||||
|
||||
typeMembers = _extendedMembers.GetOrAdd(typeName, k => new PSMemberInfoInternalCollection<PSMemberInfo>());
|
||||
ProcessMembersData(errors, typeName, typeData.Members.Values, typeMembers, typeData.IsOverride);
|
||||
|
||||
foreach (var memberName in typeData.Members.Keys)
|
||||
|
@ -3216,9 +3215,10 @@ namespace System.Management.Automation.Runspaces
|
|||
|
||||
if (typeData.StandardMembers.Count > 0 || propertySets.Count > 0)
|
||||
{
|
||||
PSMemberInfoInternalCollection<PSMemberInfo> typeMembers
|
||||
= _extendedMembers.GetOrAdd(typeName, k => new PSMemberInfoInternalCollection<PSMemberInfo>());
|
||||
|
||||
if (typeMembers == null)
|
||||
{
|
||||
typeMembers = _extendedMembers.GetOrAdd(typeName, k => new PSMemberInfoInternalCollection<PSMemberInfo>());
|
||||
}
|
||||
ProcessStandardMembers(errors, typeName, typeData.StandardMembers.Values, propertySets, typeMembers, typeData.IsOverride);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ using Microsoft.Win32;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
|
@ -258,7 +259,6 @@ namespace System.Management.Automation
|
|||
baseDirectories.Add(appBase);
|
||||
}
|
||||
#if !UNIX
|
||||
// Win8: 454976
|
||||
// Now add the two variations of System32
|
||||
baseDirectories.Add(Environment.GetFolderPath(Environment.SpecialFolder.System));
|
||||
string systemX86 = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86);
|
||||
|
@ -267,20 +267,6 @@ namespace System.Management.Automation
|
|||
baseDirectories.Add(systemX86);
|
||||
}
|
||||
#endif
|
||||
// And built-in modules
|
||||
string progFileDir;
|
||||
// TODO: #1184 will resolve this work-around
|
||||
// Side-by-side versions of PowerShell use modules from their application base, not
|
||||
// the system installation path.
|
||||
progFileDir = Path.Combine(appBase, "Modules");
|
||||
|
||||
if (!string.IsNullOrEmpty(progFileDir))
|
||||
{
|
||||
baseDirectories.Add(Path.Combine(progFileDir, "PackageManagement"));
|
||||
baseDirectories.Add(Path.Combine(progFileDir, "PowerShellGet"));
|
||||
baseDirectories.Add(Path.Combine(progFileDir, "Pester"));
|
||||
baseDirectories.Add(Path.Combine(progFileDir, "PSReadLine"));
|
||||
}
|
||||
Interlocked.CompareExchange(ref s_productFolderDirectories, baseDirectories.ToArray(), null);
|
||||
}
|
||||
|
||||
|
@ -1927,4 +1913,50 @@ namespace System.Management.Automation.Internal
|
|||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A readonly Hashset.
|
||||
/// </summary>
|
||||
internal sealed class ReadOnlyBag<T> : IEnumerable
|
||||
{
|
||||
private HashSet<T> _hashset;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the readonly Hashset.
|
||||
/// </summary>
|
||||
internal ReadOnlyBag(HashSet<T> hashset)
|
||||
{
|
||||
if (hashset == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(hashset));
|
||||
}
|
||||
|
||||
_hashset = hashset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the count of the Hashset.
|
||||
/// </summary>
|
||||
public int Count => _hashset.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate if it's a readonly Hashset.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => true;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the set contains an item.
|
||||
/// </summary>
|
||||
public bool Contains(T item) => _hashset.Contains(item);
|
||||
|
||||
/// <summary>
|
||||
/// GetEnumerator method.
|
||||
/// </summary>
|
||||
public IEnumerator GetEnumerator() => _hashset.GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Get an empty singleton.
|
||||
/// </summary>
|
||||
internal static readonly ReadOnlyBag<T> Empty = new ReadOnlyBag<T>(new HashSet<T>(capacity: 0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -678,30 +678,27 @@ namespace System.Management.Automation.Runspaces
|
|||
s_runspaceInitTracer.WriteLine("runspace opened successfully");
|
||||
|
||||
// Now do initial state configuration that requires an active runspace
|
||||
if (InitialSessionState != null)
|
||||
Exception initError = InitialSessionState.BindRunspace(this, s_runspaceInitTracer);
|
||||
if (initError != null)
|
||||
{
|
||||
Exception initError = InitialSessionState.BindRunspace(this, s_runspaceInitTracer);
|
||||
if (initError != null)
|
||||
{
|
||||
// Log engine health event
|
||||
LogEngineHealthEvent(initError);
|
||||
// Log engine health event
|
||||
LogEngineHealthEvent(initError);
|
||||
|
||||
// Log engine for end of engine life
|
||||
Debug.Assert(_engine.Context != null,
|
||||
"if startLifeCycleEventWritten is true, ExecutionContext must be present");
|
||||
MshLog.LogEngineLifecycleEvent(_engine.Context, EngineState.Stopped);
|
||||
// Log engine for end of engine life
|
||||
Debug.Assert(_engine.Context != null,
|
||||
"if startLifeCycleEventWritten is true, ExecutionContext must be present");
|
||||
MshLog.LogEngineLifecycleEvent(_engine.Context, EngineState.Stopped);
|
||||
|
||||
// Open failed. Set the RunspaceState to Broken.
|
||||
SetRunspaceState(RunspaceState.Broken, initError);
|
||||
// Open failed. Set the RunspaceState to Broken.
|
||||
SetRunspaceState(RunspaceState.Broken, initError);
|
||||
|
||||
// Raise the event
|
||||
RaiseRunspaceStateEvents();
|
||||
// Raise the event
|
||||
RaiseRunspaceStateEvents();
|
||||
|
||||
// Throw the exception. For asynchronous execution,
|
||||
// OpenThreadProc will catch it. For synchronous execution
|
||||
// caller of open will catch it.
|
||||
throw initError;
|
||||
}
|
||||
// Throw the exception. For asynchronous execution,
|
||||
// OpenThreadProc will catch it. For synchronous execution
|
||||
// caller of open will catch it.
|
||||
throw initError;
|
||||
}
|
||||
|
||||
#if LEGACYTELEMETRY
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace System.Management.Automation
|
|||
|
||||
internal CompiledScriptBlockData(string scriptText, bool isProductCode)
|
||||
{
|
||||
this.IsProductCode = isProductCode;
|
||||
_isProductCode = isProductCode;
|
||||
_scriptText = scriptText;
|
||||
this.Id = Guid.NewGuid();
|
||||
}
|
||||
|
@ -163,11 +163,6 @@ namespace System.Management.Automation
|
|||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
#endif
|
||||
if (!IsProductCode && SecuritySupport.IsProductBinary(((Ast)_ast).Extent.File))
|
||||
{
|
||||
this.IsProductCode = true;
|
||||
}
|
||||
|
||||
bool etwEnabled = ParserEventSource.Log.IsEnabled();
|
||||
if (etwEnabled)
|
||||
{
|
||||
|
@ -199,9 +194,19 @@ namespace System.Management.Automation
|
|||
return;
|
||||
}
|
||||
|
||||
// Call the AMSI API to determine if the script block has malicious content
|
||||
var scriptExtent = scriptBlockAst.Extent;
|
||||
var amsiResult = AmsiUtils.ScanContent(scriptExtent.Text, scriptExtent.File);
|
||||
var scriptFile = scriptExtent.File;
|
||||
|
||||
if (scriptFile != null &&
|
||||
scriptFile.EndsWith(StringLiterals.PowerShellDataFileExtension, StringComparison.OrdinalIgnoreCase)
|
||||
&& IsScriptBlockInFactASafeHashtable())
|
||||
{
|
||||
// Skip the scan for .psd1 files if their content is in fact a safe HashtableAst.
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the AMSI API to determine if the script block has malicious content
|
||||
var amsiResult = AmsiUtils.ScanContent(scriptExtent.Text, scriptFile);
|
||||
|
||||
if (amsiResult == AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_DETECTED)
|
||||
{
|
||||
|
@ -221,6 +226,45 @@ namespace System.Management.Automation
|
|||
{
|
||||
HasSuspiciousContent = true;
|
||||
}
|
||||
|
||||
// A local function to check if the ScriptBlockAst is in fact a safe HashtableAst.
|
||||
bool IsScriptBlockInFactASafeHashtable()
|
||||
{
|
||||
// NOTE: The code below depends on the current member structure of 'ScriptBlockAst'
|
||||
// to determine if the ScriptBlockAst is in fact just a HashtableAst. If AST types
|
||||
// are enhanced, such as new members added to 'ScriptBlockAst', the code here needs
|
||||
// to be reviewed and changed accordingly.
|
||||
|
||||
if (scriptBlockAst.BeginBlock != null || scriptBlockAst.ProcessBlock != null ||
|
||||
scriptBlockAst.ParamBlock != null || scriptBlockAst.DynamicParamBlock != null ||
|
||||
scriptBlockAst.ScriptRequirements != null || scriptBlockAst.UsingStatements.Count > 0 ||
|
||||
scriptBlockAst.Attributes.Count > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NamedBlockAst endBlock = scriptBlockAst.EndBlock;
|
||||
if (!endBlock.Unnamed || endBlock.Traps != null || endBlock.Statements.Count != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PipelineAst pipelineAst = endBlock.Statements[0] as PipelineAst;
|
||||
if (pipelineAst == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HashtableAst hashtableAst = pipelineAst.GetPureExpression() as HashtableAst;
|
||||
if (hashtableAst == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// After the above steps, we know the ScriptBlockAst is in fact just a HashtableAst,
|
||||
// now we need to check if the HashtableAst is safe.
|
||||
return IsSafeValueVisitor.IsAstSafe(hashtableAst, GetSafeValueVisitor.SafeValueContext.Default);
|
||||
}
|
||||
}
|
||||
|
||||
// We delay parsing scripts loaded on startup, so we save the text.
|
||||
|
@ -269,12 +313,23 @@ namespace System.Management.Automation
|
|||
private bool _compiledOptimized;
|
||||
private bool _compiledUnoptimized;
|
||||
private bool _hasSuspiciousContent;
|
||||
private bool? _isProductCode;
|
||||
internal bool DebuggerHidden { get; set; }
|
||||
internal bool DebuggerStepThrough { get; set; }
|
||||
internal Guid Id { get; private set; }
|
||||
internal bool HasLogged { get; set; }
|
||||
internal bool IsFilter { get; private set; }
|
||||
internal bool IsProductCode { get; private set; }
|
||||
internal bool IsProductCode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_isProductCode == null)
|
||||
{
|
||||
_isProductCode = SecuritySupport.IsProductBinary(((Ast)_ast).Extent.File);
|
||||
}
|
||||
return _isProductCode.Value;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool GetIsConfiguration()
|
||||
{
|
||||
|
|
|
@ -366,7 +366,7 @@ namespace System.Management.Automation
|
|||
|
||||
if (!Signature.CatalogApiAvailable.HasValue)
|
||||
{
|
||||
string productFile = Path.Combine(Utils.DefaultPowerShellAppBase, "Modules\\Microsoft.PowerShell.Utility\\Microsoft.PowerShell.Utility.psm1");
|
||||
string productFile = Path.Combine(Utils.DefaultPowerShellAppBase, "Modules\\PSDiagnostics\\PSDiagnostics.psm1");
|
||||
if (signature.Status != SignatureStatus.Valid)
|
||||
{
|
||||
if (string.Equals(filename, productFile, StringComparison.OrdinalIgnoreCase))
|
||||
|
|
|
@ -1531,11 +1531,11 @@ namespace System.Management.Automation
|
|||
#if UNIX
|
||||
return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
|
||||
#else
|
||||
return WinScanContent(content, sourceMetadata);
|
||||
return WinScanContent(content, sourceMetadata, warmUp: false);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static AmsiNativeMethods.AMSI_RESULT WinScanContent(string content, string sourceMetadata)
|
||||
internal static AmsiNativeMethods.AMSI_RESULT WinScanContent(string content, string sourceMetadata, bool warmUp)
|
||||
{
|
||||
if (String.IsNullOrEmpty(sourceMetadata))
|
||||
{
|
||||
|
@ -1595,6 +1595,13 @@ namespace System.Management.Automation
|
|||
}
|
||||
}
|
||||
|
||||
if (warmUp)
|
||||
{
|
||||
// We are warming up the AMSI component in console startup, and that means we initialize AMSI
|
||||
// and create a AMSI session, but don't really scan anything.
|
||||
return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
|
||||
}
|
||||
|
||||
AmsiNativeMethods.AMSI_RESULT result = AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_CLEAN;
|
||||
|
||||
// Run AMSI content scan
|
||||
|
|
|
@ -624,6 +624,63 @@ namespace System.Management.Automation
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A simple implementation of CRC32.
|
||||
/// See "CRC-32 algorithm" in https://en.wikipedia.org/wiki/Cyclic_redundancy_check.
|
||||
/// </summary>
|
||||
internal class CRC32Hash
|
||||
{
|
||||
// CRC-32C polynomial representations
|
||||
private const uint polynomial = 0x1EDC6F41;
|
||||
private static uint[] table;
|
||||
|
||||
static CRC32Hash()
|
||||
{
|
||||
uint temp = 0;
|
||||
table = new uint[256];
|
||||
|
||||
for (int i = 0; i < table.Length; i++)
|
||||
{
|
||||
temp = (uint)i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if ((temp & 1) == 1)
|
||||
{
|
||||
temp = (temp >> 1) ^ polynomial;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp >>= 1;
|
||||
}
|
||||
}
|
||||
table[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
private static uint Compute(byte[] buffer)
|
||||
{
|
||||
uint crc = 0xFFFFFFFF;
|
||||
for (int i = 0; i < buffer.Length; ++i)
|
||||
{
|
||||
var index = (byte)(crc ^ buffer[i] & 0xff);
|
||||
crc = (crc >> 8) ^ table[index];
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
internal static byte[] ComputeHash(byte[] buffer)
|
||||
{
|
||||
uint crcResult = Compute(buffer);
|
||||
return BitConverter.GetBytes(crcResult);
|
||||
}
|
||||
|
||||
internal static string ComputeHash(string input)
|
||||
{
|
||||
byte[] hashBytes = ComputeHash(Encoding.UTF8.GetBytes(input));
|
||||
return BitConverter.ToString(hashBytes).Replace("-", string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
#region ReferenceEqualityComparer
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<AssemblyName>TypeCatalogGen</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<RuntimeIdentifiers>win7-x86;win7-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<Description>PowerShell top-level project with .NET CLI host</Description>
|
||||
<AssemblyName>pwsh</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<RuntimeIdentifiers>linux-x64;osx-x64;</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<Description>PowerShell Core on Windows top-level project</Description>
|
||||
<AssemblyName>pwsh</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers>
|
||||
<RootNamespace>Microsoft.PowerShell</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -347,7 +347,7 @@ $pid
|
|||
$script | Out-File -FilePath $testScriptPath -Force
|
||||
$testPid = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath
|
||||
|
||||
Export-PSOsLog -After $after -LogPid $testPid -TimeoutInMilliseconds 30000 -IntervalInMilliseconds 3000 -MinimumCount 18 |
|
||||
Export-PSOsLog -After $after -LogPid $testPid -TimeoutInMilliseconds 30000 -IntervalInMilliseconds 3000 -MinimumCount 17 |
|
||||
Set-Content -Path $contentFile
|
||||
$items = @(Get-PSOsLog -Path $contentFile -Id $logId -After $after -Verbose)
|
||||
|
||||
|
@ -385,7 +385,7 @@ $pid
|
|||
$script | Out-File -FilePath $testScriptPath -Force
|
||||
$testPid = & $powershell -NoProfile -SettingsFile $configFile -Command $testScriptPath
|
||||
|
||||
Export-PSOsLog -After $after -LogPid $testPid -TimeoutInMilliseconds 30000 -IntervalInMilliseconds 3000 -MinimumCount 18 |
|
||||
Export-PSOsLog -After $after -LogPid $testPid -TimeoutInMilliseconds 30000 -IntervalInMilliseconds 3000 -MinimumCount 17 |
|
||||
Set-Content -Path $contentFile
|
||||
$items = @(Get-PSOsLog -Path $contentFile -Id $logId -After $after -Verbose)
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
Describe "ConvertFrom-SddlString Tests" -Tags "CI", "RequireAdminOnWindows" {
|
||||
|
||||
BeforeAll {
|
||||
if (-not $IsWindows) { return }
|
||||
$sddl = (Get-Item -Path WSMan:\localhost\Service\RootSDDL).Value
|
||||
$testCases = @(
|
||||
@{ Type = "_UNSPECIFIED_" }
|
||||
@{ Type = "FileSystemRights" }
|
||||
@{ Type = "RegistryRights" }
|
||||
@{ Type = "ActiveDirectoryRights" }
|
||||
@{ Type = "MutexRights" }
|
||||
@{ Type = "SemaphoreRights" }
|
||||
@{ Type = "EventWaitHandleRights" }
|
||||
)
|
||||
$expectedProperties = @('Owner', 'Group', 'DiscretionaryAcl', 'SystemAcl', 'RawDescriptor')
|
||||
}
|
||||
|
||||
It "Validate ConvertFrom-SddlString with type <Type>" -Skip:(!$IsWindows) -TestCases $testCases {
|
||||
param($Type)
|
||||
|
||||
$arguments = @{ Sddl = $sddl; }
|
||||
if ($Type -ne "_UNSPECIFIED_") {
|
||||
$arguments.Add("Type", $Type)
|
||||
}
|
||||
|
||||
$result = ConvertFrom-SddlString @arguments
|
||||
foreach ($property in $expectedProperties)
|
||||
{
|
||||
$result.$property | Should -Not -Be $null
|
||||
}
|
||||
}
|
||||
|
||||
It "Validate that ConvertFrom-SddlString with type <Type> via ValueFromPipeline" -Skip:(!$IsWindows) -TestCases $testCases {
|
||||
param($Type)
|
||||
|
||||
$arguments = @{ }
|
||||
if ($Type -ne "_UNSPECIFIED_") {
|
||||
$arguments.Add("Type", $Type)
|
||||
}
|
||||
|
||||
$result = $sddl | ConvertFrom-SddlString @arguments
|
||||
foreach ($property in $expectedProperties)
|
||||
{
|
||||
$result.$property | Should -Not -Be $null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -195,6 +195,7 @@ Describe "Verify approved aliases list" -Tags "CI" {
|
|||
"Cmdlet", "ConvertFrom-SecureString", , $($FullCLR -or $CoreWindows -or $CoreUnix)
|
||||
"Cmdlet", "ConvertFrom-String", , $($FullCLR )
|
||||
"Cmdlet", "ConvertFrom-StringData", , $($FullCLR -or $CoreWindows -or $CoreUnix)
|
||||
"Cmdlet", "ConvertFrom-SddlString", , $( $CoreWindows )
|
||||
"Cmdlet", "Convert-Path", , $($FullCLR -or $CoreWindows -or $CoreUnix)
|
||||
"Cmdlet", "Convert-String", , $($FullCLR )
|
||||
"Cmdlet", "ConvertTo-Csv", , $($FullCLR -or $CoreWindows -or $CoreUnix)
|
||||
|
|
|
@ -901,7 +901,7 @@ function Export-PSOsLog
|
|||
Write-Output $log
|
||||
}
|
||||
else {
|
||||
throw "did not recieve at least $MinimumCount records but $($log.Count) instead."
|
||||
throw "did not recieve at least $MinimumCount records but $($logToCount.Count) instead."
|
||||
}
|
||||
} -TimeoutInMilliseconds $TimeoutInMilliseconds -IntervalInMilliseconds $IntervalInMilliseconds -LogErrorSb {
|
||||
$log = Start-NativeExecution -command {log show --info @extraParams}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<Description>Very simple little console class that you can use to for testing PowerShell interaction with native commands</Description>
|
||||
<AssemblyName>testexe</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<RuntimeIdentifiers>win7-x86;win7-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<Description>Very tiny windows service to do service testing</Description>
|
||||
<AssemblyName>TestService</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
<file src="__INPATHROOT__\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1" signType="AuthenticodeFormer" dest="__OUTPATHROOT__\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1" />
|
||||
<file src="__INPATHROOT__\Modules\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.psd1" signType="AuthenticodeFormer" dest="__OUTPATHROOT__\Modules\Microsoft.PowerShell.Security\Microsoft.PowerShell.Security.psd1" />
|
||||
<file src="__INPATHROOT__\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" signType="AuthenticodeFormer" dest="__OUTPATHROOT__\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psd1" />
|
||||
<file src="__INPATHROOT__\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psm1" signType="AuthenticodeFormer" dest="__OUTPATHROOT__\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psm1" />
|
||||
<file src="__INPATHROOT__\Modules\Microsoft.WSMan.Management\Microsoft.WSMan.Management.psd1" signType="AuthenticodeFormer" dest="__OUTPATHROOT__\Modules\Microsoft.WSMan.Management\Microsoft.WSMan.Management.psd1" />
|
||||
<file src="__INPATHROOT__\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psm1" signType="AuthenticodeFormer" dest="__OUTPATHROOT__\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psm1" />
|
||||
<file src="__INPATHROOT__\Modules\PSDiagnostics\PSDiagnostics.psd1" signType="AuthenticodeFormer" dest="__OUTPATHROOT__\Modules\PSDiagnostics\PSDiagnostics.psd1" />
|
||||
|
|
Loading…
Reference in a new issue