I'm trying to change the computer name of a PC with VB.net using this code:
Declare Auto Function SetComputerName Lib "kernel32" (ByVal lpComputerName As String) As Integer
computerName = "Testing"
SetComputerName(computerName.ToString)
Is this right? Because it doesn't change the computer name.
Really preciate your help.
I've gotten this to work in the past by having my vb.net code generate a bat file and then execute it. the bat script contains the wmic command for renaming the PC.
wmic computersystem where name="%computername%" call rename name="[NEW PC NAME]"
you can compile the new name right into the bat file on the fly. The vb.net code just needs to obtain the new name with an argument, or if you're using a windows form, a text box.
VB PART:
Public rename As String = "wmic computersystem where name=""%computername%"" call rename name="
...
dim source as new system.text.stringbuilder
source.AppendLine("#echo off")
source.AppendLine(rename + """" + [put your new hostname here] + """")
source.AppendLine("shutdown /r -t 10") 'PC rename only works after reboot. omit this line to reboot later
source.AppendLine("del %0") 'this will make the bat file delete itself after it runs
IO.File.WriteAllText("source.bat", source.ToString())
process.start("source.bat")
Do keep in mind this has absolutely no error checking other than what is already built into wmi. You'll need some more code if you want to do things like check for whitespaces, prohibited characters or ensure that the new hostname string is less than 15 characters which is the max set by Windows. This will also only work if the vb.net code is executed with administrator rights. You may also see the Windows CMD briefly open.
Related
I made a simplified version of my code that directly highlights the issue.
I have read dozens of similar issues/solution.
Part of my workflow in VBA in Microsoft Access involves calling an R script that does some logic and returns information to a table in the same database.
It was working until we moved the location of the R installation to a new drive. Changing the path to this new install location does not work. No other code is changed.
cmd = "C:\R\bin\i386\Rscript.exe C:\R\test.R"
Debug.Print cmd
Shell cmd
I get
runtime error '5'
I am using the immediate window to check the paths are correct and copying them into RUN to verify that they do work.
The above outputs:
C:\R\bin\i386\Rscript.exe C:\R\test.R
It works in RUN.
The first thing I found when searching online is to add more (") as shell can handle them weirdly:
cmd = """C:\R\bin\i386\Rscript.exe""" & " " & """C:\R\test.R"""
Or any iterations of using "s in different places, output:
"C:\R\bin\i386\Rscript.exe" "C:\R\test.R"
Same error but works in RUN. I also tried them all successfully in CMD.
It seems just Shell refuses to launch R from that path. I have moved it elsewhere on my C drive with same effect.
I cannot recreate the original R installation path as that shared drive is now completely dead.
EDIT:
I changed to using ShellExecute simply to try and make Notepad ++ open, again works in cmd.
Set objShell = CreateObject("Shell.Application")
objShell.ShellExecute "C:\N\notepad++.exe", "C:\R\test_in.csv", "", "open", 1
This time I hit a "suspicious macro error" that leads me to believe that it may be an antivirus setting (macros are enabled in Access) blocking Shell from calling anything.
After days of testing I have found the solution, hopefully this can help anyone else in a similar situation. Windows Defender only blocks shell calls to non-Microsoft products, so I nested a call to PowerShell within the call to Shell:
Shell ("powershell.exe C:\R\bin\i386\Rscript.exe C:\R\test.R")
Take note you need to play around with the "s a lot ot get it working, my actual pipeline has more arguments and I had to enclose them in 5 sets of "s for it to pass through to powershell properly. IE:
Dim codePath As String: codePath = """""\\example\example"""""
Try these variations using Start or a second Command:
cmd = "Start C:\R\bin\i386\Rscript.exe C:\R\test.R"
or:
cmd = "cmd /c ""C:\R\bin\i386\Rscript.exe C:\R\test.R"""
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).
i used this example to open a command prompt from within vb.net 2010
lnk to stackoverflow document
the command prompt opens as expected and i can do directories open commands like regedit etc. without an issue
but what i really want is tftp.exe when i look for it it does not show up, when doing a dir it is not listed when type tftp at command prompt i get the to recognzed command
when comparing to a normal command prompt by type cmd at the run line i can see it in the windows\system32 folder
also when i do a dir from normal command prompt and compare to dir from the cmd prompt opened by vb.net there is a 400+ number of files difference out of close to 3000 files
trying to find out why i cant see all the files here is the actul code i used
Private Sub Button30_Click(sender As System.Object, e As System.EventArgs) Handles Button30.Click
Dim command As String = "tftp -i 192.168.10.177 put test1.bin"
Dim arguments As String = ""
Dim permanent As Boolean = True
Dim p As Process = New Process()
Dim pi As ProcessStartInfo = New ProcessStartInfo()
pi.Arguments = " " + If(permanent = True, "/K", "/C") + " " + command + " " + arguments
pi.FileName = "cmd.exe"
p.StartInfo = pi
p.Start()
End Sub
This seems like a very convuluted approch you are taking, but to answer your question directly, you probably need to set the working directory like so:
pi.WorkingDirectory = "c:\windows\system32"
I have to say though, you might want to reconsider the whole approach of opening a DOS window for the user to type commands. Doesn't see very user friendly.
ok found the answer, it is becuase i am running 64bit windows and when its looking for the tftp.exe it is actually looking in the syswow64 directory and tftp.exe is not in that directory.
since i have this running and compiled for x86 and not 64bit here is the work around
Public Declare Function Wow64DisableWow64FsRedirection Lib "kernel32" (ByRef oldvalue As Long) As Boolean
then
Wow64DisableWow64FsRedirection(0)
after adding tthis to my code the tftp upload works flawlessly
I'm currently using the VBA code similar to the following to specify a location of a shared library for use in communicating (passing a string) from an Office application to a desktop application. The VBA code/macros will need to exist in an add-in (.ppa).
Private Declare Sub sharedLibPassString CDecl Lib "/Users/myUserName/Library/Application Support/myCompanyName/MySharedLib.dylib" Alias "PassString" (ByVal aString As String)
In code from a VBA Macro, I then can do the following.
Call sharedLibPassString(myString)
I've got the communication working, but I'd like to replace the /Users/myUserName/ part with the current user's home directory. Normally on a Mac, you'd specify ~/Library/Application Support/..., but the ~/ syntax doesn't work, producing a "File not found" runtime error.
I discovered that using the following Environment Variable method gets me the ~/ location that I need:
Environ("HOME")
However, I don't see a way to make this part of the CDecl Lib statement, since, as far as I can tell, Environ is evaluated at runtime.
Is there any way to specify a location of a shared library in the user's home directory (~/) in VBA?
Here are a few notes about my environment/approach:
I'm using a Mac, though I believe if there is a solution it would be similar on a PC.
I don't believe it shouldn't matter, but the Office application I'm using is PowerPoint (2011).
The reason I'm trying to access an area inside of the Application Support directory, instead of the default location for shared libraries is because I'd like the Desktop application to place the shared library in a location without an installer, and without requiring a user's or administrator's privileges. If there is a better solution or location to accomplish the same task, this would be very helpful as well.
Sorry for giving a long response, I just wanted to make sure I explained this fairly well.
From this page (Anatomy of a Declare Statement) we read that
The Lib keyword specifies which DLL contains the function. Note that
the name of the DLL is contained in a string within the Declare
statement.
(emphasis added)
From experimentation, the VBE scolds me if I try to give anything but a string constant.
The only work around that I'm aware of requires rewriting the string constant at runtime.
Here is an example of how this could be done: Let's say your delaration statement is in Module1 in your current project, and that you deliberately wrote the declaration in this format at the top of your module:
Private Declare Sub sharedLibPassString CDecl Lib _
"/Users/myUserName/Library/Application Support/myCompanyName/MySharedLib.dylib" _
Alias "PassString" (ByVal aString As String)
You can access that module via code through this (requires permissions to VBA in trust Center listed under Developer Macro Settings):
Dim myModule
set myModule = ActivePresentation.VBProject.VBComponents("Module1").CodeModule
Once you've gained the CodeModule, you can replace the 2nd line directly:
myModule.ReplaceLine 2, Environ("HOME") & " _"
Mission accomplished!
If you do this, you will need to update the path prior to attempting to call your declared sub. There must be a break in execution that allows VBA to recognize the change. Also, you will not be able to modify the code while in break mode.
Now if I were doing this, I'd want to make sure I replace the right line, to not break code. You can check the contents of the 2nd line by calling this myModule.Lines(2,1) which will return the string value of the line.
However, here is a more robust solution that will find the correct line and then replace it (assumes myModule has already been defined as listed above):
Dim SL As Long, EL As Long, SC As Long, EC As Long
Dim Found As Boolean
SL = 1 ' Start on line 1
SC = 1 ' Start on Column 1
EL = 99999 ' Search until the 99999th line
EC = 999 ' Search until the 999th column
With myModule
'If found, the correct line will be be placed in the variable SL
'Broke search string into two pieces so that I won't accidentally find it.
Found = .Find("/Users/myUserName/Library/Application Support/myCompanyName/" & _
"MySharedLib.dylib", SL, SC, EL, EC, True, False, False)
If Found = True Then
'Replace the line with the line you want, second paramater should be a string of the value.
.ReplaceLine SL, Environ("HOME") & " _"
End If
End With
I don't have a Mac, so this is an incomplete answer and I don't know if it will help, but it's a couple of ideas.
I know on Windows, VB doesn't load an external library until you first try to call a function declared with it, and if you specify only the filename in the declare statement, it will use the system path to look for it. Once I did the same thing you are doing, loading a library from a dynamic path, by specifying only a filename, then making a system API call to set the current working directory to the directory of the library before loading it. Changing the PATH environment variable would probably also work.
Second idea: you could hard-code the path to a filename in the /tmp directory; then automatically copy the desired library to that location before loading it. Watch out for the file being in use by another process, but that's only an error if it is a different version of the file to the one that you want.
Long story short, my application needs to copy a file to a remote target where UNC connections TO the target might not be possible. However UNC connections FROM the target and BACK to the server will always be possible. So the plan was to use WMI to start a remote command shell (cmd) and use the copy command to grab the file. But this doesn't work. The following command works fine when executed manually from the command line of the target:
copy \\192.168.100.12\c$\remotefile.txt c:\localfile.txt
But when I try this same command as part of the InputParameters("CommandLine") it does not work, and produces no error. Note that I can use WMI to connect to the target and remote execution works just fine as I can start calc.exe etc. Here is the code that doesn't work:
Dim ConnectionOptions As New System.Management.ConnectionOptions
With ConnectionOptions
.Username = "target\Administrator"
.Password = "password"
End With
Dim ManagementScope As New System.Management.ManagementScope("\\192.168.100.11\root\cimv2", ConnectionOptions)
Try
ManagementScope.Connect()
MsgBox("connected")
Dim ManagementPath As New System.Management.ManagementPath("Win32_Process")
Dim ManagementOptions As New System.Management.ObjectGetOptions
Dim ManagementClass As New System.Management.ManagementClass(ManagementScope, ManagementPath, ManagementOptions)
Dim InputParameters As System.Management.ManagementBaseObject = ManagementClass.GetMethodParameters("Create")
InputParameters("CommandLine") = "cmd /c copy \\192.168.100.12\c$\remotefile.txt c:\localfile.txt"
Dim OutputParameters As System.Management.ManagementBaseObject = ManagementClass.InvokeMethod("Create", InputParameters, Nothing)
MsgBox("done")
Catch ex As Exception
MsgBox(ex.Message)
End Try
Any ideas why this isn't working? Or does anyone have a better way of doing what I'm trying to do?
Frank you should actually give yourself credit since the method you created is likely the first ever to get around WMI limitations of remote file copy! I did 3 weeks of searching for info/workaround and yours is the only one that works! If I had any points I would vote for your solution...
I created a fully working VBS & WMI script based on your method:
InputParameters("CommandLine") = "cmd /c echo myFTPCommands > c:\ftpscript.txt"
where you replace myFTPCommands as needed with whatever script you want to go into the file c:\ftpscript.bat (or .vbs, .ps1, or whatever you like). If you couldn't fit enough text in the one-line script, then append with the same method using >>. Now, you can use XCOPY, PSEXEC, COPY, or anything else to run the script you just created on the remote host's file system.
Here's my fully fleshed out VBScript using your method. Thanks again. :)
HTH,
Lizz
For security reasons, most methods of programatically connecting to a remote machine and telling it to copy a file to itself from another machine are blocked. One thing that finally worked for me is FTP. Using the above code I can do something like this:
InputParameters("CommandLine") = "ftp -s:c:\ftpscript.txt"
Which causes the ftp commandline utility to run on the remote machine, using c:\ftpscript.txt to get a list of commands from. Since there is no way to copy the ftp script file to the target (again, no UNC connection), I can first do:
InputParameters("CommandLine") = "cmd /c echo myFTPCommands > c:\ftpscript.txt"
And this works :)
UPDATE: Never thought to use XCOPY and it works perfectly:
InputParameters("CommandLine") = "cmd /c echo F | xcopy remotefile localfile"
UPDATE: XCOPY worked yesterday, now it doesn't. NOTHING has changed, so I am at a complete loss for explanation.