2

I am setting up powershell scripts to automate environment installs for a variety of systems. I need to script the running of an MSI installer file to setup a Windows Service. How do I include the required Username and Password to make the installation fully 'quiet'

I've gotten to:

$installFile = "C:\[path]\Installer.msi"
$username = "[ad user account]"
$password = convertto-securestring -String "[secure password]" -AsPlainText -Force  

msiexec /i $installFile /quiet "UserName=$username,Password=$password"

but the provided credentials are not being accepted.

Suggestions?

user11861660
  • 41
  • 1
  • 6
  • First run it with hard coded values to prove it can work. Only then try it with variables. Then copy the complete script into the question with the exact error message. – John Rees Jul 31 '19 at 04:13
  • The MSI and the Windows Service that it installs are both fine; I ironed those issues out months ago. The script above doesn't throw an error, but it does prompt for the service credentials to be entered. I'm trying to provide the credentials up front so the install is fully automated. – user11861660 Jul 31 '19 at 04:16
  • Great. Now please show the complete script and error message. – John Rees Jul 31 '19 at 04:17
  • If you want a unattended installation you've to add the `/quiet` switch. – Moerwald Jul 31 '19 at 04:43
  • Yes, the /quiet switch after the $installFile does supress the normal windows, it still pops up the window for the credentials the service is to run under. That is the issue I need help resolving. – user11861660 Jul 31 '19 at 04:52
  • You need to check using Orca or Installshield tool for the msi if the credential windows screen used to take input username and password have variables in capital letters(public property) or not. If its not fully capital, i 'm afraid you can't pass as parameter to msi. – Vivek Jaiswal Jul 31 '19 at 05:33
  • You have used Username and Password as variables. if these are the same names used as property in msi for service credentials, you can't pass it from outside. Check the property table within msi if Username and Password variable in capital letters or not – Vivek Jaiswal Jul 31 '19 at 05:39
  • I would recommend solving this problem first using CMD and hard coded values. Only after that is working turn it into a Powershell script with variables. Powershell command line parsing is full of gotchas. – John Rees Jul 31 '19 at 20:49
  • Do you have any documentation for the particular installer that states that the arguments are "Username" and "Password"? If they are then try `msiexec /i "C\:installer.msi" /quiet "Username=blah" "Password=boo"` – John Rees Jul 31 '19 at 21:50
  • From most posts I have seen, it seems that these public parameters are always upper case. Using CMD try `msiexec /i "C\:installer.msi" /quiet "USERNAME=blah" "PASSWORD=boo"` – John Rees Jul 31 '19 at 21:54
  • For investigation into the names of msi parameters I would suggest you read https://stackoverflow.com/q/2366480/37572 – John Rees Jul 31 '19 at 22:00

2 Answers2

2

First of all, thank you everyone for your help.

Reading through your suggestions and the following question in the list of “Related” suggestions got me thinking in another direction (Msi insaller passing paramenter from command prompt for Set Service Login).

A little more hunting and I found this article: Change Service Account Username & Password–PowerShell Script

So, my new plan is to default the service account inside installer via code and then change it after installation using PowerShell. In the source code for the windows service I have a ProjectInstaller.cs file. Opening the ProjectInstaller.Designer.cs code and looking in the InitializeComponent() method I saw the following lines:

this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;

Adding the following line below successfully suppresses any request for service account credentials during installation:

this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalService;

After that I used the code sample from the TechNet article to change the account post-installation. The final script looks something like this:

$serviceName = "Service"
$oldInstallFile = "C:\Old_Installer.msi" #Only required if upgrading a previous installation
$installFile = "C:\New_Installer.msi"

$serviceConfigSource = "C:\Config"
$serviceConfigSourceFile = "C:\Config\Service.exe.config"
$serviceConfigDestinationFile = "C:\Program Files (x86)\Service\Service.exe.config"

$username = "[UserName]"
$password = "[Password]"  


#Checking for existing service installation and uninstalling it
$existingService = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"

if($existingService)
{
    Write-Host "$serviceName found. Begining the uninstall process..."
    if($existingService.Started)
    {
        $existingService.StopService()
        Start-Sleep -Seconds 5
    }

    msiexec /uninstall $oldInstallFile /quiet
    Start-Sleep -Seconds 5
    Write-Host "$serviceName Uninstalled."

}

#Install New service
Write-Host "$serviceName installation starting."
msiexec /i $newInstallFile /quiet
Start-Sleep -Seconds 5
Write-Host "$serviceName installation completed."



#copy config file
if(Test-Path $serviceConfigSource)
{
    Copy-Item -Path $serviceConfigSourceFile -Destination $serviceConfigDestinationFile -Force
}


#Final service setup and start up
$newService = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"

$changeStatus = $newService.Change($null,$null,$null,$null,$null,$null,$userName,$password,$null,$null,$null) 
if ($changeStatus.ReturnValue -eq "0")  
{
    Write-Host "$serviceName -> Sucessfully Changed User Name"
} 

if(!$newService.Started)
{
    $startStatus = $newService.StartService()
    if ($startStatus.ReturnValue -eq "0")  
    {
        Write-Host "$serviceName -> Service Started Successfully"
    } 

}

Hope this helps people.

user11861660
  • 41
  • 1
  • 6
0

Try to seperate your arguments with spaces:

 $installArgs = "UserName=$username Password=$password" 

Afterwards you can call msiexec via:

 $msiArgs = "/i ""{0}"" /qn /norestart /l*v ""C:\temp\msiInstall.log"" {1}" -f $msiLocation,$installArgs
 $process = Start-Process -FilePath "$env:systemroot\system32\msiexec.exe" -ArgumentList $msiArgs -Wait -PassThru
 if ($process.ExitCode -ne 0) {
      Write-Error "Installation failed"
 }
Moerwald
  • 10,448
  • 9
  • 43
  • 83