Я пытался запустить сценарий powershell из веб-приложения .Net Core (здесь не обсуждаются лучшие практики;)) со следующим кодом:
string command = @"& """c:\\my Folder\\myScript.ps1""";
using (var ps = PowerShell.Create())
{
var results = ps.AddScript(command).Invoke();
}
Он хорошо работает на моей машине разработки, но в продакшене при попытке выполнить эту функцию происходит сбой:
ps.AddScript(command).Invoke()
Я получаю следующее исключение:
System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Management.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified. File name: 'Microsoft.Management.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' at System.Reflection.RuntimeAssembly.GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes) at System.Reflection.RuntimeAssembly.GetExportedTypes() at System.Management.Automation.Runspaces.PSSnapInHelpers.GetAssemblyTypes(Assembly assembly, String name) at System.Management.Automation.Runspaces.PSSnapInHelpers.AnalyzeModuleAssemblyWithReflection(Assembly assembly, String name, PSSnapInInfo psSnapInInfo, PSModuleInfo moduleInfo, Boolean isModuleLoad, Dictionary
2& cmdlets, Dictionary
2& aliases, Dictionary2& providers, String helpFile, Type& randomCmdletToCheckLinkDemand, Type& randomProviderToCheckLinkDemand) at System.Management.Automation.Runspaces.PSSnapInHelpers.AnalyzePSSnapInAssembly(Assembly assembly, String name, PSSnapInInfo psSnapInInfo, PSModuleInfo moduleInfo, Boolean isModuleLoad, Dictionary
2& cmdlets, Dictionary2& aliases, Dictionary
2& providers, String& helpFile) at System.Management.Automation.Runspaces.InitialSessionState.ImportPSSnapIn(PSSnapInInfo psSnapInInfo, PSSnapInException& warning) at System.Management.Automation.Runspaces.InitialSessionState.CreateDefault() at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(PSHost host) at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace() at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync) at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection1 input, PSDataCollection
1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection1 input, PSDataCollection
1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection`1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings)
Я не знаю, какой фреймворк/пакет я должен установить, чтобы он работал. Target Framework — это .Net Core 2.1, который установлен, поэтому приложение работает нормально, за исключением строки, упомянутой выше.
Файл deps.json содержит следующее:
"Microsoft.Management.Infrastructure/1.0.0": {
"dependencies": {
"NETStandard.Library": "2.0.3",
"System.Runtime.CompilerServices.VisualC": "4.3.0",
"System.Runtime.Serialization.Xml": "4.3.0",
"System.Security.SecureString": "4.3.0",
"System.Threading.ThreadPool": "4.3.0"
},
"compile": {
"ref/netstandard1.6/Microsoft.Management.Infrastructure.Native.dll": {},
"ref/netstandard1.6/Microsoft.Management.Infrastructure.dll": {}
}
}
Установленные пакеты Nuget:
Microsoft.AspNetCore.App (2.1.1)
Microsoft.PowerShell.Commands.Diagnostics (6.0.5)
Microsoft.PowerShell.SDK (6.0.5)
Microsoft.PowerShell.WSMan.Management (6.0.5)
Редактировать Я также добавил Microsoft.Management.Infrastructure (1.0.0) но это не решило проблему
Редактировать2 Dev — это Windows 10 Pro, а Prod — это Windows Server 2016 Standard.
Редактировать3 Скрипт отлично работает на prod при прямом запуске через PowerShell. Показанная ошибка возникает, когда веб-приложение пытается запустить PowerShell.
Редактировать4 Учетная запись пула приложений имеет права администратора и является той же учетной записью, которую я использовал для запуска сценария вручную (не очень хорошая практика, но сейчас я просто пытаюсь запустить этот процесс).
Изменить5 Пробовал положить dll в папку приложения на сервере и перезапустить сайт + перезапустить пул приложений. Я пробовал каждую версию, которую мог найти на машине разработчика, и ничего не получалось :/
Редактировать6 Обновлены пакеты nuget с 6.0.5 до последней версии 6.2.1, та же проблема
к сожалению, мой код такой же, и у меня те же пакеты Nuget (но версия 6.0.5 вместо 6.0.0-rc). На самом деле я нашел код для запуска powershell из этого ответа.
Вы используете дословный идентификатор в string command = @"& """c:\\my Folder\\myScript.ps1""";
. В этом случае вам не нужно экранировать обратную косую черту, измените код на string command = @"& ""c:\my Folder\myScript.ps1"" ";
Какая у вас среда разработки и какая производственная среда?
@DhruvMurarka Win 10 Pro для разработчиков и Win Server 2016 Standard для продуктов.
Когда вы публикуете свое приложение, какой RID вы используете?
@ Bearcat9425 Когда я публикую, варианты, которые я выбираю: Целевая платформа: netcoreapp2.1, Целевая среда выполнения: win-x64 (я могу выбирать только между win-x86, win-x64, win-arm, osx-x64, linux-x64, linux -arm), я использую VS 2019
Я не могу выбрать «win10-x64» или «Win7-x64», как некоторые люди упоминают на github github.com/PowerShell/PowerShell/issues/8119. Я подозреваю, что это потому, что мой проект является веб-приложением...
Вы можете загрузить любую DLL из Powershell, поэтому одно решение, которое определенно должно работать, — это загрузка Microsoft.Management.Infrastructure
DLL как части скрипта. Но перед этим давайте проверим разницу между тем, что загружено в сеансах powershell dev и prod.
Вы можете получить список загруженных в данный момент сборок в PowerShell, запустив [Threading.Thread]::GetDomain().GetAssemblies()
. Добавьте эту строку в начало и конец сценария (в конец, поскольку PowerShell будет автоматически загружать сборки, на которые имеются ссылки, если это возможно, при их первом использовании в сценарии). Теперь запустите скрипт на dev и prod и сравните результаты. Скорее всего, Microsoft.Management.Infrastructure
будет отсутствовать в prod.
Выходные данные списка сборок показывают расположение сборок. Из списка разработчиков возьмите Microsoft.Management.Infrastructure
DLL-файл. Теперь у вас есть два варианта:
[Reflection.Assembly]::LoadFile($fullPathToDLL)
в начале вашего скрипта (или в любом месте перед использованием Microsoft.Management.Infrastructure
).Есть ли способ сделать это в Visual Studio?
Сценарий работает нормально при прямом запуске в PowerShell. Ошибка отсутствия dll отображается в журналах .Net, поэтому я думаю, что dll требуется для .Net, а не для PowerShell.
Я думал о добавлении dll Microsoft.Management.Infrastructure в GAC, но это не похоже на то, что вы можете просто перетащить файл, как он его использовал, поэтому не уверен, смогу ли я это сделать.
Попробуйте добавить DLL в файлы проекта. По моему опыту, Visual Studio автоматически добавляет ссылки на библиотеки DLL в ваш проект, в противном случае вы можете добавить файл DLL вручную.
@rayray какую часть делает в VS? Все это?
@DhruvMurarka Да, потому что в моем случае мое приложение основано на VS
Если добавление DLL в файлы вашего проекта не работает, я бы очень рекомендовал загрузить часть DLL скрипта, как описано в ответе. Это устранит зависимость от VS или чего-либо еще.
@rayray это приложение также основано на VS, оно вызывает Powershell из проекта C# VS. Если ваш сценарий отличается, вы можете опубликовать отдельный вопрос?
Загрузка dll в PowerShell дала мне ту же ошибку. dll требуется .Net для загрузки самой powershell, скрипт еще не вызывался.
О, я вижу. Ну, последнее, что у меня есть, это разместить необходимую DLL в файлах вашего проекта. Либо VS автоматически обнаружит его и добавит ссылку, либо добавит ссылку в DLL вручную. Если это не сработает, я сдаюсь :P
Проверьте пул удостоверений приложений для веб-приложений в пуле. Это может быть проблема с правами Используйте олицетворение личности или запускайте под учетной записью администратора. когда вы запускаете из консоли, вы запускаете свою личность, когда вы запускаете приложение, его пул идентификаторов приложений
да, это та же учетная запись администратора для пула приложений, которую я использовал для запуска скрипта :(
Итак, вы говорите, что приложение dotnet запускает эту строку var results = ps.AddScript(command).Invoke(); не работает, но PS c:\\my Folder\\myScript.ps1 работает из командной строки ps
Я работаю с идентификацией пула приложений, и мой код пытается убить некоторые процессы, так что это означает, что эти команды остановки процесса не будут работать при развертывании на сервере, верно?
У меня была такая же проблема, Microsoft.Management.Infrastructure.dll
(и связанные файлы) не были опубликованы.
Решается путем указания непереносной RID в профиле публикации (*.pubxml
, нет*.csproj
):
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
Проблема, вероятно, вызвана тем, что под C:\Users\UserName\.nuget\packages\microsoft.management.infrastructure\1.0.0\runtimes
находятся только папки с непереносимыми RID; нет win-x86
и win-x64
.
Спасибо, это было! Это означает, что запуск Powershell из .Net Core еще не совсем переносим.
win10-x64 в моем случае для Windows Server 2016 в качестве цели
Если вы выберете среди них «наименьший общий знаменатель», то есть win7-x64
или win7-x86
, он должен быть переносим на все поддерживаемые версии Windows. Не уверен насчет unix
. Он не упоминается на странице каталога RID: docs.microsoft.com/en-us/dotnet/core/rid-catalog.
Добавьте это в свой csproj.
<PackageReference Include = "NETStandard.Library" Version = "1.6.1" />
У меня не сработало...
Я использую это в своем проекте, и он работает, <PackageReference Include = "Microsoft.PowerShell.SDK" Version = "6.2.4" /> <PackageReference Include = "NETStandard.Library" Version = "1.6.1" />
Посмотрите этот предыдущий ответ: stackoverflow.com/a/47777636/303696