我正在.NET Framework 4.8 下開發。請注意,我嚴格鎖定使用 .NET 4.8。
我已經安裝了“Microsoft.PowerShell.5.1.ReferenceAssemblies”Nuget 包,以便能夠自動執行 Powershell 命令,因為 PS6 和 PS7 的 Nuget 包至少需要 .net 核心。
問題是在這種情況下我無法運行
創建一個新專案:
Windows Forms App (.NET Framework)
下載/安裝 NuGet 包:
由于您使用的是 .NET Framework 4.8 和 PowerShell v5.1,請下載/安裝 NuGet 包:Microsoft.PowerShell.5.1.ReferenceAssemblies
有關詳細資訊,請參閱為 .NET 專案選擇正確的 PowerShell NuGet 包。
使用指令添加以下內容:
Imports System.Management.AutomationImports System.Management.Automation.RunspacesImports Microsoft.PowerShell
然后使用以下方法之一:
Public Function PSGetModule() As String
Dim sb As System.Text.StringBuilder = New System.Text.StringBuilder()
'create the default initial session state.
Dim sessionState As InitialSessionState = InitialSessionState.CreateDefault()
sessionState.ExecutionPolicy = ExecutionPolicy.Unrestricted
sessionState.ImportPSModule({"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Dism\Dism.psd1"})
'sessionState.ImportPSModule({"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Dism"})
Using ps As PowerShell = PowerShell.Create(sessionState)
Dim results As ObjectModel.Collection(Of PSObject) = ps.AddCommand("Get-Module").Invoke()
'Dim results As ObjectModel.Collection(Of PSObject) = ps.AddScript("Get-Module").Invoke()
For Each result As PSObject In results
sb.AppendLine(result.ToString())
Next
End Using
Return sb.ToString()
End Function
Public Function PSGetModule2() As String
Debug.WriteLine($"PSGetModule2")
Dim sb As System.Text.StringBuilder = New System.Text.StringBuilder()
'create the default initial session state.
Dim sessionState As InitialSessionState = InitialSessionState.CreateDefault()
sessionState.ExecutionPolicy = ExecutionPolicy.Unrestricted
sessionState.ImportPSModule({"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Dism\Dism.psd1"})
'sessionState.ImportPSModule({"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Dism"})
Using rs As Runspace = RunspaceFactory.CreateRunspace(sessionState)
'open
rs.Open()
Using ps As PowerShell = PowerShell.Create()
ps.Runspace = rs
Dim results As ObjectModel.Collection(Of PSObject) = ps.AddCommand("Get-Module").Invoke()
For Each result As PSObject In results
sb.AppendLine(result.ToString())
Next
End Using
End Using
Return sb.ToString()
End Function
Public Async Function PSGetModuleAsync() As Task(Of String)
Dim sb As System.Text.StringBuilder = New System.Text.StringBuilder()
'create the default initial session state.
Dim sessionState As InitialSessionState = InitialSessionState.CreateDefault()
sessionState.ExecutionPolicy = ExecutionPolicy.Unrestricted
sessionState.ImportPSModule({"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Dism\Dism.psd1"})
'sessionState.ImportPSModule({"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Dism"})
Using ps As PowerShell = PowerShell.Create(sessionState)
ps.AddCommand("Get-Module")
Dim results = Await Task.Factory.FromAsync(ps.BeginInvoke(), Function(asyncResult As IAsyncResult) ps.EndInvoke(asyncResult))
For Each result As PSObject In results
sb.AppendLine(result.ToString())
Next
End Using
Return sb.ToString()
End Function
用法:
Dim result As String = PSGetModule()
Debug.WriteLine($"result (PSGetModule): {result}")
用法(異步)
Dim result As String = Await PSGetModuleAsync()
Debug.WriteLine($"result: {result}")
我能夠使用這篇文章Get-WindowsDriver中的代碼執行。這是我用于測驗的方法(您可能希望將其更改為函式):
Public Sub GetSystemDrivers(flags As GetDriverFlags)
'create the default initial session state.
Dim sessionState As InitialSessionState = InitialSessionState.CreateDefault()
sessionState.ExecutionPolicy = ExecutionPolicy.Unrestricted
'sessionState.ImportPSModule("Dism")
'create a runspace. using the default host
Using rs As Runspace = RunspaceFactory.CreateRunspace(sessionState)
'open
rs.Open()
Dim hasFlagInbox As Boolean = flags.HasFlag(GetDriverFlags.Inbox)
Dim hasFlagNotInbox As Boolean = flags.HasFlag(GetDriverFlags.NotInbox)
'set value
Runspace.DefaultRunspace = rs
Using ps As PowerShell = PowerShell.Create()
ps.Runspace = rs
Dim dismDriverObjects = ps.AddCommand("Get-WindowsDriver").AddParameter("Online").Invoke()
For Each dismDriverObject As PSObject In dismDriverObjects
'create new instance
Dim driverInfo As New DismDriverInfo(dismDriverObject)
If flags <> GetDriverFlags.Any Then
If (hasFlagInbox AndAlso Not driverInfo.Inbox) OrElse
(hasFlagNotInbox AndAlso driverInfo.Inbox) Then
Continue For
End If
End If
Debug.WriteLine($"Driver: {driverInfo.DriverFile}")
Debug.WriteLine($"Date: {driverInfo.BuildDate}")
Debug.WriteLine($"Version: {driverInfo.Version}")
Next
End Using
End Using
End Sub
注意:由于Get-WindowsDriver需要管理權限,因此將Application Manifest File(Project => Add New Item... => Application Manifest File) 添加到您的專案中。然后從 更改<requestedExecutionLevel level="asInvoker" uiAccess="false" />為<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />。
資源:
- 為您的 .NET 專案選擇正確的 PowerShell NuGet 包
- 如何為同一臺機器自動化 PowerShell 或 PowerShell Core
- 電源外殼
- 在 Windows、Linux 和 macOS 上安裝 PowerShell
- 創建 InitialSessionState
- PowerShell - 添加和呼叫命令
- TaskFactory.FromAsync 方法
- Lambda 運算式 (Visual Basic)
- 在 Windows PowerShell 中使用 DISM
- 在 Windows PowerShell 中使用 DISM (<= Win 8.1)
- 開始使用 PowerShell 運行空間:第 1 部分
uj5u.com熱心網友回復:
可以通過使用System.Diagnostics.ProcessWindows Forms App (.NET Framework)在專案中使用 PowerShell 7 。下面展示了如何使用PowerShell 運行和檢索輸出。Process
添加以下匯入:
Imports Microsoft.Win32Imports System.IO
添加以下代碼:
Public Sub ExecutePowerShell(arguments As String, Optional encoding As System.Text.Encoding = Nothing)
Dim sb As System.Text.StringBuilder = New System.Text.StringBuilder()
'get fully-qualified PowerShell filename
Dim powerShellFilename As String = GetPowerShellFullyQualifiedFilename()
Debug.WriteLine($"powerShellFilename: {powerShellFilename}")
Debug.WriteLine($"arguments: {arguments}")
'create new instance
Dim startInfo As ProcessStartInfo = New ProcessStartInfo(powerShellFilename)
'set values
startInfo.Arguments = arguments
startInfo.CreateNoWindow = True 'don't create a window
'if specified, set encoding
If encoding IsNot Nothing Then
startInfo.StandardErrorEncoding = encoding
startInfo.StandardOutputEncoding = encoding
End If
startInfo.RedirectStandardError = True 'redirect StandardError
startInfo.RedirectStandardInput = False 'don't redirect StandardInput
startInfo.RedirectStandardOutput = True ' redirect StandardInput
startInfo.UseShellExecute = False 'If True, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.Verb = "runas" 'run elevated
startInfo.WindowStyle = ProcessWindowStyle.Hidden 'hide window
'create new instance and set properties
Using p As Process = New Process() With {.EnableRaisingEvents = True, .StartInfo = startInfo}
'subscribe to events (add event handlers)
AddHandler p.ErrorDataReceived, AddressOf P_ErrorDataReceived
AddHandler p.OutputDataReceived, AddressOf P_OutputDataReceived
'start
p.Start()
'begin async reading for both standard error and standard output
p.BeginErrorReadLine()
p.BeginOutputReadLine()
'wait until the process is finished before continuing
p.WaitForExit()
'unsubscribe from events (remove event handlers)
RemoveHandler p.ErrorDataReceived, AddressOf P_ErrorDataReceived
RemoveHandler p.OutputDataReceived, AddressOf P_OutputDataReceived
End Using
End Sub
Private Sub P_ErrorDataReceived(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("error: " & e.Data)
End If
End Sub
Private Sub P_OutputDataReceived(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("output: " & e.Data)
End If
End Sub
Public Function GetPowerShellFullyQualifiedFilename(Optional regView As RegistryView = RegistryView.Registry64) As String
Dim installLocation As String = String.Empty
Dim powerShellFilename As String = String.Empty
Dim version As String = String.Empty
'get PowerShell version < 7
Using localKey As RegistryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, regView)
If localKey IsNot Nothing Then
Using subkey As RegistryKey = localKey.OpenSubKey("SOFTWARE\Microsoft\PowerShell", False)
If subkey IsNot Nothing Then
For Each key As String In subkey.GetSubKeyNames() 'ex: 3
Using subkey2 As RegistryKey = subkey.OpenSubKey(Path.Combine(key, "PowerShellEngine")) 'ex: 3\PowerShellEngine
installLocation = subkey2.GetValue("ApplicationBase", String.Empty).ToString()
If File.Exists(Path.Combine(installLocation, "powershell.exe")) Then
powerShellFilename = Path.Combine(installLocation, "powershell.exe")
End If
version = subkey2.GetValue("PowerShellVersion", String.Empty).ToString()
Debug.WriteLine($"installLocation: '{installLocation}' version: '{version}'")
End Using
Next
End If
End Using
End If
End Using
'check if PowerShell v7 is installed
Using localKey As RegistryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, regView)
If localKey IsNot Nothing Then
Using subkey As RegistryKey = localKey.OpenSubKey("SOFTWARE\Microsoft\PowerShellCore\InstalledVersions", False)
If subkey IsNot Nothing Then
For Each key As String In subkey.GetSubKeyNames()
Using subkey2 As RegistryKey = subkey.OpenSubKey(key)
installLocation = subkey2.GetValue("InstallLocation", String.Empty).ToString()
If File.Exists(Path.Combine(installLocation, "powershell.exe")) Then
powerShellFilename = Path.Combine(installLocation, "powershell.exe")
ElseIf File.Exists(Path.Combine(installLocation, "pwsh.exe")) Then
powerShellFilename = Path.Combine(installLocation, "pwsh.exe")
End If
version = subkey2.GetValue("SemanticVersion", String.Empty).ToString()
Debug.WriteLine($"installLocation: '{installLocation}' version: '{version}'")
End Using
Next
End If
End Using
End If
End Using
Return powerShellFilename
End Function
注意:根據需要修改內部P_ErrorDataReceived代碼P_OutputDataReceived。
用法(獲取模塊):
ExecutePowerShell("-NoLogo -Command ""& {Get-Module | Out-String}""")
注意:當雙引號"中使用雙引號 ( ) 時,必須對其進行轉義。為了逃避它,一個人添加了第二個雙引號。有關為什么&使用 , 的資訊,請參閱pwsh -Command
某些 PowerShell 命令可能需要提升(管理權限)。如果希望執行這些命令之一,例如Get-WindowsDriver,將應用程式清單檔案添加到您的專案中。
添加應用程式清單檔案:
- 在 VS 選單中,單擊專案
- 選擇添加新專案...
- 選擇應用程式清單檔案(名稱:app.manifest)
- 點擊添加
打開解決方案資源管理器:
- 在 VS 選單中,單擊查看
- 選擇解決方案資源管理器
修改請求的執行級別:
- 在解決方案資源管理器中,右鍵單擊app.manifest并選擇打開
更改自:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
更改為:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
用法(Get-WindowsDriver):
ExecutePowerShell("-NoLogo -Command ""& {Get-WindowsDriver -Online | Out-String}""")
資源:
- System.Diagnostics.Process
- Microsoft.Win32 命名空間
- 注冊表類
- RegistryKey 類
- RegistryKey.View 屬性
- RegistryView 列舉
- PowerShell v7 (pwsh.exe)
- PowerShell v5.1 (powershell.exe)
- PowerShell 執行策略
uj5u.com熱心網友回復:
我發現這個問題與某些處理器架構缺少依賴項有關,與 DISM 相關。我使用的是 Windows 10 x64,因此基于 DISM / Get-WindowsDriver cmdlet 的 PowerShell 自動化代碼僅在將我的應用程式編譯為 x64 時才會成功運行(無例外)。
問題是我正在編譯到“AnyCPU”,這就是為什么 PowerShell 無法找到 DISM 模塊并拋出該例外的原因。不要問我這個架構問題是否正常,但這是問題的根源,在針對 x86 架構時它會拋出相同的例外。所以解決方案是為x64編譯。
我將分享這個我用來運行Get-Module cmdlet 以確保加載 DISM 模塊的通用用法函式:
<DebuggerStepThrough>
Public Shared Function ExecutePowerShellAction(powerShellAction As Action(Of PowerShell), ParamArray importModules As String()) As Collection(Of PSObject)
Dim results As Collection(Of PSObject)
Dim sessionState As InitialSessionState = InitialSessionState.CreateDefault()
sessionState.ExecutionPolicy = ExecutionPolicy.Unrestricted
sessionState.ImportPSModule(importModules)
Using runspace As Runspace = RunspaceFactory.CreateRunspace(sessionState)
' Save current default runspace, if any.
Dim previousDefaultRunSpace As Runspace = Runspace.DefaultRunspace
' By using this custom default runspace on which we have specified "ExecutionPolicy.Unrestricted" policy,
' we ensure that PowerShell don't run on new/different threads that can have restricted execution policies,
' otherwise it will throw an exception due the restriction policy.
Runspace.DefaultRunspace = runspace
Runspace.DefaultRunspace.Open()
Using ps As PowerShell = PowerShell.Create(RunspaceMode.CurrentRunspace)
Try
powerShellAction.Invoke(ps)
results = ps.Invoke()
' The PowerShell environment has a "PowerShell.HadErrors" property
' that indicates in the assumption whether errors have occurred.
' Unfortunately, most often, I have found that despite errors
' its value can be "False", and vice versa, I have found that
' in the absence of errors its value can be "True".
'
' Therefore, we check the fact that errors have occurred,
' using the error counter in "PowerShell.Streams" property:
If ps.Streams.Error.Any() Then
Throw ps.Streams.Error.First().Exception
End If
Catch ex As Exception
Throw ' ps.Streams.Error.First().Exception
End Try
End Using
' Restore previous default runspace, if any.
' ( Note that due the "Using" statement we can ignore to call "Runspace.DefaultRunspace.Close()" )
Runspace.DefaultRunspace = previousDefaultRunSpace
End Using
Return results
End Function
示例用法:
Dim importModules As String() = {"Dism", "PSReadline", "WindowsSearch"}
Dim script As String = "Get-Module|Format-Table -Property Name, Version|Out-String"
Dim powerShellAction As New Action(Of PowerShell)(Sub(ps) ps.AddScript(script))
Dim results As Collection(Of PSObject) =
ExecutePowerShellAction(powerShellAction, importModules)
Debug.WriteLine(results.Single().ToString())
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/511596.html
