diff --git a/.gitignore b/.gitignore
index cb49aabbaec..87ec2702b4d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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/
diff --git a/assets/files.wxs b/assets/files.wxs
index dee0720a3d0..6359a9cc638 100644
--- a/assets/files.wxs
+++ b/assets/files.wxs
@@ -1641,9 +1641,6 @@
-
-
-
@@ -2733,7 +2730,6 @@
-
diff --git a/build.psm1 b/build.psm1
index 866cc51de4a..2c2d05079f4 100644
--- a/build.psm1
+++ b/build.psm1
@@ -2197,6 +2197,7 @@ function Start-CrossGen {
"System.IO.Pipes.dll"
"System.Diagnostics.FileVersionInfo.dll"
"System.Collections.Specialized.dll"
+ "Microsoft.ApplicationInsights.dll"
)
# Common PowerShell libraries to crossgen
diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
index 9bbce557c78..845cf89d4d9 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
+++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
@@ -67,6 +67,7 @@
+
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-SddlString.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-SddlString.cs
new file mode 100644
index 00000000000..6962f8beb38
--- /dev/null
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFrom-SddlString.cs
@@ -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
+{
+ ///
+ /// Converts a SDDL string into an object-based representation of a security descriptor.
+ ///
+ [Cmdlet(VerbsData.ConvertFrom, "SddlString", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=623636", RemotingCapability = RemotingCapability.None)]
+ [OutputType(typeof(SecurityDescriptorInfo))]
+ public sealed class ConvertFromSddlStringCommand : PSCmdlet
+ {
+ ///
+ /// Gets and sets the string representing the security descriptor in SDDL syntax.
+ ///
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)]
+ public string Sddl { get; set; }
+
+ ///
+ /// Gets and sets type of rights that this SDDL string represents.
+ ///
+ [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 GetApplicableAccessRights(int accessMask, AccessRightTypeNames? typeName)
+ {
+ List typesToExamine = new List();
+ List foundAccessRightNames = new List();
+ HashSet foundAccessRightValues = new HashSet();
+
+ 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();
+ }
+
+ List aceStringList = new List(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 accessRightList = GetApplicableAccessRights(ace.AccessMask, typeName);
+ if (accessRightList.Count > 0)
+ {
+ string accessRights = String.Join(", ", accessRightList);
+ aceString.Append($" ({accessRights})");
+ }
+ aceStringList.Add(aceString.ToString());
+ }
+
+ return aceStringList.ToArray();
+ }
+
+ ///
+ /// ProcessRecord method.
+ ///
+ 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);
+ }
+
+ ///
+ /// AccessRight type names.
+ ///
+ public enum AccessRightTypeNames
+ {
+ ///
+ /// FileSystemRights.
+ ///
+ FileSystemRights,
+
+ ///
+ /// RegistryRights.
+ ///
+ RegistryRights,
+
+ ///
+ /// ActiveDirectoryRights.
+ ///
+ ActiveDirectoryRights,
+
+ ///
+ /// MutexRights.
+ ///
+ MutexRights,
+
+ ///
+ /// SemaphoreRights.
+ ///
+ SemaphoreRights,
+
+ // We have 'CryptoKeyRights' in the list for Windows PowerShell, but that type is not available in .NET Core.
+ // CryptoKeyRights,
+
+ ///
+ /// EventWaitHandleRights.
+ ///
+ EventWaitHandleRights
+ }
+ }
+
+ ///
+ /// Representation of a security descriptor.
+ ///
+ 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;
+ }
+
+ ///
+ /// EventWaitHandle rights.
+ ///
+ public readonly string Owner;
+
+ ///
+ /// EventWaitHandle rights.
+ ///
+ public readonly string Group;
+
+ ///
+ /// EventWaitHandle rights.
+ ///
+ public readonly string[] DiscretionaryAcl;
+
+ ///
+ /// EventWaitHandle rights.
+ ///
+ public readonly string[] SystemAcl;
+
+ ///
+ /// EventWaitHandle rights.
+ ///
+ public readonly CommonSecurityDescriptor RawDescriptor;
+ }
+}
+
+#endif
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs
index 3b309abab2a..4355e5be3e7 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs
@@ -19,7 +19,7 @@ public class GetFileHashCommand : HashCmdletBase
{
///
/// Path parameter.
- /// The paths of the files to calculate a hashs.
+ /// The paths of the files to calculate hash values.
/// Resolved wildcards.
///
///
@@ -266,7 +266,7 @@ protected void InitHasher(String Algorithm)
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));
}
}
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs
index 6cf92b28a5a..a1ac032c6ed 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs
@@ -79,7 +79,7 @@ private void WritePathNotFoundError(string path)
{
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 @@ private void WritePathNotFoundError(string path)
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);
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UtilityCommon.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UtilityCommon.cs
index f44b616e562..f8c1bd2b3d9 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UtilityCommon.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UtilityCommon.cs
@@ -62,6 +62,7 @@ public enum TextEncodingType
///
/// Utility class to contain resources for the Microsoft.PowerShell.Utility module.
///
+ [Obsolete("This class is obsolete", true)]
public static class UtilityResources
{
///
diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx
index f8e5623d8fc..551f0d1fcb8 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx
+++ b/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx
@@ -171,7 +171,7 @@
The file '{0}' could not be parsed as a PowerShell Data File.
-
- '{0}' is not supported in this system.
+
+ Cannot construct a security descriptor from the given SDDL due to the following error: {0}
diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
index e4152f09f68..057c0639d9f 100644
--- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
+++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
@@ -21,7 +21,6 @@
-
diff --git a/src/Modules/Shared/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1 b/src/Modules/Shared/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1
deleted file mode 100644
index c55839fd440..00000000000
--- a/src/Modules/Shared/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1
+++ /dev/null
@@ -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
- }
- }
-}
diff --git a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
index e901694f4f9..863b38f7498 100644
--- a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
+++ b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
@@ -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'
}
diff --git a/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
index 316852c1728..2db43e68531 100644
--- a/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
+++ b/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1
@@ -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'
}
diff --git a/src/ResGen/ResGen.csproj b/src/ResGen/ResGen.csproj
index 2596f346664..1283eb4b85b 100644
--- a/src/ResGen/ResGen.csproj
+++ b/src/ResGen/ResGen.csproj
@@ -5,6 +5,7 @@
netcoreapp2.0
resgen
Exe
+ true
win7-x86;win7-x64;osx-x64;linux-x64
diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs
index 574186721d3..86d25b94026 100644
--- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs
+++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs
@@ -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 @@ internal ExperimentalFeature(string name, string description, string source, boo
///
/// Experimental feature names that are enabled in the config file.
///
- internal static readonly ImmutableHashSet EnabledExperimentalFeatureNames;
+ internal static readonly ReadOnlyBag EnabledExperimentalFeatureNames;
///
/// Type initializer. Initialize the engine experimental feature list.
@@ -99,7 +99,7 @@ static ExperimentalFeature()
var engineExpFeatureMap = engineFeatures.ToDictionary(f => f.Name, StringComparer.OrdinalIgnoreCase);
EngineExperimentalFeatureMap = new ReadOnlyDictionary(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 @@ static ExperimentalFeature()
///
/// 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.
///
- private static ImmutableHashSet ProcessEnabledFeatures(string[] enabledFeatures)
+ private static ReadOnlyBag ProcessEnabledFeatures(string[] enabledFeatures)
{
- if (enabledFeatures.Length == 0) { return ImmutableHashSet.Empty; }
+ if (enabledFeatures.Length == 0) { return ReadOnlyBag.Empty; }
var list = new List(enabledFeatures.Length);
foreach (string name in enabledFeatures)
@@ -151,7 +151,7 @@ private static ImmutableHashSet ProcessEnabledFeatures(string[] enabledF
LogError(PSEventId.ExperimentalFeature_InvalidName, name, message);
}
}
- return ImmutableHashSet.CreateRange(StringComparer.OrdinalIgnoreCase, list);
+ return new ReadOnlyBag(new HashSet(list, StringComparer.OrdinalIgnoreCase));
}
///
diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs
index e18f794ab44..6c83d545b5a 100644
--- a/src/System.Management.Automation/engine/InitialSessionState.cs
+++ b/src/System.Management.Automation/engine/InitialSessionState.cs
@@ -41,15 +41,13 @@ internal static void Init()
// * 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 @@ internal static void Init()
// 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 @@ internal Exception BindRunspace(Runspace initializedRunspace, PSTraceSource runs
// 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)
{
diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs
index 483c33bb60f..35e5e6dc3dd 100644
--- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs
+++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs
@@ -10,7 +10,6 @@
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 @@ static AnalysisCacheData()
}
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())
- {
- 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);
+ string hashString = CRC32Hash.ComputeHash(Utils.DefaultPowerShellAppBase);
+ cacheFileName = string.Format(CultureInfo.InvariantCulture, "{0}-{1}", cacheFileName, hashString);
- if (ExperimentalFeature.EnabledExperimentalFeatureNames.Count > 0)
+ 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);
+ featureNames[index++] = featureName.ToLowerInvariant();
+ }
- // 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));
+ Array.Sort(featureNames);
+ string allNames = string.Join(Environment.NewLine, featureNames);
- // 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);
- }
+ // 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
diff --git a/src/System.Management.Automation/engine/TypeTable.cs b/src/System.Management.Automation/engine/TypeTable.cs
index 1d626186283..0070b0e6892 100644
--- a/src/System.Management.Automation/engine/TypeTable.cs
+++ b/src/System.Management.Automation/engine/TypeTable.cs
@@ -3201,11 +3201,10 @@ private void ProcessTypeDataToAdd(ConcurrentBag errors, TypeData typeDat
return;
}
+ PSMemberInfoInternalCollection typeMembers = null;
if (typeData.Members.Count > 0)
{
- PSMemberInfoInternalCollection typeMembers
- = _extendedMembers.GetOrAdd(typeName, k => new PSMemberInfoInternalCollection());
-
+ typeMembers = _extendedMembers.GetOrAdd(typeName, k => new PSMemberInfoInternalCollection());
ProcessMembersData(errors, typeName, typeData.Members.Values, typeMembers, typeData.IsOverride);
foreach (var memberName in typeData.Members.Keys)
@@ -3216,9 +3215,10 @@ PSMemberInfoInternalCollection typeMembers
if (typeData.StandardMembers.Count > 0 || propertySets.Count > 0)
{
- PSMemberInfoInternalCollection typeMembers
- = _extendedMembers.GetOrAdd(typeName, k => new PSMemberInfoInternalCollection());
-
+ if (typeMembers == null)
+ {
+ typeMembers = _extendedMembers.GetOrAdd(typeName, k => new PSMemberInfoInternalCollection());
+ }
ProcessStandardMembers(errors, typeName, typeData.StandardMembers.Values, propertySets, typeMembers, typeData.IsOverride);
}
diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs
index 8f1c971f5aa..c17782be1a0 100644
--- a/src/System.Management.Automation/engine/Utils.cs
+++ b/src/System.Management.Automation/engine/Utils.cs
@@ -15,6 +15,7 @@
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 @@ private static string[] GetProductFolderDirectories()
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 @@ private static string[] GetProductFolderDirectories()
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 @@ internal T Pop()
return item;
}
}
+
+ ///
+ /// A readonly Hashset.
+ ///
+ internal sealed class ReadOnlyBag : IEnumerable
+ {
+ private HashSet _hashset;
+
+ ///
+ /// Constructor for the readonly Hashset.
+ ///
+ internal ReadOnlyBag(HashSet hashset)
+ {
+ if (hashset == null)
+ {
+ throw new ArgumentNullException(nameof(hashset));
+ }
+
+ _hashset = hashset;
+ }
+
+ ///
+ /// Get the count of the Hashset.
+ ///
+ public int Count => _hashset.Count;
+
+ ///
+ /// Indicate if it's a readonly Hashset.
+ ///
+ public bool IsReadOnly => true;
+
+ ///
+ /// Check if the set contains an item.
+ ///
+ public bool Contains(T item) => _hashset.Contains(item);
+
+ ///
+ /// GetEnumerator method.
+ ///
+ public IEnumerator GetEnumerator() => _hashset.GetEnumerator();
+
+ ///
+ /// Get an empty singleton.
+ ///
+ internal static readonly ReadOnlyBag Empty = new ReadOnlyBag(new HashSet(capacity: 0));
+ }
}
diff --git a/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs b/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
index 3d93afc65e7..e42ec1a6399 100644
--- a/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
+++ b/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
@@ -678,30 +678,27 @@ private void DoOpenHelper()
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
diff --git a/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs b/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs
index 01398dcb0e6..113ae5457ff 100644
--- a/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs
+++ b/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs
@@ -49,7 +49,7 @@ internal CompiledScriptBlockData(IParameterMetadataProvider ast, bool isFilter)
internal CompiledScriptBlockData(string scriptText, bool isProductCode)
{
- this.IsProductCode = isProductCode;
+ _isProductCode = isProductCode;
_scriptText = scriptText;
this.Id = Guid.NewGuid();
}
@@ -163,11 +163,6 @@ private void ReallyCompile(bool optimize)
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 @@ private void PerformSecurityChecks()
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 @@ private void PerformSecurityChecks()
{
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 @@ private IParameterMetadataProvider DelayParseScriptText()
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()
{
diff --git a/src/System.Management.Automation/security/Authenticode.cs b/src/System.Management.Automation/security/Authenticode.cs
index 5bef9917017..d9850133bdf 100644
--- a/src/System.Management.Automation/security/Authenticode.cs
+++ b/src/System.Management.Automation/security/Authenticode.cs
@@ -366,7 +366,7 @@ private static Signature GetSignatureFromCatalog(string filename)
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))
diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs
index 124307db9d9..dd89eb4ee65 100644
--- a/src/System.Management.Automation/security/SecuritySupport.cs
+++ b/src/System.Management.Automation/security/SecuritySupport.cs
@@ -1531,11 +1531,11 @@ internal static AmsiNativeMethods.AMSI_RESULT ScanContent(string content, string
#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 @@ internal static AmsiNativeMethods.AMSI_RESULT WinScanContent(string content, str
}
}
+ 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
diff --git a/src/System.Management.Automation/utils/PsUtils.cs b/src/System.Management.Automation/utils/PsUtils.cs
index 7e2d3af8403..33951ef1ea3 100644
--- a/src/System.Management.Automation/utils/PsUtils.cs
+++ b/src/System.Management.Automation/utils/PsUtils.cs
@@ -624,6 +624,63 @@ internal static object[] Base64ToArgsConverter(string base64)
}
}
+ ///
+ /// A simple implementation of CRC32.
+ /// See "CRC-32 algorithm" in https://en.wikipedia.org/wiki/Cyclic_redundancy_check.
+ ///
+ 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
///
diff --git a/src/TypeCatalogGen/TypeCatalogGen.csproj b/src/TypeCatalogGen/TypeCatalogGen.csproj
index d5aaa7462a9..9102abcb768 100644
--- a/src/TypeCatalogGen/TypeCatalogGen.csproj
+++ b/src/TypeCatalogGen/TypeCatalogGen.csproj
@@ -5,6 +5,7 @@
netcoreapp2.0
TypeCatalogGen
Exe
+ true
win7-x86;win7-x64;osx-x64;linux-x64
diff --git a/src/powershell-unix/powershell-unix.csproj b/src/powershell-unix/powershell-unix.csproj
index f9ccc3451d6..d2619f9990a 100644
--- a/src/powershell-unix/powershell-unix.csproj
+++ b/src/powershell-unix/powershell-unix.csproj
@@ -6,6 +6,7 @@
PowerShell top-level project with .NET CLI host
pwsh
Exe
+ true
linux-x64;osx-x64;
diff --git a/src/powershell-win-core/powershell-win-core.csproj b/src/powershell-win-core/powershell-win-core.csproj
index 63486744e9a..93f3a9446f0 100644
--- a/src/powershell-win-core/powershell-win-core.csproj
+++ b/src/powershell-win-core/powershell-win-core.csproj
@@ -4,6 +4,7 @@
PowerShell Core on Windows top-level project
pwsh
Exe
+ true
win7-x86;win7-x64
Microsoft.PowerShell
diff --git a/test/powershell/Host/Logging.Tests.ps1 b/test/powershell/Host/Logging.Tests.ps1
index 42f637e4fa1..32900e44b18 100644
--- a/test/powershell/Host/Logging.Tests.ps1
+++ b/test/powershell/Host/Logging.Tests.ps1
@@ -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)
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertFrom-SddlString.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertFrom-SddlString.ps1
new file mode 100644
index 00000000000..c7e302ad29f
--- /dev/null
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertFrom-SddlString.ps1
@@ -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 " -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 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
+ }
+ }
+}
diff --git a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1
index 5fd62c5f895..a35281c1497 100644
--- a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1
+++ b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1
@@ -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)
diff --git a/test/tools/Modules/PSSysLog/PSSysLog.psm1 b/test/tools/Modules/PSSysLog/PSSysLog.psm1
index 8c0c5779a98..1b62e4d2c56 100644
--- a/test/tools/Modules/PSSysLog/PSSysLog.psm1
+++ b/test/tools/Modules/PSSysLog/PSSysLog.psm1
@@ -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}
diff --git a/test/tools/TestExe/TestExe.csproj b/test/tools/TestExe/TestExe.csproj
index 66a1238b489..d1e58bb8534 100644
--- a/test/tools/TestExe/TestExe.csproj
+++ b/test/tools/TestExe/TestExe.csproj
@@ -6,6 +6,7 @@
Very simple little console class that you can use to for testing PowerShell interaction with native commands
testexe
Exe
+ true
win7-x86;win7-x64;osx-x64;linux-x64
diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj
index 2544875784f..f414855d473 100644
--- a/test/tools/TestService/TestService.csproj
+++ b/test/tools/TestService/TestService.csproj
@@ -6,6 +6,7 @@
Very tiny windows service to do service testing
TestService
Exe
+ true
win7-x86;win7-x64
diff --git a/tools/releaseBuild/signing.xml b/tools/releaseBuild/signing.xml
index b93c543b4f7..7fc788b7912 100644
--- a/tools/releaseBuild/signing.xml
+++ b/tools/releaseBuild/signing.xml
@@ -35,7 +35,6 @@
-