Visual Basic Powershell query Server Pending Reboot status - vb.net

I am new to VB.net & Powershell.
Never the less I am programming an application which querys the PendingReboot status of our Win2012 Servers.
There is this wonderful script which I implemented into my programm which does exactly that:
https://gallery.technet.microsoft.com/scriptcenter/Get-PendingReboot-Query-bdb79542
This is the code I use from Zainnab, to get access from VB2010.net to Powershell an return the result as a string.
'Takes script text as input and runs it, then converts
'the results to a string to return to the user
Private Function RunScript(ByVal scriptText As String) As String
'create Powershell runspace
Dim MyRunSpace As Runspace = RunspaceFactory.CreateRunspace()
'open it
MyRunSpace.Open()
‘ create a pipeline and feed it the script text
Dim MyPipeline As Pipeline = MyRunSpace.CreatePipeline()
MyPipeline.Commands.AddScript(scriptText)
‘ add an extra command to transform the script output objects into nicely formatted strings
‘ remove this line to get the actual objects that the script returns. For example, the script
‘ "Get-Process" returns a collection of System.Diagnostics.Process instances.
MyPipeline.Commands.Add("Out-String")
‘ execute the script
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
‘ close the runspace
MyRunSpace.Close()
‘ convert the script result into a single string
Dim MyStringBuilder As New StringBuilder()
For Each obj As PSObject In results
MyStringBuilder.AppendLine(obj.ToString())
Next
‘ return the results of the script that has
‘ now been converted to text
Return MyStringBuilder.ToString()
End Function
#
Try
‘ Create an instance of StreamReader to read from our file.
‘ The using statement also closes the StreamReader.
Dim sr As New StreamReader(filename)
‘ use a string builder to get all our lines from the file
Dim fileContents As New StringBuilder()
‘ string to hold the current line
Dim curLine As String = ""
‘ loop through our file and read each line into our
‘ stringbuilder as we go along
Do
‘ read each line and MAKE SURE YOU ADD BACK THE
‘ LINEFEED THAT IT THE ReadLine() METHOD STRIPS OFF
curLine = sr.ReadLine()
fileContents.Append(curLine + vbCrLf)
Loop Until curLine Is Nothing
‘ close our reader now that we are done
sr.Close()
‘ call RunScript and pass in our file contents
‘ converted to a string
Return fileContents.ToString()
Catch e As Exception
‘ Let the user know what went wrong.
Dim errorText As String = "The file could not be read:"
errorText += e.Message + "\n"
Return errorText
End Try
End Function
......
Dim ausgabe2 As String
ausgabe2 = RunScript(LoadScript("c:\FHServerStat\PS_PR.stat\60.2.ps1"))
------
I managed to get it partially working.
How ever the problem which I encounter is, by executing the script in powershell the rusult is correct.
By executing the script through visual basic, SOME returned values are incorrect, but see for yourself:
enter image description here
Please help me out on this
Regards
Okun

Related

running powershell script with parameters with vb.net

i have a powershell script that i want to kick off with vb.net code, however when it gets to the part where i invoke the pipeline i get the error "Cannot process command because of one or more missing mandatory parameters: District County FMS."
the powershell script is very simple, it takes 3 parameters and write-host's the param values back to the shell. pretty much my question is, how do i make it work? thank you everyone for you time.
vb.net(the other professionals i work with have boiled the error down to 'get-process' not being the right command for my scriptParams variable, but we're not sure which command to use)
Sub Main()
Console.WriteLine(RunScript(LoadScript(Directory.GetCurrentDirectory() + "/CreateProject.ps1 ")))
Console.ReadLine()
End Sub
Private Function RunScript(ByVal scriptText As String) As String
' create Powershell runspace
Dim MyRunSpace As Runspace = RunspaceFactory.CreateRunspace()
' open it
MyRunSpace.Open()
' create a pipeline and feed it the script text
Dim MyPipeline As Pipeline = MyRunSpace.CreatePipeline()
MyPipeline.Commands.AddScript(scriptText)
' add an extra command to transform the script output objects into nicely formatted strings
' remove this line to get the actual objects that the script returns. For example, the script
' "Get-Process" returns a collection of System.Diagnostics.Process instances.
MyPipeline.Commands.Add("Out-String")
'[ay]create a command object by bassing the command to the constructor
Dim scriptParams As New Command("get-process")
'[ay]pass parameters to the command
scriptParams.Parameters.Add("District", "D1")
scriptParams.Parameters.Add("County", "Lee")
scriptParams.Parameters.Add("FMS", "101000")
MyPipeline.Commands.Add(scriptParams)
' execute the script
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
' close the runspace
MyRunSpace.Close()
' convert the script result into a single string
Dim MyStringBuilder As New StringBuilder()
For Each obj As PSObject In results
MyStringBuilder.AppendLine(obj.ToString())
Next
' return the results of the script that has
' now been converted to text
Return MyStringBuilder.ToString()
End Function
Private Function LoadScript(ByVal filename As String) As String
Try
' Create an instance of StreamReader to read from our file.
' The using statement also closes the StreamReader.
Dim sr As New StreamReader(filename)
' use a string builder to get all our lines from the file
Dim fileContents As New StringBuilder()
' string to hold the current line
Dim curLine As String = ""
' loop through our file and read each line into our
' stringbuilder as we go along
Do
' read each line and MAKE SURE YOU ADD BACK THE
' LINEFEED THAT IT THE ReadLine() METHOD STRIPS OFF
curLine = sr.ReadLine()
fileContents.Append(curLine + vbCrLf)
Loop Until curLine Is Nothing
' close our reader now that we are done
sr.Close()
' call RunScript and pass in our file contents
' converted to a string
Return fileContents.ToString()
Catch e As Exception
' Let the user know what went wrong.
Dim errorText As String = "The file could not be read:"
errorText += e.Message + "\n"
Return errorText
End Try
End Function
PowerShell
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True)]
[string]$District,
[Parameter(Mandatory = $True)]
[string]$County,
[Parameter(Mandatory = $True)]
[string]$FMS
)
Write-Host "District: $Dsistrict"
Write-Host "County: $County"
Write-Host "FMS: $FMS"
These examples are in C#, but it's the same API.
https://blogs.msdn.microsoft.com/kebab/2014/04/28/executing-powershell-scripts-from-c/
More C# examples, but these are using the RunspaceFactory API you already have in your pipeline.
Execute PowerShell Script from C# with Commandline Arguments
I'm new to PowerShell but may this help you
in your code
scriptParams.Parameters.Add("District", "D1")
scriptParams.Parameters.Add("County", "Lee")
scriptParams.Parameters.Add("FMS", "101000")
MyPipeline.Commands.Add(scriptParams)
I think this ADD new params to your script so value for already exit params not set
You need to pass param values to your script not add new param
I know this is an old question but there was no good answer and I just spent too long getting this to work to not share my knowledge.
In the VB code, you'd remove the following:
MyPipeline.Commands.AddScript(scriptText)
MyPipeline.Commands.Add("Out-String")
Then, in place of the Out-String addition, add:
Dim myCommand As Command = New Command(scriptText, True)
' Add your parameters here.
' Obviously you can add variables instead of static strings if needed.
myCommand.Parameters.Add("District", "D1")
myCommand.Parameters.Add("County", "Lee")
myCommand.Parameters.Add("FMS", "101000")
' You can add switches in this manner as well. For example, a switch "I"
' You need to include the - with switches
myCommand.Parameters.Add("-i")
' Finally, apply your command object to the pipeline and proceed as normal
MyPipeline.Commands.Add(myCommand)

Visual Basic Append to a specific point in a text file

I am currently trying to manipulate a line in a file that we are using to retain data, using comma delimiters. For example -
121,1212, XJAY,Sean K,Kean S,AAAA-BBBB-AAAA-BBBB-AAAA
12456,987654,WYST,Steve Jobs,Bill Gates,CAAA-BBBB-AAAA-BBBB-AAAA
If I assume that the last line is always a unique code, is it possible to identify that line in the text file and append it with another field?
Prior research has been reading through the APIs for StreamReader and StreamWriter, and looking through other StackOverflow questions, however most questions seem focused on just appending to the end of the file, or in different languages!
As always thank you for your time, and if there is anything I've left off please let me know!
You can't manipulate a line in a file in any reasonably easy way.
There are no methods to work with lines in a file, because files are not line based. They are not even character based. The bytes in the file are decoded into characters, then the line break characters are recognised and the characters can be split into lines.
The easiest way to manipulate a line is to read the entire file into a string array, change the string that you want change, then write the entire string array to the file.
Example:
Dim fileName As String = "c:\data.txt"
Dim lines As String() = File.ReadAllLines(fileName)
For i As Integer = 0 To lines.Length - 1
Dim line As String = lines(i)
If line.StartsWith("12456,") Then
lines(i) = line & ",More data"
End If
Next
File.WriteAllLines(fileName, lines)
If you are looking for a way to parse Each line with StreamReader and StreamWriter: Here it is:
'You will need Imports System.IO
Dim TheNewFile As String
Dim MyLine As String
Dim MyStream2 As New FileStream("C:\Your Directory\YourFile.txt", FileMode.Open)
Dim MyReader As New StreamReader(MyStream2)
Dim MySettings As New StringReader(MyReader.ReadToEnd)
MyReader.BaseStream.Seek(0, SeekOrigin.Begin)
MyReader.Close()
MyStream2.Close()
Try
Do
MyLine = MySettings.ReadLine
'This if statement is an exit parameter. It can be if it contains or if 5 consecutive lines are nothing. It could be a number of things
If MyLine Is Nothing Then Exit Do
'This is the file you will write. You could do if MyLine = "Test" Then ........... append whatever and however you need to
TheNewFile = TheNewFile & MyLine & vbCrLf
Loop
Catch ex As Exception
MsgBox(ex.ToString())
End Try
'-----------------Write The new file!!!----------------
Dim MyStream3 As New FileStream("C:\Where you want to write New File\NewFileName.txt", FileMode.Create)
Dim MyWriter3 As New StreamWriter(MyStream3)
MyWriter3.Write(TheNewFile & "Test")
MyWriter3.Close()
MyStream3.Close()

dispose of IO.File.ReadAllLines

I am reading very large text files (6-10 MB). I am splitting the text files in to multiple new text files. There is common "header" and "footer" in the "read" text file that I will store as variable to be called at later time. I can't figure out how to properly dispose of IO.File.ReadAllLines. I'm concerned this will be held in memory if I don't dispose of it properly.
Text.Dispose or Text.Close isn't valid.
Dim testHeader As String
Dim testSite As String
Dim testStart As String
Dim testStop As String
Dim testTime As String
Dim text() As String = IO.File.ReadAllLines("C:\Users\anobis\Desktop\temp.txt")
testHeader = text(0)
testSite = text(text.Length - 4)
testStart = text(text.Length - 3)
testStop = text(text.Length - 2)
testTime = text(text.Length - 1)
text.dispose()
Later in the program I will be initiating another StreamReader and want to avoid conflicts and memory resource issues. I am new at coding so be gentle! Thanks!
' Open temp.txt with "Using" statement.
Using r As StreamReader = New StreamReader("C:\Users\anobis\Desktop\temp.txt")
' Store contents in this String.
Dim line As String
line = r.ReadLine
' Loop over each line in file, While list is Not Nothing.
Do While (Not line Is Nothing)
If line Like (sourceSN.Text + "*") Then 'Substitute in source serial number "xxxxxx*"
file.WriteLine(line)
End If
' Read in the next line of text file.
line = r.ReadLine
Loop
End Using
file.WriteLine(testSite)
file.WriteLine(testStart)
file.WriteLine(testStop)
file.WriteLine(testTime)
' Close transfer.txt file
file.Close()
You don't need to dispose of it. It returns a managed string array, who's lifetime is managed by the garbage collector. Internally, File.ReadAllLines is disposing of the underlying native file handle it created to read all of the lines for you.

How can I append a string that contains "" to an existing string in VB .NET?

I am working on a utility that will take the contents of a .ps1 script (Powershell), and run it in the context of a VB.NET Winform. Basically it does this by referencing some Powershell DLLs, opening the .ps1 file, reading a line of text and feeding it into an internal string that will run on a button click event.
Here's the full code I have so far:
Private Function RunScript(ByVal scriptText As String) As String
' create Powershell runspace
Dim MyRunSpace As Runspace = RunspaceFactory.CreateRunspace()
' open it
MyRunSpace.Open()
' create a pipeline and feed it the script text
Dim MyPipeline As Pipeline = MyRunSpace.CreatePipeline()
MyPipeline.Commands.AddScript(scriptText)
' add an extra command to transform the script output objects into nicely formatted strings
' remove this line to get the actual objects that the script returns. For example, the script
' "Get-Process" returns a collection of System.Diagnostics.Process instances.
MyPipeline.Commands.Add("Out-String")
' execute the script
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
' close the runspace
MyRunSpace.Close()
' convert the script result into a single string
Dim MyStringBuilder As New StringBuilder()
For Each obj As PSObject In results
MyStringBuilder.AppendLine(obj.ToString())
Next
' return the results of the script that has
' now been converted to text
Return MyStringBuilder.ToString()
End Function
' helper method that takes your script path, loads up the script
' into a variable, and passes the variable to the RunScript method
' that will then execute the contents
Private Function LoadScript(ByVal filename As String) As String
Try
' Create an instance of StreamReader to read from our file.
' The using statement also closes the StreamReader.
Dim sr As New StreamReader(filename)
' use a string builder to get all our lines from the file
Dim fileContents As New StringBuilder()
' string to hold the current line
Dim curLine As String = ""
' loop through our file and read each line into our
' stringbuilder as we go along
Do
' read each line and MAKE SURE YOU ADD BACK THE
' LINEFEED THAT IT THE ReadLine() METHOD STRIPS OFF
curLine = sr.ReadLine()
If curLine.Contains("") Then
fileContents.AppendLine("$Folder=tbpath.selectedpath")
Else
fileContents.Append(curLine + vbCrLf)
If curLine.Contains ($Folder="") Then
Loop Until curLine Is Nothing
' close our reader now that we are done
sr.Close()
' call RunScript and pass in our file contents
' converted to a string
Return fileContents.ToString()
Sorry for the lengthy stuff, but the lines I am curious about are the curLine.Contains part. What I'm trying to do is have the parser detect whether or not the line is a specific one (which reads $Folder = "") and replace the empty quotes with a folder path that is stored in a text box (tbpath.selectedtext). Unfortunately, since the Powershell script requires quotes around the path string (in case there are spaces) I am having trouble figuring out how to do what I want it to do.
What should I do there? Should I build what I want into a new variable (maybe vbPath = tbpath.selectedtext) and put it into the new line? Are there any "best practices"?
Double up the quotes
Dim s As String = "$Folder = """""
s =
$Folder = ""
In your code
If curLine.Contains("$Folder = """"") Then
End If
Do you want curLine.Contains() to check for a literal string $Folder=""? If so, you need to put the whole string in double quotes and escape the inner ones. Double quotes are escaped by doubling them. Also, if you want to insert a variable, you need to concatenate it with the string literals, so the command should probably look like this:
If curLine.Contains ("$Folder = """"") Then
fileContents.Append("$Folder = """ & tbpath.selectedpath & """")
End If

unable to run Exchange Powershell through vb.net application

So I'm going round in circles trying to get this to work, I've been trying for two days and I just can't figure it out.
I have the following vb function that takes a created powershell script, and should run it in powershell. Everything works fine, until the point at which the command pipeline is invoked. At this point, no commands run.
As you can see, I have tried to add the Microsoft.Exchange.Management.PowerShell.E2010 snapin to the runspace, it didn't like that at all stating something along the lines of the snapin didnt exist (which it does), and also when I run the code as shown, no commands are recognised as valid. I even added the specific command "Add-PSSnapin" to try and load any Exchange snapins, but it states that "Add-PSSnapin" is not recognised as a valid command.
If I pause the program just before the commands are involked, I can see every command within the pipeline, in the correct format. If I copy and paste the command text in the pipeline directly into a powershell window, it runs fine.
My code is below, any suggestions welcome.
edit: I have also tried adding the line "Add-PSSnapin Ex" (with an asterisk each side of Ex - I cant figure the formatting out on this, sorry)
to try and load the Exchange PS Snapins as the first thing the script would run (opposed to setting this up in the runspace) but no luck
Private Function scriptRunner(ByVal scripttorun As String) As String
Dim initial As InitialSessionState = InitialSessionState.CreateDefault()
Dim result As String = ""
Dim lineFromScript As String = ""
Dim reader As New StreamReader(tempScript)
Dim rsConfig As RunspaceConfiguration = RunspaceConfiguration.Create()
Dim snapInException As New PSSnapInException
Dim strUserName As String = "DOMAIN\USER"
Dim strPassword As String = "PASSWORD"
Dim SecuredPSWD As New System.Security.SecureString()
For Each character As Char In strPassword
SecuredPSWD.AppendChar(character)
Next
Dim wsmConnectionInfo As WSManConnectionInfo
Dim strSystemURI As String = "http://SERVER.DOMAIN/powershell?serializationLevel=Full"
Dim strShellURI As String = "http://schemas.microsoft.com/powershell/Microsoft.Exchange"
Dim powerShellCredentials As PSCredential = New PSCredential(strUserName, SecuredPSWD)
wsmConnectionInfo = New WSManConnectionInfo(New Uri(strSystemURI), strShellURI, powerShellCredentials)
Dim runspace As Runspace = RunspaceFactory.CreateRunspace(wsmConnectionInfo)
Runspace.Open()
' runspace.RunspaceConfiguration.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", snapInException)
Dim pipeLine As Pipeline = runspace.CreatePipeline()
Dim command As Command = New Command("")
' TEST >> pipeLine.Commands.Add("Add-PSSnapin *Ex*")
Do While reader.Peek() <> -1
lineFromScript = Nothing
lineFromScript = reader.ReadLine()
pipeLine.Commands.Add(lineFromScript)
'command.Parameters.Add(lineFromScript)
'pipeLine.Commands.Add(command)
Loop
'' Run the contents of the pipeline
Dim psObjCollection As Collection(Of PSObject) = pipeLine.Invoke()
runspace.Close()
runspace.Dispose()
Return ""
End Function
I ended up working around the problem rather than fixing it.
I moved the script code into the vb.net application, and wrote each line to a file, i.e.
writer.WriteLine("Add-PSSnapin *Ex*")
Then I loaded the script through PowerShell as an application;
Dim exeStartInfo As System.Diagnostics.ProcessStartInfo
Dim exeStart As New System.Diagnostics.Process
exeStartInfo = New System.Diagnostics.ProcessStartInfo("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe")
exeStartInfo.Arguments = ("-command work\scriptbuilder.ps1")
exeStartInfo.WorkingDirectory = "C:\ExchangeManager\"
exeStartInfo.UseShellExecute = False
exeStart.StartInfo = exeStartInfo
exeStart.Start()
exeStart.Close()
Not ideal but it got the job done.