diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs
index d589cd887..814614f93 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs
+++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs
@@ -63,6 +63,15 @@ namespace Microsoft.PowerShell
}
}
+ internal bool ShowBanner
+ {
+ get
+ {
+ Dbg.Assert(dirty, "Parse has not been called yet");
+ return showBanner;
+ }
+ }
+
internal bool NoExit
{
get
@@ -229,7 +238,7 @@ namespace Microsoft.PowerShell
ui.WriteLine("");
}
- private void ShowBanner()
+ private void DisplayBanner()
{
// We need to show the banner only if it has not been already shown in native layer
if (!showInitialPrompt)
@@ -699,7 +708,7 @@ namespace Microsoft.PowerShell
if (showBanner && !showHelp)
{
- ShowBanner();
+ DisplayBanner();
}
Dbg.Assert(
diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
index 44e580197..5eeef3c10 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
+++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
@@ -10,6 +10,7 @@ using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
@@ -36,7 +37,7 @@ using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle;
using NakedWin32Handle = System.IntPtr;
using System.Management.Automation.Tracing;
using Microsoft.PowerShell.Telemetry.Internal;
-
+using Debugger = System.Management.Automation.Debugger;
namespace Microsoft.PowerShell
{
@@ -51,7 +52,8 @@ namespace Microsoft.PowerShell
:
PSHost,
IDisposable,
- IHostSupportsInteractiveSession
+ IHostSupportsInteractiveSession,
+ IHostProvidesTelemetryData
{
#region static methods
@@ -202,17 +204,8 @@ namespace Microsoft.PowerShell
theConsoleHost.UI.WriteWarningLine(preStartWarning);
}
- using (theConsoleHost)
+ try
{
-#region Telemetry
-
- // Data Point to Collect: PowerShell Version on this device
- // If null Version is supplied, the Telemetry infrastucture will log an empty value for null
- string version = theConsoleHost.ver.ToString();
- Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage("PSCONSOLEHOST_START", new { PSVersion = version });
-
-#endregion
-
cpp = new CommandLineParameterParser(theConsoleHost, theConsoleHost.ver, bannerText, helpText);
string[] tempArgs = new string[args.GetLength(0)];
args.CopyTo(tempArgs, 0);
@@ -239,15 +232,17 @@ namespace Microsoft.PowerShell
else if (cpp.NamedPipeServerMode)
{
ClrFacade.StartProfileOptimization("StartupProfileData-NamedPipeServerMode");
- System.Management.Automation.Remoting.RemoteSessionNamedPipeServer.RunServerMode(cpp.ConfigurationName);
+ System.Management.Automation.Remoting.RemoteSessionNamedPipeServer.RunServerMode(
+ cpp.ConfigurationName);
exitCode = 0;
}
else if (cpp.SocketServerMode)
{
ClrFacade.StartProfileOptimization("StartupProfileData-SocketServerMode");
- System.Management.Automation.Remoting.Server.HyperVSocketMediator.Run(cpp.InitialCommand, cpp.ConfigurationName);
+ System.Management.Automation.Remoting.Server.HyperVSocketMediator.Run(cpp.InitialCommand,
+ cpp.ConfigurationName);
exitCode = 0;
- }
+ }
else
{
ClrFacade.StartProfileOptimization(
@@ -256,7 +251,14 @@ namespace Microsoft.PowerShell
: "StartupProfileData-NonInteractive");
exitCode = theConsoleHost.Run(cpp, !string.IsNullOrEmpty(preStartWarning));
}
+
}
+ finally
+ {
+ TelemetryAPI.ReportExitTelemetry(theConsoleHost);
+ theConsoleHost.Dispose();
+ }
+
unchecked
{
return (int)exitCode;
@@ -970,6 +972,22 @@ namespace Microsoft.PowerShell
}
}
+ bool IHostProvidesTelemetryData.HostIsInteractive
+ {
+ get
+ {
+ return !cpp.NonInteractive && !cpp.AbortStartup &&
+ ((cpp.InitialCommand == null && cpp.File == null) || cpp.NoExit);
+ }
+ }
+ double IHostProvidesTelemetryData.ProfileLoadTimeInMS { get { return _profileLoadTimeInMS; } }
+ double IHostProvidesTelemetryData.ReadyForInputTimeInMS { get { return _readyForInputTimeInMS; } }
+ int IHostProvidesTelemetryData.InteractiveCommandCount { get { return _interactiveCommandCount; } }
+
+ private double _profileLoadTimeInMS;
+ private double _readyForInputTimeInMS;
+ private int _interactiveCommandCount;
+
#endregion overrides
#region non-overrides
@@ -1370,6 +1388,7 @@ namespace Microsoft.PowerShell
RunspaceCreationEventArgs args = new RunspaceCreationEventArgs(initialCommand, skipProfiles, staMode, importSystemModules, configurationName, initialCommandArgs);
CreateRunspace(args);
+
if (ExitCode == ExitCodeInitFailure) { break; }
if (!noExit && !ui.ReadFromStdin)
@@ -1564,6 +1583,9 @@ namespace Microsoft.PowerShell
PSTask.PowershellConsoleStartup, PSKeyword.UseAlwaysOperational);
}
+ // Record how long it took from process start to runspace open for telemetry.
+ _readyForInputTimeInMS = (DateTime.Now - Process.GetCurrentProcess().StartTime).TotalMilliseconds;
+
DoRunspaceInitialization(importSystemModules, skipProfiles, initialCommand, configurationName, initialCommandArgs);
}
@@ -1697,10 +1719,21 @@ namespace Microsoft.PowerShell
// 3. host independent profile of the current user
// 4. host specific profile of the current user
+ var sw = new Stopwatch();
+ sw.Start();
RunProfile(allUsersProfile, exec);
RunProfile(allUsersHostSpecificProfile, exec);
RunProfile(currentUserProfile, exec);
RunProfile(currentUserHostSpecificProfile, exec);
+ sw.Stop();
+
+ var profileLoadTimeInMs = sw.ElapsedMilliseconds;
+ if (profileLoadTimeInMs > 500 && cpp.ShowBanner)
+ {
+ Console.Error.WriteLine(ConsoleHostStrings.SlowProfileLoadingMessage, profileLoadTimeInMs);
+ }
+
+ _profileLoadTimeInMS = profileLoadTimeInMs;
}
else
{
@@ -1708,6 +1741,10 @@ namespace Microsoft.PowerShell
}
}
+ // Startup is reported after possibly running the profile, but before running the initial command (or file)
+ // if one is specified.
+ TelemetryAPI.ReportStartupTelemetry(this);
+
// If a file was specified as the argument to run, then run it...
if (cpp != null && cpp.File != null)
{
@@ -2714,6 +2751,9 @@ namespace Microsoft.PowerShell
parent.PopRunspace();
}
}
+
+ if (!inBlockMode)
+ theConsoleHost._interactiveCommandCount += 1;
}
}
// NTRAID#Windows Out Of Band Releases-915506-2005/09/09
diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx
index 6a7c355d8..7c1e06807 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx
+++ b/src/Microsoft.PowerShell.ConsoleHost/resources/CommandLineParameterParserStrings.resx
@@ -133,13 +133,13 @@
PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]
[-NoLogo] [-NoExit] [-NoProfile] [-NonInteractive] [-STA]
[-OutputFormat {Text | XML}] [-InputFormat {Text | XML}]
+ [-ConfigurationName <string>]
+ [-File fileName [arguments...]] [-ExecutionPolicy <ExecutionPolicy>]
[-Command { - | <script-block> [-args <arg-array>]
| <string> [<CommandParameters>] } ]
- [-File fileName [arguments...]] [-ExecutionPolicy <ExecutionPolicy>]
PowerShell[.exe] -Help | -? | /?
-
-PSConsoleFile
Loads the specified Windows PowerShell console file. To create a console
file, use Export-Console in Windows PowerShell.
@@ -170,6 +170,12 @@ PowerShell[.exe] -Help | -? | /?
Describes the format of data sent to Windows PowerShell. Valid values are
"Text" (text strings) or "XML" (serialized CLIXML format).
+-ConfigurationName
+ Specifies a configuration endpoint in which Windows PowerShell is run.
+ This can be any endpoint registered on the local machine including the
+ default Windows PowerShell remoting endpoints or a custom endpoint having
+ specific user role capabilities.
+
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
@@ -201,6 +207,7 @@ PowerShell[.exe] -Help | -? | /?
EXAMPLES
PowerShell -PSConsoleFile SqlSnapin.Psc1
PowerShell -version 1.0 -NoLogo -InputFormat text -OutputFormat XML
+ PowerShell -ConfigurationName AdminRoles
PowerShell -Command {Get-EventLog -LogName security}
PowerShell -Command "& {Get-EventLog -LogName security}"
diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx
index 256ab2726..c4ce91a47 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx
+++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ConsoleHostStrings.resx
@@ -185,4 +185,7 @@ The current session does not support debugging; execution will continue.
More than one server mode parameter was specified. Server mode parameters must be used exclusively.
-
+
+ Loading personal and system profiles took {0}ms.
+
+
\ No newline at end of file
diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx
index 95bdb87d3..587047c25 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx
+++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx
@@ -124,8 +124,9 @@ Copyright (C) 2016 Microsoft Corporation. All rights reserved.
PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]
[-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive]
- [-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
- [-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]
+ [-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
+ [-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]
+ [-ConfigurationName <string>]
[-File <filePath> <args>] [-ExecutionPolicy <ExecutionPolicy>]
[-Command { - | <script-block> [-args <arg-array>]
| <string> [<CommandParameters>] } ]
@@ -174,6 +175,12 @@ PowerShell[.exe] -Help | -? | /?
Accepts a base-64-encoded string version of a command. Use this parameter
to submit commands to Windows PowerShell that require complex quotation
marks or curly braces.
+
+-ConfigurationName
+ Specifies a configuration endpoint in which Windows PowerShell is run.
+ This can be any endpoint registered on the local machine including the
+ default Windows PowerShell remoting endpoints or a custom endpoint having
+ specific user role capabilities.
-File
Runs the specified script in the local scope ("dot-sourced"), so that the
@@ -220,6 +227,7 @@ PowerShell[.exe] -Help | -? | /?
EXAMPLES
PowerShell -PSConsoleFile SqlSnapIn.Psc1
PowerShell -version 2.0 -NoLogo -InputFormat text -OutputFormat XML
+ PowerShell -ConfigurationName AdminRoles
PowerShell -Command {Get-EventLog -LogName security}
PowerShell -Command "& {Get-EventLog -LogName security}"
diff --git a/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1 b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1
index 859ea5512..776ae8c49 100644
--- a/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1
+++ b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1
@@ -3,8 +3,9 @@ GUID="eb74e8da-9ae2-482a-a648-e96550fb8733"
Author="Microsoft Corporation"
CompanyName="Microsoft Corporation"
Copyright="© Microsoft Corporation. All rights reserved."
-ModuleVersion="1.0.0.0"
+ModuleVersion="1.0.1.0"
FunctionsToExport = @('Compress-Archive', 'Expand-Archive')
+DotNetFrameworkVersion = 4.5
CmdletsToExport = @()
AliasesToExport = @()
NestedModules="Microsoft.PowerShell.Archive.psm1"
diff --git a/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1 b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1
index b301646d6..3b57dcb84 100644
Binary files a/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1 and b/src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1 differ
diff --git a/src/Modules/PSGet/PSGet.Resource.psd1 b/src/Modules/PSGet/PSGet.Resource.psd1
index 7dfaf7c0e..42a789da6 100644
Binary files a/src/Modules/PSGet/PSGet.Resource.psd1 and b/src/Modules/PSGet/PSGet.Resource.psd1 differ
diff --git a/src/Modules/PSGet/PSModule.psm1 b/src/Modules/PSGet/PSModule.psm1
index 7f8adb3d9..35c2b88cc 100644
--- a/src/Modules/PSGet/PSModule.psm1
+++ b/src/Modules/PSGet/PSModule.psm1
@@ -79,6 +79,10 @@ $script:PackageManagementProviderParam = "PackageManagementProvider"
$script:PublishLocation = "PublishLocation"
$script:ScriptSourceLocation = 'ScriptSourceLocation'
$script:ScriptPublishLocation = 'ScriptPublishLocation'
+$script:Proxy = 'Proxy'
+$script:ProxyCredential = 'ProxyCredential'
+$script:Credential = 'Credential'
+$script:VSTSAuthenticatedFeedsDocUrl = 'https://go.microsoft.com/fwlink/?LinkID=698608'
$script:NuGetProviderName = "NuGet"
$script:NuGetProviderVersion = [Version]'2.8.5.201'
@@ -271,8 +275,8 @@ function PackageManagementMessageResolver($MsgID, $Message) {
if($Message)
{
$tempMessage = $Message -creplace "PackageSource", "PSRepository"
- $tempMessage = $tempMessage -creplace "packagesource", "psrepository"
- $tempMessage = $tempMessage -creplace "Package", "Module"
+ $tempMessage = $tempMessage -creplace "packagesource", "psrepository"
+ $tempMessage = $tempMessage -creplace "Package", "Module"
$tempMessage = $tempMessage -creplace "package", "module"
$tempMessage = $tempMessage -creplace "Sources", "Repositories"
$tempMessage = $tempMessage -creplace "sources", "repositories"
@@ -369,8 +373,8 @@ function PackageManagementMessageResolverForScripts($MsgID, $Message) {
if($Message)
{
$tempMessage = $Message -creplace "PackageSource", "PSRepository"
- $tempMessage = $tempMessage -creplace "packagesource", "psrepository"
- $tempMessage = $tempMessage -creplace "Package", "Script"
+ $tempMessage = $tempMessage -creplace "packagesource", "psrepository"
+ $tempMessage = $tempMessage -creplace "Package", "Script"
$tempMessage = $tempMessage -creplace "package", "script"
$tempMessage = $tempMessage -creplace "Sources", "Repositories"
$tempMessage = $tempMessage -creplace "sources", "repositories"
@@ -387,7 +391,7 @@ function PackageManagementMessageResolverForScripts($MsgID, $Message) {
Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -filename PSGet.Resource.psd1
-#region Add .Net type for Telemetry APIs
+#region Add .Net type for Telemetry APIs and WebProxy
# This code is required to add a .Net type and call the Telemetry APIs
# This is required since PowerShell does not support generation of .Net Anonymous types
@@ -398,6 +402,7 @@ $requiredAssembly = (
$source = @"
using System;
+using System.Net;
using System.Management.Automation;
namespace Microsoft.PowerShell.Get
@@ -414,6 +419,47 @@ namespace Microsoft.PowerShell.Get
Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { SourceLocationType = sourceLocationType, SourceLocationHash = sourceLocationHash, InstallationPolicy = installationPolicy, PackageManagementProvider = packageManagementProvider, PublishLocationHash = publishLocationHash, ScriptSourceLocationHash = scriptSourceLocationHash, ScriptPublishLocationHash = scriptPublishLocationHash });
}
+ }
+
+ ///
+ /// Used by Ping-Endpoint function to supply webproxy to HttpClient
+ /// We cannot use System.Net.WebProxy because this is not available on CoreClr
+ ///
+ public class InternalWebProxy : IWebProxy
+ {
+ Uri _proxyUri;
+ ICredentials _credentials;
+
+ public InternalWebProxy(Uri uri, ICredentials credentials)
+ {
+ Credentials = credentials;
+ _proxyUri = uri;
+ }
+
+ ///
+ /// Credentials used by WebProxy
+ ///
+ public ICredentials Credentials
+ {
+ get
+ {
+ return _credentials;
+ }
+ set
+ {
+ _credentials = value;
+ }
+ }
+
+ public Uri GetProxy(Uri destination)
+ {
+ return _proxyUri;
+ }
+
+ public bool IsBypassed(Uri host)
+ {
+ return false;
+ }
}
}
"@
@@ -484,6 +530,10 @@ function Publish-Module
[string]
$Repository = $Script:PSGalleryModuleSource,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential,
+
[Parameter()]
[ValidateSet("1.0")]
[Version]
@@ -511,11 +561,11 @@ function Publish-Module
[Parameter()]
[ValidateNotNullOrEmpty()]
[Uri]
- $ProjectUri,
-
- [Parameter()]
- [switch]
- $Force
+ $ProjectUri,
+
+ [Parameter()]
+ [switch]
+ $Force
)
Begin
@@ -565,7 +615,7 @@ function Publish-Module
-ExceptionObject $ProjectUri
}
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe -Force:$Force
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe -Force:$Force
}
Process
@@ -853,15 +903,24 @@ function Publish-Module
-ExceptionObject $moduleName
}
+ $FindParameters = @{
+ Name = $moduleName
+ Repository = $Repository
+ Tag = 'PSScript'
+ Verbose = $VerbosePreference
+ ErrorAction = 'SilentlyContinue'
+ WarningAction = 'SilentlyContinue'
+ Debug = $DebugPreference
+ }
+
+ if($Credential)
+ {
+ $FindParameters[$script:Credential] = $Credential
+ }
+
# Check if the specified module name is already used for a script on the specified repository
# Use Find-Script to check if that name is already used as scriptname
- $scriptPSGetItemInfo = Find-Script -Name $moduleName `
- -Repository $Repository `
- -Tag 'PSScript' `
- -Verbose:$VerbosePreference `
- -ErrorAction SilentlyContinue `
- -WarningAction SilentlyContinue `
- -Debug:$DebugPreference |
+ $scriptPSGetItemInfo = Find-Script @FindParameters |
Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleName} |
Microsoft.PowerShell.Utility\Select-Object -Last 1
if($scriptPSGetItemInfo)
@@ -875,12 +934,8 @@ function Publish-Module
-ExceptionObject $moduleName
}
- $currentPSGetItemInfo = Find-Module -Name $moduleInfo.Name `
- -Repository $Repository `
- -Verbose:$VerbosePreference `
- -ErrorAction SilentlyContinue `
- -WarningAction SilentlyContinue `
- -Debug:$DebugPreference |
+ $null = $FindParameters.Remove('Tag')
+ $currentPSGetItemInfo = Find-Module @FindParameters |
Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleInfo.Name} |
Microsoft.PowerShell.Utility\Select-Object -Last 1
@@ -895,7 +950,7 @@ function Publish-Module
}
$shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name)
- if($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module"))
+ if($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module"))
{
Publish-PSArtifactUtility -PSModuleInfo $moduleInfo `
-ManifestPath $manifestPath `
@@ -991,17 +1046,30 @@ function Find-Module
[string[]]
$Command,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
[Parameter()]
[ValidateNotNullOrEmpty()]
[string[]]
- $Repository
+ $Repository,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential
)
Begin
{
Get-PSGalleryApiAvailability -Repository $Repository
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
}
Process
@@ -1156,6 +1224,19 @@ function Save-Module
[string]
$LiteralPath,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential,
+
[Parameter()]
[switch]
$Force
@@ -1165,7 +1246,7 @@ function Save-Module
{
Get-PSGalleryApiAvailability -Repository $Repository
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
# Module names already tried in the current pipeline for InputObject parameterset
$moduleNamesInPipeline = @()
@@ -1359,11 +1440,24 @@ function Install-Module
[string[]]
$Repository,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential,
+
[Parameter()]
[ValidateSet("CurrentUser","AllUsers")]
[string]
$Scope = "AllUsers",
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
[Parameter()]
[switch]
$Force
@@ -1385,7 +1479,7 @@ function Install-Module
-ErrorCategory InvalidArgument
}
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
# Module names already tried in the current pipeline for InputObject parameterset
$moduleNamesInPipeline = @()
@@ -1569,6 +1663,19 @@ function Update-Module
[Version]
$MaximumVersion,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
[Parameter()]
[Switch]
$Force
@@ -1576,7 +1683,7 @@ function Update-Module
Begin
{
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
# Module names already tried in the current pipeline
$moduleNamesInPipeline = @()
@@ -1914,6 +2021,15 @@ function Find-DscResource
[string]
$Filter,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
[Parameter()]
[ValidateNotNullOrEmpty()]
[string[]]
@@ -2008,6 +2124,15 @@ function Find-Command
[string]
$Filter,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
[Parameter()]
[ValidateNotNullOrEmpty()]
[string[]]
@@ -2104,6 +2229,15 @@ function Find-RoleCapability
[string]
$Filter,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
[Parameter()]
[ValidateNotNullOrEmpty()]
[string[]]
@@ -2187,11 +2321,15 @@ function Publish-Script
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]
- $Repository = $Script:PSGalleryModuleSource,
-
- [Parameter()]
- [switch]
- $Force
+ $Repository = $Script:PSGalleryModuleSource,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential,
+
+ [Parameter()]
+ [switch]
+ $Force
)
Begin
@@ -2208,7 +2346,7 @@ function Publish-Script
Get-PSGalleryApiAvailability -Repository $Repository
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe -Force:$Force
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe -Force:$Force
}
Process
@@ -2369,15 +2507,24 @@ function Publish-Script
try
{
+ $FindParameters = @{
+ Name = $scriptName
+ Repository = $Repository
+ Tag = 'PSModule'
+ Verbose = $VerbosePreference
+ ErrorAction = 'SilentlyContinue'
+ WarningAction = 'SilentlyContinue'
+ Debug = $DebugPreference
+ }
+
+ if($Credential)
+ {
+ $FindParameters[$script:Credential] = $Credential
+ }
+
# Check if the specified script name is already used for a module on the specified repository
# Use Find-Module to check if that name is already used as module name
- $modulePSGetItemInfo = Find-Module -Name $scriptName `
- -Repository $Repository `
- -Tag 'PSModule' `
- -Verbose:$VerbosePreference `
- -ErrorAction SilentlyContinue `
- -WarningAction SilentlyContinue `
- -Debug:$DebugPreference |
+ $modulePSGetItemInfo = Find-Module @FindParameters |
Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} |
Microsoft.PowerShell.Utility\Select-Object -Last 1
if($modulePSGetItemInfo)
@@ -2391,13 +2538,10 @@ function Publish-Script
-ExceptionObject $scriptName
}
+ $null = $FindParameters.Remove('Tag')
+
$currentPSGetItemInfo = $null
- $currentPSGetItemInfo = Find-Script -Name $scriptName `
- -Repository $Repository `
- -Verbose:$VerbosePreference `
- -ErrorAction SilentlyContinue `
- -WarningAction SilentlyContinue `
- -Debug:$DebugPreference |
+ $currentPSGetItemInfo = Find-Script @FindParameters |
Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} |
Microsoft.PowerShell.Utility\Select-Object -Last 1
@@ -2415,7 +2559,7 @@ function Publish-Script
}
$shouldProcessMessage = $LocalizedData.PublishScriptwhatIfMessage -f ($PSScriptInfo.Version, $scriptName)
- if($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Script"))
+ if($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Script"))
{
Publish-PSArtifactUtility -PSScriptInfo $PSScriptInfo `
-NugetApiKey $NuGetApiKey `
@@ -2494,17 +2638,30 @@ function Find-Script
[string[]]
$Command,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
[Parameter()]
[ValidateNotNullOrEmpty()]
[string[]]
- $Repository
+ $Repository,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential
)
Begin
{
Get-PSGalleryApiAvailability -Repository $Repository
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
}
Process
@@ -2690,6 +2847,19 @@ function Save-Script
[string]
$LiteralPath,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential,
+
[Parameter()]
[switch]
$Force
@@ -2699,7 +2869,7 @@ function Save-Script
{
Get-PSGalleryApiAvailability -Repository $Repository
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
# Script names already tried in the current pipeline for InputObject parameterset
$scriptNamesInPipeline = @()
@@ -2905,7 +3075,20 @@ function Install-Script
[Parameter()]
[Switch]
$NoPathUpdate,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential,
+
[Parameter()]
[switch]
$Force
@@ -2943,7 +3126,7 @@ function Install-Script
-NoPathUpdate:$NoPathUpdate `
-Force:$Force
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
# Script names already tried in the current pipeline for InputObject parameterset
$scriptNamesInPipeline = @()
@@ -3175,6 +3358,19 @@ function Update-Script
[Version]
$MaximumVersion,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $Credential,
+
[Parameter()]
[Switch]
$Force
@@ -3182,7 +3378,7 @@ function Update-Script
Begin
{
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
# Script names already tried in the current pipeline
$scriptNamesInPipeline = @()
@@ -3500,50 +3696,59 @@ function Register-PSRepository
<#
.ExternalHelp PSGet.psm1-help.xml
#>
- [CmdletBinding(DefaultParameterSetName='NameParameterSet',
+ [CmdletBinding(DefaultParameterSetName='NameParameterSet',
HelpUri='http://go.microsoft.com/fwlink/?LinkID=517129')]
Param
(
- [Parameter(Mandatory=$true,
- Position=0,
- ParameterSetName='NameParameterSet')]
+ [Parameter(Mandatory=$true,
+ Position=0,
+ ParameterSetName='NameParameterSet')]
[ValidateNotNullOrEmpty()]
[string]
$Name,
- [Parameter(Mandatory=$true,
- Position=1,
- ParameterSetName='NameParameterSet')]
+ [Parameter(Mandatory=$true,
+ Position=1,
+ ParameterSetName='NameParameterSet')]
[ValidateNotNullOrEmpty()]
[Uri]
$SourceLocation,
- [Parameter(ParameterSetName='NameParameterSet')]
+ [Parameter(ParameterSetName='NameParameterSet')]
[ValidateNotNullOrEmpty()]
[Uri]
$PublishLocation,
- [Parameter(ParameterSetName='NameParameterSet')]
+ [Parameter(ParameterSetName='NameParameterSet')]
[ValidateNotNullOrEmpty()]
[Uri]
$ScriptSourceLocation,
- [Parameter(ParameterSetName='NameParameterSet')]
+ [Parameter(ParameterSetName='NameParameterSet')]
[ValidateNotNullOrEmpty()]
[Uri]
$ScriptPublishLocation,
- [Parameter(Mandatory=$true,
- ParameterSetName='PSGalleryParameterSet')]
- [Switch]
- $Default,
-
+ [Parameter(Mandatory=$true,
+ ParameterSetName='PSGalleryParameterSet')]
+ [Switch]
+ $Default,
+
[Parameter()]
[ValidateSet('Trusted','Untrusted')]
[string]
$InstallationPolicy = 'Untrusted',
- [Parameter(ParameterSetName='NameParameterSet')]
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
+ [Parameter(ParameterSetName='NameParameterSet')]
[ValidateNotNullOrEmpty()]
[string]
$PackageManagementProvider
@@ -3573,7 +3778,7 @@ function Register-PSRepository
{
Get-PSGalleryApiAvailability -Repository $Name
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
if($PackageManagementProvider)
{
@@ -3602,86 +3807,88 @@ function Register-PSRepository
Process
{
- if($PSCmdlet.ParameterSetName -eq 'PSGalleryParameterSet')
+ if($PSCmdlet.ParameterSetName -eq 'PSGalleryParameterSet')
{
- if(-not $Default)
- {
- return
- }
+ if(-not $Default)
+ {
+ return
+ }
- $PSBoundParameters['Name'] = $Script:PSGalleryModuleSource
- $null = $PSBoundParameters.Remove('Default')
+ $PSBoundParameters['Name'] = $Script:PSGalleryModuleSource
+ $null = $PSBoundParameters.Remove('Default')
}
else
{
- if($Name -eq $Script:PSGalleryModuleSource)
- {
- $message = $LocalizedData.UseDefaultParameterSetOnRegisterPSRepository
- ThrowError -ExceptionName "System.ArgumentException" `
- -ExceptionMessage $message `
- -ErrorId 'UseDefaultParameterSetOnRegisterPSRepository' `
- -CallerPSCmdlet $PSCmdlet `
- -ErrorCategory InvalidArgument `
- -ExceptionObject $Name
- return
- }
+ if($Name -eq $Script:PSGalleryModuleSource)
+ {
+ $message = $LocalizedData.UseDefaultParameterSetOnRegisterPSRepository
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'UseDefaultParameterSetOnRegisterPSRepository' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Name
+ return
+ }
- # Ping and resolve the specified location
- $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) `
- -LocationParameterName 'SourceLocation' `
- -CallerPSCmdlet $PSCmdlet
- if(-not $SourceLocation)
- {
- # Above Resolve-Location function throws an error when it is not able to resolve a location
- return
- }
+ # Ping and resolve the specified location
+ $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) `
+ -LocationParameterName 'SourceLocation' `
+ -Proxy $Proxy `
+ -ProxyCredential $ProxyCredential `
+ -CallerPSCmdlet $PSCmdlet
+ if(-not $SourceLocation)
+ {
+ # Above Resolve-Location function throws an error when it is not able to resolve a location
+ return
+ }
- $providerName = $null
+ $providerName = $null
- if($PackageManagementProvider)
- {
- $providerName = $PackageManagementProvider
- }
- elseif($selctedProviderName)
- {
- $providerName = $selctedProviderName
- }
- else
- {
- $providerName = Get-PackageManagementProviderName -Location $SourceLocation
- }
-
- if($providerName)
- {
- $PSBoundParameters[$script:PackageManagementProviderParam] = $providerName
- }
-
- if($PublishLocation)
- {
- $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation
- }
-
- if($ScriptPublishLocation)
- {
- $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation
- }
-
- if($ScriptSourceLocation)
- {
- $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation
- }
-
- $PSBoundParameters["Location"] = Get-LocationString -LocationUri $SourceLocation
- $null = $PSBoundParameters.Remove("SourceLocation")
+ if($PackageManagementProvider)
+ {
+ $providerName = $PackageManagementProvider
+ }
+ elseif($selctedProviderName)
+ {
+ $providerName = $selctedProviderName
+ }
+ else
+ {
+ $providerName = Get-PackageManagementProviderName -Location $SourceLocation
+ }
+
+ if($providerName)
+ {
+ $PSBoundParameters[$script:PackageManagementProviderParam] = $providerName
+ }
+
+ if($PublishLocation)
+ {
+ $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation
+ }
+
+ if($ScriptPublishLocation)
+ {
+ $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation
+ }
+
+ if($ScriptSourceLocation)
+ {
+ $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation
+ }
+
+ $PSBoundParameters["Location"] = Get-LocationString -LocationUri $SourceLocation
+ $null = $PSBoundParameters.Remove("SourceLocation")
}
- if($InstallationPolicy -eq "Trusted")
+ if($InstallationPolicy -eq "Trusted")
{
- $PSBoundParameters['Trusted'] = $true
+ $PSBoundParameters['Trusted'] = $true
}
$null = $PSBoundParameters.Remove("InstallationPolicy")
- $PSBoundParameters["Provider"] = $script:PSModuleProviderName
+ $PSBoundParameters["Provider"] = $script:PSModuleProviderName
$PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock
$null = PackageManagement\Register-PackageSource @PSBoundParameters
@@ -3697,12 +3904,12 @@ function Set-PSRepository
HelpUri='http://go.microsoft.com/fwlink/?LinkID=517128')]
Param
(
- [Parameter(Mandatory=$true, Position=0)]
+ [Parameter(Mandatory=$true, Position=0)]
[ValidateNotNullOrEmpty()]
[string]
$Name,
- [Parameter(Position=1)]
+ [Parameter(Position=1)]
[ValidateNotNullOrEmpty()]
[Uri]
$SourceLocation,
@@ -3727,6 +3934,15 @@ function Set-PSRepository
[string]
$InstallationPolicy,
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [ValidateNotNullOrEmpty()]
+ [Uri]
+ $Proxy,
+
+ [Parameter(ValueFromPipelineByPropertyName=$true)]
+ [PSCredential]
+ $ProxyCredential,
+
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]
@@ -3764,7 +3980,7 @@ function Set-PSRepository
{
Get-PSGalleryApiAvailability -Repository $Name
- Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet
+ Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential
if($PackageManagementProvider)
{
@@ -3799,6 +4015,8 @@ function Set-PSRepository
# Ping and resolve the specified location
$SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) `
-LocationParameterName 'SourceLocation' `
+ -Proxy $Proxy `
+ -ProxyCredential $ProxyCredential `
-CallerPSCmdlet $PSCmdlet
if(-not $SourceLocation)
{
@@ -5431,6 +5649,27 @@ function Get-ScriptCommentHelpInfoString
#endregion *-ScriptFileInfo cmdlets
#region Utility functions
+function Get-ParametersHashtable
+{
+ param(
+ $Proxy,
+ $ProxyCredential
+ )
+
+ $ParametersHashtable = @{}
+ if($Proxy)
+ {
+ $ParametersHashtable[$script:Proxy] = $Proxy
+ }
+
+ if($ProxyCredential)
+ {
+ $ParametersHashtable[$script:ProxyCredential] = $ProxyCredential
+ }
+
+ return $ParametersHashtable
+}
+
function ToUpper
{
param([string]$str)
@@ -5629,6 +5868,7 @@ function HttpClientApisAvailable
function Ping-Endpoint
{
+ [CmdletBinding()]
param
(
[Parameter()]
@@ -5636,6 +5876,12 @@ function Ping-Endpoint
[string]
$Endpoint,
+ [Parameter()]
+ $Proxy,
+
+ [Parameter()]
+ $ProxyCredential,
+
[Parameter()]
[switch]
$AllowAutoRedirect = $true
@@ -5643,6 +5889,18 @@ function Ping-Endpoint
$results = @{}
+ $WebProxy = $null
+ if($Proxy)
+ {
+ $ProxyNetworkCredential = $null
+ if($ProxyCredential)
+ {
+ $ProxyNetworkCredential = $ProxyCredential.GetNetworkCredential()
+ }
+
+ $WebProxy = New-Object Microsoft.PowerShell.Get.InternalWebProxy -ArgumentList $Proxy,$ProxyNetworkCredential
+ }
+
if(HttpClientApisAvailable)
{
$response = $null
@@ -5650,6 +5908,12 @@ function Ping-Endpoint
{
$handler = New-Object System.Net.Http.HttpClientHandler
$handler.UseDefaultCredentials = $true
+
+ if($WebProxy)
+ {
+ $handler.Proxy = $WebProxy
+ }
+
$httpClient = New-Object System.Net.Http.HttpClient -ArgumentList $handler
$response = $httpclient.GetAsync($endpoint)
}
@@ -5671,6 +5935,8 @@ function Ping-Endpoint
$iss.LanguageMode = "FullLanguage"
$WebRequestcmd = @'
+ param($WebProxy)
+
try
{{
$request = [System.Net.WebRequest]::Create("{0}")
@@ -5678,6 +5944,12 @@ function Ping-Endpoint
$request.Timeout = 30000
$request.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$request.AllowAutoRedirect = ${1}
+
+ if($WebProxy)
+ {{
+ $request.Proxy = $WebProxy
+ }}
+
$response = [System.Net.HttpWebResponse]$request.GetResponse()
if($response.StatusCode.value__ -eq 302)
{{
@@ -5696,6 +5968,12 @@ function Ping-Endpoint
'@ -f $EndPoint, $AllowAutoRedirect
$ps = [powershell]::Create($iss).AddScript($WebRequestcmd)
+
+ if($WebProxy)
+ {
+ $ps.AddParameter($WebProxy)
+ }
+
$response = $ps.Invoke()
$ps.dispose()
if ($response -ne "Error:System.Net.WebException")
@@ -5965,54 +6243,75 @@ function Set-PSGetSettingsVariable
}
}
-function Set-PSGalleryRepository
-{
- [CmdletBinding()]
- param([switch]$Trusted)
-
- $psgalleryLocation = Resolve-Location -Location $Script:PSGallerySourceUri `
- -LocationParameterName 'SourceLocation' `
- -ErrorAction SilentlyContinue `
- -WarningAction SilentlyContinue
-
- $scriptSourceLocation = Resolve-Location -Location $Script:PSGalleryScriptSourceUri `
- -LocationParameterName 'ScriptSourceLocation' `
- -ErrorAction SilentlyContinue `
- -WarningAction SilentlyContinue
- if($psgalleryLocation)
- {
- $result = Ping-Endpoint -Endpoint $Script:PSGalleryPublishUri -AllowAutoRedirect:$false
- if ($result.ContainsKey($Script:ResponseUri) -and $result[$Script:ResponseUri])
- {
- $script:PSGalleryPublishUri = $result[$Script:ResponseUri]
- }
-
- $repository = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
- Name = $Script:PSGalleryModuleSource
- SourceLocation = $psgalleryLocation
- PublishLocation = $Script:PSGalleryPublishUri
- ScriptSourceLocation = $scriptSourceLocation
- ScriptPublishLocation = $Script:PSGalleryPublishUri
- Trusted=$Trusted
- Registered=$true
- InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'}
- PackageManagementProvider=$script:NuGetProviderName
- ProviderOptions = @{}
- })
-
- $repository.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository")
- $script:PSGetModuleSources[$Script:PSGalleryModuleSource] = $repository
-
- Save-ModuleSources
-
- return $repository
- }
-}
-
+function Set-PSGalleryRepository
+{
+ [CmdletBinding()]
+ param(
+ [Parameter()]
+ [switch]
+ $Trusted,
+
+ [Parameter()]
+ $Proxy,
+
+ [Parameter()]
+ $ProxyCredential
+ )
+
+ $psgalleryLocation = Resolve-Location -Location $Script:PSGallerySourceUri `
+ -LocationParameterName 'SourceLocation' `
+ -Proxy $Proxy `
+ -ProxyCredential $ProxyCredential `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+
+ $scriptSourceLocation = Resolve-Location -Location $Script:PSGalleryScriptSourceUri `
+ -LocationParameterName 'ScriptSourceLocation' `
+ -Proxy $Proxy `
+ -ProxyCredential $ProxyCredential `
+ -ErrorAction SilentlyContinue `
+ -WarningAction SilentlyContinue
+ if($psgalleryLocation)
+ {
+ $result = Ping-Endpoint -Endpoint $Script:PSGalleryPublishUri -AllowAutoRedirect:$false -Proxy $Proxy -ProxyCredential $ProxyCredential
+ if ($result.ContainsKey($Script:ResponseUri) -and $result[$Script:ResponseUri])
+ {
+ $script:PSGalleryPublishUri = $result[$Script:ResponseUri]
+ }
+
+ $repository = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
+ Name = $Script:PSGalleryModuleSource
+ SourceLocation = $psgalleryLocation
+ PublishLocation = $Script:PSGalleryPublishUri
+ ScriptSourceLocation = $scriptSourceLocation
+ ScriptPublishLocation = $Script:PSGalleryPublishUri
+ Trusted=$Trusted
+ Registered=$true
+ InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'}
+ PackageManagementProvider=$script:NuGetProviderName
+ ProviderOptions = @{}
+ })
+
+ $repository.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository")
+ $script:PSGetModuleSources[$Script:PSGalleryModuleSource] = $repository
+
+ Save-ModuleSources
+
+ return $repository
+ }
+}
+
function Set-ModuleSourcesVariable
{
[CmdletBinding()]
- param([switch]$Force)
+ param(
+ [switch]
+ $Force,
+
+ $Proxy,
+
+ $ProxyCredential
+ )
if(-not $script:PSGetModuleSources -or $Force)
{
@@ -6027,7 +6326,7 @@ function Set-ModuleSourcesVariable
if(-not $script:PSGetModuleSources.Contains($Script:PSGalleryModuleSource))
{
- $null = Set-PSGalleryRepository
+ $null = Set-PSGalleryRepository -Proxy $Proxy -ProxyCredential $ProxyCredential
}
}
@@ -6039,7 +6338,7 @@ function Set-ModuleSourcesVariable
if(-not (Get-Member -InputObject $moduleSource -Name $script:ScriptSourceLocation))
{
- $scriptSourceLocation = Get-ScriptSourceLocation -Location $moduleSource.SourceLocation
+ $scriptSourceLocation = Get-ScriptSourceLocation -Location $moduleSource.SourceLocation -Proxy $Proxy -ProxyCredential $ProxyCredential
Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] `
-MemberType NoteProperty `
@@ -6584,6 +6883,12 @@ function Install-NuGetClientBinaries
[switch]
$BootstrapNuGetExe,
+ [Parameter()]
+ $Proxy,
+
+ [Parameter()]
+ $ProxyCredential,
+
[parameter()]
[switch]
$Force
@@ -6715,6 +7020,8 @@ function Install-NuGetClientBinaries
$shouldContinueCaption = $LocalizedData.InstallNuGetExeShouldContinueCaption
}
+ $AdditionalParams = Get-ParametersHashtable -Proxy $Proxy -ProxyCredential $ProxyCredential
+
if($Force -or $psCmdlet.ShouldContinue($shouldContinueQueryMessage, $shouldContinueCaption))
{
if($bootstrapNuGetProvider)
@@ -6731,7 +7038,7 @@ function Install-NuGetClientBinaries
$null = PackageManagement\Install-PackageProvider -Name $script:NuGetProviderName `
-MinimumVersion $script:NuGetProviderVersion `
-Scope $scope `
- -Force
+ -Force @AdditionalParams
# Force import ensures that nuget provider with minimum version got loaded.
$null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName `
@@ -6772,7 +7079,8 @@ function Install-NuGetClientBinaries
# Download the NuGet.exe from http://nuget.org/NuGet.exe
$null = Microsoft.PowerShell.Utility\Invoke-WebRequest -Uri $script:NuGetClientSourceURL `
- -OutFile $nugetExeFilePath
+ -OutFile $nugetExeFilePath `
+ @AdditionalParams
if (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeFilePath)
{
@@ -7604,7 +7912,7 @@ function Publish-PSArtifactUtility
Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false
- Microsoft.PowerShell.Management\Set-Content -Value $nuspec -Path $NuspecPath -Force -Confirm:$false -WhatIf:$false
+ Microsoft.PowerShell.Management\Set-Content -Value $nuspec -Path $NuspecPath -Force -Confirm:$false -WhatIf:$false
# Create .nupkg file
$output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory $NugetPackageRoot
@@ -7640,6 +7948,12 @@ function Publish-PSArtifactUtility
if($errorMsg)
{
+ if(($NugetApiKey -eq 'VSTS') -and
+ ($errorMsg -match 'Cannot prompt for input in non-interactive mode.') )
+ {
+ $errorMsg = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl)
+ }
+
if($PSArtifactType -eq $script:PSArtifactTypeModule)
{
$message = $LocalizedData.FailedToPublish -f ($Name,$errorMsg)
@@ -8005,11 +8319,11 @@ function Get-DynamicOptions
switch($category)
{
Package {
- Write-Output -InputObject (New-DynamicOption -Category $category `
- -Name $script:PSArtifactType `
- -ExpectedType String `
- -IsRequired $false `
- -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All))
+ Write-Output -InputObject (New-DynamicOption -Category $category `
+ -Name $script:PSArtifactType `
+ -ExpectedType String `
+ -IsRequired $false `
+ -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All))
Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Filter -ExpectedType String -IsRequired $false)
Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Tag -ExpectedType StringArray -IsRequired $false)
Write-Output -InputObject (New-DynamicOption -Category $category -Name Includes -ExpectedType StringArray -IsRequired $false -PermittedValues $script:IncludeValidSet)
@@ -8026,11 +8340,11 @@ function Get-DynamicOptions
Install
{
- Write-Output -InputObject (New-DynamicOption -Category $category `
- -Name $script:PSArtifactType `
- -ExpectedType String `
- -IsRequired $false `
- -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All))
+ Write-Output -InputObject (New-DynamicOption -Category $category `
+ -Name $script:PSArtifactType `
+ -ExpectedType String `
+ -IsRequired $false `
+ -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All))
Write-Output -InputObject (New-DynamicOption -Category $category -Name "Scope" -ExpectedType String -IsRequired $false -PermittedValues @("CurrentUser","AllUsers"))
Write-Output -InputObject (New-DynamicOption -Category $category -Name "InstallUpdate" -ExpectedType Switch -IsRequired $false)
Write-Output -InputObject (New-DynamicOption -Category $category -Name 'NoPathUpdate' -ExpectedType Switch -IsRequired $false)
@@ -8055,13 +8369,11 @@ function Add-PackageSource
Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource'))
- Set-ModuleSourcesVariable -Force
+ if(-not $Name)
+ {
+ return
+ }
- if(-not $Name)
- {
- return
- }
-
$IsNewModuleSource = $false
$Options = $request.Options
@@ -8070,6 +8382,31 @@ function Add-PackageSource
Write-Debug ( "OPTION: {0} => {1}" -f ($o, $Options[$o]) )
}
+ $Proxy = $null
+ if($Options.ContainsKey($script:Proxy))
+ {
+ $Proxy = $Options[$script:Proxy]
+
+ if(-not (Test-WebUri -Uri $Proxy))
+ {
+ $message = $LocalizedData.InvalidWebUri -f ($Proxy, $script:Proxy)
+ ThrowError -ExceptionName 'System.ArgumentException' `
+ -ExceptionMessage $message `
+ -ErrorId 'InvalidWebUri' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Proxy
+ }
+ }
+
+ $ProxyCredential = $null
+ if($Options.ContainsKey($script:ProxyCredential))
+ {
+ $ProxyCredential = $Options[$script:ProxyCredential]
+ }
+
+ Set-ModuleSourcesVariable -Force -Proxy $Proxy -ProxyCredential $ProxyCredential
+
if($Options.ContainsKey('IsNewModuleSource'))
{
$IsNewModuleSource = $Options['IsNewModuleSource']
@@ -8108,17 +8445,17 @@ function Add-PackageSource
$PublishLocation = $null
if($Options.ContainsKey($script:PublishLocation))
{
- if($Name -eq $Script:PSGalleryModuleSource)
- {
- $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('PublishLocation')
- ThrowError -ExceptionName "System.ArgumentException" `
- -ExceptionMessage $message `
- -ErrorId 'ParameterIsNotAllowedWithPSGallery' `
- -CallerPSCmdlet $PSCmdlet `
- -ErrorCategory InvalidArgument `
- -ExceptionObject $PublishLocation
- }
-
+ if($Name -eq $Script:PSGalleryModuleSource)
+ {
+ $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('PublishLocation')
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'ParameterIsNotAllowedWithPSGallery' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $PublishLocation
+ }
+
$PublishLocation = $Options[$script:PublishLocation]
if(-not (Microsoft.PowerShell.Management\Test-Path $PublishLocation) -and
@@ -8151,17 +8488,17 @@ function Add-PackageSource
$ScriptSourceLocation = $null
if($Options.ContainsKey($script:ScriptSourceLocation))
{
- if($Name -eq $Script:PSGalleryModuleSource)
- {
- $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('ScriptSourceLocation')
- ThrowError -ExceptionName "System.ArgumentException" `
- -ExceptionMessage $message `
- -ErrorId 'ParameterIsNotAllowedWithPSGallery' `
- -CallerPSCmdlet $PSCmdlet `
- -ErrorCategory InvalidArgument `
- -ExceptionObject $ScriptSourceLocation
- }
-
+ if($Name -eq $Script:PSGalleryModuleSource)
+ {
+ $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('ScriptSourceLocation')
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'ParameterIsNotAllowedWithPSGallery' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $ScriptSourceLocation
+ }
+
$ScriptSourceLocation = $Options[$script:ScriptSourceLocation]
if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptSourceLocation) -and
@@ -8194,17 +8531,17 @@ function Add-PackageSource
$ScriptPublishLocation = $null
if($Options.ContainsKey($script:ScriptPublishLocation))
{
- if($Name -eq $Script:PSGalleryModuleSource)
- {
- $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('ScriptPublishLocation')
- ThrowError -ExceptionName "System.ArgumentException" `
- -ExceptionMessage $message `
- -ErrorId 'ParameterIsNotAllowedWithPSGallery' `
- -CallerPSCmdlet $PSCmdlet `
- -ErrorCategory InvalidArgument `
- -ExceptionObject $ScriptPublishLocation
- }
-
+ if($Name -eq $Script:PSGalleryModuleSource)
+ {
+ $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('ScriptPublishLocation')
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'ParameterIsNotAllowedWithPSGallery' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $ScriptPublishLocation
+ }
+
$ScriptPublishLocation = $Options[$script:ScriptPublishLocation]
if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptPublishLocation) -and
@@ -8234,53 +8571,55 @@ function Add-PackageSource
}
}
- $currentSourceObject = $null
-
- # Check if Name is already registered
- if($script:PSGetModuleSources.Contains($Name))
- {
- $currentSourceObject = $script:PSGetModuleSources[$Name]
- }
-
- # Location is not allowed for PSGallery source
- # However OneGet passes Location value during Set-PackageSource cmdlet,
- # that's why ensuring that Location value is same as the current SourceLocation
- #
- if(($Name -eq $Script:PSGalleryModuleSource) -and
- $Location -and
- ((-not $IsUpdatePackageSource) -or ($currentSourceObject -and $currentSourceObject.SourceLocation -ne $Location)))
- {
- $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('Location, NewLocation or SourceLocation')
- ThrowError -ExceptionName "System.ArgumentException" `
- -ExceptionMessage $message `
- -ErrorId 'ParameterIsNotAllowedWithPSGallery' `
- -CallerPSCmdlet $PSCmdlet `
- -ErrorCategory InvalidArgument `
- -ExceptionObject $Location
- }
-
- if($Name -eq $Script:PSGalleryModuleSource)
- {
- # Add or update the PSGallery repostory
- $repository = Set-PSGalleryRepository -Trusted:$Trusted
-
- if($repository)
- {
- # return the package source object.
- Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $repository)
- }
-
- return
- }
-
- if($Location)
- {
- # Ping and resolve the specified location
- $Location = Resolve-Location -Location $Location `
- -LocationParameterName 'Location' `
- -CallerPSCmdlet $PSCmdlet
- }
-
+ $currentSourceObject = $null
+
+ # Check if Name is already registered
+ if($script:PSGetModuleSources.Contains($Name))
+ {
+ $currentSourceObject = $script:PSGetModuleSources[$Name]
+ }
+
+ # Location is not allowed for PSGallery source
+ # However OneGet passes Location value during Set-PackageSource cmdlet,
+ # that's why ensuring that Location value is same as the current SourceLocation
+ #
+ if(($Name -eq $Script:PSGalleryModuleSource) -and
+ $Location -and
+ ((-not $IsUpdatePackageSource) -or ($currentSourceObject -and $currentSourceObject.SourceLocation -ne $Location)))
+ {
+ $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('Location, NewLocation or SourceLocation')
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId 'ParameterIsNotAllowedWithPSGallery' `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument `
+ -ExceptionObject $Location
+ }
+
+ if($Name -eq $Script:PSGalleryModuleSource)
+ {
+ # Add or update the PSGallery repostory
+ $repository = Set-PSGalleryRepository -Trusted:$Trusted
+
+ if($repository)
+ {
+ # return the package source object.
+ Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $repository)
+ }
+
+ return
+ }
+
+ if($Location)
+ {
+ # Ping and resolve the specified location
+ $Location = Resolve-Location -Location $Location `
+ -LocationParameterName 'Location' `
+ -Proxy $Proxy `
+ -ProxyCredential $ProxyCredential `
+ -CallerPSCmdlet $PSCmdlet
+ }
+
if(-not $Location)
{
# Above Resolve-Location function throws an error when it is not able to resolve a location
@@ -8324,7 +8663,7 @@ function Add-PackageSource
-ExceptionObject $Name
}
- $LocationString = Get-ValidModuleLocation -LocationString $Location -ParameterName "Location"
+ $LocationString = Get-ValidModuleLocation -LocationString $Location -ParameterName "Location" -Proxy $Proxy -ProxyCredential $ProxyCredential
# Check if Location is already registered with another Name
$existingSourceName = Get-SourceName -Location $LocationString
@@ -8413,7 +8752,8 @@ function Add-PackageSource
if($SelectedProvider -and $SelectedProvider.Features.ContainsKey($script:SupportsPSModulesFeatureName))
{
- $packageSource = $SelectedProvider.ResolvePackageSources( (New-Request -Sources @($LocationString)) )
+ $NewRequest = $request.CloneRequest( $null, @($LocationString), $request.Credential )
+ $packageSource = $SelectedProvider.ResolvePackageSources( $NewRequest )
}
else
{
@@ -8454,7 +8794,8 @@ function Add-PackageSource
}
Write-Verbose ($LocalizedData.PollingSingleProviderForLocation -f ($LocationString, $provider.ProviderName))
- $packageSource = $provider.ResolvePackageSources((New-Request -Option @{} -Sources @($LocationString)))
+ $NewRequest = $request.CloneRequest( @{}, @($LocationString), $request.Credential )
+ $packageSource = $provider.ResolvePackageSources($NewRequest)
if($packageSource)
{
@@ -8525,7 +8866,7 @@ function Add-PackageSource
if(-not $ScriptSourceLocation)
{
- $ScriptSourceLocation = Get-ScriptSourceLocation -Location $LocationString
+ $ScriptSourceLocation = Get-ScriptSourceLocation -Location $LocationString -Proxy $Proxy -ProxyCredential $ProxyCredential
}
elseif($Options.ContainsKey($script:ScriptSourceLocation))
{
@@ -8546,7 +8887,14 @@ function Add-PackageSource
}
else
{
- if($ScriptSourceLocation -eq $LocationString)
+ if($ScriptSourceLocation -eq $LocationString -and
+ -not ($LocationString.EndsWith('/nuget/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('/nuget/v2/', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('/nuget', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('/nuget/', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('index.json', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('index.json/', [System.StringComparison]::OrdinalIgnoreCase))
+ )
{
$message = $LocalizedData.SourceLocationUrisForModulesAndScriptsShouldBeDifferent -f ($LocationString, $ScriptSourceLocation)
ThrowError -ExceptionName "System.InvalidOperationException" `
@@ -8826,12 +9174,10 @@ function Find-Package
else
{
$message = $LocalizedData.RepositoryNotFound -f ($sourceName)
- ThrowError -ExceptionName "System.ArgumentException" `
- -ExceptionMessage $message `
- -ErrorId "RepositoryNotFound" `
- -CallerPSCmdlet $PSCmdlet `
- -ErrorCategory InvalidArgument `
- -ExceptionObject $sourceName
+ Write-Error -Message $message `
+ -ErrorId 'RepositoryNotFound' `
+ -Category InvalidArgument `
+ -TargetObject $sourceName
}
}
}
@@ -9135,11 +9481,13 @@ function Find-Package
$providerOptions["Headers"] = 'PSGalleryClientVersion=1.1'
+ $NewRequest = $request.CloneRequest( $providerOptions, @($Location), $request.Credential )
+
$pkgs = $provider.FindPackages($names,
$requiredVersion,
$minimumVersion,
$maximumVersion,
- (New-Request -Sources @($Location) -Options $providerOptions) )
+ $NewRequest )
foreach($pkg in $pkgs)
{
@@ -9754,9 +10102,12 @@ function Install-PackageUtility
Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($provider.ProviderName, $providerName))
- $newRequest = New-Request -Options @{Destination=$tempDestination;
- ExcludeVersion=$true} `
- -Sources @($SourceLocation)
+ $ProviderOptions = @{
+ Destination=$tempDestination;
+ ExcludeVersion=$true
+ }
+
+ $newRequest = $request.CloneRequest( $ProviderOptions, @($SourceLocation), $request.Credential )
if($artfactType -eq $script:PSArtifactTypeModule)
{
@@ -10008,11 +10359,11 @@ function Install-PackageUtility
if($IsSavePackage)
{
- $message = $LocalizedData.ModuleSavedSuccessfully -f ($psgItemInfo.Name)
+ $message = $LocalizedData.ModuleSavedSuccessfully -f ($psgItemInfo.Name, $installLocation)
}
else
{
- $message = $LocalizedData.ModuleInstalledSuccessfully -f ($psgItemInfo.Name)
+ $message = $LocalizedData.ModuleInstalledSuccessfully -f ($psgItemInfo.Name, $installLocation)
}
Write-Verbose $message
}
@@ -10135,11 +10486,11 @@ function Install-PackageUtility
if($IsSavePackage)
{
- $message = $LocalizedData.ScriptSavedSuccessfully -f ($psgItemInfo.Name)
+ $message = $LocalizedData.ScriptSavedSuccessfully -f ($psgItemInfo.Name, $installLocation)
}
else
{
- $message = $LocalizedData.ScriptInstalledSuccessfully -f ($psgItemInfo.Name)
+ $message = $LocalizedData.ScriptInstalledSuccessfully -f ($psgItemInfo.Name, $installLocation)
}
Write-Verbose $message
}
@@ -11032,7 +11383,7 @@ function New-SoftwareIdentityFromPSGetItemInfo
}
$entities = New-Object -TypeName System.Collections.ArrayList
- if($psgetItemInfo.Author)
+ if($psgetItemInfo.Author -and $psgetItemInfo.Author.ToString())
{
$entities.Add( (New-Entity -Name $psgetItemInfo.Author -Role 'author') )
}
@@ -11373,7 +11724,13 @@ function Get-ValidModuleLocation
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]
- $ParameterName
+ $ParameterName,
+
+ [Parameter()]
+ $Proxy,
+
+ [Parameter()]
+ $ProxyCredential
)
# Get the actual Uri from the Location
@@ -11381,6 +11738,12 @@ function Get-ValidModuleLocation
{
# Append '/api/v2/' to the $LocationString, return if that URI works.
if(($LocationString -notmatch 'LinkID') -and
+ -not ($LocationString.EndsWith('/nuget/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('/nuget/v2/', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('/nuget', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('/nuget/', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('index.json', [System.StringComparison]::OrdinalIgnoreCase)) -and
+ -not ($LocationString.EndsWith('index.json/', [System.StringComparison]::OrdinalIgnoreCase)) -and
-not ($LocationString.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and
-not ($LocationString.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase))
)
@@ -11401,6 +11764,8 @@ function Get-ValidModuleLocation
# Ping and resolve the specified location
$tempLocation = Resolve-Location -Location $tempLocation `
-LocationParameterName $ParameterName `
+ -Proxy $Proxy `
+ -ProxyCredential $ProxyCredential `
-ErrorAction SilentlyContinue `
-WarningAction SilentlyContinue
if($tempLocation)
@@ -11414,6 +11779,8 @@ function Get-ValidModuleLocation
# Ping and resolve the specified location
$LocationString = Resolve-Location -Location $LocationString `
-LocationParameterName $ParameterName `
+ -Proxy $Proxy `
+ -ProxyCredential $ProxyCredential `
-CallerPSCmdlet $PSCmdlet
}
@@ -11750,6 +12117,11 @@ function Update-ModuleManifest
[System.Reflection.ProcessorArchitecture]
$ProcessorArchitecture,
+ [Parameter()]
+ [ValidateSet('Desktop','Core')]
+ [string[]]
+ $CompatiblePSEditions,
+
[Parameter()]
[ValidateNotNullOrEmpty()]
[Version]
@@ -11908,20 +12280,27 @@ function Update-ModuleManifest
}
#Get the original module manifest and migrate all the fields to the new module manifest, including the specified parameter values
+ $moduleInfo = $null
+
try
{
$moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $Path -ErrorAction Stop
}
catch
{
- $message = $LocalizedData.TestModuleManifestFail -f ($_.Exception.Message)
- ThrowError -ExceptionName "System.ArgumentException" `
- -ExceptionMessage $message `
- -ErrorId "InvalidModuleManifestFile" `
- -ExceptionObject $Path `
- -CallerPSCmdlet $PSCmdlet `
- -ErrorCategory InvalidArgument
- return
+ # Throw an error only if Test-ModuleManifest did not return the PSModuleInfo object.
+ # This enables the users to use Update-ModuleManifest cmdlet to update the metadata.
+ if(-not $moduleInfo)
+ {
+ $message = $LocalizedData.TestModuleManifestFail -f ($_.Exception.Message)
+ ThrowError -ExceptionName "System.ArgumentException" `
+ -ExceptionMessage $message `
+ -ErrorId "InvalidModuleManifestFile" `
+ -ExceptionObject $Path `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
}
#Params to pass to New-ModuleManifest module
@@ -12214,6 +12593,31 @@ function Update-ModuleManifest
}
}
+ if($CompatiblePSEditions)
+ {
+ # CompatiblePSEditions field is not available in PowerShell version lower than 5.1
+ #
+ if (($PSVersionTable.PSVersion -lt [Version]'5.1') -or ($PowerShellVersion -and $PowerShellVersion -lt [Version]'5.1') `
+ -or (-not $PowerShellVersion -and $moduleInfo.PowerShellVersion -and $moduleInfo.PowerShellVersion -lt [Version]'5.1') `
+ -or (-not $PowerShellVersion -and -not $moduleInfo.PowerShellVersion))
+ {
+ ThrowError -ExceptionName 'System.ArgumentException' `
+ -ExceptionMessage $LocalizedData.CompatiblePSEditionsNotSupportedOnLowerPowerShellVersion `
+ -ErrorId 'CompatiblePSEditionsNotSupported' `
+ -ExceptionObject $CompatiblePSEditions `
+ -CallerPSCmdlet $PSCmdlet `
+ -ErrorCategory InvalidArgument
+ return
+ }
+
+ $params.Add('CompatiblePSEditions', $CompatiblePSEditions)
+ }
+ elseif( (Microsoft.PowerShell.Utility\Get-Member -InputObject $moduleInfo -name 'CompatiblePSEditions') -and
+ $moduleInfo.CompatiblePSEditions)
+ {
+ $params.Add('CompatiblePSEditions', $moduleInfo.CompatiblePSEditions)
+ }
+
if($HelpInfoUri)
{
$params.Add("HelpInfoUri",$HelpInfoUri)
@@ -12900,7 +13304,13 @@ function Get-ScriptSourceLocation
(
[Parameter()]
[String]
- $Location
+ $Location,
+
+ [Parameter()]
+ $Proxy,
+
+ [Parameter()]
+ $ProxyCredential
)
$scriptLocation = $null
@@ -12930,6 +13340,8 @@ function Get-ScriptSourceLocation
# Ping and resolve the specified location
$scriptLocation = Resolve-Location -Location $tempScriptLocation `
-LocationParameterName 'ScriptSourceLocation' `
+ -Proxy $Proxy `
+ -ProxyCredential $ProxyCredential `
-ErrorAction SilentlyContinue `
-WarningAction SilentlyContinue
}
@@ -12994,6 +13406,12 @@ function Resolve-Location
[Parameter(Mandatory=$true)]
[string]
$LocationParameterName,
+
+ [Parameter()]
+ $Proxy,
+
+ [Parameter()]
+ $ProxyCredential,
[Parameter()]
[System.Management.Automation.PSCmdlet]
@@ -13020,7 +13438,7 @@ function Resolve-Location
}
else
{
- $pingResult = Ping-Endpoint -Endpoint $Location
+ $pingResult = Ping-Endpoint -Endpoint $Location -Proxy $Proxy -ProxyCredential $ProxyCredential
$statusCode = $null
$exception = $null
$resolvedLocation = $null
diff --git a/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs b/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs
index aed8e2d4e..8b5153d7e 100644
--- a/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs
+++ b/src/System.Management.Automation/engine/CommandCompletion/CommandCompletion.cs
@@ -6,11 +6,13 @@ Copyright (c) Microsoft Corporation. All rights reserved.
using System.Collections.ObjectModel;
using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
using System.Text.RegularExpressions;
+using Microsoft.PowerShell.Telemetry.Internal;
namespace System.Management.Automation
{
@@ -518,6 +520,9 @@ namespace System.Management.Automation
// This is the start of the real implementation of autocomplete/intellisense/tab completion
private static CommandCompletion CompleteInputImpl(Ast ast, Token[] tokens, IScriptPosition positionOfCursor, Hashtable options)
{
+ var sw = new Stopwatch();
+ sw.Start();
+
using (var powershell = PowerShell.Create(RunspaceMode.CurrentRunspace))
{
var context = LocalPipeline.GetExecutionContextFromTLS();
@@ -585,8 +590,13 @@ namespace System.Management.Automation
}
*/
}
+
+ var completionResults = results ?? EmptyCompletionResult;
+ sw.Stop();
+ TelemetryAPI.ReportTabCompletionTelemetry(sw.ElapsedMilliseconds, completionResults.Count,
+ completionResults.Count > 0 ? completionResults[0].ResultType : CompletionResultType.Text);
return new CommandCompletion(
- new Collection(results ?? EmptyCompletionResult),
+ new Collection(completionResults),
-1,
replacementIndex,
replacementLength);
diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs
index d71495ad6..24ceecc55 100644
--- a/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs
+++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs
@@ -1376,7 +1376,8 @@ namespace System.Management.Automation
var moduleExtensions = new HashSet(StringComparer.OrdinalIgnoreCase)
{
StringLiterals.PowerShellModuleFileExtension,
- StringLiterals.PowerShellDataFileExtension,
+ StringLiterals.PowerShellDataFileExtension,
+ StringLiterals.PowerShellNgenAssemblyExtension,
StringLiterals.DependentWorkflowAssemblyExtension,
StringLiterals.PowerShellCmdletizationFileExtension,
StringLiterals.WorkflowFileExtension
diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
index 9b6b1735a..a391cfbe6 100644
--- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
+++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
@@ -3111,8 +3111,9 @@ namespace System.Management.Automation
var moduleExtensions = new HashSet(StringComparer.OrdinalIgnoreCase)
{ StringLiterals.PowerShellScriptFileExtension,
StringLiterals.PowerShellModuleFileExtension,
- StringLiterals.PowerShellDataFileExtension,
- StringLiterals.DependentWorkflowAssemblyExtension,
+ StringLiterals.PowerShellDataFileExtension,
+ StringLiterals.PowerShellNgenAssemblyExtension,
+ StringLiterals.DependentWorkflowAssemblyExtension,
StringLiterals.PowerShellCmdletizationFileExtension,
StringLiterals.WorkflowFileExtension
};
@@ -4113,7 +4114,7 @@ namespace System.Management.Automation
wordToComplete = WildcardPattern.Escape(wordToComplete, Utils.Separators.StarOrQuestion);
}
- if (!defaultRelative && wordToComplete.Length >= 2 && wordToComplete[1] == ':' && char.IsLetter(wordToComplete[0]))
+ if (!defaultRelative && wordToComplete.Length >= 2 && wordToComplete[1] == ':' && char.IsLetter(wordToComplete[0]) && context.ExecutionContext != null)
{
// We don't actually need the drive, but the drive must be "mounted" in PowerShell before completion
// can succeed. This call will mount the drive if it wasn't already.
diff --git a/src/System.Management.Automation/engine/CommandSearcher.cs b/src/System.Management.Automation/engine/CommandSearcher.cs
index ff6620369..5f46c22a1 100644
--- a/src/System.Management.Automation/engine/CommandSearcher.cs
+++ b/src/System.Management.Automation/engine/CommandSearcher.cs
@@ -607,12 +607,9 @@ namespace System.Management.Automation
do // false loop
{
- if (!File.Exists(path))
+ if (!Utils.NativeFileExists(path))
{
- CommandDiscovery.discoveryTracer.TraceError(
- "The path does not exist: {0}",
- path);
-
+ CommandDiscovery.discoveryTracer.TraceError("The path does not exist: {0}", path);
break;
}
diff --git a/src/System.Management.Automation/engine/CompiledCommandParameter.cs b/src/System.Management.Automation/engine/CompiledCommandParameter.cs
index fbc237b0b..d973df684 100644
--- a/src/System.Management.Automation/engine/CompiledCommandParameter.cs
+++ b/src/System.Management.Automation/engine/CompiledCommandParameter.cs
@@ -60,7 +60,7 @@ namespace System.Management.Automation
Collection validationAttributes = null;
Collection argTransformationAttributes = null;
- Collection aliases = null;
+ string[] aliases = null;
// First, process attributes that aren't type conversions
foreach (Attribute attribute in runtimeDefinedParameter.Attributes)
@@ -166,7 +166,7 @@ namespace System.Management.Automation
Collection validationAttributes = null;
Collection argTransformationAttributes = null;
- Collection aliases = null;
+ string[] aliases = null;
foreach (Attribute attr in memberAttributes)
{
@@ -179,9 +179,7 @@ namespace System.Management.Automation
this.ArgumentTransformationAttributes = argTransformationAttributes == null
? Utils.EmptyArray()
: argTransformationAttributes.ToArray();
- this.Aliases = aliases == null
- ? Utils.EmptyArray()
- : aliases.ToArray();
+ this.Aliases = aliases ?? Utils.EmptyArray();
}
#endregion ctor
@@ -437,7 +435,7 @@ namespace System.Management.Automation
Attribute attribute,
ref Collection validationAttributes,
ref Collection argTransformationAttributes,
- ref Collection aliases)
+ ref string[] aliases)
{
// NTRAID#Windows Out Of Band Releases-926374-2005/12/22-JonN
if (null == attribute)
@@ -471,14 +469,15 @@ namespace System.Management.Automation
{
if (aliases == null)
{
- aliases = new Collection(aliasAttr.aliasNames);
+ aliases = aliasAttr.aliasNames;
}
else
{
- for (int i = 0; i < aliasAttr.aliasNames.Length; i++)
- {
- aliases.Add(aliasAttr.aliasNames[i]);
- }
+ var prevAliasNames = aliases;
+ var newAliasNames = aliasAttr.aliasNames;
+ aliases = new string[prevAliasNames.Length + newAliasNames.Length];
+ Array.Copy(prevAliasNames, aliases, prevAliasNames.Length);
+ Array.Copy(newAliasNames, 0, aliases, prevAliasNames.Length, newAliasNames.Length);
}
return;
}
diff --git a/src/System.Management.Automation/engine/EventManager.cs b/src/System.Management.Automation/engine/EventManager.cs
index 5c6c2e35c..1412b6d62 100644
--- a/src/System.Management.Automation/engine/EventManager.cs
+++ b/src/System.Management.Automation/engine/EventManager.cs
@@ -2643,9 +2643,10 @@ namespace System.Management.Automation
private void OnPSEventReceived(Object sender, PSEventArgs e)
{
- if (PSEventReceived != null)
+ PSEventReceivedEventHandler eventHandler = PSEventReceived;
+ if (eventHandler != null)
{
- PSEventReceived(sender, e);
+ eventHandler(sender, e);
}
}
diff --git a/src/System.Management.Automation/engine/GetCommandCommand.cs b/src/System.Management.Automation/engine/GetCommandCommand.cs
index da5ed24d9..885df395a 100644
--- a/src/System.Management.Automation/engine/GetCommandCommand.cs
+++ b/src/System.Management.Automation/engine/GetCommandCommand.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Diagnostics;
using System.IO;
using System.Management.Automation;
using System.Diagnostics.CodeAnalysis;
@@ -381,6 +382,8 @@ namespace Microsoft.PowerShell.Commands
///
protected override void BeginProcessing()
{
+ _timer.Start();
+
base.BeginProcessing();
if (ShowCommandInfo.IsPresent && Syntax.IsPresent)
@@ -522,8 +525,10 @@ namespace Microsoft.PowerShell.Commands
{
CommandOrigin origin = this.MyInvocation.CommandOrigin;
+ int count = 0;
foreach (CommandInfo result in results)
{
+ count += 1;
// Only write the command if it is visible to the requestor
if (SessionState.IsVisible(origin, result))
{
@@ -556,6 +561,17 @@ namespace Microsoft.PowerShell.Commands
}
}
}
+
+ _timer.Stop();
+
+ // We want telemtry on commands people look for but don't exist - this should give us an idea
+ // what sort of commands people expect but either don't exist, or maybe should be installed by default.
+ // The StartsWith is to avoid logging telemetry when suggestion mode checks the
+ // current directory for scripts/exes in the current directory and '.' is not in the path.
+ if (count == 0 && Name != null && Name.Length > 0 && !Name[0].StartsWith(".\\"))
+ {
+ Telemetry.Internal.TelemetryAPI.ReportGetCommandFailed(Name, _timer.ElapsedMilliseconds);
+ }
}
///
@@ -1396,6 +1412,8 @@ namespace Microsoft.PowerShell.Commands
Collection nounPatterns;
Collection _modulePatterns;
+ private Stopwatch _timer = new Stopwatch();
+
#endregion
#region ShowCommandInfo support
diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs
index c38707f96..7923ef0de 100644
--- a/src/System.Management.Automation/engine/InitialSessionState.cs
+++ b/src/System.Management.Automation/engine/InitialSessionState.cs
@@ -2965,7 +2965,7 @@ namespace System.Management.Automation.Runspaces
// Get initial list of public commands in session.
HashSet publicCommands = new HashSet();
foreach (CommandInfo sessionCommand in initializedRunspace.ExecutionContext.SessionState.InvokeCommand.GetCommands(
- "*", CommandTypes.All, true))
+ "*", CommandTypes.Alias | CommandTypes.Function | CommandTypes.Filter | CommandTypes.Cmdlet, true))
{
if (sessionCommand.Visibility == SessionStateEntryVisibility.Public)
{
@@ -3626,15 +3626,12 @@ namespace System.Management.Automation.Runspaces
if (this.DefaultCommandVisibility != SessionStateEntryVisibility.Public)
{
foreach (CommandInfo importedCommand in initializedRunspace.ExecutionContext.SessionState.InvokeCommand.GetCommands(
- "*", CommandTypes.All, true))
+ "*", CommandTypes.Alias | CommandTypes.Function | CommandTypes.Filter | CommandTypes.Cmdlet, true))
{
try
{
// All commands except for the initial session public commands should be made private.
- // Exclude ApplicationInfo/ExternalScriptInfo commands as they throw on the setter (because
- // visibility is governed via the ExceutionContext.SessionState lists).
- if (!(importedCommand is ApplicationInfo) && !(importedCommand is ExternalScriptInfo) &&
- (importedCommand.Visibility != this.DefaultCommandVisibility) &&
+ if ((importedCommand.Visibility != this.DefaultCommandVisibility) &&
!publicCommands.Contains(importedCommand))
{
importedCommand.Visibility = this.DefaultCommandVisibility;
@@ -6128,6 +6125,7 @@ if($paths) {
{"Invoke-History", new SessionStateCmdletEntry("Invoke-History", typeof(InvokeHistoryCommand), helpFile) },
{"New-Module", new SessionStateCmdletEntry("New-Module", typeof(NewModuleCommand), helpFile) },
{"New-ModuleManifest", new SessionStateCmdletEntry("New-ModuleManifest", typeof(NewModuleManifestCommand), helpFile) },
+ {"New-PSRoleCapabilityFile", new SessionStateCmdletEntry("New-PSRoleCapabilityFile", typeof(NewPSRoleCapabilityFileCommand), helpFile) },
{"New-PSSession", new SessionStateCmdletEntry("New-PSSession", typeof(NewPSSessionCommand), helpFile) },
{"New-PSSessionConfigurationFile", new SessionStateCmdletEntry("New-PSSessionConfigurationFile", typeof(NewPSSessionConfigurationFileCommand), helpFile) },
{"New-PSSessionOption", new SessionStateCmdletEntry("New-PSSessionOption", typeof(NewPSSessionOptionCommand), helpFile) },
@@ -6159,7 +6157,6 @@ if($paths) {
{"Enable-PSRemoting", new SessionStateCmdletEntry("Enable-PSRemoting", typeof(EnablePSRemotingCommand), helpFile) },
{"Export-Console", new SessionStateCmdletEntry("Export-Console", typeof(ExportConsoleCommand), helpFile) },
{"Get-PSSnapin", new SessionStateCmdletEntry("Get-PSSnapin", typeof(GetPSSnapinCommand), helpFile) },
- {"New-PSRoleCapabilityFile", new SessionStateCmdletEntry("New-PSRoleCapabilityFile", typeof(NewPSRoleCapabilityFileCommand), helpFile) },
{"New-PSTransportOption", new SessionStateCmdletEntry("New-PSTransportOption", typeof(NewPSTransportOptionCommand), helpFile) },
{"Remove-PSSnapin", new SessionStateCmdletEntry("Remove-PSSnapin", typeof(RemovePSSnapinCommand), helpFile) },
{"Resume-Job", new SessionStateCmdletEntry("Resume-Job", typeof(ResumeJobCommand), helpFile) },
@@ -6189,9 +6186,6 @@ if($paths) {
}
}
- internal static readonly CallSite> CreateModuleInitializerInstance =
- CallSite>.Create(PSCreateInstanceBinder.Get(new CallInfo(0), null));
-
private static void ExecuteModuleInitializer(Assembly assembly, Type[] assemblyTypes, bool isModuleLoad)
{
for (int i = 0; i < assemblyTypes.Length; i++)
@@ -6203,9 +6197,7 @@ if($paths) {
if (isModuleLoad && typeof(IModuleAssemblyInitializer).IsAssignableFrom(type) && type != typeof(IModuleAssemblyInitializer))
{
_assembliesWithModuleInitializerCache.Value[assembly] = true;
- var moduleInitializer = (IModuleAssemblyInitializer) CreateModuleInitializerInstance
- .Target.Invoke(
- CreateModuleInitializerInstance, type);
+ IModuleAssemblyInitializer moduleInitializer = (IModuleAssemblyInitializer)Activator.CreateInstance(type, true);
moduleInitializer.OnImport();
}
}
diff --git a/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs b/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs
index 30fa35ddd..aea5ad892 100644
--- a/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs
+++ b/src/System.Management.Automation/engine/Modules/ImportModuleCommand.cs
@@ -24,6 +24,7 @@ using Parser = System.Management.Automation.Language.Parser;
using ScriptBlock = System.Management.Automation.ScriptBlock;
using Token = System.Management.Automation.Language.Token;
using System.Collections.ObjectModel;
+using Microsoft.PowerShell.Telemetry.Internal;
#if CORECLR
// Use stub for SecurityZone.
@@ -266,7 +267,7 @@ namespace Microsoft.PowerShell.Commands
}
set
{
- if (value == null)
+ if (string.IsNullOrWhiteSpace(value))
{
BaseMaximumVersion = null;
}
@@ -1752,6 +1753,8 @@ namespace Microsoft.PowerShell.Commands
if (null != foundModule)
{
SetModuleBaseForEngineModules(foundModule.Name, this.Context);
+
+ TelemetryAPI.ReportModuleLoad(foundModule);
}
}
}
diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs
index d8beb019a..ac692127d 100644
--- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs
+++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs
@@ -1256,8 +1256,18 @@ namespace Microsoft.PowerShell.Commands
currentlyProcessingModules[file] = null;
// Create a fake module info for this file
+ string extension;
+ file = file.TrimEnd();
- string extension = Path.GetExtension(file);
+ // In case the file is a Ngen Assembly.
+ if (file.EndsWith(StringLiterals.PowerShellNgenAssemblyExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ extension = StringLiterals.PowerShellNgenAssemblyExtension;
+ }
+ else
+ {
+ extension = Path.GetExtension(file);
+ }
ManifestProcessingFlags flags = ManifestProcessingFlags.NullOnFirstError;
// We are creating the ModuleInfo for Get-Module..so ignoring
@@ -1334,7 +1344,7 @@ namespace Microsoft.PowerShell.Commands
}
}
- else if (extension.Equals(".dll", StringComparison.OrdinalIgnoreCase))
+ else if (extension.Equals(StringLiterals.DependentWorkflowAssemblyExtension, StringComparison.OrdinalIgnoreCase) || extension.Equals(StringLiterals.PowerShellNgenAssemblyExtension, StringComparison.OrdinalIgnoreCase))
{
moduleInfo.SetModuleType(ModuleType.Binary);
moduleInfo.RootModule = moduleInfo.Path;
@@ -2273,12 +2283,18 @@ namespace Microsoft.PowerShell.Commands
}
else
{
- string fileName = FixupFileName(moduleBase, assembly, ".dll");
-
+ string fileName = FixupFileName(moduleBase, assembly, StringLiterals.PowerShellNgenAssemblyExtension);
string loadMessage = StringUtil.Format(Modules.LoadingFile, "Assembly", fileName);
WriteVerbose(loadMessage);
iss.Assemblies.Add(new SessionStateAssemblyEntry(assembly, fileName));
fixedUpAssemblyPathList.Add(fileName);
+
+ fileName = FixupFileName(moduleBase, assembly, StringLiterals.DependentWorkflowAssemblyExtension);
+
+ loadMessage = StringUtil.Format(Modules.LoadingFile, "Assembly", fileName);
+ WriteVerbose(loadMessage);
+ iss.Assemblies.Add(new SessionStateAssemblyEntry(assembly, fileName));
+ fixedUpAssemblyPathList.Add(fileName);
doBind = true;
}
}
@@ -5244,8 +5260,7 @@ namespace Microsoft.PowerShell.Commands
{
if (typeof(IModuleAssemblyCleanup).IsAssignableFrom(type) && type != typeof(IModuleAssemblyCleanup))
{
- var moduleCleanup = (IModuleAssemblyCleanup) PSSnapInHelpers.CreateModuleInitializerInstance.Target.Invoke(
- PSSnapInHelpers.CreateModuleInitializerInstance, type);
+ var moduleCleanup = (IModuleAssemblyCleanup)Activator.CreateInstance(type, true);
moduleCleanup.OnRemove(module);
}
}
@@ -5628,8 +5643,10 @@ namespace Microsoft.PowerShell.Commands
var importingModule = 0 != (manifestProcessingFlags & ManifestProcessingFlags.LoadElements);
- foreach (string ext in extensions)
+ // "ni.dll" has a higher priority then ".dll" to be loaded.
+ for (int i = 0; i < extensions.Length; i++)
{
+ string ext = extensions[i];
string fileName = fileBaseName + ext;
// Get the resolved file name
@@ -5859,7 +5876,16 @@ namespace Microsoft.PowerShell.Commands
var importingModule = 0 != (manifestProcessingFlags & ManifestProcessingFlags.LoadElements);
var writingErrors = 0 != (manifestProcessingFlags & ManifestProcessingFlags.WriteErrors);
- string ext = Path.GetExtension(fileName);
+ // In case the file is a Ngen Assembly.
+ string ext;
+ if (fileName.EndsWith(StringLiterals.PowerShellNgenAssemblyExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ ext = StringLiterals.PowerShellNgenAssemblyExtension;
+ }
+ else
+ {
+ ext = Path.GetExtension(fileName);
+ }
PSModuleInfo module = null;
// If MinimumVersion/RequiredVersion/MaximumVersion has been specified, then only try to process manifest modules...
@@ -6113,7 +6139,7 @@ namespace Microsoft.PowerShell.Commands
found = false;
}
}
- else if (ext.Equals(".dll", StringComparison.OrdinalIgnoreCase))
+ else if (ext.Equals(".dll", StringComparison.OrdinalIgnoreCase) || ext.Equals(StringLiterals.PowerShellNgenAssemblyExtension))
{
module = LoadBinaryModule(false, ModuleIntrinsics.GetModuleName(fileName), fileName, null,
moduleBase, ss, options, manifestProcessingFlags, prefix, true, true, out found);
diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs
index 6fe29f7e8..129fd8db5 100644
--- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs
+++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs
@@ -479,22 +479,24 @@ namespace System.Management.Automation
return new Guid();
}
- // The extensions of all of the files that can be processed with Import-Module
+ // The extensions of all of the files that can be processed with Import-Module, put the ni.dll in front of .dll to have higher priority to be loaded.
internal static string[] PSModuleProcessableExtensions = new string[] {
StringLiterals.PowerShellDataFileExtension,
StringLiterals.PowerShellScriptFileExtension,
StringLiterals.PowerShellModuleFileExtension,
StringLiterals.PowerShellCmdletizationFileExtension,
StringLiterals.WorkflowFileExtension,
- ".dll" };
+ StringLiterals.PowerShellNgenAssemblyExtension,
+ StringLiterals.DependentWorkflowAssemblyExtension};
- // A list of the extensions to check for implicit module loading and discovery
+ // A list of the extensions to check for implicit module loading and discovery, put the ni.dll in front of .dll to have higher priority to be loaded.
internal static string[] PSModuleExtensions = new string[] {
StringLiterals.PowerShellDataFileExtension,
StringLiterals.PowerShellModuleFileExtension,
StringLiterals.PowerShellCmdletizationFileExtension,
StringLiterals.WorkflowFileExtension,
- ".dll" };
+ StringLiterals.PowerShellNgenAssemblyExtension,
+ StringLiterals.DependentWorkflowAssemblyExtension};
///
/// Returns true if the extension is one of the module extensions...
@@ -519,7 +521,15 @@ namespace System.Management.Automation
internal static string GetModuleName(string path)
{
string fileName = path == null ? string.Empty : Path.GetFileName(path);
- string ext = Path.GetExtension(fileName);
+ string ext;
+ if (fileName.EndsWith(StringLiterals.PowerShellNgenAssemblyExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ ext = StringLiterals.PowerShellNgenAssemblyExtension;
+ }
+ else
+ {
+ ext = Path.GetExtension(fileName);
+ }
if (!string.IsNullOrEmpty(ext) && IsPowerShellModuleExtension(ext))
{
return fileName.Substring(0, fileName.Length - ext.Length);
diff --git a/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs b/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs
index c452b6561..b74c18bfa 100644
--- a/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs
+++ b/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs
@@ -141,7 +141,11 @@ namespace Microsoft.PowerShell.Commands
{
foreach (ModuleSpecification nestedModule in nestedModules)
{
- if (!IsValidFilePath(nestedModule.Name, module, true) && !IsValidFilePath(nestedModule.Name + ".dll", module, true) && !IsValidFilePath(nestedModule.Name + ".psm1", module, true) && !IsValidGacAssembly(nestedModule.Name))
+ if (!IsValidFilePath(nestedModule.Name, module, true)
+ && !IsValidFilePath(nestedModule.Name + StringLiterals.DependentWorkflowAssemblyExtension, module, true)
+ && !IsValidFilePath(nestedModule.Name + StringLiterals.PowerShellNgenAssemblyExtension, module, true)
+ && !IsValidFilePath(nestedModule.Name + StringLiterals.PowerShellModuleFileExtension, module, true)
+ && !IsValidGacAssembly(nestedModule.Name))
{
// The nested module could be dependencies. We compare if it can be loaded by loadmanifest
bool isDependency = false;
@@ -323,16 +327,23 @@ namespace Microsoft.PowerShell.Commands
{
string gacPath = System.Environment.GetEnvironmentVariable("windir") + "\\Microsoft.NET\\assembly";
string assemblyFile = assemblyName;
- if (!assemblyName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
+ string ngenAssemblyFile = assemblyName;
+ if (!assemblyName.EndsWith(StringLiterals.DependentWorkflowAssemblyExtension, StringComparison.OrdinalIgnoreCase))
{
- assemblyFile = assemblyName + ".dll";
+ assemblyFile = assemblyName + StringLiterals.DependentWorkflowAssemblyExtension;
+ ngenAssemblyFile = assemblyName + StringLiterals.PowerShellNgenAssemblyExtension;
}
try
{
var allFiles = Directory.GetFiles(gacPath, assemblyFile, SearchOption.AllDirectories);
+
if (allFiles.Length == 0)
{
- return false;
+ var allNgenFiles = Directory.GetFiles(gacPath, ngenAssemblyFile, SearchOption.AllDirectories);
+ if (allNgenFiles.Length == 0)
+ {
+ return false;
+ }
}
}
catch
diff --git a/src/System.Management.Automation/engine/SessionStateStrings.cs b/src/System.Management.Automation/engine/SessionStateStrings.cs
index e932264be..4ea503ed5 100644
--- a/src/System.Management.Automation/engine/SessionStateStrings.cs
+++ b/src/System.Management.Automation/engine/SessionStateStrings.cs
@@ -138,6 +138,11 @@ namespace System.Management.Automation
///
internal const string DependentWorkflowAssemblyExtension = ".dll";
+ ///
+ /// The file extension (including the dot) of an workflow dependent Ngen assembly
+ ///
+ internal const string PowerShellNgenAssemblyExtension = ".ni.dll";
+
internal const string PowerShellConsoleFileExtension = ".psc1";
///
diff --git a/src/System.Management.Automation/engine/Types_Ps1Xml.generated.cs b/src/System.Management.Automation/engine/Types_Ps1Xml.generated.cs
index 1b16b739f..5f0e7a90f 100644
--- a/src/System.Management.Automation/engine/Types_Ps1Xml.generated.cs
+++ b/src/System.Management.Automation/engine/Types_Ps1Xml.generated.cs
@@ -689,7 +689,7 @@ namespace System.Management.Automation.Runspaces
# WMI team fixed the formatting issue related to InstalledOn
# property in Windows7 (to return string)..so returning the WMI's
# version directly
- [DateTime]::Parse($this.psBase.properties[""InstalledOn""].Value)
+ [DateTime]::Parse($this.psBase.properties[""InstalledOn""].Value, [System.Globalization.DateTimeFormatInfo]::new())
}
else
{
@@ -1781,7 +1781,7 @@ namespace System.Management.Automation.Runspaces
# WMI team fixed the formatting issue related to InstalledOn
# property in Windows7 (to return string)..so returning the WMI's
# version directly
- [DateTime]::Parse($this.psBase.CimInstanceProperties[""InstalledOn""].Value)
+ [DateTime]::Parse($this.psBase.CimInstanceProperties[""InstalledOn""].Value, [System.Globalization.DateTimeFormatInfo]::new())
}
else
{
diff --git a/src/System.Management.Automation/engine/hostifaces/ConnectionBase.cs b/src/System.Management.Automation/engine/hostifaces/ConnectionBase.cs
index c8dbad660..fb267e465 100644
--- a/src/System.Management.Automation/engine/hostifaces/ConnectionBase.cs
+++ b/src/System.Management.Automation/engine/hostifaces/ConnectionBase.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Threading;
using System.Management.Automation.Host;
using System.Management.Automation.Internal;
+using Microsoft.PowerShell.Telemetry.Internal;
using Dbg = System.Management.Automation.Diagnostics;
#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings
@@ -308,6 +309,16 @@ namespace System.Management.Automation.Runspaces
OpenHelper(syncCall);
if (etwEnabled) RunspaceEventSource.Log.OpenRunspaceStop();
+
+ // We report startup telemtry when opening the runspace - because this is the first time
+ // we are really using PowerShell. This isn't the cleanest place though, because
+ // sometimes there are many runspaces created - the callee ensures telemetry is only
+ // reported once. Note that if the host implements IHostProvidesTelemetryData, we rely
+ // on the host calling ReportStartupTelemetry.
+ if (!(this.Host is IHostProvidesTelemetryData))
+ {
+ TelemetryAPI.ReportStartupTelemetry(null);
+ }
}
diff --git a/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs b/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
index 093c06e22..c66853dbb 100644
--- a/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
+++ b/src/System.Management.Automation/engine/hostifaces/LocalConnection.cs
@@ -16,6 +16,7 @@ using System.Diagnostics.CodeAnalysis; // for fxcop
using Dbg = System.Management.Automation.Diagnostics;
using System.Diagnostics;
using System.Linq;
+using Microsoft.PowerShell.Telemetry.Internal;
#if CORECLR
@@ -933,6 +934,28 @@ namespace System.Management.Automation.Runspaces
//Raise Event
RaiseRunspaceStateEvents ();
+
+ // Report telemetry if we have no more open runspaces.
+ bool allRunspacesClosed = true;
+ bool hostProvidesExitTelemetry = false;
+ foreach (var r in Runspace.RunspaceList)
+ {
+ if (r.RunspaceStateInfo.State != RunspaceState.Closed)
+ {
+ allRunspacesClosed = false;
+ break;
+ }
+ var localRunspace = r as LocalRunspace;
+ if (localRunspace != null && localRunspace.Host is IHostProvidesTelemetryData)
+ {
+ hostProvidesExitTelemetry = true;
+ break;
+ }
+ }
+ if (allRunspacesClosed && !hostProvidesExitTelemetry)
+ {
+ TelemetryAPI.ReportExitTelemetry(null);
+ }
}
///
diff --git a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs
index 053b69ab2..f64753422 100644
--- a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs
+++ b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs
@@ -1109,6 +1109,8 @@ namespace System.Management.Automation.Host
///
public void Dispose()
{
+ if (disposed) { return; }
+
// Wait for any pending output to be flushed to disk so that Stop-Transcript
// can be trusted to immediately have all content from that session in the file)
int outputWait = 0;
@@ -1124,6 +1126,7 @@ namespace System.Management.Automation.Host
{
contentWriter.Flush();
contentWriter.Dispose();
+ contentWriter = null;
}
disposed = true;
diff --git a/src/System.Management.Automation/engine/remoting/commands/NewPSSessionConfigurationFile.cs b/src/System.Management.Automation/engine/remoting/commands/NewPSSessionConfigurationFile.cs
index 5ae32f5c0..70618687d 100644
--- a/src/System.Management.Automation/engine/remoting/commands/NewPSSessionConfigurationFile.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/NewPSSessionConfigurationFile.cs
@@ -584,7 +584,7 @@ namespace Microsoft.PowerShell.Commands
#region Overrides
///
- ///
+ ///
///
protected override void ProcessRecord()
{
@@ -739,6 +739,8 @@ namespace Microsoft.PowerShell.Commands
}
else
{
+ DISCUtils.ValidateRoleDefinitions(roleDefinitions);
+
result.Append(SessionConfigurationUtils.ConfigFragment(ConfigFileConstants.RoleDefinitions, RemotingErrorIdStrings.DISCRoleDefinitionsComment,
SessionConfigurationUtils.CombineHashtable(roleDefinitions, streamWriter), streamWriter, false));
}
@@ -1055,6 +1057,10 @@ namespace Microsoft.PowerShell.Commands
}
}
+ #endregion
+
+ #region Private methods
+
private bool ShouldGenerateConfigurationSnippet(string parameterName)
{
return Full || MyInvocation.BoundParameters.ContainsKey(parameterName);
@@ -1068,9 +1074,7 @@ namespace Microsoft.PowerShell.Commands
///
/// Creates a role capability file suitable for use in a Role Capability (which can be referenced in a Session Configuration file)
///
-#if !CORECLR
[Cmdlet(VerbsCommon.New, "PSRoleCapabilityFile", HelpUri = "http://go.microsoft.com/fwlink/?LinkId=623708")]
-#endif
public class NewPSRoleCapabilityFileCommand : PSCmdlet
{
#region Parameters
@@ -1745,6 +1749,8 @@ namespace Microsoft.PowerShell.Commands
#endregion
}
+ #region SessionConfigurationUtils
+
///
/// Utility methods for configuration file commands
///
@@ -2029,4 +2035,6 @@ namespace Microsoft.PowerShell.Commands
return sb.ToString();
}
}
+
+ #endregion
}
\ No newline at end of file
diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs
index d6368c285..516591e21 100644
--- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs
+++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs
@@ -2661,7 +2661,7 @@ namespace System.Management.Automation.Runspaces
var computeSystemPropertiesHandle = getComputeSystemPropertiesInfo.Invoke(null, new object[]{ ContainerId });
- ContainerName = (string)computeSystemPropertiesType.GetProperty("Name").GetValue(computeSystemPropertiesHandle);
+ ContainerName = (string)computeSystemPropertiesType.GetProperty("SiloGuid").GetValue(computeSystemPropertiesHandle);
RuntimeId = (Guid)computeSystemPropertiesType.GetProperty("RuntimeId").GetValue(computeSystemPropertiesHandle);
}
catch (FileNotFoundException)
diff --git a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs
index 886483780..650d1618e 100644
--- a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs
+++ b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs
@@ -947,12 +947,6 @@ namespace System.Management.Automation.Remoting
internal static readonly string VisibleProviders = "VisibleProviders";
internal static readonly string VisibleExternalCommands = "VisibleExternalCommands";
- // Keys that are not allowed in RoleDefinitions or a role capability
- internal static HashSet DisallowedRoleCapabilityKeys = new HashSet(StringComparer.OrdinalIgnoreCase)
- {
- PowerShellVersion, SessionType, RoleDefinitions, LanguageMode, ExecutionPolicy
- };
-
internal static ConfigTypeEntry[] ConfigFileKeys = new ConfigTypeEntry[] {
new ConfigTypeEntry(AliasDefinitions, new ConfigTypeEntry.TypeValidationCallback(AliasDefinitionsTypeValidationCallback)),
new ConfigTypeEntry(AssembliesToLoad, new ConfigTypeEntry.TypeValidationCallback(StringArrayTypeValidationCallback)),
@@ -1366,13 +1360,41 @@ namespace System.Management.Automation.Remoting
}
}
+ #region DISC Utilities
+
///
/// DISC utilities
///
internal static class DISCUtils
{
+ #region Private data
+
internal static Type ExecutionPolicyType = null;
+ ///
+ /// !! NOTE that this list MUST be updated when new capability session configuration properties are added.
+ ///
+ private static readonly HashSet AllowedRoleCapabilityKeys = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ "RoleCapabilities",
+ "ModulesToImport",
+ "VisibleAliases",
+ "VisibleCmdlets",
+ "VisibleFunctions",
+ "VisibleExternalCommands",
+ "VisibleProviders",
+ "ScriptsToProcess",
+ "AliasDefinitions",
+ "FunctionDefinitions",
+ "VariableDefinitions",
+ "EnvironmentVariables",
+ "TypesToProcess",
+ "FormatsToProcess",
+ "AssembliesToLoad"
+ };
+
+ #endregion
+
///
/// Create an ExternalScriptInfo object from a file path.
///
@@ -1432,8 +1454,6 @@ namespace System.Management.Automation.Remoting
return result as Hashtable;
}
-
-
///
/// Verifies the configuration hashtable
///
@@ -1606,8 +1626,68 @@ namespace System.Management.Automation.Remoting
}
}
}
+
+ ///
+ /// Validates Role Definition hash entries
+ ///
+ /// RoleDefinitions = @{
+ /// 'Everyone' = @{
+ /// 'RoIeCapabilities' = 'Basic' };
+ /// 'Administrators' = @{
+ /// 'VisibleCmdlets' = 'Get-Process','Get-Location'; 'VisibleFunctions = 'TabExpansion2' } }
+ ///
+ ///
+ internal static void ValidateRoleDefinitions(IDictionary roleDefinitions)
+ {
+ foreach (var roleKey in roleDefinitions.Keys)
+ {
+ if (!(roleKey is string))
+ {
+ var invalidOperationEx = new PSInvalidOperationException(
+ string.Format(RemotingErrorIdStrings.InvalidRoleKeyType, roleKey.GetType().FullName));
+ invalidOperationEx.SetErrorId("InvalidRoleKeyType");
+ throw invalidOperationEx;
+ }
+
+ //
+ // Each role capability in the role definition item should contain a hash table with allowed role capability key.
+ //
+
+ IDictionary roleDefinition = roleDefinitions[roleKey] as IDictionary;
+ if (roleDefinition == null)
+ {
+ var invalidOperationEx = new PSInvalidOperationException(
+ StringUtil.Format(RemotingErrorIdStrings.InvalidRoleValue, roleKey));
+ invalidOperationEx.SetErrorId("InvalidRoleEntryNotHashtable");
+ throw invalidOperationEx;
+ }
+
+ foreach (var key in roleDefinition.Keys)
+ {
+ // Ensure each role capability key is valid.
+ string roleCapabilityKey = key as string;
+ if (roleCapabilityKey == null)
+ {
+ var invalidOperationEx = new PSInvalidOperationException(
+ string.Format(RemotingErrorIdStrings.InvalidRoleCapabilityKeyType, key.GetType().FullName));
+ invalidOperationEx.SetErrorId("InvalidRoleCapabilityKeyType");
+ throw invalidOperationEx;
+ }
+
+ if (!AllowedRoleCapabilityKeys.Contains(roleCapabilityKey))
+ {
+ var invalidOperationEx = new PSInvalidOperationException(
+ string.Format(RemotingErrorIdStrings.InvalidRoleCapabilityKey, roleCapabilityKey));
+ invalidOperationEx.SetErrorId("InvalidRoleCapabilityKey");
+ throw invalidOperationEx;
+ }
+ }
+ }
+ }
}
+ #endregion
+
///
/// Creates an initial session state based on the configuration language for PSSC files
///
@@ -1683,12 +1763,15 @@ namespace System.Management.Automation.Remoting
{
string message = StringUtil.Format(RemotingErrorIdStrings.InvalidRoleEntry, configHash["Roles"].GetType().FullName);
PSInvalidOperationException ioe = new PSInvalidOperationException(message);
- ioe.SetErrorId("InvalidRoleEntryNotHashtable");
+ ioe.SetErrorId("InvalidRoleDefinitionNotHashtable");
throw ioe;
}
+ // Ensure that role definitions contain valid entries.
+ DISCUtils.ValidateRoleDefinitions(roleEntry);
+
// Go through the Roles hashtable
- foreach(Object role in roleEntry.Keys)
+ foreach (Object role in roleEntry.Keys)
{
// Check if this role applies to the connected user
if (roleVerifier(role.ToString()))
@@ -1744,13 +1827,6 @@ namespace System.Management.Automation.Remoting
foreach (Object customization in childConfigHash.Keys)
{
string customizationString = customization.ToString();
- if (ConfigFileConstants.DisallowedRoleCapabilityKeys.Contains(customizationString))
- {
- string message = StringUtil.Format(RemotingErrorIdStrings.InvalidRoleCapabilityKey, customizationString);
- PSInvalidOperationException ioe = new PSInvalidOperationException(message);
- ioe.SetErrorId("InvalidRoleTookitKey");
- throw ioe;
- }
ArrayList customizationValue = new ArrayList();
diff --git a/src/System.Management.Automation/engine/remoting/server/ServerRemoteHost.cs b/src/System.Management.Automation/engine/remoting/server/ServerRemoteHost.cs
index de01f477f..251db9086 100644
--- a/src/System.Management.Automation/engine/remoting/server/ServerRemoteHost.cs
+++ b/src/System.Management.Automation/engine/remoting/server/ServerRemoteHost.cs
@@ -323,11 +323,14 @@ namespace System.Management.Automation.Remoting
{
if (_serverDriverRemoteHost.PropagatePop)
{
- // Optionally forward the PopRunspace command to client.
+ // Forward the PopRunspace command to client and keep *this* pushed runspace as
+ // the configured JEA restricted session.
_serverMethodExecutor.ExecuteVoidMethod(RemoteHostMethodId.PopRunspace);
}
-
- _serverDriverRemoteHost.PopRunspace();
+ else
+ {
+ _serverDriverRemoteHost.PopRunspace();
+ }
}
else
{
diff --git a/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs b/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs
index ca48ef6f2..9ced86889 100644
--- a/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs
+++ b/src/System.Management.Automation/engine/remoting/server/ServerRunspacePoolDriver.cs
@@ -515,8 +515,6 @@ namespace System.Management.Automation
// Let exceptions propagate.
RemoteRunspace remoteRunspace = HostUtilities.CreateConfiguredRunspace(this.configurationName, this.remoteHost);
- // Ensure session ends and configured runspace is closed on pop.
- remoteRunspace.ShouldCloseOnPop = true;
this.remoteHost.AllowPushRunspace = true;
this.remoteHost.PropagatePop = true;
@@ -665,7 +663,9 @@ namespace System.Management.Automation
args.Runspace.ExecutionContext.LanguageMode = PSLanguageMode.ConstrainedLanguage;
}
- // Set the current location to Personal folder for this runspace.
+ // Set the current location to MyDocuments folder for this runspace.
+ // This used to be set to the Personal folder but was changed to MyDocuments folder for
+ // compatibility with PowerShell on Nano Server for PowerShell V5.
// This is needed because in the remoting scenario, Environment.CurrentDirectory
// always points to System Folder (%windir%\system32) irrespective of the
// user as %HOMEDRIVE% and %HOMEPATH% are not available for the logon process.
@@ -676,17 +676,12 @@ namespace System.Management.Automation
string personalfolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
args.Runspace.ExecutionContext.EngineSessionState.SetLocation(personalfolder);
}
- catch (ArgumentException)
- {
- }
- catch (ProviderNotFoundException)
- {
- }
- catch (DriveNotFoundException)
- {
- }
- catch (ProviderInvocationException)
+ catch (Exception e)
{
+ // SetLocation API can call 3rd party code and so there is no telling what exception may be thrown.
+ // Setting location is not critical and is expected not to work with some account types, so we want
+ // to ignore all but critical errors.
+ CommandProcessorBase.CheckForSevereException(e);
}
// Run startup scripts
@@ -875,6 +870,7 @@ namespace System.Management.Automation
StartPowerShellCommandOnPushedRunspace(
powershell,
+ null,
data.PowerShellId,
data.RunspacePoolId,
hostInfo,
@@ -1085,23 +1081,41 @@ namespace System.Management.Automation
"Name", "Namespace", "HelpUri", "CommandType", "ResolvedCommandName", "OutputType", "Parameters" });
HostInfo useRunspaceHost = new HostInfo(null);
- useRunspaceHost.UseRunspaceHost = true;
- ServerPowerShellDriver driver = new ServerPowerShellDriver(
- countingPipeline,
- mainPipeline,
- true /* no input */,
- data.PowerShellId,
- data.RunspacePoolId,
- this,
-#if !CORECLR // No ApartmentState In CoreCLR
- ApartmentState.Unknown,
-#endif
- useRunspaceHost,
- 0 /* stream options */,
- false /* addToHistory */,
- null /* use default rsPool runspace */);
+ useRunspaceHost.UseRunspaceHost = true;
- driver.Start();
+ if (remoteHost.IsRunspacePushed)
+ {
+ // If we have a pushed runspace then execute there.
+ StartPowerShellCommandOnPushedRunspace(
+ countingPipeline,
+ mainPipeline,
+ data.PowerShellId,
+ data.RunspacePoolId,
+ useRunspaceHost,
+ 0,
+ true,
+ false);
+ }
+ else
+ {
+ // Run on usual driver.
+ ServerPowerShellDriver driver = new ServerPowerShellDriver(
+ countingPipeline,
+ mainPipeline,
+ true /* no input */,
+ data.PowerShellId,
+ data.RunspacePoolId,
+ this,
+#if !CORECLR // No ApartmentState In CoreCLR
+ ApartmentState.Unknown,
+#endif
+ useRunspaceHost,
+ 0 /* stream options */,
+ false /* addToHistory */,
+ null /* use default rsPool runspace */);
+
+ driver.Start();
+ }
}
///
@@ -1206,6 +1220,7 @@ namespace System.Management.Automation
/// Starts the PowerShell command on the currently pushed Runspace
///
/// PowerShell command or script
+ /// PowerShell command to run after first completes
/// PowerShell Id
/// RunspacePool Id
/// Host Info
@@ -1214,6 +1229,7 @@ namespace System.Management.Automation
/// Add to history
private void StartPowerShellCommandOnPushedRunspace(
PowerShell powershell,
+ PowerShell extraPowerShell,
Guid powershellId,
Guid runspacePoolId,
HostInfo hostInfo,
@@ -1225,7 +1241,7 @@ namespace System.Management.Automation
ServerPowerShellDriver driver = new ServerPowerShellDriver(
powershell,
- null,
+ extraPowerShell,
noInput,
powershellId,
runspacePoolId,
diff --git a/src/System.Management.Automation/engine/remoting/server/serverremotesession.cs b/src/System.Management.Automation/engine/remoting/server/serverremotesession.cs
index d2e5b8955..7fd08b9ec 100644
--- a/src/System.Management.Automation/engine/remoting/server/serverremotesession.cs
+++ b/src/System.Management.Automation/engine/remoting/server/serverremotesession.cs
@@ -1053,29 +1053,41 @@ namespace System.Management.Automation.Remoting
if (onConnect)
{
- // Win10 server can support Win8 client
- if (clientProtocolVersion == RemotingConstants.ProtocolVersionWin8RTM &&
- (
- (serverProtocolVersion == RemotingConstants.ProtocolVersionWin10RTM)
- ))
+ bool connectSupported = false;
+
+ // Win10 server can support reconstruct/reconnect for all 2.x protocol versions
+ // that support reconstruct/reconnect, Protocol 2.2+
+ // Major protocol version differences (2.x -> 3.x) are not supported.
+ if ((serverProtocolVersion == RemotingConstants.ProtocolVersionWin10RTM) &&
+ (clientProtocolVersion.Major == serverProtocolVersion.Major))
{
- // - report that server is Win8 version to the client
- serverProtocolVersion = RemotingConstants.ProtocolVersionWin8RTM;
- _context.ServerCapability.ProtocolVersion = serverProtocolVersion;
- }
- else
- {
- // All other version mismatches, throw an error.
- if (clientProtocolVersion != serverProtocolVersion)
+ if (clientProtocolVersion.Minor == RemotingConstants.ProtocolVersionWin8RTM.Minor)
{
- PSRemotingDataStructureException reasonOfFailure =
- new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnNegotiation,
- RemoteDataNameStrings.PS_STARTUP_PROTOCOL_VERSION_NAME,
- clientProtocolVersion,
- PSVersionInfo.BuildVersion,
- RemotingConstants.ProtocolVersion);
- throw reasonOfFailure;
+ // Report that server is Win8 version to the client
+ // Protocol: 2.2
+ connectSupported = true;
+ serverProtocolVersion = RemotingConstants.ProtocolVersionWin8RTM;
+ _context.ServerCapability.ProtocolVersion = serverProtocolVersion;
}
+ else if (clientProtocolVersion.Minor > RemotingConstants.ProtocolVersionWin8RTM.Minor)
+ {
+ // All other minor versions are supported and the server returns its full capability
+ // Protocol: 2.3, 2.4, 2.5 ...
+ connectSupported = true;
+ }
+ }
+
+ if (!connectSupported)
+ {
+ // Throw for protocol versions 2.x that don't support disconnect/reconnect.
+ // Protocol: < 2.2
+ PSRemotingDataStructureException reasonOfFailure =
+ new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnNegotiation,
+ RemoteDataNameStrings.PS_STARTUP_PROTOCOL_VERSION_NAME,
+ clientProtocolVersion,
+ PSVersionInfo.BuildVersion,
+ RemotingConstants.ProtocolVersion);
+ throw reasonOfFailure;
}
}
else
diff --git a/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs b/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs
index 71492531a..6bec3a28f 100644
--- a/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs
+++ b/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs
@@ -22,6 +22,7 @@ using System.Text;
using Microsoft.Win32;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.PowerShell.Telemetry.Internal;
#if CORECLR
// Use stub for Serializable attribute and ISerializable related types
@@ -63,6 +64,8 @@ namespace System.Management.Automation
internal bool Compile(bool optimized)
{
+ var sw = new Stopwatch();
+ sw.Start();
if (_attributes == null)
{
InitializeMetadata();
@@ -86,6 +89,9 @@ namespace System.Management.Automation
CompileOptimized();
}
+ sw.Stop();
+ TelemetryAPI.ReportScriptTelemetry((Ast)_ast, !optimized, sw.ElapsedMilliseconds);
+
return optimized;
}
diff --git a/src/System.Management.Automation/help/HelpCommands.cs b/src/System.Management.Automation/help/HelpCommands.cs
index 49d08cb04..ed8593d90 100644
--- a/src/System.Management.Automation/help/HelpCommands.cs
+++ b/src/System.Management.Automation/help/HelpCommands.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Management.Automation;
using System.Globalization;
using System.Management.Automation.Internal;
@@ -306,6 +307,9 @@ namespace Microsoft.PowerShell.Commands
private GraphicalHostReflectionWrapper graphicalHostReflectionWrapper;
#endif
+ private readonly Stopwatch _timer = new Stopwatch();
+ private bool _updatedHelp;
+
#endregion
#region Cmdlet API implementation
@@ -315,11 +319,14 @@ namespace Microsoft.PowerShell.Commands
///
protected override void BeginProcessing()
{
+ _timer.Start();
+
if (!Online.IsPresent && UpdatableHelpSystem.ShouldPromptToUpdateHelp() && HostUtilities.IsProcessInteractive(MyInvocation) && HasInternetConnection())
{
if(ShouldContinue(HelpDisplayStrings.UpdateHelpPromptBody, HelpDisplayStrings.UpdateHelpPromptTitle))
{
System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace).AddCommand("Update-Help").Invoke();
+ _updatedHelp = true;
}
UpdatableHelpSystem.SetDisablePromptToUpdateHelp();
@@ -397,6 +404,11 @@ namespace Microsoft.PowerShell.Commands
countOfHelpInfos++;
}
+ _timer.Stop();
+
+ if (!string.IsNullOrEmpty(Name))
+ Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.ReportGetHelpTelemetry(Name, countOfHelpInfos, _timer.ElapsedMilliseconds, _updatedHelp);
+
// Write full help as there is only one help info object
if (1 == countOfHelpInfos)
{
diff --git a/src/System.Management.Automation/help/HelpCommentsParser.cs b/src/System.Management.Automation/help/HelpCommentsParser.cs
index e4a2e4f3e..4cc9e18d9 100644
--- a/src/System.Management.Automation/help/HelpCommentsParser.cs
+++ b/src/System.Management.Automation/help/HelpCommentsParser.cs
@@ -172,7 +172,7 @@ namespace System.Management.Automation
XmlElement parameterValue = doc.CreateElement("command:parameterValue", commandURI);
parameterValue.SetAttribute("required", isSwitchParameter ? "false" : "true");
//parameterValue.SetAttribute("variableLength", "unknown");
- XmlText parameterValue_text = doc.CreateTextNode(elementType.Name);
+ XmlText parameterValue_text = doc.CreateTextNode(type.Name);
command_parameter.AppendChild(parameterValue).AppendChild(parameterValue_text);
}
}
diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
index 74aaef459..452090122 100644
--- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
+++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
@@ -1071,9 +1071,6 @@ All WinRM sessions connected to Windows PowerShell session configurations, such
The 'Roles' entry must be a hashtable, but was a {0}.
-
- The key '{0}' is not valid in a role capability or role definition.
-
Could not convert the value of the '{0}' role entry to a hashtable. The 'Roles' entry must be a hashtable with group names for keys, where the value associated with each key is another hashtable of session configuration properties for that role.
@@ -1599,4 +1596,13 @@ All WinRM sessions connected to Windows PowerShell session configurations, such
Cannot create a session User Drive because the current user name contains invalid file path characters.
+
+ Invalid role capability key: {0}. Make sure the role capability name is spelled correctly and is a valid session configuration property.
+
+
+ Invalid role capability key type: {0}. Role capability keys must be strings that identify a valid session configuration property.
+
+
+ Invalid role key type: {0}. Role keys must be strings that identify a security group.
+
\ No newline at end of file
diff --git a/src/System.Management.Automation/security/nativeMethods.cs b/src/System.Management.Automation/security/nativeMethods.cs
index 27c769369..b04c6ef5e 100644
--- a/src/System.Management.Automation/security/nativeMethods.cs
+++ b/src/System.Management.Automation/security/nativeMethods.cs
@@ -2144,8 +2144,44 @@ namespace System.Management.Automation.Security
[DllImport("wintrust.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr CryptCATStoreFromHandle(
IntPtr hCatalog
- );
-
+ );
+
+ [DllImport("wintrust.dll", CharSet = CharSet.Unicode)]
+ internal static extern bool CryptCATAdminAcquireContext2(
+ ref IntPtr phCatAdmin,
+ IntPtr pgSubsystem,
+ [MarshalAs(UnmanagedType.LPWStr)]
+ string pwszHashAlgorithm,
+ IntPtr pStrongHashPolicy,
+ DWORD dwFlags
+ );
+
+ [DllImport("wintrust.dll", CharSet = CharSet.Unicode)]
+ internal static extern bool CryptCATAdminReleaseContext(
+ IntPtr phCatAdmin,
+ DWORD dwFlags
+ );
+
+ [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
+ internal static extern unsafe IntPtr CreateFile(
+ string lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ DWORD lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ IntPtr hTemplateFile
+ );
+
+ [DllImport("wintrust.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ internal static extern bool CryptCATAdminCalcHashFromFileHandle2(
+ IntPtr hCatAdmin,
+ IntPtr hFile,
+ [In, Out] ref DWORD pcbHash,
+ IntPtr pbHash,
+ DWORD dwFlags
+ );
+
[DllImport("wintrust.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr CryptCATEnumerateMember(
IntPtr hCatalog,
diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs
index 9f6d54e0e..edb4de9d6 100644
--- a/src/System.Management.Automation/utils/ClrFacade.cs
+++ b/src/System.Management.Automation/utils/ClrFacade.cs
@@ -479,6 +479,7 @@ namespace System.Management.Automation
{
uint zoneId;
object curSecMgr = null;
+ const UInt32 MUTZ_DONT_USE_CACHE = 0x00001000;
int hr = NativeMethods.CoInternetCreateSecurityManager(null, out curSecMgr, 0);
if (hr != NativeMethods.S_OK)
@@ -490,7 +491,7 @@ namespace System.Management.Automation
try
{
NativeMethods.IInternetSecurityManager ism = (NativeMethods.IInternetSecurityManager)curSecMgr;
- hr = ism.MapUrlToZone(filePath, out zoneId, 0);
+ hr = ism.MapUrlToZone(filePath, out zoneId, MUTZ_DONT_USE_CACHE);
if (hr == NativeMethods.S_OK)
{
SecurityZone result;
diff --git a/src/System.Management.Automation/utils/PSTelemetryMethods.cs b/src/System.Management.Automation/utils/PSTelemetryMethods.cs
index 9d7eac52c..3aacd6083 100644
--- a/src/System.Management.Automation/utils/PSTelemetryMethods.cs
+++ b/src/System.Management.Automation/utils/PSTelemetryMethods.cs
@@ -3,10 +3,21 @@ Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Management.Automation.Internal;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation;
using System.Management.Automation.Language;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.PowerShell.Telemetry.Internal;
+#if CORECLR
+using Environment = System.Management.Automation.Environment;
+#else
+using Environment = System.Environment;
+#endif
namespace Microsoft.PowerShell.Telemetry.Internal
{
@@ -15,7 +26,7 @@ namespace Microsoft.PowerShell.Telemetry.Internal
[SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")]
public static class TelemetryAPI
{
- #region Public API
+#region Public API
///
/// Public API to expose Telemetry in PowerShell
@@ -27,6 +38,369 @@ namespace Microsoft.PowerShell.Telemetry.Internal
TelemetryWrapper.TraceMessage(message, arguments);
}
- #endregion
+#endregion
+
+ static int anyPowerShellSessionOpen;
+ static DateTime sessionStartTime;
+
+ enum HostIsInteractive
+ {
+ Unknown,
+ Iteractive,
+ NonInteractive
+ }
+
+ ///
+ /// Called either after opening a runspace (the default), or by the host application.
+ ///
+ public static void ReportStartupTelemetry(IHostProvidesTelemetryData ihptd)
+ {
+ // Avoid reporting startup more than once, except if we report "exited" and
+ // another runspace gets opened.
+ if (Interlocked.CompareExchange(ref anyPowerShellSessionOpen, 1, 0) == 1)
+ return;
+
+ bool is32Bit;
+#if CORECLR
+ is32Bit = IntPtr.Size == 4;
+#else
+ is32Bit = !Environment.Is64BitProcess;
+#endif
+ var psversion = PSVersionInfo.PSVersion.ToString();
+ var hostName = Process.GetCurrentProcess().ProcessName;
+ if (ihptd != null)
+ {
+ TelemetryWrapper.TraceMessage("PSHostStart", new
+ {
+ Interactive = ihptd.HostIsInteractive ? HostIsInteractive.Iteractive : HostIsInteractive.NonInteractive,
+ ProfileLoadTime = ihptd.ProfileLoadTimeInMS,
+ ReadyForInputTime = ihptd.ReadyForInputTimeInMS,
+ Is32Bit = is32Bit,
+ PSVersion = psversion,
+ ProcessName = hostName,
+ });
+ }
+ else
+ {
+ TelemetryWrapper.TraceMessage("PSHostStart", new
+ {
+ Interactive = HostIsInteractive.Unknown,
+ ProfileLoadTime = 0,
+ ReadyForInputTime = 0,
+ Is32Bit = is32Bit,
+ PSVersion = psversion,
+ ProcessName = hostName,
+ });
+ }
+ sessionStartTime = DateTime.Now;
+ }
+
+ ///
+ /// Called after there are no more open runspaces. In some host applications, this could
+ /// report multiple exits.
+ ///
+ public static void ReportExitTelemetry(IHostProvidesTelemetryData ihptd)
+ {
+ TelemetryWrapper.TraceMessage("PSHostStop", new
+ {
+ InteractiveCommandCount = ihptd != null ? ihptd.InteractiveCommandCount : 0,
+ TabCompletionTimes = tabCompletionTimes,
+ TabCompletionCounts = tabCompletionCounts,
+ TabCompletionResultCounts = tabCompletionResultCounts,
+ SessionTime = (DateTime.Now - sessionStartTime).TotalMilliseconds
+ });
+
+ // In case a host opens another runspace, we will want another PSHostStart event,
+ // so reset our flag here to allow that event to fire.
+ anyPowerShellSessionOpen = 0;
+ }
+
+ ///
+ /// Report Get-Help requests, how many results are returned, and how long it took.
+ ///
+ internal static void ReportGetHelpTelemetry(string name, int topicsFound, long timeInMS, bool updatedHelp)
+ {
+ TelemetryWrapper.TraceMessage("PSHelpRequest", new
+ {
+ TopicCount = topicsFound,
+ TimeInMS = timeInMS,
+ RanUpdateHelp = updatedHelp,
+ HelpTopic = name,
+ });
+ }
+
+ ///
+ /// Report when Get-Command fails to find something.
+ ///
+ internal static void ReportGetCommandFailed(string[] name, long timeInMS)
+ {
+ TelemetryWrapper.TraceMessage("PSGetCommandFailed", new { TimeInMS = timeInMS, CommandNames = name });
+ }
+
+
+ private static long[] tabCompletionTimes = new long[(int)CompletionResultType.DynamicKeyword + 1];
+ private static int[] tabCompletionCounts = new int[(int)CompletionResultType.DynamicKeyword + 1];
+ private static int[] tabCompletionResultCounts = new int[(int)CompletionResultType.DynamicKeyword + 1];
+ internal static void ReportTabCompletionTelemetry(long elapsedMilliseconds, int count, CompletionResultType completionResultType)
+ {
+ // We'll collect some general statistics.
+ int idx = (int)completionResultType;
+ if (idx >= 0 && idx <= (int)CompletionResultType.DynamicKeyword)
+ {
+ tabCompletionTimes[idx] += elapsedMilliseconds;
+ tabCompletionCounts[idx]++;
+ tabCompletionResultCounts[idx] += count;
+ }
+
+ // Also write an event for any slow tab completion (> 250ms).
+ if (elapsedMilliseconds > 250)
+ {
+ TelemetryWrapper.TraceMessage("PSSlowTabCompletion", new {
+ Time = elapsedMilliseconds,
+ Count = count,
+ Type = completionResultType,
+ });
+ }
+ }
+
+ ///
+ /// Report that a module was loaded, but only do so for modules that *might* be authored by Microsoft. We can't
+ /// be 100% certain, but we'll ignore non-Microsoft module names when looking at any data, so it's best to
+ /// at least attempt avoiding collecting data we'll ignore.
+ ///
+ internal static void ReportModuleLoad(PSModuleInfo foundModule)
+ {
+ var modulePath = foundModule.Path;
+ var companyName = foundModule.CompanyName;
+ bool couldBeMicrosoftModule =
+ (modulePath != null &&
+ (modulePath.StartsWith(Utils.GetApplicationBase(Utils.DefaultPowerShellShellID), StringComparison.OrdinalIgnoreCase) ||
+ // The following covers both 64 and 32 bit Program Files by assuming 32bit is just ...\Program Files + " (x86)"
+ modulePath.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), StringComparison.OrdinalIgnoreCase))) ||
+ (companyName != null &&
+ foundModule.CompanyName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase));
+ if (couldBeMicrosoftModule)
+ {
+ TelemetryWrapper.TraceMessage("PSImportModule", new
+ {
+ ModuleName = foundModule.Name,
+ Version = foundModule.Version.ToString()
+ });
+ }
+ }
+
+ enum ScriptFileType
+ {
+ None = 0,
+ Ps1 = 1,
+ Psd1 = 2,
+ Psm1 = 3,
+ Other = 4,
+ }
+
+ private static readonly int promptHashCode = "prompt".GetHashCode();
+
+ ///
+ /// Report some telemetry about the scripts that are run
+ ///
+ internal static void ReportScriptTelemetry(Ast ast, bool dotSourced, long compileTimeInMS)
+ {
+ if (ast.Parent != null || !TelemetryWrapper.IsEnabled)
+ return;
+
+ Task.Run(() =>
+ {
+ var extent = ast.Extent;
+ var text = extent.Text;
+ var hash = text.GetHashCode();
+
+ // Ignore 'prompt' so we don't generate an event for every 'prompt' that is invoked.
+ // (We really should only create 'prompt' once, but we don't.
+ if (hash == promptHashCode)
+ return;
+
+ var visitor = new ScriptBlockTelemetry();
+
+ ast.Visit(visitor);
+
+ var scriptFileType = ScriptFileType.None;
+ var fileName = extent.File;
+ if (fileName != null)
+ {
+ var ext = System.IO.Path.GetExtension(fileName);
+ if (".ps1".Equals(ext, StringComparison.OrdinalIgnoreCase))
+ {
+ scriptFileType = ScriptFileType.Ps1;
+ }
+ else if (".psd1".Equals(ext, StringComparison.OrdinalIgnoreCase))
+ {
+ scriptFileType = ScriptFileType.Psd1;
+ }
+ else if (".psm1".Equals(ext, StringComparison.OrdinalIgnoreCase))
+ {
+ scriptFileType = ScriptFileType.Psm1;
+ }
+ else
+ {
+ // Reachable?
+ scriptFileType = ScriptFileType.Other;
+ }
+ }
+
+ TelemetryWrapper.TraceMessage("PSScriptDetails", new
+ {
+ Hash = hash,
+ IsDotSourced = dotSourced,
+ ScriptFileType = scriptFileType,
+ Length = text.Length,
+ LineCount = extent.EndLineNumber - extent.StartLineNumber,
+ CompileTimeInMS = compileTimeInMS,
+ StatementCount = visitor.StatementCount,
+ CountOfCommands = visitor.CountOfCommands,
+ CountOfDotSourcedCommands = visitor.CountOfDotSourcedCommands,
+ MaxArrayLength = visitor.MaxArraySize,
+ ArrayLiteralCount = visitor.ArrayLiteralCount,
+ ArrayLiteralCumulativeSize = visitor.ArrayLiteralCumulativeSize,
+ MaxStringLength = visitor.MaxStringSize,
+ StringLiteralCount = visitor.StringLiteralCount,
+ StringLiteralCumulativeSize = visitor.StringLiteralCumulativeSize,
+ MaxPipelineDepth = visitor.MaxPipelineDepth,
+ PipelineCount = visitor.PipelineCount,
+ FunctionCount = visitor.FunctionCount,
+ ScriptBlockCount = visitor.ScriptBlockCount,
+ ClassCount = visitor.ClassCount,
+ EnumCount = visitor.EnumCount,
+ CommandsCalled = visitor.CommandsCalled,
+ });
+ });
+ }
}
-}
\ No newline at end of file
+
+ class ScriptBlockTelemetry : AstVisitor2
+ {
+ internal ScriptBlockTelemetry()
+ {
+ CommandsCalled = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ }
+
+ internal Dictionary CommandsCalled { get; private set; }
+ internal int CountOfCommands { get; private set; }
+ internal int CountOfDotSourcedCommands { get; private set; }
+
+ public override AstVisitAction VisitCommand(CommandAst commandAst)
+ {
+ CountOfCommands++;
+ var commandName = commandAst.GetCommandName();
+ if (commandName != null)
+ {
+ int commandCount;
+ CommandsCalled.TryGetValue(commandName, out commandCount);
+ CommandsCalled[commandName] = commandCount + 1;
+ }
+
+ if (commandAst.InvocationOperator == TokenKind.Dot)
+ CountOfDotSourcedCommands++;
+
+ return AstVisitAction.Continue;
+ }
+
+ internal int MaxStringSize { get; private set; }
+ internal int StringLiteralCount { get; private set; }
+ internal int StringLiteralCumulativeSize { get; private set; }
+ public override AstVisitAction VisitStringConstantExpression(StringConstantExpressionAst stringConstantExpressionAst)
+ {
+ var stringSize = stringConstantExpressionAst.Value.Length;
+ StringLiteralCount += 1;
+ StringLiteralCumulativeSize += stringSize;
+ MaxStringSize = Math.Max(MaxStringSize, stringSize);
+ return AstVisitAction.Continue;
+ }
+
+ public override AstVisitAction VisitExpandableStringExpression(ExpandableStringExpressionAst expandableStringExpressionAst)
+ {
+ var stringSize = expandableStringExpressionAst.Value.Length;
+ StringLiteralCount += 1;
+ StringLiteralCumulativeSize += stringSize;
+ MaxStringSize = Math.Max(MaxStringSize, stringSize);
+ return AstVisitAction.Continue;
+ }
+
+ internal int MaxArraySize { get; private set; }
+ internal int ArrayLiteralCount { get; private set; }
+ internal int ArrayLiteralCumulativeSize { get; private set; }
+ public override AstVisitAction VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst)
+ {
+ var elementCount = arrayLiteralAst.Elements.Count;
+ ArrayLiteralCount += 1;
+ ArrayLiteralCumulativeSize += elementCount;
+ MaxArraySize = Math.Max(MaxArraySize, elementCount);
+ return AstVisitAction.Continue;
+ }
+
+ internal int StatementCount { get; private set; }
+ public override AstVisitAction VisitBlockStatement(BlockStatementAst blockStatementAst)
+ {
+ StatementCount += blockStatementAst.Body.Statements.Count;
+ return AstVisitAction.Continue;
+ }
+
+ public override AstVisitAction VisitNamedBlock(NamedBlockAst namedBlockAst)
+ {
+ StatementCount += namedBlockAst.Statements.Count;
+ return AstVisitAction.Continue;
+ }
+
+ internal int FunctionCount { get; private set; }
+ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
+ {
+ FunctionCount += 1;
+ return AstVisitAction.Continue;
+ }
+
+ internal int ScriptBlockCount { get; private set; }
+ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)
+ {
+ ScriptBlockCount += 1;
+ return AstVisitAction.Continue;
+ }
+
+ internal int MaxPipelineDepth { get; private set; }
+ internal int PipelineCount { get; private set; }
+ public override AstVisitAction VisitPipeline(PipelineAst pipelineAst)
+ {
+ MaxPipelineDepth = Math.Max(MaxPipelineDepth, pipelineAst.PipelineElements.Count);
+ PipelineCount += 1;
+ return AstVisitAction.Continue;
+ }
+
+ internal int ClassCount { get; private set; }
+ internal int EnumCount { get; private set; }
+ public override AstVisitAction VisitTypeDefinition(TypeDefinitionAst typeDefinitionAst)
+ {
+ if (typeDefinitionAst.IsClass)
+ ClassCount += 1;
+ else if (typeDefinitionAst.IsEnum)
+ EnumCount += 1;
+ return AstVisitAction.Continue;
+ }
+ }
+
+ ///
+ /// If implemented by the host, the host should call and
+ /// and track the data defined by this interface.
+ ///
+ public interface IHostProvidesTelemetryData
+ {
+ /// A host sets this property as appropriate - used when reporting telemetry.
+ bool HostIsInteractive { get; }
+
+ /// A host sets this property as appropriate - used when reporting telemetry.
+ double ProfileLoadTimeInMS { get; }
+
+ /// A host sets this property as appropriate - used when reporting telemetry.
+ double ReadyForInputTimeInMS { get; }
+
+ /// A host sets this property as appropriate - used when reporting telemetry.
+ int InteractiveCommandCount { get; }
+ }
+}
diff --git a/src/System.Management.Automation/utils/PSTelemetryWrapper.cs b/src/System.Management.Automation/utils/PSTelemetryWrapper.cs
index 38cc18589..74ecb2ad9 100644
--- a/src/System.Management.Automation/utils/PSTelemetryWrapper.cs
+++ b/src/System.Management.Automation/utils/PSTelemetryWrapper.cs
@@ -44,10 +44,10 @@ namespace System.Management.Automation.Internal
const int EtwSelfDescribingEventFormat = 8;
var eventSourceSettingsEnumObject = Enum.ToObject(eventSourceSettingsType, EtwSelfDescribingEventFormat);
- // Create instance of the class EventSource with Provider name of "Microsoft.Windows.PowerShell"
+ // Create instance of the class EventSource with Provider name of "Microsoft-PowerShell-Telemetry"
// Supply this eventSourceTrait to EventSource constructor to enable Asimov type events
var eventSource = (EventSource)Activator.CreateInstance(typeof(EventSource),
- new object[] {"Microsoft.Windows.PowerShell",
+ new object[] {"Microsoft-PowerShell-Telemetry",
eventSourceSettingsEnumObject,
new[] { "ETW_GROUP", "{4f50731a-89cf-4782-b3e0-dce8c90476ba}" }});