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:
Dongbo Wang 2018-12-02 12:52:39 -08:00 committed by GitHub
parent 2a469b7d0f
commit a11810bf33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 628 additions and 356 deletions

3
.gitignore vendored
View file

@ -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/

View file

@ -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" />

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -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));
}
}

View file

@ -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);

View file

@ -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>

View file

@ -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>

View file

@ -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" />

View file

@ -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
}
}
}

View file

@ -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'
}

View file

@ -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'
}

View file

@ -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>

View file

@ -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>

View file

@ -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)
{

View file

@ -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

View file

@ -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);
}

View file

@ -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));
}
}

View file

@ -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

View file

@ -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()
{

View file

@ -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))

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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)

View file

@ -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
}
}
}

View file

@ -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)

View file

@ -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}

View file

@ -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>

View file

@ -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>

View file

@ -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" />