Merge pull request #1560 from PowerShell/vors/sd-sync

Bring the latest changes from windows source tree
This commit is contained in:
Sergei Vorobev 2016-07-28 22:59:53 -07:00 committed by GitHub
commit 3f9c4d648e
32 changed files with 889 additions and 385 deletions

View file

@ -34,8 +34,5 @@
"wmi/WMIv2/client/CIMCmdlets/RemoveCimSessionCommand.cs" : "RemoveCimSessionCommand.cs",
"wmi/WMIv2/client/CIMCmdlets/SetCimInstanceCommand.cs" : "SetCimInstanceCommand.cs",
"wmi/WMIv2/client/CIMCmdlets/Utils.cs" : "Utils.cs",
"wmi/WMIv2/client/CIMCmdlets/BinaryMiLogBase.cs" : "BinaryMiLogBase.cs",
"wmi/WMIv2/client/CIMCmdlets/ExportBinaryMiLogCommand.cs" : "ExportBinaryMiLogCommand.cs",
"wmi/WMIv2/client/CIMCmdlets/ImportBinaryMiLogCommand.cs" : "ImportBinaryMiLogCommand.cs",
"wmi/WMIv2/client/CIMCmdlets/Strings.resx" : "resources/Microsoft.Management.Infrastructure.CimCmdlets.Strings.resx"
}

View file

@ -32,7 +32,6 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
using Directory = System.IO.Directory;
using ErrorCategory = PackageManagement.Internal.ErrorCategory;
using File = System.IO.File;
using System.IO.Compression;
public class BootstrapProvider {
private static readonly Dictionary<string, string[]> _features = new Dictionary<string, string[]> {
@ -324,127 +323,12 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
return false;
}
case Iso19770_2.MediaType.NuGetPackage:
return InstallNugetPackage(provider, link, fastPath, request);
default:
request.Warning("Provider '{0}' with link '{1}' has unknown media type '{2}'.", provider.Name, link.HRef, link.MediaType);
return false;
}
}
private bool InstallNugetPackage(Package provider, Link link, string fastPath, BootstrapRequest request)
{
// download the nuget package
string downloadedNupkg = request.DownloadAndValidateFile(provider._swidtag);
if (downloadedNupkg != null)
{
// extracted folder
string extractedFolder = String.Concat(FilesystemExtensions.GenerateTemporaryFileOrDirectoryNameInTempDirectory());
try
{
//unzip the file
ZipFile.ExtractToDirectory(downloadedNupkg, extractedFolder);
if (Directory.Exists(extractedFolder))
{
string versionFolder = Path.Combine(request.DestinationPath(request), provider.Name, provider.Version);
// tool folder is where we find things like nuget.exe
string toolFolder = Path.Combine(extractedFolder, "tools");
string libFolder = Path.Combine(extractedFolder, "lib");
// create the directory version folder if not exist
if (!Directory.Exists(versionFolder))
{
Directory.CreateDirectory(versionFolder);
}
// copy the tools directory
if (Directory.Exists(toolFolder))
{
string destinationToolFolder = Path.Combine(versionFolder, "tools");
if (!Directory.Exists(destinationToolFolder))
{
Directory.CreateDirectory(destinationToolFolder);
}
foreach (string child in Directory.EnumerateFiles(toolFolder))
{
try
{
// try copy and overwrite
File.Copy(child, Path.Combine(destinationToolFolder, Path.GetFileName(child)), true);
}
catch (Exception e)
{
request.Debug(e.StackTrace);
if (!(e is UnauthorizedAccessException || e is IOException))
{
// something wrong, delete the version folder
versionFolder.TryHardToDelete();
return false;
}
// otherwise this means the file is just being used. so just moves on to copy other files
}
}
}
// copy files from lib
if (Directory.Exists(libFolder))
{
// check that the lib folder has at most 1 dll
if (Directory.EnumerateFiles(libFolder).Count(file => String.Equals(Path.GetExtension(file), ".dll", StringComparison.OrdinalIgnoreCase)) > 1)
{
request.Warning(String.Format(CultureInfo.CurrentCulture, Resources.Messages.MoreThanOneDllExists, provider.Name));
return false;
}
foreach (string child in Directory.EnumerateFiles(libFolder))
{
try
{
File.Copy(child, Path.Combine(versionFolder, Path.GetFileName(child)), true);
}
catch (Exception e)
{
request.Debug(e.StackTrace);
if (!(e is UnauthorizedAccessException || e is IOException))
{
// something wrong, delete the version folder
versionFolder.TryHardToDelete();
return false;
}
// otherwise this means the file is just being used. so just moves on to copy other files
}
}
}
// target file name is the assembly provider
string targetFile = Path.Combine(versionFolder, Path.GetFileName(link.Attributes[Iso19770_2.Discovery.TargetFilename]));
if (File.Exists(targetFile))
{
request.Verbose(Resources.Messages.InstalledPackage, provider.Name, targetFile);
request.YieldFromSwidtag(provider, fastPath);
return true;
}
}
}
finally
{
downloadedNupkg.TryHardToDelete();
extractedFolder.TryHardToDelete();
}
}
return false;
}
private bool InstallPackageFile(Package provider, string fastPath, BootstrapRequest request) {
// we can download and verify this package and get the core to install it.
var file = request.DownloadAndValidateFile(provider._swidtag);
@ -522,7 +406,6 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
return false;
}
string targetFilename = fastPath;
string file = fastPath;
@ -532,7 +415,7 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
targetFilename = link.Attributes[Iso19770_2.Discovery.TargetFilename];
// download the file
file = request.DownloadAndValidateFile(provider._swidtag);
file = request.DownloadAndValidateFile(provider._swidtag);
}
@ -551,22 +434,23 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
//... providername\version\.dll
var versionFolder = Path.Combine(request.DestinationPath(request), provider.Name, provider.Version);
if (!Directory.Exists(versionFolder)) {
//we create it
// if version folder exists, remove it
if (Directory.Exists(versionFolder))
{
RemoveDirectory(versionFolder);
}
// create the directory if we successfully deleted it
if (!Directory.Exists(versionFolder))
{
Directory.CreateDirectory(versionFolder);
}
var targetFile = Path.Combine(versionFolder, targetFilename);
if (file != null) {
try
{
// looks good! let's keep it
if (File.Exists(targetFile)) {
request.Debug("Removing old file '{0}'", targetFile);
targetFile.TryHardToDelete();
}
// is that file still there?
if (File.Exists(targetFile)) {
request.Error(ErrorCategory.InvalidOperation, fastPath, Constants.Messages.UnableToRemoveFile, targetFile);
@ -575,7 +459,16 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
request.Debug("Copying file '{0}' to '{1}'", file, targetFile);
try {
File.Copy(file, targetFile);
if (File.Exists(file))
{
// if this is a file
File.Copy(file, targetFile);
}
else if (Directory.Exists(file))
{
// if this is a directory, copy items over
CopyDirectory(file, versionFolder);
}
}
catch (Exception ex) {
request.Debug(ex.StackTrace);
@ -599,11 +492,61 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
file.TryHardToDelete();
}
}
}
}
return false;
}
private void RemoveDirectory(string directoryFolder)
{
// remove all files
foreach (var fileToBeRemoved in Directory.EnumerateFiles(directoryFolder))
{
fileToBeRemoved.TryHardToDelete();
}
// remove all subdirectories
foreach (var folderToBeRemoved in Directory.EnumerateDirectories(directoryFolder))
{
RemoveDirectory(folderToBeRemoved);
}
try
{
// now try to remove the directory
Directory.Delete(directoryFolder);
}
catch { }
}
private void CopyDirectory(string sourceFolder, string destinationFolder)
{
// check that source and destination folders exist
if (!sourceFolder.DirectoryExists() || !destinationFolder.DirectoryExists())
{
return;
}
// copy the files over
foreach (var file in Directory.EnumerateFiles(sourceFolder))
{
File.Copy(file, Path.Combine(destinationFolder, Path.GetFileName(file)), true);
}
// copy the directories over
foreach (var directory in Directory.EnumerateDirectories(sourceFolder))
{
var destinationDirName = Path.Combine(destinationFolder, Path.GetFileName(directory));
if (!Directory.Exists(destinationDirName))
{
Directory.CreateDirectory(destinationDirName);
}
CopyDirectory(directory, destinationDirName);
}
}
private void InstallPackageFromFile(string fastPath, BootstrapRequest request)
{
var filePath = new Uri(fastPath).LocalPath;

View file

@ -29,6 +29,9 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
using PackageManagement.Internal.Utility.Collections;
using PackageManagement.Internal.Utility.Extensions;
using ErrorCategory = PackageManagement.Internal.ErrorCategory;
using System.IO.Compression;
using File = System.IO.File;
using Directory = System.IO.Directory;
public abstract class BootstrapRequest : Request {
internal Uri[] _urls
@ -201,6 +204,51 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
}
}
/// <summary>
/// Extract zipped package and return the unzipped folder
/// </summary>
/// <param name="zippedPackagePath"></param>
/// <returns></returns>
private string ExtractZipPackage(string zippedPackagePath)
{
if (zippedPackagePath != null && zippedPackagePath.FileExists())
{
// extracted folder
string extractedFolder = FilesystemExtensions.GenerateTemporaryFileOrDirectoryNameInTempDirectory();
try
{
//unzip the file
ZipFile.ExtractToDirectory(zippedPackagePath, extractedFolder);
// extraction fails
if (!Directory.Exists(extractedFolder))
{
Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.FailToExtract, zippedPackagePath, extractedFolder));
return string.Empty;
}
// the zipped folder
var zippedDirectory = Directory.EnumerateDirectories(extractedFolder).FirstOrDefault();
if (!string.IsNullOrWhiteSpace(zippedDirectory) && Directory.Exists(zippedDirectory))
{
return zippedDirectory;
}
}
catch (Exception ex)
{
Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.FailToInstallZipFolder, zippedPackagePath, ex.Message));
Debug(ex.StackTrace);
// remove the extracted folder
extractedFolder.TryHardToDelete();
}
}
return string.Empty;
}
/// <summary>
/// Helper function to retry downloading a file.
/// downloadFileFunction is the main function that is used to download the file when given a uri
@ -257,7 +305,22 @@ namespace Microsoft.PackageManagement.Providers.Internal.Bootstrap {
link.HRef);
// got a valid file!
if (file != null && file.FileExists()) {
if (file != null && file.FileExists()) {
// if file is zip, unpack it and return the unpacked folder
if (link.MediaType == Iso19770_2.MediaType.ZipPackage)
{
try
{
// let's extract the zipped file
return ExtractZipPackage(file);
}
finally
{
// delete the zipped file
file.TryHardToDelete();
}
}
return file;
}
}

View file

@ -121,6 +121,16 @@
<value>Fail to extract and copy to '{0}'.</value>
<comment>0 - The directory we are copying to</comment>
</data>
<data name="FailToDeleteExistingFolder" xml:space="preserve">
<value>Cannot delete existing provider folder '{0}'.</value>
</data>
<data name="FailToExtract" xml:space="preserve">
<value>Cannot extract from '{0}' to '{1}'</value>
</data>
<data name="FailToInstallZipFolder" xml:space="preserve">
<value>Fail to extract zip package '{0}': '{1}'</value>
<comment>0 - package path, 1 - exception message</comment>
</data>
<data name="FindingPackage" xml:space="preserve">
<value>Finding the package '{0}'.</value>
<comment>0 - package name</comment>

View file

@ -240,7 +240,17 @@
var partialManifestNameMatches = GetPackageFiles(partialManifestName).Where(
path => FileNameMatchesPattern(packageId, version, path));
return filesMatchingFullName.Concat(partialNameMatches).Concat(partialManifestNameMatches);
filesMatchingFullName = filesMatchingFullName.Concat(partialNameMatches).Concat(partialManifestNameMatches);
}
// cannot find matching files, we should try to search for just packageid.nupkg
if (filesMatchingFullName.Count() == 0)
{
// exclude version
var packageWithoutVersionName = FileUtility.MakePackageFileName(true, packageId, null, NuGetConstant.PackageExtension);
var packageWithoutVersionManifest = Path.ChangeExtension(packageWithoutVersionName, NuGetConstant.ManifestExtension);
return GetPackageFiles(packageWithoutVersionName).Concat(GetPackageFiles(packageWithoutVersionManifest));
}
return filesMatchingFullName;

View file

@ -44,10 +44,8 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
request.Verbose("Package: '{0}'", exePackage);
// validate the file
if (!WebDownloader.PerformSecurityScan(exePackage))
{
//TODO Security Scan work
request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, "The package download from '{0}' failed in the security scan.", package.Source);
if (!WebDownloader.VerifyHash(exePackage,package, request))
{
return false;
}

View file

@ -180,6 +180,11 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
{
item.Common = common;
item.FilePath = packageSpecPath;
if (string.IsNullOrWhiteSpace(item.Version))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Messages.VersionNotFound, item.Name));
}
}
item.PackageSource = packageSource;
@ -201,6 +206,11 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
else
{
convertedPackage.Common = new CommonDefinition();
if (String.IsNullOrWhiteSpace(convertedPackage.Version))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Messages.VersionNotFound, convertedPackage.Name, packageSpecPath));
}
}
convertedPackage.FilePath = packageSpecPath;
@ -249,6 +259,13 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
public List<string> installationOption { get; set; }
}
public class PackageHash
{
public string algorithm { get; set; }
public string hashCode { get; set; }
}
public class CommonDefinition
{
public string Name { get; set; }
@ -285,16 +302,20 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
private string _destination;
private List<Dependencies> _dependencies;
private List<PackageJson> _dependencyObjects;
private OSRequirement _osRequirement;
private OSRequirement _osRequirement;
private string _type;
private string _isTrustedSource;
private bool _isPackageProvider;
private string _installArguments;
private string _unInstallAdditionalArguments;
private string _source;
public CommonDefinition Common { get; set; }
public string Version { get; set; }
public PackageHash Hash { get; set; }
public SemanticVersion SemVer
{
get
@ -306,7 +327,36 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
return null;
}
}
public string Source { get; set; }
public string Source
{
get
{
return _source;
}
set
{
if (value != null)
{
Uri uri;
// check whether source is http instead of https
if (!Uri.TryCreate(value, UriKind.Absolute, out uri))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Messages.UnsuportedUriFormat, Constants.ProviderName, value));
}
if (!uri.IsFile)
{
if (uri.Scheme != "https")
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Messages.UriSchemeNotSupported, uri.Scheme, "https"));
}
}
_source = value;
}
}
}
public string Name
{

View file

@ -22,10 +22,12 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Management.Automation;
using Microsoft.PackageManagement.Provider.Utility;
using PackageManagement.Packaging;
using ErrorCategory = PackageManagement.Internal.ErrorCategory;
using ErrorCategory = PackageManagement.Internal.ErrorCategory;
using System.Security.Cryptography;
public class PackageSourceListProvider {
@ -37,6 +39,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
private const string RequiredPackageManagementVersion = "1.0.0.1";
private static bool _doesPackageManagementVersionMatch = false;
private static Version _currentPackageManagementVersion;
private static string _pslDirLocation = Path.Combine(Environment.GetEnvironmentVariable("appdata"), Constants.ProviderName);
/// <summary>
/// The features that this package supports.
@ -125,6 +128,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
case "install":
request.YieldDynamicOption("Scope", "String", false, new[] {"CurrentUser", "AllUsers"});
request.YieldDynamicOption("SkipHashValidation", Constants.OptionType.Switch, false);
break;
}
}
@ -189,23 +193,16 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
return;
}
request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, "GetOptionValue");
// if this is supposed to be an update, there will be a dynamic parameter set for IsUpdatePackageSource
// Set-PackageSource will update the existing package source. In that case IsUpdate = true.
var isUpdate = request.GetOptionValue(Constants.Parameters.IsUpdate).IsTrue();
request.Debug(Resources.Messages.VariableCheck, "IsUpdate", isUpdate);
// if your source supports credentials you get get them too:
// string username =request.Username;
// SecureString password = request.Password;
// feel free to send back an error here if your provider requires credentials for package sources.
// check first that we're not clobbering an existing source, unless this is an update
request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "FindRegisteredSource -name'{0}'", name));
var src = request.FindRegisteredSource(name);
if (src != null && !isUpdate) {
// tell the user that there's one here already
request.WriteError(ErrorCategory.InvalidArgument, name, Constants.Messages.PackageSourceExists, name);
@ -213,29 +210,72 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
}
// conversely, if it didn't find one, and it is an update, that's bad too:
if (src == null && isUpdate) {
if (src == null && isUpdate)
{
// you can't find that package source? Tell that to the user
request.WriteError(ErrorCategory.ObjectNotFound, name, Constants.Messages.UnableToResolveSource, Constants.ProviderName, name);
request.WriteError(ErrorCategory.ObjectNotFound, name, Constants.Messages.UnableToResolveSource, name);
return;
}
// ok, we know that we're ok to save this source
// next we check if the location is valid (if we support that kind of thing)
var validated = false;
if (!request.SkipValidate.Value) {
// the user has not opted to skip validating the package source location, so check if the source is valid
validated = request.ValidateSourceLocation(location);
if (!validated) {
request.WriteError(ErrorCategory.InvalidData, name, Constants.Messages.SourceLocationNotValid, location);
return;
}
validated = request.ValidateSourceLocation(location);
if (!validated) {
request.WriteError(ErrorCategory.InvalidData, name, Constants.Messages.SourceLocationNotValid, location);
return;
}
else
{
request.Verbose(Resources.Messages.SuccessfullyValidated, name);
}
bool force = request.GetOptionValue("Force") != null;
//if source is UNC location/ copy it to local path;
Uri uri;
if (Uri.TryCreate(location, UriKind.Absolute, out uri))
{
if (uri.IsFile && uri.IsUnc)
{
string fileName = Path.GetFileNameWithoutExtension(location);
string directory = Path.GetDirectoryName(location);
string catalogFilePath = Path.Combine(directory, fileName+".cat");
if (!File.Exists(catalogFilePath))
{
request.WriteError(ErrorCategory.InvalidData, location, Resources.Messages.CatalogFileMissing, location);
return;
}
if (!TestCatalogFile(location, catalogFilePath, request))
{
return;
}
if (force || request.ShouldContinue(Resources.Messages.QueryDownloadPackageSourceList.format(location), Resources.Messages.PackageSourceListNotTrusted))
{
string destination = Path.Combine(_pslDirLocation, Path.GetFileName(uri.LocalPath));
if (File.Exists(destination))
{
if (force || request.ShouldContinue(Resources.Messages.OverwriteFile, Resources.Messages.FileExists))
{
File.Copy(location, destination, true);
location = destination;
}
else
{
return;
}
}
else {
File.Copy(location, destination);
location = destination;
}
}
else
{
return;
}
}
}
// it's good to check just before you actaully write something to see if the user has cancelled the operation
if (request.IsCanceled) {
return;
@ -314,13 +354,13 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
request.Warning(Resources.Messages.WildCardCharsAreNotSupported, name);
return;
}
var packages = request.GetPackages(name);
if (request.GetOptionValue("AllVersions").IsTrue())
{
// if version is specified then name can not be empty or with wildcard. in this case the cmdlet has been errored out already.
// here we just return all packages we can find
if (request.FilterOnVersion(packages, requiredVersion, minimumVersion, maximumVersion, minInclusive: true, maxInclusive: true, latest: false).Any(p => !request.YieldFromSwidtag(p, p.Name)))
if (request.FilterOnVersion(packages, requiredVersion, minimumVersion, maximumVersion, minInclusive: true, maxInclusive: true, latest: false).OrderBy(p => p.Name).Any(p => !request.YieldFromSwidtag(p, p.Name)))
{
return;
}
@ -329,7 +369,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
//return the latest version
if (packages.GroupBy(p => p.Name)
.Select(each => each.OrderByDescending(pp => pp.Version).FirstOrDefault()).Any( item =>!request.YieldFromSwidtag(item, item.Name)))
.Select(each => each.OrderByDescending(pp => pp.Version).FirstOrDefault()).OrderBy(p=>p.Name).Any( item =>!request.YieldFromSwidtag(item, item.Name)))
{
return;
}
@ -717,20 +757,19 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
//download the msi package to the temp file
WebDownloader.DownloadFile(package.Source, destination, request, null);
if (!File.Exists(destination))
{
return;
}
// validate the file
if (!WebDownloader.PerformSecurityScan(destination))
if (!WebDownloader.VerifyHash(destination,package, request))
{
//TODO Security Scan work
request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, "The package download from '{0}' failed in the security scan.", package.Source);
return;
}
if (!package.IsTrustedSource)
{
if (!request.ShouldContinueWithUntrustedPackageSource(package.Name, package.Source))
@ -868,7 +907,38 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
return Enumerable.Empty<PSModuleInfo>();
}
}
internal static bool TestCatalogFile(string jsonFile, string catalogFile, PackageSourceListRequest request)
{
try
{
PSObject result = null;
using (PowerShell powershell = PowerShell.Create())
{
if (powershell != null)
{
result = powershell
.AddCommand("Test-FileCatalog")
.AddParameter("CatalogFilePath", catalogFile)
.AddParameter("Path", jsonFile)
.Invoke().FirstOrDefault();
}
if (result.ToString().EqualsIgnoreCase("Valid"))
return true;
}
}
catch(Exception ex)
{
request.WriteError(ErrorCategory.InvalidData, catalogFile, Resources.Messages.CatalogFileVerificationFailedWithError, catalogFile, ex.Message.ToString());
return false;
}
request.WriteError(ErrorCategory.InvalidData, catalogFile, Resources.Messages.CatalogFileVerificationFailed, jsonFile);
return false;
}
}
}

View file

@ -37,12 +37,16 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
using SemanticVersion = Microsoft.PackageManagement.Provider.Utility.SemanticVersion;
public abstract class PackageSourceListRequest : Request {
private IEnumerable<PackageQuery> _packageQuery;
private static IDictionary<string, PackageSource> _registeredPackageSources;
private string _configurationFileLocation;
private XDocument _config;
private string _defaultConfig;
private string PowerShellSourceURL = @"http://go.microsoft.com/fwlink/?LinkID=821777&clcid=0x409";
private string PowerShellNanoSourceURL = @"http://go.microsoft.com/fwlink/?LinkID=821783&clcid=0x409";
private string PowerShellSourceCatalogURL = @"http://go.microsoft.com/fwlink/?LinkID=823093&clcid=0x409";
private string PowerShellNanoSourceCatalogURL = @"http://go.microsoft.com/fwlink/?LinkID=823094&clcid=0x409";
private IEnumerable<string> _packageSources;
private const string _PackageSourceListRequest = "PackageSourceListRequest";
private HttpClient _httpClient;
@ -57,6 +61,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
internal Lazy<bool> SkipValidate;
internal readonly Lazy<bool> AllVersions;
internal readonly Lazy<string[]> Headers;
internal Lazy<bool> SkipHashValidation;
internal const WildcardOptions WildcardOptions = System.Management.Automation.WildcardOptions.CultureInvariant | System.Management.Automation.WildcardOptions.IgnoreCase;
@ -67,6 +72,12 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
</packageSources>
</configuration>";
internal const string EmptyConfig = @"<?xml version=""1.0""?>
<configuration>
<packageSources>
</packageSources>
</configuration>";
/// <summary>
/// Ctor required by the PackageManagement Platform
/// </summary>
@ -75,20 +86,48 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
AllVersions = new Lazy<bool>(() => GetOptionValue("AllVersions").IsTrue());
SkipValidate = new Lazy<bool>(() => GetOptionValue("SkipValidate").IsTrue());
Headers = new Lazy<string[]>(() => (GetOptionValues("Headers") ?? new string[0]).ToArray());
SkipHashValidation = new Lazy<bool>(() => GetOptionValue("SkipHashValidation").IsTrue());
}
internal string DefaultConfigLocation
internal string DefaultJSONFileLocation
{
get
{
return Path.Combine(Environment.GetEnvironmentVariable("appdata"), Constants.ProviderName, Constants.JSONFileName);
}
}
internal string DefaultCatlogFileLocation
{
get
{
return Path.Combine(Environment.GetEnvironmentVariable("appdata"), Constants.ProviderName, Constants.CatFileName);
}
}
internal string DefaultJSONSourceLocation
{
get
{
#if CORECLR
return Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles"), "PackageManagement\\ProviderAssemblies\\PSL", "PSL.json");
return PowerShellNanoSourceURL;
#else
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "PackageManagement\\ProviderAssemblies\\PSL", "PSL.json");
return PowerShellSourceURL;
#endif
}
}
internal string DefaultJSONCatalogFileLocation
{
get
{
#if CORECLR
return PowerShellNanoSourceCatalogURL;
#else
return PowerShellSourceCatalogURL;
#endif
}
}
internal string DefaultConfig
{
@ -96,13 +135,13 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
{
if (_defaultConfig == null)
{
_defaultConfig = DefaultConfigDefinition.Replace("##", DefaultConfigLocation);
_defaultConfig = DefaultConfigDefinition.Replace("##", DefaultJSONFileLocation);
}
return _defaultConfig;
}
}
internal IEnumerable<string> PackageSources
{
get
@ -790,66 +829,23 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
Debug(Resources.Messages.NotFoundRegisteredSource, src, Constants.ProviderName);
// doesn't look like we have this as a source.
if (Uri.IsWellFormedUriString(src, UriKind.Absolute))
{
// we have been passed in an URI
var srcUri = new Uri(src);
if (SupportedSchemes.Contains(srcUri.Scheme.ToLower()))
{
// it's one of our supported uri types.
var isValidated = false;
//if (!SkipValidate.Value)
//{
// isValidated = PathUtility.ValidateSourceUri(SupportedSchemes, srcUri, this);
//}
if (SkipValidate.Value || isValidated)
{
Debug(Resources.Messages.SuccessfullyValidated, src);
yield return new PackageSource
{
Request = this,
Location = srcUri.ToString(),
Name = srcUri.ToString(),
Trusted = false,
IsRegistered = false,
IsValidated = isValidated,
};
continue;
}
if (userSpecifiesArrayOfSources)
{
Verbose(Constants.Messages.UnableToResolveSource, Constants.ProviderName, src);
}
else
{
Warning(Constants.Messages.UnableToResolveSource, Constants.ProviderName, src);
}
continue;
}
// Not a valid location?
if (userSpecifiesArrayOfSources)
{
Verbose(Constants.Messages.UnableToResolveSource, Constants.ProviderName, src);
}
else
{
Warning(Constants.Messages.UnableToResolveSource, Constants.ProviderName, src);
}
continue;
}
// is it a file path?
if (System.IO.Directory.Exists(src))
{
Debug(Resources.Messages.SourceIsADirectory, src);
PackageSource newSource = new PackageSource
{
Request = this,
Location = src,
Name = src,
Trusted = true,
IsRegistered = false,
IsValidated = true,
};
yield return newSource;
}
else if (File.Exists(src) && (Path.GetExtension(src).EqualsIgnoreCase(".json")) )
{
PackageSource newSource = new PackageSource
{
Request = this,
@ -947,47 +943,52 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
{
get
{
if (String.IsNullOrWhiteSpace(_configurationFileLocation))
{
// get the value from the request
var path = GetOptionValue("ConfigFile");
if (string.IsNullOrWhiteSpace(_configurationFileLocation))
{
var appdataFolder = Environment.GetEnvironmentVariable("appdata");
_configurationFileLocation = Path.Combine(appdataFolder, Constants.ProviderName, Constants.SettingsFileName);
if (!String.IsNullOrWhiteSpace(path))
//create directory if does not exist
string dir = Path.GetDirectoryName(_configurationFileLocation);
if (dir != null && !System.IO.Directory.Exists(dir))
{
_configurationFileLocation = path;
if (!System.IO.File.Exists(_configurationFileLocation))
{
WriteError(Internal.ErrorCategory.InvalidArgument, _configurationFileLocation, Resources.Messages.FileNotFound);
}
Debug(Resources.Messages.CreateDirectory, dir);
System.IO.Directory.CreateDirectory(dir);
}
else
//create place holder config file
if (!System.IO.File.Exists(_configurationFileLocation))
{
var appdataFolder = Environment.GetEnvironmentVariable("appdata");
_configurationFileLocation = Path.Combine(appdataFolder, Constants.ProviderName, Constants.SettingsFileName);
Debug(Resources.Messages.CreateFile, _configurationFileLocation);
bool addDefaultConfig = false;
if (System.IO.File.Exists(DefaultJSONFileLocation))
{
addDefaultConfig = true;
}
else
{
bool force = this.GetOptionValue("Force") != null;
if (force || this.ShouldContinue(Resources.Messages.QueryDownloadPackageSourceList.format(DefaultJSONSourceLocation), Resources.Messages.PackageSourceListNotFound.format(DefaultJSONFileLocation)))
{
WebDownloader.DownloadFile(DefaultJSONSourceLocation, DefaultJSONFileLocation, this, null);
WebDownloader.DownloadFile(DefaultJSONCatalogFileLocation, DefaultCatlogFileLocation, this, null);
if (System.IO.File.Exists(DefaultJSONFileLocation) && System.IO.File.Exists(DefaultCatlogFileLocation) &&
PackageSourceListProvider.TestCatalogFile(DefaultJSONFileLocation, DefaultCatlogFileLocation, this))
{
addDefaultConfig = true;
}
}
}
//create directory if does not exist
string dir = Path.GetDirectoryName(_configurationFileLocation);
if (dir != null && !System.IO.Directory.Exists(dir))
{
Debug(Resources.Messages.CreateDirectory, dir);
System.IO.Directory.CreateDirectory(dir);
}
//create place holder config file
if (!System.IO.File.Exists(_configurationFileLocation))
{
Debug(Resources.Messages.CreateFile, _configurationFileLocation);
if(addDefaultConfig)
System.IO.File.WriteAllText(_configurationFileLocation, DefaultConfig);
}
else
System.IO.File.WriteAllText(_configurationFileLocation, EmptyConfig);
}
}
return _configurationFileLocation;
}
}
internal bool WriteError(Internal.ErrorCategory category, string targetObjectValue, string messageText, params object[] args)
{
return Error(messageText, category.ToString(), targetObjectValue, base.FormatMessageString(messageText, args));
@ -1001,9 +1002,11 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
internal bool ValidateSourceLocation(string location)
{
Debug(Resources.Messages.DebugInfoCallMethod3, _PackageSourceListRequest, "ValidateSourceLocation", location);
//TODO this is needed for register-packagesource
return true;
if (File.Exists(location) && (Path.GetExtension(location).EqualsIgnoreCase(".json")))
{
return true;
}
return false;
}
internal static IRequest ExtendRequest(Dictionary<string, string[]> options, string[] sources, bool isTrusted, PackageSourceListRequest request) {

View file

@ -43,6 +43,12 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
throw new ArgumentNullException("packageSource");
}
if(string.IsNullOrWhiteSpace(packageSource.Location) || !System.IO.File.Exists(packageSource.Location))
{
request.Warning(Resources.Messages.PackageSourceManifestNotFound, packageSource.Location, Constants.ProviderName);
return;
}
Uri uri;
if (Uri.TryCreate(packageSource.Location, UriKind.Absolute, out uri))
@ -56,6 +62,12 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
}
catch (Exception ex)
{
request.Warning(ex.Message);
while (ex.InnerException != null)
{
ex = ex.InnerException;
request.Warning(ex.Message);
}
request.Warning(string.Format(CultureInfo.CurrentCulture, Resources.Messages.InvalidPackageListFormat, uri.AbsolutePath));
ex.Dump(request);
}
@ -82,6 +94,12 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
}
catch (Exception ex)
{
request.Warning(ex.Message);
while (ex.InnerException != null)
{
ex = ex.InnerException;
request.Warning(ex.Message);
}
request.Warning(string.Format(CultureInfo.CurrentCulture, Resources.Messages.InvalidPackageListFormat, file));
ex.Dump(request);
}

View file

@ -25,9 +25,13 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
using File = System.IO.File;
using System.Threading.Tasks;
using Microsoft.PackageManagement.Provider.Utility;
using System.Security.Cryptography;
using System.Linq;
using ErrorCategory = PackageManagement.Internal.ErrorCategory;
public class WebDownloader
{
public class WebDownloader {
/// <summary>
/// Download data from remote via uri query.
/// </summary>
@ -44,11 +48,11 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
// try downloading for 3 times
int remainingTry = 3;
long totalDownloaded = 0;
CancellationTokenSource cts;
Stream input = null;
FileStream output = null;
Stream input = null;
FileStream output = null;
while (remainingTry > 0)
{
// if user cancel the request, no need to do anything
@ -67,24 +71,27 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
// decrease try by 1
remainingTry -= 1;
var httpClient = request.Client;
var httpClient = request.Client;
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "text/html; charset=iso-8859-1");
input = await httpClient.GetStreamAsync(query);
// buffer size of 64 KB, this seems to be preferable buffer size, not too small and not too big
byte[] bytes = new byte[1024 * 64];
output = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);
int current = 0;
// here we read content that we got from the http response stream into the bytes array
current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token);
int progressPercentage = progressTracker.StartPercent;
// report initial progress
request.Progress(progressTracker.ProgressID, progressTracker.StartPercent, Resources.Messages.BytesRead, current);
request.Progress(progressTracker.ProgressID, progressPercentage, Resources.Messages.BytesRead, current);
int i = progressTracker.StartPercent;
while (current > 0)
{
@ -92,10 +99,10 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
// here we write out the bytes array into the file
await output.WriteAsync(bytes, 0, current, cts.Token);
// report the progress
request.Progress(progressTracker.ProgressID, progressTracker.StartPercent, Resources.Messages.BytesRead, totalDownloaded);
request.Progress(progressTracker.ProgressID, progressPercentage<progressTracker.EndPercent?progressPercentage++:progressTracker.EndPercent, Resources.Messages.BytesRead, totalDownloaded);
// continue reading from the stream
current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token);
}
@ -113,7 +120,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
if (request.IsCanceled)
{
return 0;
}
}
}
catch (Exception ex)
{
@ -164,7 +171,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
{
throw new ArgumentNullException("destination");
}
// make sure that the parent folder is created first.
var folder = Path.GetDirectoryName(destination);
if (!Directory.Exists(folder))
@ -177,12 +184,11 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
destination.TryHardToDelete();
}
if (progressTracker == null)
{
progressTracker = new ProgressTracker(request.StartProgress(0, Resources.Messages.DownloadingPackage, queryUrl));
}
}
Uri uri;
@ -204,8 +210,8 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
input.CopyTo(output);
}
}
}
request.CompleteProgress(progressTracker.ProgressID, true);
}
else
@ -216,14 +222,14 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
if (File.Exists(destination))
{
request.Verbose(Resources.Messages.CompletedDownload, queryUrl);
request.Verbose(Resources.Messages.CompletedDownload, queryUrl);
return destination;
}
else
{
request.Error(Internal.ErrorCategory.InvalidOperation, Resources.Messages.FailedToDownload, Constants.ProviderName, queryUrl, destination);
return null;
}
}
}
catch (Exception ex)
{
@ -233,10 +239,65 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
}
}
internal static bool PerformSecurityScan(string fileFullPath)
internal static bool VerifyHash(string fileFullPath,PackageJson package, PackageSourceListRequest request)
{
//TODO need to do security scan before running install
return true;
//skip in case the skip switch is specified
if (request.SkipHashValidation.Value)
{
request.Verbose(Resources.Messages.SkipHashValidation);
return true;
}
PackageHash packageHash = package.Hash;
if (packageHash==null || string.IsNullOrWhiteSpace(packageHash.algorithm) || string.IsNullOrWhiteSpace(packageHash.hashCode))
{
request.WriteError(ErrorCategory.InvalidArgument, Constants.ProviderName, Resources.Messages.HashNotSpecified, package.Name);
return false;
}
try
{
HashAlgorithm hashAlgorithm = null;
switch (packageHash.algorithm.ToLowerInvariant())
{
case "sha256":
hashAlgorithm = SHA256.Create();
break;
case "md5":
hashAlgorithm = MD5.Create();
break;
case "sha512":
hashAlgorithm = SHA512.Create();
break;
default:
request.WriteError(ErrorCategory.InvalidArgument, Constants.ProviderName, Resources.Messages.InvalidHashAlgorithm, packageHash.algorithm);
return false;
}
using (FileStream stream = File.OpenRead(fileFullPath))
{
// compute the hash
byte[] computedHash = hashAlgorithm.ComputeHash(stream);
// convert the original hash we got from json
byte[] hashFromJSON = Convert.FromBase64String(package.Hash.hashCode);
if (!Enumerable.SequenceEqual(computedHash, hashFromJSON))
{
request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source);
return false;
}
else
{
request.Verbose(Resources.Messages.HashValidationSuccessfull);
}
}
}
catch
{
request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, Resources.Messages.HashVerificationFailed, package.Name, package.Source);
return false;
}
return true;
}
}
}

View file

@ -54,10 +54,8 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
}
// validate the file
if (!WebDownloader.PerformSecurityScan(file))
{
//TODO Security Scan work
request.WriteError(ErrorCategory.InvalidOperation, Constants.ProviderName, "The package download from '{0}' failed in the security scan.", package.Source);
if (!WebDownloader.VerifyHash(file, package,request))
{
return false;
}

View file

@ -18,7 +18,13 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
/// Config file storing the info as a result of registering a package source
/// </summary>
public static readonly string SettingsFileName = "PSL.config";
/// <summary>
/// Sample JSON file containing open powershell entry
/// </summary>
public static readonly string JSONFileName = "PSL.json";
public static readonly string CatFileName = "PSL.cat";
internal static class MediaType
{
public const string MsiPackage = "msi";
@ -79,7 +85,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
public const string ProviderSwidtagUnavailable = "MSG:ProviderSwidtagUnavailable";
public const string RemoveEnvironmentVariableRequiresElevation = "MSG:RemoveEnvironmentVariableRequiresElevation";
public const string SchemeNotSupported = "MSG:SchemeNotSupported";
public const string SourceLocationNotValid = "MSG:SourceLocationNotValid";
public const string SourceLocationNotValid = "MSG:SourceLocationNotValid_Location";
public const string UnableToCopyFileTo = "MSG:UnableToCopyFileTo";
public const string UnableToCreateShortcutTargetDoesNotExist = "MSG:UnableToCreateShortcutTargetDoesNotExist";
public const string UnableToDownload = "MSG:UnableToDownload";

View file

@ -277,7 +277,7 @@
<value>Unknown category for '{0}'::'{1}': '{2}'</value>
</data>
<data name="UriSchemeNotSupported" xml:space="preserve">
<value>Uri Scheme '{0}' is not supported.</value>
<value>Uri Scheme '{0}' is not supported. Only '{1}' is supported.</value>
</data>
<data name="UseDefaultConfig" xml:space="preserve">
<value>Use the default configuration.</value>
@ -392,4 +392,50 @@
<data name="InvalidPackageListFormat" xml:space="preserve">
<value>Package List Source '{0}' has incorrect format.</value>
</data>
<data name="QueryDownloadPackageSourceList" xml:space="preserve">
<value>Do you want to download package source list from '{0}'?</value>
<comment>0 - source list path</comment>
</data>
<data name="FileExists" xml:space="preserve">
<value>A file with this name already exists in target directory</value>
</data>
<data name="OverwriteFile" xml:space="preserve">
<value>Do you want to overwrite it?</value>
</data>
<data name="PackageSourceListNotTrusted" xml:space="preserve">
<value>PackageSourceList is not trusted</value>
</data>
<data name="VersionNotFound" xml:space="preserve">
<value>Package '{0}' in json file '{1}' is missing version information.</value>
</data>
<data name="HashNotSpecified" xml:space="preserve">
<value>Invalid hash for package '{0}'. Please correct the values in json file or use -SkipHashValidation switch to skip Hash validation.</value>
</data>
<data name="HashValidationSuccessfull" xml:space="preserve">
<value>Hash validation was successful.</value>
</data>
<data name="HashVerificationFailed" xml:space="preserve">
<value>Hash verification failed for package '{0}' downloaded from '{1}'.</value>
</data>
<data name="InvalidHashAlgorithm" xml:space="preserve">
<value>Hash algorithm '{0}' is not supported. We only support sha512, md5 and sha256.</value>
</data>
<data name="SkipHashValidation" xml:space="preserve">
<value>Skipping Hash Validation.</value>
</data>
<data name="CatalogFileMissing" xml:space="preserve">
<value>Catalog file not found for '{0}'. Catalog files are required for non local json files and should have the same name and located in the same directory as json file.</value>
</data>
<data name="CatalogFileVerificationFailed" xml:space="preserve">
<value>Catalog File verification failed for '{0}'.</value>
</data>
<data name="CatalogFileVerificationFailedWithError" xml:space="preserve">
<value>Catalog File '{0}' verification failed with '{1}'.</value>
</data>
<data name="PackageSourceListNotFound" xml:space="preserve">
<value>Cannot find source list file '{0}'.</value>
</data>
<data name="PackageSourceManifestNotFound" xml:space="preserve">
<value>File '{0}' is registered as a package source location for the provider '{1}'. But it does not exist. Run 'Get-PackageSource' to view the registered package sources, 'Unregister-PackageSource' to unregister the source if you do not wish to use it or 'Set-PackageSource' to fix the source location.</value>
</data>
</root>

View file

@ -198,6 +198,43 @@ namespace Microsoft.PowerShell.Workflow
/// based on the definition provided by this script block.
/// </returns>
public List<WorkflowInfo> CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, out ParseException parsingErrors, string rootWorkflowName)
{
return CompileWorkflowsImpl(ast, definingModule, initialSessionState, null, out parsingErrors, rootWorkflowName);
}
/// <summary>
/// Converts a PowerShell AST into a script block that represents
/// the workflow to run.
/// </summary>
/// <param name="ast">The PowerShell AST correpsponding to the job's definition.</param>
/// <param name="definingModule">The module that is defining this command (if any).</param>
/// <param name="initialSessionState">The initial session state of a runspace.</param>
/// <param name="sourceLanguageMode">Language mode of source that is creating the workflow.</param>
/// <param name="parsingErrors">Optional, once assigned, only root Workflow will be compiled.</param>
/// <returns>
/// A PowerShell script block that invokes an underlying job,
/// based on the definition provided by this script block.
/// </returns>
public List<WorkflowInfo> CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, PSLanguageMode? sourceLanguageMode, out ParseException parsingErrors)
{
return CompileWorkflowsImpl(ast, definingModule, initialSessionState, sourceLanguageMode, out parsingErrors, null);
}
/// <summary>
/// Converts a PowerShell AST into a script block that represents
/// the workflow to run.
/// </summary>
/// <param name="ast">The PowerShell AST correpsponding to the job's definition.</param>
/// <param name="definingModule">The module that is defining this command (if any)</param>
/// <param name="initialSessionState">The initial session state of a runspace.</param>
/// <param name="sourceLanguageMode">Language mode of source that is creating the workflow.</param>
/// <param name="parsingErrors">parsing errors</param>
/// <param name="rootWorkflowName">Optional, once assigned, only root Workflow will be compiled</param>
/// <returns>
/// A PowerShell script block that invokes an underlying job,
/// based on the definition provided by this script block.
/// </returns>
private List<WorkflowInfo> CompileWorkflowsImpl(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, PSLanguageMode? sourceLanguageMode, out ParseException parsingErrors, string rootWorkflowName)
{
List<ParseError> errorList = new List<ParseError>();
@ -327,7 +364,7 @@ namespace Microsoft.PowerShell.Workflow
try
{
entry.workflowInfo = CompileSingleWorkflow(entry.scope, func, scriptBlockTokenCache, definingModule, requiredAssemblies, activityMap, processedActivityLibraries, invoker, rootWorkflowName);
entry.workflowInfo = CompileSingleWorkflow(entry.scope, func, scriptBlockTokenCache, definingModule, requiredAssemblies, activityMap, processedActivityLibraries, invoker, sourceLanguageMode, rootWorkflowName);
result.Add(entry.workflowInfo);
}
catch (ParseException e)
@ -365,6 +402,7 @@ namespace Microsoft.PowerShell.Workflow
Dictionary<string, Type> activityMap,
HashSet<string> processedActivityLibraries,
System.Management.Automation.PowerShell invoker,
PSLanguageMode? sourceLanguageMode = (PSLanguageMode?)null,
string rootWorkflowName = null)
{
Dictionary<string, ParameterAst> parameterValidation;
@ -399,10 +437,11 @@ namespace Microsoft.PowerShell.Workflow
// Pass either the workflow script file path if available or the full source otherwise.
string scriptFile = parentAst.Extent.File;
string scriptSource = string.IsNullOrEmpty(scriptFile) ? parentAst.Extent.StartScriptPosition.GetFullScript() : null;
ReadOnlyCollection<AttributeAst> attributeAstCollection = (func.Body.ParamBlock != null) ? func.Body.ParamBlock.Attributes : null;
var functionDefinition = ImportWorkflowCommand.CreateFunctionFromXaml(func.Name, xaml,
referencedAssemblies, calledWorkflows.Select(wfi => wfi.NestedXamlDefinition).ToArray(),
null, parameterValidation, modulePath, true, workflowAttributes,
scriptFile, scriptSource, rootWorkflowName);
scriptFile, scriptSource, rootWorkflowName, sourceLanguageMode, attributeAstCollection);
var helpContent = func.GetHelpContent(scriptBlockTokenCache);
if (helpContent != null)

View file

@ -1,39 +0,0 @@
{
"monad/src/commands/utility/WebCmdlet/ConvertFromJsonCommand.cs": "ConvertFromJsonCommand.cs",
"monad/src/commands/utility/WebCmdlet/ConvertToJsonCommand.cs": "ConvertToJsonCommand.cs",
"monad/src/commands/utility/WebCmdlet/FormObject.cs": "FormObject.cs",
"monad/src/commands/utility/WebCmdlet/FormObjectCollection.cs": "FormObjectCollection.cs",
"monad/src/commands/utility/WebCmdlet/JsonObject.cs": "JsonObject.cs",
"monad/src/commands/utility/WebCmdlet/PSUserAgent.cs": "PSUserAgent.cs",
"monad/src/commands/utility/WebCmdlet/StreamHelper.cs": "StreamHelper.cs",
"monad/src/commands/utility/WebCmdlet/WebCmdletElementCollection.cs": "WebCmdletElementCollection.cs",
"monad/src/commands/utility/WebCmdlet/WebRequestMethod.cs": "WebRequestMethod.cs",
"monad/src/commands/utility/WebCmdlet/WebRequestSession.cs": "WebRequestSession.cs",
"monad/src/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs": "Common/BasicHtmlWebResponseObject.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs": "Common/ContentHelper.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/HtmlWebResponseObject.Common.cs": "Common/HtmlWebResponseObject.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs": "Common/InvokeRestMethodCommand.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs": "Common/WebRequestPSCmdlet.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs": "Common/WebResponseObject.Common.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/BasicHtmlWebResponseObject.CoreClr.cs": "CoreCLR/BasicHtmlWebResponseObject.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/ContentHelper.CoreClr.cs": "CoreCLR/ContentHelper.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/HtmlWebResponseObject.CoreClr.cs": "CoreCLR/HtmlWebResponseObject.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs": "CoreCLR/HttpKnownHeaderNames.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/InvokeRestMethodCommand.CoreClr.cs": "CoreCLR/InvokeRestMethodCommand.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs": "CoreCLR/InvokeWebRequestCommand.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs": "CoreCLR/WebProxy.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs": "CoreCLR/WebRequestPSCmdlet.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs": "CoreCLR/WebResponseHelper.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebResponseObject.CoreClr.cs": "CoreCLR/WebResponseObject.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs": "CoreCLR/WebResponseObjectFactory.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/BasicHtmlWebResponseObject.FullClr.cs": "FullClr/BasicHtmlWebResponseObject.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/ContentHelper.FullClr.cs": "FullClr/ContentHelper.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/HtmlWebResponseObject.FullClr.cs": "FullClr/HtmlWebResponseObject.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/InvokeRestMethodCommand.FullClr.cs": "FullClr/InvokeRestMethodCommand.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/InvokeWebRequestCommand.FullClr.cs": "FullClr/InvokeWebRequestCommand.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/JsonObjectTypeResolver.cs": "FullClr/JsonObjectTypeResolver.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/WebRequestPSCmdlet.FullClr.cs": "FullClr/WebRequestPSCmdlet.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/WebResponseHelper.FullClr.cs": "FullClr/WebResponseHelper.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/WebResponseObject.FullClr.cs": "FullClr/WebResponseObject.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/WebResponseObjectFactory.FullClr.cs": "FullClr/WebResponseObjectFactory.FullClr.cs"
}

View file

@ -134,4 +134,42 @@
"monad/src/commands/utility/WriteProgressCmdlet.cs": "commands/utility/WriteProgressCmdlet.cs",
"monad/src/commands/utility/XmlCommands.cs": "commands/utility/XmlCommands.cs",
"monad/src/singleshell/installer/MshUtilityMshSnapin.cs": "singleshell/installer/MshUtilityMshSnapin.cs",
"monad/src/commands/utility/WebCmdlet/ConvertFromJsonCommand.cs": "ConvertFromJsonCommand.cs",
"monad/src/commands/utility/WebCmdlet/ConvertToJsonCommand.cs": "ConvertToJsonCommand.cs",
"monad/src/commands/utility/WebCmdlet/FormObject.cs": "FormObject.cs",
"monad/src/commands/utility/WebCmdlet/FormObjectCollection.cs": "FormObjectCollection.cs",
"monad/src/commands/utility/WebCmdlet/JsonObject.cs": "JsonObject.cs",
"monad/src/commands/utility/WebCmdlet/PSUserAgent.cs": "PSUserAgent.cs",
"monad/src/commands/utility/WebCmdlet/StreamHelper.cs": "StreamHelper.cs",
"monad/src/commands/utility/WebCmdlet/WebCmdletElementCollection.cs": "WebCmdletElementCollection.cs",
"monad/src/commands/utility/WebCmdlet/WebRequestMethod.cs": "WebRequestMethod.cs",
"monad/src/commands/utility/WebCmdlet/WebRequestSession.cs": "WebRequestSession.cs",
"monad/src/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs": "Common/BasicHtmlWebResponseObject.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/ContentHelper.Common.cs": "Common/ContentHelper.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/HtmlWebResponseObject.Common.cs": "Common/HtmlWebResponseObject.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs": "Common/InvokeRestMethodCommand.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs": "Common/WebRequestPSCmdlet.Common.cs",
"monad/src/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs": "Common/WebResponseObject.Common.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/BasicHtmlWebResponseObject.CoreClr.cs": "CoreCLR/BasicHtmlWebResponseObject.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/ContentHelper.CoreClr.cs": "CoreCLR/ContentHelper.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/HtmlWebResponseObject.CoreClr.cs": "CoreCLR/HtmlWebResponseObject.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/HttpKnownHeaderNames.cs": "CoreCLR/HttpKnownHeaderNames.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/InvokeRestMethodCommand.CoreClr.cs": "CoreCLR/InvokeRestMethodCommand.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs": "CoreCLR/InvokeWebRequestCommand.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebProxy.cs": "CoreCLR/WebProxy.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs": "CoreCLR/WebRequestPSCmdlet.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebResponseHelper.CoreClr.cs": "CoreCLR/WebResponseHelper.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebResponseObject.CoreClr.cs": "CoreCLR/WebResponseObject.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/CoreCLR/WebResponseObjectFactory.CoreClr.cs": "CoreCLR/WebResponseObjectFactory.CoreClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/BasicHtmlWebResponseObject.FullClr.cs": "FullClr/BasicHtmlWebResponseObject.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/ContentHelper.FullClr.cs": "FullClr/ContentHelper.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/HtmlWebResponseObject.FullClr.cs": "FullClr/HtmlWebResponseObject.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/InvokeRestMethodCommand.FullClr.cs": "FullClr/InvokeRestMethodCommand.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/InvokeWebRequestCommand.FullClr.cs": "FullClr/InvokeWebRequestCommand.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/JsonObjectTypeResolver.cs": "FullClr/JsonObjectTypeResolver.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/WebRequestPSCmdlet.FullClr.cs": "FullClr/WebRequestPSCmdlet.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/WebResponseHelper.FullClr.cs": "FullClr/WebResponseHelper.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/WebResponseObject.FullClr.cs": "FullClr/WebResponseObject.FullClr.cs",
"monad/src/commands/utility/WebCmdlet/FullClr/WebResponseObjectFactory.FullClr.cs": "FullClr/WebResponseObjectFactory.FullClr.cs"
}

View file

@ -3545,7 +3545,7 @@ namespace Microsoft.PowerShell.Commands
{
if (DownLevelHelper.NativeFilteringSupported())
{
Collection<string> ekuCollection = System.Management.Automation.SecuritySupport.GetCertEKU(cert);
Collection<string> ekuCollection = System.Management.Automation.Internal.SecuritySupport.GetCertEKU(cert);
foreach (string oidString in ekuCollection)
{

View file

@ -5,6 +5,7 @@ Copyright (c) Microsoft Corporation. All rights reserved.
using System;
using System.Management.Automation;
using System.Management.Automation.Internal;
using Dbg=System.Management.Automation.Diagnostics;
using System.Collections.Generic;
using System.Collections;

View file

@ -110,17 +110,15 @@ namespace Microsoft.PowerShell.Commands
protected override void ProcessRecord()
{
// In ConstrainedLanguage, XAML workflows are not supported (even from a trusted FullLanguage state),
// since we can't prevent tampering.
// unless they are signed in-box OS binaries.
bool checkSignatures = false;
if ((SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Enforce) ||
(this.SessionState.LanguageMode == PSLanguageMode.ConstrainedLanguage))
{
// However, this static internal property can be changed by tests that can already run a script
// in full-language mode.
PropertyInfo xamlProperty = typeof(SystemPolicy).GetProperty("XamlWorkflowSupported", BindingFlags.NonPublic | BindingFlags.Static);
if (! ((bool) xamlProperty.GetValue(null, null)))
{
throw new NotSupportedException(Resources.XamlWorkflowsNotSupported);
}
checkSignatures = !((bool)xamlProperty.GetValue(null, null));
}
string dependentWorkflowAssemblyPath = string.Empty;
@ -174,8 +172,10 @@ namespace Microsoft.PowerShell.Commands
WriteError(er);
Tracer.TraceErrorRecord(er);
continue;
}
CheckFileSignatureAsNeeded(checkSignatures, resolvedPath);
try
{
// Finally load the file. If there is an access violation, write a
@ -251,6 +251,8 @@ namespace Microsoft.PowerShell.Commands
continue;
}
CheckFileSignatureAsNeeded(checkSignatures, resolvedPath);
FunctionDetails detailsToUseForUpdate = null;
try
{
@ -302,7 +304,8 @@ namespace Microsoft.PowerShell.Commands
requiredAssemblies,
dependentWorkflowContent.ToArray(),
dependentWorkflowAssemblyPath,
resolvedPath);
resolvedPath,
this.SessionState.LanguageMode);
// check if the function cache already has the entry to this file
// If detailsToUseForUpdate is not null it is a forced import module
@ -342,6 +345,14 @@ namespace Microsoft.PowerShell.Commands
} //ProcessRecord
private static void CheckFileSignatureAsNeeded(bool checkSignatures, string filePath)
{
if (checkSignatures && !System.Management.Automation.Internal.SecuritySupport.IsProductBinary(filePath))
{
throw new NotSupportedException(Resources.XamlWorkflowsNotSupported);
}
}
private static readonly ConcurrentDictionary<string, FunctionDetails> FunctionCache =
new ConcurrentDictionary<string, FunctionDetails>(StringComparer.OrdinalIgnoreCase);
@ -358,7 +369,15 @@ namespace Microsoft.PowerShell.Commands
/// <param name="dependentWorkflows">Any workflows required by this workflow.</param>
/// <param name="dependentAssemblyPath">Path to the dependent assembly.</param>
/// <param name="resolvedPath">Resolved Path of the xaml</param>
private static FunctionDetails GenerateFunctionFromXaml(string name, string xaml, Dictionary<string, string> requiredAssemblies, string[] dependentWorkflows, string dependentAssemblyPath, string resolvedPath)
/// <param name="sourceLanguageMode">Language mode of source in which workflow should run</param>
private static FunctionDetails GenerateFunctionFromXaml(
string name,
string xaml,
Dictionary<string, string> requiredAssemblies,
string[] dependentWorkflows,
string dependentAssemblyPath,
string resolvedPath,
PSLanguageMode sourceLanguageMode)
{
if (name == null)
{
@ -368,7 +387,21 @@ namespace Microsoft.PowerShell.Commands
}
string modulePath = System.IO.Path.GetDirectoryName(resolvedPath);
string functionDefinition = CreateFunctionFromXaml(name, xaml, requiredAssemblies, dependentWorkflows, dependentAssemblyPath, null, modulePath, false, "[CmdletBinding()]");
string functionDefinition = CreateFunctionFromXaml(
name,
xaml,
requiredAssemblies,
dependentWorkflows,
dependentAssemblyPath,
null,
modulePath,
false,
"[CmdletBinding()]",
null, /* scriptContent */
null, /* fullScript */
null, /* rootWorkflowName */
sourceLanguageMode,
null);
FunctionDetails details = new FunctionDetails
{Name = name, FunctionDefinition = functionDefinition, Xaml = xaml};
@ -438,6 +471,24 @@ namespace Microsoft.PowerShell.Commands
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "workFlowDefinition")]
public static ContainerParentJob StartWorkflowApplication(PSCmdlet command, string jobName, string workflowGuid, bool startAsync,
bool parameterCollectionProcessed, Hashtable[] parameters, bool debuggerActive)
{
return StartWorkflowApplication(command, jobName, workflowGuid, startAsync, parameterCollectionProcessed, parameters, false, null);
}
/// <summary>
/// Executes an instance of the workflow object graph identified by the passed
/// GUID, binding parameters from the Parameters hastable.
/// </summary>
/// <param name="command">The powershell command.</param>
/// <param name="workflowGuid">The GUID used to identify the workflow to run.</param>
/// <param name="parameters">The parameters to pass to the workflow instance.</param>
/// <param name="jobName">The friendly name for the job</param>
/// <param name="parameterCollectionProcessed">True if there was a PSParameters collection</param>
/// <param name="startAsync"></param>
/// <param name="debuggerActive">True if debugger is in active state.</param>
/// <param name="SourceLanguageMode">Language mode of source creating workflow.</param>
public static ContainerParentJob StartWorkflowApplication(PSCmdlet command, string jobName, string workflowGuid, bool startAsync,
bool parameterCollectionProcessed, Hashtable[] parameters, bool debuggerActive, string SourceLanguageMode)
{
Guid trackingGuid = Guid.NewGuid();
_structuredTracer.BeginStartWorkflowApplication(trackingGuid);
@ -573,6 +624,15 @@ namespace Microsoft.PowerShell.Commands
myJob = command.JobManager.NewJob(specification) as ContainerParentJob;
_structuredTracer.EndCreateNewJob(trackingGuid);
// Pass the source language mode to the workflow job so that it can be
// applied during activity execution.
PSLanguageMode sourceLanguageModeValue;
PSLanguageMode? sourceLanguageMode = null;
if (!string.IsNullOrEmpty(SourceLanguageMode) && Enum.TryParse<PSLanguageMode>(SourceLanguageMode, out sourceLanguageModeValue))
{
sourceLanguageMode = sourceLanguageModeValue;
}
// Raise engine event of new WF job start for debugger, if
// debugger is active (i.e., has breakpoints set).
if (debuggerActive)
@ -582,12 +642,13 @@ namespace Microsoft.PowerShell.Commands
if (startAsync)
{
if (!PSSessionConfigurationData.IsServerManager)
foreach(PSWorkflowJob childjob in myJob.ChildJobs)
{
foreach(PSWorkflowJob childjob in myJob.ChildJobs)
if (!PSSessionConfigurationData.IsServerManager)
{
childjob.EnableStreamUnloadOnPersistentState();
}
childjob.SourceLanguageMode = sourceLanguageMode;
}
myJob.StartJobAsync();
}
@ -598,6 +659,7 @@ namespace Microsoft.PowerShell.Commands
foreach (PSWorkflowJob childJob in myJob.ChildJobs)
{
childJob.SynchronousExecution = true;
childJob.SourceLanguageMode = sourceLanguageMode;
}
myJob.StartJob();
}
@ -605,8 +667,8 @@ namespace Microsoft.PowerShell.Commands
// write an event specifying that job creation is done
_structuredTracer.EndStartWorkflowApplication(trackingGuid);
_structuredTracer.TrackingGuidContainerParentJobCorrelation(trackingGuid, myJob.InstanceId);
return myJob;
return myJob;
}
private static void RaiseWFJobEvent(PSCmdlet command, ContainerParentJob job, bool startAsync)
@ -1010,6 +1072,46 @@ namespace Microsoft.PowerShell.Commands
string fullScript,
string rootWorkflowName
)
{
return CreateFunctionFromXaml(name, xaml, requiredAssemblies, dependentWorkflows, dependentAssemblyPath, parameterValidation, modulePath,
scriptWorkflow, workflowAttributes, scriptContent, fullScript, rootWorkflowName, null, null);
}
/// <summary>
/// Creates a workflow activity based on the provided Xaml and returns PowerShell script that will
/// run the workflow.
/// </summary>
/// <param name="name">Workflow name</param>
/// <param name="xaml">Workflow Xaml definition</param>
/// <param name="requiredAssemblies">Required assemblies</param>
/// <param name="dependentWorkflows">Dependent workflows</param>
/// <param name="dependentAssemblyPath">Path for dependent assemblies</param>
/// <param name="parameterValidation">Workflow parameters</param>
/// <param name="modulePath">Module path</param>
/// <param name="scriptWorkflow">True if this is script workflow</param>
/// <param name="workflowAttributes">the attribute string to use for the workflow, should be '[CmdletBinding()]'</param>
/// <param name="scriptContent">File path containing script content.</param>
/// <param name="fullScript">Full source script.</param>
/// <param name="rootWorkflowName">Only root Workflow will be compiled</param>
/// <param name="sourceLanguageMode">Language mode of source that is creating the workflow</param>
/// <param name="attributeAstCollection">Optional collection of parameter attribute Asts</param>
/// <returns></returns>
public static string CreateFunctionFromXaml(
string name,
string xaml,
Dictionary<string, string> requiredAssemblies,
string[] dependentWorkflows,
string dependentAssemblyPath,
Dictionary<string, ParameterAst> parameterValidation,
string modulePath,
bool scriptWorkflow,
string workflowAttributes,
string scriptContent,
string fullScript,
string rootWorkflowName,
PSLanguageMode? sourceLanguageMode,
ReadOnlyCollection<AttributeAst> attributeAstCollection
)
{
// check to see if the specified name is allowed
if (!Regex.IsMatch(name, functionNamePattern))
@ -1304,9 +1406,15 @@ namespace Microsoft.PowerShell.Commands
completeFunctionDefinitionTemplate.AppendLine(" }}");
completeFunctionDefinitionTemplate.AppendLine(FunctionBodyTemplate);
// Mark the function definition with sourceLanguageMode (language mode that function can run under, i.e.,
// as trusted or not trusted), unless the workflow script is marked with the "SecurityCritical" attribute in
// which case the function will always be run under the current system lock down setting.
bool isSecurityCritical = ContainsSecurityCriticalAttribute(attributeAstCollection);
string sourceLanguageModeStr = (!isSecurityCritical && (sourceLanguageMode != null)) ? sourceLanguageMode.ToString() : string.Empty;
// Combine the pieces to create the complete function
string functionDefinition = String.Format(CultureInfo.InvariantCulture, completeFunctionDefinitionTemplate.ToString(),
defaultUpdates, workflowGuid, modulePath);
defaultUpdates, workflowGuid, modulePath, sourceLanguageModeStr);
#if DEBUG
// Verify that the generated function is valid powershell. This is only an issue when changing the
@ -1334,6 +1442,23 @@ namespace Microsoft.PowerShell.Commands
return functionDefinition;
}
private static Type securityCriticalAttributeType = typeof(System.Security.SecurityCriticalAttribute);
private static bool ContainsSecurityCriticalAttribute(ReadOnlyCollection<AttributeAst> attributeAsts)
{
if (attributeAsts != null)
{
foreach (var attributeAst in attributeAsts)
{
if (attributeAst.TypeName.GetReflectionAttributeType() == securityCriticalAttributeType)
{
return true;
}
}
}
return false;
}
/// <summary>
///
@ -1515,6 +1640,9 @@ namespace Microsoft.PowerShell.Commands
# which uses this as a base path to find localized content files.
$psBoundParameters['" + Constants.ModulePath + @"'] = '{2}'
# Variable that contains the source language mode.
[string] $SourceLanguageMode = '{3}'
if (Test-Path variable:\PSSenderInfo)
{{
$psBoundParameters['" + Constants.PSSenderInfo + @"'] = $PSSenderInfo
@ -1693,7 +1821,8 @@ namespace Microsoft.PowerShell.Commands
$AsJob,
$parameterCollectionProcessed,
$finalParameterCollection,
$debuggerActive)
$debuggerActive,
$SourceLanguageMode)
}}
catch
{{

View file

@ -80,23 +80,29 @@ namespace Microsoft.PowerShell.Workflow
return EndGetRunspace(asyncResult);
}
private Runspace AssignRunspaceIfPossible()
private Runspace AssignRunspaceIfPossible(PSLanguageMode? sourceLanguageMode = null)
{
Runspace runspace = null;
PSLanguageMode languageMode = (sourceLanguageMode != null) ? sourceLanguageMode.Value :
(_languageMode != null) ? _languageMode.Value : GetSystemLanguageMode();
lock (_runspaceCache.TimerServicingSyncObject)
{
// Retrieve or create a local runspace having the same language mode as the source, if provided.
foreach (Item<Runspace> item in _runspaceCache.Cast<Item<Runspace>>().Where(item => !item.Busy))
{
item.Idle = false;
item.Busy = true;
runspace = item.Value;
break;
if (item.Value.SessionStateProxy.LanguageMode == languageMode)
{
item.Idle = false;
item.Busy = true;
runspace = item.Value;
break;
}
}
if ((runspace == null || runspace.RunspaceStateInfo.State != RunspaceState.Opened) &&
(_maxRunspaces == MaxRunspacesPossible || _runspaceCache.Cache.Count < _maxRunspaces))
{
runspace = CreateLocalActivityRunspace(_languageMode);
runspace = CreateLocalActivityRunspace(languageMode);
runspace.Open();
_tracer.WriteMessage("New local runspace created");
@ -108,6 +114,11 @@ namespace Microsoft.PowerShell.Workflow
return runspace;
}
private static PSLanguageMode GetSystemLanguageMode()
{
return (SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Enforce) ?
PSLanguageMode.ConstrainedLanguage : PSLanguageMode.FullLanguage;
}
private void TraceThreadPoolInfo(string message)
{
@ -208,7 +219,23 @@ namespace Microsoft.PowerShell.Workflow
LocalRunspaceAsyncResult asyncResult = new LocalRunspaceAsyncResult(state, callback, Guid.Empty);
Runspace runspace = AssignRunspaceIfPossible();
// Get the source language mode from the activity arguments if available and pass to runspace fetching.
PSLanguageMode? sourceLanguageMode = null;
RunCommandsArguments args = state as RunCommandsArguments;
if (args != null)
{
PSWorkflowRuntime wfRuntime = args.WorkflowHost as PSWorkflowRuntime;
if (wfRuntime != null)
{
PSWorkflowJob wfJob = wfRuntime.JobManager.GetJob(args.PSActivityContext.JobInstanceId);
if (wfJob != null)
{
sourceLanguageMode = wfJob.SourceLanguageMode;
}
}
}
Runspace runspace = AssignRunspaceIfPossible(sourceLanguageMode);
if (runspace != null)
{
asyncResult.Runspace = runspace;

View file

@ -1205,6 +1205,8 @@ namespace Microsoft.PowerShell.Workflow
internal bool? IsSuspendable = null;
internal PSLanguageMode? SourceLanguageMode { get; set; }
#endregion Internal Accessors
#region Internal Methods

View file

@ -413,7 +413,7 @@ For more information about how to add checkpoints, see the help topics for Windo
<comment>{0} is a number and should not be localized.</comment>
</data>
<data name="XamlWorkflowsNotSupported" xml:space="preserve">
<value>Cannot load workflow. XAML-based workflows are not supported in this language mode. Only script-based workflows are supported.</value>
<value>Cannot load the workflow. Only signed in-box XAML-based workflows or script-based workflows are supported in the current language mode.</value>
</data>
<data name="RetryingConnection" xml:space="preserve">
<value>Retrying activity connection: attempt {0} of {1}.</value>

View file

@ -1,17 +1,17 @@
@{
@{
GUID="1DA87E53-152B-403E-98DC-74D7B4D63D59"
Author="Microsoft Corporation"
CompanyName="Microsoft Corporation"
Copyright="© Microsoft Corporation. All rights reserved."
Copyright="© Microsoft Corporation. All rights reserved."
ModuleVersion="3.1.0.0"
PowerShellVersion="3.0"
CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide",
"Out-File", "Out-String", "Get-FormatData", "Export-FormatData", "ConvertFrom-Json", "ConvertTo-Json",
"Invoke-RestMethod", "Invoke-WebRequest",
"Register-ObjectEvent", "Register-EngineEvent", "Wait-Event", "Get-Event", "Remove-Event",
"Get-EventSubscriber", "Unregister-Event", "New-Event", "Add-Member", "Add-Type", "Compare-Object",
"ConvertFrom-StringData", "Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias",
"Invoke-Expression", "Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random",
"Invoke-RestMethod", "Invoke-WebRequest", "Register-ObjectEvent", "Register-EngineEvent",
"Wait-Event", "Get-Event", "Remove-Event", "Get-EventSubscriber", "Unregister-Event",
"New-Event", "Add-Member", "Add-Type", "Compare-Object", "ConvertFrom-StringData",
"Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression",
"Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random",
"Get-UICulture", "Get-Unique", "Import-Alias", "Import-LocalizedData",
"Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date",
"Start-Sleep", "Tee-Object", "Measure-Command", "Update-TypeData", "Update-FormatData",
@ -20,7 +20,6 @@ CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide",
"Clear-Variable", "Export-Clixml", "Import-Clixml", "ConvertTo-Xml", "Select-Xml", "Write-Debug",
"Write-Verbose", "Write-Warning", "Write-Error", "Write-Information", "Write-Output", "Set-PSBreakpoint",
"Get-PSBreakpoint", "Remove-PSBreakpoint", "Enable-PSBreakpoint", "Disable-PSBreakpoint", "Get-PSCallStack",
"Get-TraceSource", "Set-TraceSource", "Trace-Command",
"Unblock-File", "Get-Runspace", "Debug-Runspace", "Enable-RunspaceDebug", "Disable-RunspaceDebug",
"Get-RunspaceDebug", "Wait-Debugger"
FunctionsToExport= "Get-FileHash", "New-TemporaryFile", "New-Guid", "Format-Hex", "Import-PowerShellDataFile",

View file

@ -1,8 +1,9 @@
workflow Invoke-AsWorkflow
workflow Invoke-AsWorkflow
{
<#
.EXTERNALHELP Microsoft.PowerShell.Workflow.ServiceCore.dll-help.xml
#>
[System.Security.SecurityCritical()]
[CmdletBinding(DefaultParameterSetName='Command', HelpUri='http://go.microsoft.com/fwlink/?LinkId=238267')]
param(
[Parameter(Mandatory=$true,ParameterSetName="Command")]

View file

@ -3777,7 +3777,7 @@ namespace Microsoft.PowerShell.Commands
if (workflowsToProcess != null && workflowsToProcess.Count > 0)
{
// In ConstrainedLanguage, XAML workflows are not supported (even from a trusted FullLanguage state),
// since we can't prevent tampering.
// unless they are signed in-box OS binaries.
if ((SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Enforce) ||
(Context.LanguageMode == PSLanguageMode.ConstrainedLanguage))
{
@ -3785,15 +3785,30 @@ namespace Microsoft.PowerShell.Commands
// in full-language mode.
if (! SystemPolicy.XamlWorkflowSupported)
{
throw new NotSupportedException(Modules.XamlWorkflowsNotSupported);
foreach (string workflowPath in ResolveWorkflowFiles(moduleBase, workflowsToProcess))
{
if (!SecuritySupport.IsProductBinary(workflowPath))
{
throw new NotSupportedException(Modules.XamlWorkflowsNotSupported);
}
}
}
}
SessionStateInternal oldSessionStateWF = Context.EngineSessionState;
PSLanguageMode? savedLanguageMode = null;
try
{
Context.EngineSessionState = ss.Internal;
// Always run workflow import script as trusted since only signed in-box files can be imported
// on locked down machines.
if (Context.LanguageMode != PSLanguageMode.FullLanguage)
{
savedLanguageMode = Context.LanguageMode;
Context.LanguageMode = PSLanguageMode.FullLanguage;
}
if (dependentWorkflows != null && dependentWorkflows.Count > 0)
{
ScriptBlock importWorkflow = ScriptBlock.Create(Context,
@ -3811,7 +3826,7 @@ namespace Microsoft.PowerShell.Commands
else
{
ScriptBlock importWorkflow = ScriptBlock.Create(Context,
"param($files, $dependentFiles) Microsoft.PowerShell.Workflow.ServiceCore\\Import-PSWorkflow -Path \"$files\" -Force:$"+BaseForce
"param($files, $dependentFiles) Microsoft.PowerShell.Workflow.ServiceCore\\Import-PSWorkflow -Path \"$files\" -Force:$" + BaseForce
);
foreach (string workflowPath in ResolveWorkflowFiles(moduleBase, workflowsToProcess))
@ -3830,6 +3845,11 @@ namespace Microsoft.PowerShell.Commands
finally
{
Context.EngineSessionState = oldSessionStateWF;
if (savedLanguageMode != null)
{
Context.LanguageMode = savedLanguageMode.Value;
}
}
}
}

View file

@ -11084,6 +11084,9 @@ namespace System.Management.Automation.Internal
/// <summary/>
List<WorkflowInfo> CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, out ParseException parsingErrors);
/// <summary/>
List<WorkflowInfo> CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, PSLanguageMode? languageMode, out ParseException parsingErrors);
/// <summary/>
List<WorkflowInfo> CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, string rootWorkflowName);

View file

@ -1828,7 +1828,7 @@ namespace System.Management.Automation
if (_scriptBlock.HasBeginBlock)
{
RunClause(_runOptimized ? _scriptBlock.BeginBlock : _scriptBlock.UnoptimizedBeginBlock, AutomationNull.Value, _input.GetEnumerator());
RunClause(_runOptimized ? _scriptBlock.BeginBlock : _scriptBlock.UnoptimizedBeginBlock, AutomationNull.Value, _input);
}
}
@ -1851,7 +1851,7 @@ namespace System.Management.Automation
}
if (_scriptBlock.HasProcessBlock)
{
RunClause(_runOptimized ? _scriptBlock.ProcessBlock : _scriptBlock.UnoptimizedProcessBlock, dollarUnder, _input.GetEnumerator());
RunClause(_runOptimized ? _scriptBlock.ProcessBlock : _scriptBlock.UnoptimizedProcessBlock, dollarUnder, _input);
_input.Clear();
}
}
@ -1865,7 +1865,7 @@ namespace System.Management.Automation
if (_scriptBlock.HasEndBlock)
{
RunClause(_runOptimized ? _scriptBlock.EndBlock : _scriptBlock.UnoptimizedEndBlock, AutomationNull.Value, _input.ToArray().GetEnumerator());
RunClause(_runOptimized ? _scriptBlock.EndBlock : _scriptBlock.UnoptimizedEndBlock, AutomationNull.Value, _input.ToArray());
}
}

View file

@ -1125,7 +1125,8 @@ namespace System.Management.Automation
try
{
var converterInstance = Utils.GetAstToWorkflowConverterAndEnsureWorkflowModuleLoaded(context);
var workflows = converterInstance.CompileWorkflows(scriptBlockAst, context.EngineSessionState.Module, null, out parseErrors);
PSLanguageMode? languageMode = (context != null) ? context.LanguageMode : (PSLanguageMode?) null;
var workflows = converterInstance.CompileWorkflows(scriptBlockAst, context.EngineSessionState.Module, null, languageMode, out parseErrors);
foreach (var workflow in workflows)
{
context.EngineSessionState.SetWorkflowRaw(workflow,

View file

@ -597,7 +597,7 @@
<value>Cannot define the workflow. The language mode for this session is incompatible with the system-wide language mode.</value>
</data>
<data name="XamlWorkflowsNotSupported" xml:space="preserve">
<value>Cannot load the workflow. XAML-based workflows are not supported in the current language mode. Only script-based workflows are supported in this language mode.</value>
<value>Cannot load the workflow. Only signed in-box XAML-based workflows or script-based workflows are supported in the current language mode.</value>
</data>
<data name="CannotDetectNetFrameworkVersion" xml:space="preserve">
<value>Cannot verify the Microsoft .NET Framework version {0} because it is not included in the list of permitted versions.</value>

View file

@ -100,7 +100,7 @@ namespace Microsoft.PowerShell
}
}
namespace System.Management.Automation
namespace System.Management.Automation.Internal
{
/// <summary>
/// The SAFER policy associated with this file
@ -118,7 +118,10 @@ namespace System.Management.Automation
Disallowed = 2
}
internal static class SecuritySupport
/// <summary>
/// Security Support APIs
/// </summary>
public static class SecuritySupport
{
#region execution policy
@ -414,7 +417,12 @@ namespace System.Management.Automation
}
}
internal static bool IsProductBinary(string file)
/// <summary>
/// Returns true if file has product binary signature
/// </summary>
/// <param name="file">Name of file to check</param>
/// <returns>True when file has product binary signature</returns>
public static bool IsProductBinary(string file)
{
if(String.IsNullOrEmpty(file) || (! IO.File.Exists(file)))
{

View file

@ -1,6 +1,8 @@
Describe 'Automatic variable $input' -Tags "CI" {
It '$input Type should be enumerator' {
# Skip on hold for discussion on https://github.com/PowerShell/PowerShell/issues/1563
# $input type in advanced functions
It '$input Type should be enumerator' -Skip {
function from_begin { [cmdletbinding()]param() begin { Write-Output -NoEnumerate $input } }
function from_process { [cmdletbinding()]param() process { Write-Output -NoEnumerate $input } }
function from_end { [cmdletbinding()]param() end { Write-Output -NoEnumerate $input } }