Using VB.net - pull a file from GitLab - vb.net

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.

Related

How to pass quoted args to Visual Basic's Process.Start()

I need to unpin my own program from the Taskbar using Visual Basic.
Therefor I am using the tool "syspin.exe", the final working command is:
syspin.exe "C:\Program Files\OEM\BrowserChoice\OEMBrowserChoice.exe" 5387
But I can't execute this command within my Visual Basic application.
I guess it's a problem with these quotes, single quotes do not work with syspin.exe, the command has to be exactly as above.
In VB I'm trying to execute it as follows:
Process.Start(INSTALL_PATH + "\syspin.exe", " ""C:\Program Files\OEM\BrowserChoice\OEMBrowserChoice.exe"" 5387")
I've tried many variations of this (Moved the quotes, spaces, put the args to String.Format, put the args to different strings), but nothing worked.
I don't wanna read something like: Don't do that, it's up to the user...
I am making a program for my custom built PCs, where the user can choose it's favorite browser and automatically replace the BrowserChoice utility with the actual Browser as part of my service to him.
But I am open to other ways this might work using Visual Basic.
Working Directory Overview
Edit. My actual code:
Private Function unpinFromTaskbar()
Dim advancedProcess As New ProcessStartInfo
advancedProcess.FileName = INSTALL_PATH + "\syspin.exe"
advancedProcess.Arguments = """C:\Program Files\OEM\BrowserChoice\OEMBrowserChoice.exe"" 5387"
advancedProcess.WindowStyle = ProcessWindowStyle.Minimized
Try
Process.Start(advancedProcess)
' Here it's going to be
Return True
Catch ex As Exception
' ex is empty
Return False
End Try
End Function

Is there a way to write a command directly by code in the immediate window?

I'm trying to save all lines from the output window into a log-file. That works fine when I enter the command directly into the immediate window. However, I need a way to enter the command line by code.
I searched for a way to enter a command into the immediate window so the log-file I want will be created and filled with data. That's not happening and I don't know if this is even possible. Searching Google didn't help so far.
My command line is:
> Tools.LogCommandWindowOutput C:\Users\user\AppData\test.log
And I try to get it into the immediate window by
Debug.Print("> Tools.LogCommandWindowOutput C:\Users\user\AppData\test.log")
The command line works fine when put directly into the immediate window (either by typing it in or pasting it in). When I try to do that by code, nothing happens. Is there a way to do that or do I have to try another option and if so, what option is it?
EDIT:
I've tried the solution provided by RobertBaron with the following changes:
'Dim dummy = $"C:\\log\\outputfileAddOn_{Date.Now:yyyy_MM_dd_HH_mm_ss}.log"
'cmdWindow.SendInput($"Tools.LogCommandWindowOutput {dummy}", True)
cmdWindow.SendInput("Tools.LogCommandWindowOutput C:\log\outputfile_AddOn.log", True)
(I want a new file to be written every time, so I tried to add the date at the end to have unique file names)
It creates the file but doesn't log anything in it. What do I do wrong?
Another solution I have found was to add a command parameter in project-properties-debug-command parameter:
> C:\log\outputfile.log
This creates the file and inserts all of the data from the output window. The only problem that I have now is that this file will be overwritten every time the program is started. Is there a way I can set the logging from the second, third, … start at the end of the file? (adding /on at the end of the command Parameter didn't help) Or can I provide something like "outputfile_yyyy_MM_dd_HH_mm_ss.log" (for example: outputfile_2019_07_23_15_47_45.log)?
Thank you for your help!
You need to create a Visual Studio Extension project.
Add a new Custom Command item to the VSIX project.
This will create the Command1.vb. This is where you implement the code that you want to execute inside Visual Studio. The code executes whenever you select the entry Invoke Command1 from the Tools menu.
At the bottom of the Command1.vb file, there is the Execute() Sub. It displays a message just to show that the command is working. You can remove this eventually. But for now, just run the project. Another instance of Visual Studio will start. This is where you can test and debug your code. Once the second instance of Visual Studio has started, go to its Tools menu, and select the Invoke Command1 entry. A message box will display. Stop execution.
Now we want to modify the Execute() Sub so that our code gets executed when Invoke Command1 is selected. Here is the Sub that will execute the command that you want. Add it to the Command1 class.
Public Sub ExecCommandWindow()
Dim dte As EnvDTE.DTE = CType(Microsoft.VisualStudio.Shell.Package.GetGlobalService(GetType(Microsoft.VisualStudio.Shell.Interop.SDTE)), EnvDTE.DTE)
Dim cmdWindow As CommandWindow = CType(dte.Windows.Item(EnvDTE.Constants.vsWindowKindCommandWindow).Object, CommandWindow)
'Display some text in the command window
cmdWindow.OutputString("Executing command from the automation OM...")
'Send some command strings to the command window and execute them...
'This command will start logging all input/output in the command window to the specified file
cmdWindow.SendInput("Tools.LogCommandWindowOutput cmdwindow.log", True)
''Open a file in a code editor:
'' 1. We use an alias, 'of', for the File.OpenFile command
'' 2. This command takes quote-delimited parameters (in this case,
'' the name of the editor to load the file in)
'Dim cmd As String = "of "
'cmd = (cmd + """""C:\Contoso\ContosoCommonFramework\Integration.cs""""")
'cmd = (cmd + "/e:""""CSharp Editor""""")
'cmdWindow.SendInput(cmd, True)
'cmdWindow.SendInput("Edit.Find MessageTrxId", True)
'Turn off logging
cmdWindow.SendInput("Tools.LogCommandWindowOutput /off", True)
End Sub
Change the Execute() Sub to call ExecCommandWindow().
You can change the name of the command by changing its title in the Command1 class.
The Visual Studio extension needs to be installed by each user. Just distribute the .vsix file. To install, double-click it.
It's not the best solution, but it works (for now):
adding
>> C:\log\outputfile.log
(with two '>' before the path for the log file) attaches every log at the end of the file. So I get all Information and nothing is being overwritten.
As I want to know if there is a better solution, I will keep this thread open if that is permitted.

How to call java object in VBA with classpath

We use a CMD to call a PowerShell script. In the PowerShell script, a Java program is called. Both files are in the same directory. I want this all replaced by VBA within Microsoft Access. I have found several related topics but I can't decide whether it is possible or not based on these topics. Topics like Launch jar file from VBA code
The CMD contains the following code:
SET CLASSPATH=.\yyyyy.jar
powershell .\startscript.ps1
The PowerShell script contains the following sample:
& java '-Djavax.net.ssl.trustStore="zzzz.keystore"' com.router.router.router.Router -user:... etc.
We also run the same Java program in a different setting, only with the use of one .CMD-file. This is made like:
SET USR=user
SET CLASSPATH=.\yyyyy.jar
java -Djavax.net.ssl.trustStore=zzzz.keystore com.router.router.router.Router -user:%USR% etc.
Preferably both PowerShell and CMD become obsolete and the parameters like "-user" are fed with variables from the VBA code.
Does someone have a usable link, example or code? Please advice.
What you are trying to do is to run a command via the command line. It just happens that this command runs java, as far as the VBA code is concerned it may run anything that the shell would understand.
A sample code to run a command via a shell in VBA is the following (note there are many ways and it's super easy to find these samples on internet, I'm just using the first one I found):
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = False
Dim windowStyle As Integer: windowStyle = 1
wsh.Run "cmd.exe /S /C " & yourCommand
... where yourCommand is the litteral string you would run in your command prompt. Now, it's all about string concatenation in VBA. Following your sample (and adding the username directly from VBA):
user = Environ("UserName")
yourCommand = "java -Djavax.net.ssl.trustStore=zzzz.keystore com.router.router.router.Router -user:" & user
(please note that I replaced %USR% - which asks the shell to retrieve the username - with a variable user that I've defined in VBA, even though in this specific example, the function Environ is asking environment variables so it's still asking it to a shell).

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.

VS2013 VB - Trying to add a Powershell output to ListBox

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.