One can use PowerShell 7 in a Windows Forms App (.NET Framework)
project by using System.Diagnostics.Process. Below shows how to use Process
to run PowerShell and retrieve the output.
Add the following Imports:
Imports Microsoft.Win32
Imports System.IO
Add the following code:
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
Note: Modify the code within P_ErrorDataReceived
and P_OutputDataReceived
as desired.
Usage (Get-Module):
ExecutePowerShell("-NoLogo -Command ""& {Get-Module | Out-String}""")
Note: When a double-quote ("
) is used within double-quotes, it's necessary to escape it. To escape it, one adds a second double-quote. For information on why the &
, is used, see pwsh -Command
Certain PowerShell commands may require elevation (administrative privileges). If one desires to execute one of these commands, such as Get-WindowsDriver
, add an Application Manifest File to your project.
Add Application Manifest File:
- In VS menu, click Project
- Select Add New Item...
- Select Application Manifest File (name: app.manifest)
- Click Add
Open Solution Explorer:
- In VS menu, click View
- Select Solution Explorer
Modify requestedExecutionLevel:
- In Solution Explorer, right-click app.manifest and select Open
Change From:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
Change To:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Usage (Get-WindowsDriver):
ExecutePowerShell("-NoLogo -Command ""& {Get-WindowsDriver -Online | Out-String}""")
Resources: