VS2013 VB - Trying to add a Powershell output to ListBox - vb.net

I am having some real trouble here. Working in Visual Studio 2013 Express, in Visual Basic. I have a form which has a ListBox. And a function which calls a PowerShell cmd-let 'Get-Process'. I am trying to get this output to display in said Listbox.
The code I have so far is below:
Private Function RunScript(ByVal scriptText As String) As String
' create Powershell runspace
Dim MyRunSpace As Runspace = RunspaceFactory.CreateRunspace()
MyRunSpace.Open()
' create a pipeline and feed it the script text
Dim MyPipeline As Pipeline = MyRunSpace.CreatePipeline()
MyPipeline.Commands.AddScript(scriptText)
MyPipeline.Commands.Add("Out-String")
' execute the script
Dim PSOut As Collection(Of PSObject) = MyPipeline.Invoke()
' close the runspace
MyRunSpace.Close()
For Each Id In PSOut
CheckList1.BeginUpdate()
CheckList1.Items.Add(Id)
CheckList1.EndUpdate()
Next
End Function
All this does is display the first line of the PowerShell output and nothing else. What am I missing? I thought maybe it needs to be told to loop through the collection, but I cant find anything like that in my searches thus far...
Any help will be appreciated.
Phill

Your problem is in this line:
MyPipeline.Commands.Add("Out-String")
Just remove it.
It's causing your output to be formatted as a string. Meaning after that you need to parse it back to a list of string, and then potentially do even more parsing. You don't need all that, because it's much easier to work with a list of PSObject, when each of them is actually a PSObject, and not a string wrapper.
Also regarding process format, you may consider using this instead of just Id:
Id.Properties("Name").Value.ToString()
This will populate your checklist control with a list of process names. Also consider changing your variable name, i.e. Id to psProcess, to reflect what it really is.

Related

Using stored credentials in powershell through vb.net

I've written a pair of apps; one that issues powershell scripts to clients (the server) and one that executes powershell scripts passed to it (the client).
I've added functions to detect if a particular script requires elevation.
In the event that a script requires elevation, the server app prompts the user for their credentials. The password is converted to a secure string and saved in a SQL database, as is the username along with the script.
The client app grabs the script and, if elevation is required, grabs the username and secure string then tries to build a credential object from it.
The functionality is working fine for non-elevated scripts, but elevated scripts are not working. Its not erroring or throwing an exception (finally) but the scripts are not executed.
The first part of this process reads the data from SQL into a datatable and then i loop through the rows of that datatable.
Once I've got a row that contains a script that needs running, I build the script.
Here's how I'm building and executing the powershell in VB...
If this_routine_elevation_required = 1 Then
Dim scriptbody As String = row("scriptbody").ToString
Dim elevated_user_un As String = row("elevated_user").ToString
Dim elevated_user_ss As String = row("securestring").ToString
credential_script = "$securepassword = '" & elevated_user_ss & "' | ConvertTo-SecureString; $username='" & elevated_user_un & "';$credential = New-Object System.Management.Automation.PsCredential($username, $securepassword)"
action_response = RunPowershellScript(credential_script & "; " & scriptbody)
End If
and here is the function that executes the powershell (using 'Imports System.Management.Automation)...
Private Function RunPowershellScript(ByVal scriptText As String) As String
' create Powershell runspace
Dim MyRunSpace As Runspace = RunspaceFactory.CreateRunspace()
MyRunSpace.Open()
Dim MyPipeline As Pipeline = MyRunSpace.CreatePipeline()
MyPipeline.Commands.AddScript(scriptText)
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
MyRunSpace.Close()
Dim MyStringBuilder As New StringBuilder()
For Each obj As PSObject In results
MyStringBuilder.AppendLine(obj.ToString())
Next
Return MyStringBuilder.ToString()
End Function
I've thrown up a messagebox of the script before its passed to the RunPowershellScript function so i could make sure nothing was malformed or to ensure i wasnt doing anything stupid (i've manipulated the secure string for the purposes of this image)...
The example here is just a test to see if the executor could stop the W32Time service, something that would normally require elevation. It does not work.
I get an empty response back from the RunPowershellScript function and the service continues to run.
It occured to me that I'm getting a securestring from the database and then converting that securestring to a securestring, so perhaps its not ending up with the correct valid password in $credential, but from what i understand I have to provide a securestring for the password parameter of PsCredential, and without -ConvertTo-SecureString it would consider the password to just be a string. I tried this and it threw an exception about the password being null.
Can anyone help point me in the right direction?
Many thanks in advance.
Is the script running locally on the target or from the server?
Credential objects are specific to the computer AND user account which creates them, so they are not transferable and can only be used on the computer which creates them.

VBA : Enexpected running VBA from cmd line

I wanted to open an existing ppt using Wscript and modify it. For that I am opening the file in visual studio editor and executing the script from cmd in windows using WScript hi.vbs
But when I ran the same code I am getting error.
Expected end of statement in line 4
Line 4 looks like Dim objNewPowerPoint As Object
However Same case works when I run code in excel VBA editor.
When I am removing the As object I am not getting any error nor any changes are happening in the PPT file.
Wondering what is the possible issue.
I am not using excel vba or word vba i am just running the file from cmd
Sub Open_an_existing_Presentations()
Dim objNewPowerPoint As Object
Dim MyPresentation As Object
Dim pSlides As Object
Set objNewPowerPoint = CreateObject(PowerPoint.Application)
'Make this Application Object Visible
objNewPowerPoint.Visible = True
Please help me how can i modify and more importantly how to see both errors compile and syntax.
FYI : I am completely new into VBA and I am trying to update a PPT and wanted to run vba script from another program so trying something like this. Best suggestions are always welcome
In VBScript you cannot dim something as something.
Dim objNewPowerPoint
Dim MyPresentation
Dim pSlides
And dim is optional and serves no technical purpose in VBS (it merely catches spelling mistakes if Option Explicit is specified, else it does nothing at all as in your case except take time to the process the line). In compiled languages it allocates storage and checks data types when using it.
When you use Set = VBS knows it an object and makes it one (4 x 32 bit integers - One a reference count and another a memory address of the function table for the object - two are unused). If you use x=5555 vbs knows it's a integer.

Using VB.net - pull a file from GitLab

As the title implies, I'm looking for a way to pull specific file(s) from a private GitLab repo using VB.net (2017).
I have an application that I'm writing which will call certain PowerShell scripts. I have a few other users working with me writing the scripts, so we are using GitLab as the repository for these.
We want the application to pull the latest version of the scripts from GitLab when the application opens, then from within the app, call the scripts.
I have everything done, with the exception of downloading the scripts from GitLab.
So I'm posting an answer here just in case anyone else has the same question. I was actually able to get this done pretty easily.
First, you have to generate a private token. Plenty of walk-throughs for that, so I won't go into that here.
Next, you have to get the address of raw file that you want to download. You can get this by opening the file in GitLab, then there's a button on the top right of the window to "Open Raw", which opens the raw page.
See Image Here
Grab the url from the address bar. Once you have that, you have all the pieces you need to curl the file down using VB.net.
You have to take the address of the raw file, let's say that was "https://gitlab.com/CompanyName/raw/master/folder/filename.ps1", you then append ?, with your private token so it looks like this: "https://gitlab.com/CompanyName/raw/master/folder/filename.ps1?private_token=MyPrivateToken" and use a curl (through powershell) to get it.
I already had a function in my code to run powershell scripts (with code I believe I got off this site...forgot the exact location), which was like this:
Private Function RunScript(ByVal scriptText As String) As String
' Takes script text as input and runs it, then converts
' the results to a string to return to the user
' 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
Now, I can call a curl command with that function like this:
RunScript("curl https://gitlab.com/CompanyName/raw/master/folder/filename.ps1?private_token=MyPrivateToken -outfile C:\DownloadFolder\FileName.ps1")
That's it! Anytime you need to get a file, you can simply get the location of the raw file and modify the function call to reflect the new address and grab it.

Writing a string to a text file - Visual Basic

I've been trying to write a string to a text file, but whenever the process is done, it has only written a blank line. Writing integers works fine. I've researched the problem, but haven't been able to find a solution. Code:
Dim strSave As String
strSave = strCharName
My.Computer.FileSystem.WriteAllText _
("C:\UnnamedGame\NameOne.txt", strSave, False)

how to open a vb.application from another vb.application with parameters

i have 2 vb applications. this is the code for the first one which when a button is clicked it will check if the other application is already open. If not, it'll open that application -
Dim sComputer As String
sComputer = Environ("COMPUTERNAME")
Dim LocalByName As Process() = Process.GetProcessesByName("ticket.prices", sComputer)
If LocalByName.Length = 0 Then
System.Diagnostics.Process.Start("http://ticket.prices.application")
End If
this runs fine. but what i need is that the customerid on the application 1 that is calling application 2, should be transfered while opening app 2.
e.g -
Customer 10001 screen is open on app 1. When i click open app 2, the above code runs and opens app 2. how do i make app 2 open to customer 10001 screen. Is there any way to pass parameters while opening app 2 in System.Diagnostics.Process.Start ?
Use the version of 'Process.Start' that takes 2 strings, the second being the commandline parameters. See here for details.
You want the ProcessStartInfo class, or use the Start method taking to strings. ProcessStartInfo gives you a lot of options about how to start your program, which often comes in handy. Its good to get familiar with it.
Dim info as New ProcessStartInfo()
info.Arguments = "10001"
info.FileName = "exename"
Dim LocalByName as New Process()
LocalByName.StartInfo = info
LocalByName.Start()
Getting the arguments in the new program is accomplished via Environment.GetCommandLineArgs()
For Each arg As String In Environment.GetCommandLineArgs()
Console.WriteLine(arg)
Next arg
It looks like what you ultimately want to accomplish is getting the currently selected row from App 1 and passing that to the second program, though. Is this correct? That opens a whole new ball of wax involving interprocess communication.
EDIT: The simplest way to get the selected edit would be to write the id out to a text file. You have to be careful when doing this because if you just write System.IO.File.WriteAllText("selectedrow.txt", "123"), you'll write to the app's startup path directory. You'll want to get the exe's current path as below
Dim u as New Uri(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)
dim exepath as String = System.IO.Path.GetDirectoryName(u.LocalPath)
dim fullPath as String = System.IO.Path.Combine(exepath, "selectedrow.txt")
System.IO.File.WriteAllText(fullpath, "123")
This will overwrite the text in the file every time you change rows. You want to wrap this in a try/catch block so as not to crash the program. Make sure you log the errors; don't just swallow them. To read the data, you just do
dim id as string = System.IO.File.ReadAllText(PathToFileYoureWritingToInTheOtherProgram)
in the other program.
This isn't necessarily the best way to go about things, but its the simplest way I know of off the top of my head.
You might could look at MessageQueues if you a better solution, but as long as you're not changing selected rows every 100ms, writing the file should work fine.