0

I am working on a small software deployment script which uninstalls and installs a new version of Check_MK remotely by using powershell.

Everything is working great - i am able to localize the old service, stop it and determine the installation path of it. The problem is to run the "uninstall.exe" of the service.

This can be easily done by using a Powershell session logging on the server with credential parameter in use.

$passwd = convertto-securestring -AsPlainText -Force -String "password"
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "domain\user",$passwd
$session = new-pssession -computername "192.xxx.xxx.xxx" -credential $cred
Enter-PSSession $session

The problem is you can't use PSSession in a script - it is made for personal use and not automation.

So i tried to use Powershells Invoke-Command cmdlet.

Invoke-Command -Computername "192.xxx.xxx.xxx" -credential $cred -argumentlist $cred -ScriptBlock {
    # Lots of stuff and enter uninstall directory

    uninstall.exe /S
}

Calling the exe file ends in a query for administrator credentials.

I also tried to remote start a elevated Powershell session and use it for uninstallation..

Start-Process powershell -Credential $cred

Executing a script located on the server for starting uninstall.exe using the elevated Powershell session ends in a UAC query (not querying for credentials, but asking for executing).

Is there any other solution to handle this? I tried a lot more, but nothing worked.

Marc
  • 103
  • 17
  • 1
    `$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "domain\user",$passwd ` you got a typo in "argumentlist". Maybe this is the error... – SimonS Nov 27 '15 at 14:14
  • Can't see any typo? Also the $cred object works because i can successfully login on the computer by PSSession. – Marc Nov 30 '15 at 09:18
  • Now i see it. That was just a failure by pasting in here - code in script is allright. – Marc Nov 30 '15 at 09:42
  • 1
    `invoke-command` takes a `pssession` as an arguement so no need to re-type computername, credentials etc – Kiran Reddy Nov 30 '15 at 12:42
  • The problem is i have to do that for 40 to 50 machines and i don't want to start a PSSession for every single machine. – Marc Nov 30 '15 at 12:47
  • maybe you could try credssp.... enable your client as a client(`enable-wsmancredssp`) and the remote machine as a `server`...then when you run `invoke-command` pass the `authentication` parameter value as `credssp`.. – Kiran Reddy Nov 30 '15 at 13:16
  • Have you considered disabling UAC? Honestly it's the most useless "security" feature ever conceived, it protects practically nothing as any attack worth its salt can just bypass it and it causes endless problems with elevation, as you are experiencing. – Deadly-Bagel Dec 02 '15 at 14:14
  • @Deadly-Bagel Yeah, that will actually work but so we have to deploy every server with a new image and we have to repack every image with disabled UAC. So this is unfortunately no option for me :/ – Marc Dec 03 '15 at 11:53
  • A regedit and a reboot generally do the trick but obviously with servers this isn't always an option. Just something to consider as a future project. I suspect the installer runs a separate instance of something that hits UAC separately, not sure how but we have an installer that does that with a service. I don't see any other way around it =/ – Deadly-Bagel Dec 03 '15 at 17:41
  • It looks like it is possible to add an exception to the local machines security policy to disable UAC for specific applications: http://answers.microsoft.com/en-us/windows/forum/windows_vista-security/uac-and-one-program-used-very-regulary/67bfc4b5-faff-4de4-be48-f395bf1c519d?auth=1 although, probably not what you want as it's not that far off from modifying registry, etc. – John Bartels Dec 03 '15 at 20:04
  • @Deadly-Bagel - UAC is actually one of the most important security features Windows has. If you disable it, Windows 7/8/8.1/10 are no more secure than Windows XP. Disabling it should be a last resort only. – Kevin Keane Dec 07 '15 at 07:58
  • Every piece of malware I've encountered that got through the AV in the last few years didn't care if UAC was on or not. Perhaps it's different in Windows 10, but I've yet to see it do anything other than cause grief while trying to manage computers and servers. – Deadly-Bagel Dec 08 '15 at 09:52

3 Answers3

2

Here's another approach, using Schedule Tasks.

Create a task locally using the logged-on user credentials, you must have admin rights on the remote computer of course.

Function Run-RemoteCommand
{

Param(

[Parameter(Mandatory = $true)]
[String]
$Computer,

[Parameter(Mandatory = $true)]
[String]
$Task,

[Switch]
$Background

)

$TaskName = "TempTask"
$Explorer=gwmi win32_process -ComputerName $Computer | ? {$_.ProcessName -eq "explorer.exe" }
$OWner = $Explorer.GetOwner().Domain + "\" + $Explorer.GetOwner().User
if ($Background)
{
$Create = "SCHTASKS /Create /TN ""$TaskName"" /RU System /TR ""$Task"" /SC Once /ST 22:30"
}
Else
{
$Create = "SCHTASKS /Create /TN ""$TaskName"" /RU $Owner /TR ""$Task"" /SC Once /ST 22:30"
}
$Runit = "SCHTASKS /Run /TN ""$TaskName"""
$Delete = "SCHTASKS /Delete /TN ""$TaskName"" /F"
$WMI = Get-WmiObject -List Win32_Process -ComputerName $Computer 
$WMI.Create($Create)
$WMI.Create($Runit)
Sleep 2
$WMI.Create($Delete)
}

To Run it:

Run-RemoteCommand -Computer "192.xxx.xxx.xxx" -Task 'c:\path\uninstall.exe /S'

if you want to run it as 'NT AUTHORITY\SYSTEM' add the -Background Switch

Avshalom
  • 8,657
  • 1
  • 25
  • 43
  • I tried your code and i got 3 big chunks of output including process ids and so one.. But it looks like the uninstall.exe were not executed. Checking $OWner gives me my credentials - all fine :/ – Marc Nov 30 '15 at 12:50
0

The best way would be to always have the local shell run as an elevated user. This allows you to start invoke-command without providing credentials in a script.

Once you have a Powershell running as an administrative user, and you can run your script using invoke-command. I do it all the time.

If you are scheduling this task, you will have to have the task run as the elevated user. This again, stops you from having to put the password in plain text in the script.

Unconn
  • 578
  • 4
  • 5
0

You don't mention if this is in a domain context or not.

If it is in a domain context, you could use a startup script in a Group Policy Object to accomplish your goal. It will execute on the next reboot of the workstation.

You can also do it without a group policy, but it means visiting each computer individually and changing the local group policy object - at that point, you might as well just run the powershell script.

Another solution: you could create a .zap file and deploy that using Group Policy's software deployment functionality. This would be a bit of an abuse of the system. .zap files are meant to install software that isn't packaged in MSI files, but you could also use it to launch a script that uninstalls your software. Ordinarily, .zap files cannot be uninstalled.

A third option: download Chocolatey from http://www.chocolatey.org. This is a PowerShell script that can manage the installation of a lot of standard software for you. Configure it on each workstation to run automatically (using the scheduler or so). Create a NuGet package for your software (NuGet is what Chocolatey runs under the hood), and use chocolatey to deploy or undeploy your software as needed.

As an aside, instead of rolling your own installer, you may want to consider converting it to an MSI file - those can easily be installed and uninstalled, even remotely, without excessive UAC hassle. You could also use a NullSoft installer, but those are harder to automate remotely. MSI is Microsoft's official installation method.

Some people create MSI wrappers around standard .exe-type installers, too.

Kevin Keane
  • 1,506
  • 12
  • 24