Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

OK, I'm a C# programmer that is trying to streamline the deployment of a custom windows form app I inherited and built an installer for with WiX (this app will need to be reinstalled regularly as I'm making changes to it). I'm not really used to admin type things (or vbs, or WMI, or terminal servers, or Citrix, and even WiX and MSI are not things I usually deal with) but so far I put together some vbs and have an end goal in mind. The msi does work, and I've installed it from the mapped O: drive on my dev machine and while RDP'd to a citrix machine.

End Goal: Deploy code written on my dev machine and compiled into an MSI (that I can improve upon within the confines of WiX and whatever the Windows Installer Engine allows) to the cluster of Citrix machines my users have access to.

What am I missing in my script to get the MSI to execute on the remote machines?

Layout:

  • Machine A is my dev machine, and has the vbs script and the msi file (XP SP3)
  • Machines C1 - C6 are the Citrix Servers that need the application installed them via the msi (Server 2003 R2 SP2)
  • There is also optionally a shared network resource that all the machines can access.

Script:

'Set WMI Constants
Const wbemImpersonationLevelImpersonate = 3
Const wbemAuthenticationLevelPktPrivacy = 6

'Set whether this is installing to the debug Citrix Servers
Const isDebug = true

'Set MSI location
'Network location yields error 1619 (This installation package could not be opened.)
msiLocation = "\\255.255.255.255\odrive\Citrix Deployment\Setup.msi"
'Directory on machine A yields error 3 (file not found)
'msiLocation = "C:\Temp\Deploy\Setup.msi"
'Mapped network drive (on both machines) yield error 3 (file not found)
'msiLocation = "O:\Citrix Deployment\Setup.msi"

'Set login information
strDomain = "MyDomain" 
Wscript.StdOut.Write "user name:"
strUser = Wscript.StdIn.ReadLine 
Set objPassword = CreateObject("ScriptPW.Password")
Wscript.StdOut.Write "password:"
strPassword = objPassword.GetPassword()

'Names of Citrix Servers
Dim citrixServerArray
If isDebug Then
    citrixServerArray = array("C4")
Else
    'citrixServerArray = array("C1","C2","C3","C5","C6")
End If

'Loop through each Citrix Server
For Each citrixServer in citrixServerArray

    'Login to remote computer
    Set objLocator = CreateObject("WbemScripting.SWbemLocator")
    Set objWMIService = objLocator.ConnectServer(citrixServer, _
        "root\cimv2", _
         strUser, _
         strPassword, _
         "MS_409", _
         "ntlmdomain:" + strDomain)

    'Set Remote Impersonation level
    objWMIService.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate
    objWMIService.Security_.AuthenticationLevel = wbemAuthenticationLevelPktPrivacy

    'Reference to a process on the machine
    Dim objProcess : Set objProcess = objWMIService.Get("Win32_Process")

    'Change user to install for terminal services
    errReturn = objProcess.Create _
        ("cmd.exe /c change user /install", Null, Null, intProcessID)   
    WScript.Echo errReturn

    'Install MSI here
    'Reference to a product on the machine
    Set objSoftware = objWMIService.Get("Win32_Product")
    'All users set in option parameter, I'm led to believe that the third parameter is actually ignored
    'http://www.webmasterkb.com/Uwe/Forum.aspx/vbscript/2433/Installing-programs-with-VbScript
    errReturn = objSoftware.Install(msiLocation,"ALLUSERS=2 REBOOT=ReallySuppress",True)
    Wscript.Echo errReturn

    'Change user back to execute
    errReturn = objProcess.Create _
        ("cmd.exe /c change user /execute", Null, Null, intProcessID)
    WScript.Echo errReturn

Next

I also tried using this to install, it doesn't return an error code, but doesn't install the msi either, and it makes me wonder if the change user /install command is even really working.

errReturn = objProcess.Create _
    ("cmd.exe /c msiexec /i ""O:\Citrix Deployment\Setup.msi"" /quiet")
Wscript.Echo errReturn

@tony The file copies over fine, but then I get this:

ERROR:
Code = 0x80070005
Description = Access is denied.
Facility = Win32

I need to use another user account (same domain though) for the Citrix machines, which is why I used:

Set objLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMIService = objLocator.ConnectServer( .....

I finally used a powershell script for this based on tony's input and suggestion, and it looks and acts much cleaner.

Although getting the Win32_Product class Install Method still looks a little convoluted (compared to the WMIC command), but it is what Technet suggests:

http://blogs.msdn.com/b/wmi/archive/2010/01/06/wmic-vs-wmi-powershell-cmdlets.aspx http://technet.microsoft.com/en-us/library/dd347651.aspx

#$servers = 'C1' , 'C2', 'C3' , 'C5', 'C6'
$servers = , 'C4'
$MyCredential = Get-Credential MyDomain\otherusername

foreach($server in $servers)
{
    Copy-Item -LiteralPath C:\Temp\Deploy\Setup.msi -Destination \\$server\c$\Temp\Setup.msi -Force
    (Get-WmiObject -ComputerName $server -Credential $MyCredential -List | `
    Where-Object -FilterScript {$_.Name -eq "Win32_Product"}).Install("C:\TEMP\Setup.msi")
}
share|improve this question
add comment

1 Answer

up vote 2 down vote accepted

for one citrix has its own deployment technology, secondly are you saying that your deployment method fails in someway? If so I expect it to be an impersonation issue. But I can't really tell from your explanation.

the following is a shortcut to all the code that you have
1st
copy file.msi \citrixservername\c$\pathtoyourfile

wmic /node:citrixservername product call install true,"" , "c:\PathToYour\File.msi"

notice the install file is copied local to the server 1st, if you don't do this you'll have an impersonation issue!

share|improve this answer
    
Thanks for shortening up what I wanted to do. However, I got an access denied error, I need to login with another user account (same domain) on the citrix machines. –  capn Jun 16 '10 at 19:36
    
yes login to the domain with an account that has admin on the citrix servers. –  tony roth Jun 16 '10 at 19:56
    
ok I added /user:otherusername after the /node switch and it installed, I'm gonna have to play with it more to get working completely with the for loop. thanks –  capn Jun 16 '10 at 19:56
    
the parameter for the node can also be a text file with a list of computers! the syntax is /node:@listofservers.txt –  tony roth Jun 16 '10 at 20:00
    
wmic /node:C4 /user:otherusername product call install true,"" , "C:\Temp\Setup.msi" –  capn Jun 16 '10 at 20:01
show 3 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.