Output after removing programs using WMI - Powershell - powershell

I'm using WMI to uninstall software remotely and it's working fine to remove the software. What I'm struggling with is using the results of that (Successful or not) to give a simple out put message rather than the normal output of the command. I normally use $lastexitcode for this but no matter whether or not the command succeeds it runs to my successful uninstall message. Here's what I'm trying to use:
$app = Get-WmiObject Win32_Product -ComputerName "$computer" | where { $_.vendor -eq "APN, LLC" }
$app.Uninstall()
if ($lastexitcode -eq 0)
{
write-host -ForegroundColor Green "Programm Successfully Removed"
}
else
{
write-host -ForegroundColor red "There was a problem uninstalling the program"
}
When I leave output of the operation on it returns:
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
PSComputerName :
I figure I could do something with the ReturnValue but I'm not sure how. Any help would be greatly appreciated.
EDIT: The solution thanks to Bruce's answer:
$app = Get-WmiObject Win32_Product -ComputerName "$computer" | where { $_.vendor -eq "APN, LLC" }
$appuninstall = $app.Uninstall()
if ($appuninstall.returnvalue -eq 0)
{
write-host -ForegroundColor Green "Programm Successfully Removed"
}
else
{
write-host -ForegroundColor red "There was a problem uninstalling the program"
}

$LastExitCode is only set when running native commands (external .exes). In your code, you want to capture the result of the call to Uninstall() in a variable then use the return code property from that object in your if statement.

Related

Change RDP with Invoke-WmiMethod

I want change RDP port with WMI method but my code doesn't work and I don't know why.
Invoke-WmiMethod -Class StdRegprov -Name SetDWORDvalue -ArgumentList 2147483650,"System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp", "PortNumber", 3354
I get this after execute in PowerShell:
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 5
PSComputerName :
But nothing changed?
This right here indicates your problem:
ReturnValue : 5
Return code 5 means "access denied". Your user does not have permission to write to that registry location. You probably need to run the code "as administrator".
With that said, PowerShell provides direct access to the registry. You don't need WMI for that.
$reg = 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'
$name = 'PortNumber'
$value = 3354
New-ItemProperty -Path $reg -Name $name -Value $value -Type DWORD -Force | Out-Null
You still need to run this with a user who has write access to the registry key, though.

Check for Existing Computer in AD

I'm trying to check for an existing computer name in AD before renaming the local computer. Below is the code that I started with, but don't know why it's failing.
When I enter a computer name (MNBLAP) that I know is in AD, it jumps down to the else statement. If I put in a computer name (RJKLAP) that I know doesn't exist, it throws an error.
$checkname = Get-ADComputer $newcomputername -ErrorAction SilentlyContinue
if ($checkname -eq $newcomputername){
Write-Host "The computer is already in AD."
}
else {
Write-Host "The computer is not in AD."
}
Any help would be greatly appreciated. Below is the error I receive
get-adcomputer : Cannot find an object with identity: 'RJKLAP' under: 'DC=domain,DC=domain'.
At C:\Scripts\CheckComputerName.ps1:25 char:14
+ ... checkname = get-adcomputer $newcomputername -ErrorAction SilentlyCont ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (RJKLAP:ADComputer) [Get-ADComputer], ADIdentityNotFoundException
+ FullyQualifiedErrorId : Cannot find an object with identity: 'RJKLAP' under: 'DC=domain,DC=domain'.,Microsoft.ActiveDirectory.Management.C
ommands.GetADComputer
The reason your if() statement fails is that Get-ADComputer returns an ADComputer object, not just the computer name.
To trap the error in case the machine name doesn't exist, use try/catch:
try{
$checkname = #(Get-ADComputer $newcomputername)
if($checkname.Count -eq 1){
# newcomputername found
Write-Host "The computer is already in AD."
}
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]{
# newcomputername not found
Write-Host "The computer is not in AD."
}

Create shared folder with [WMICLASS]"Win32_Share"

I'm using a PowerShell script that creates local share folder.
function shareCacheFolder() {
  $Sharename = 'cacheFolder'
  $Foldername = 'c:\cacheFolder'
  if (!(Get-WmiObject Win32_Share -Filter "name='$Sharename'")) {
    $Shares = [WMICLASS]"Win32_Share"
    $Shares.Create($Foldername, $Sharename, 0)
  }
}
This seems to work on most machines. But not on mine.
I'm getting this output:
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 8
PSComputerName :
I've also tried using this convention:
function shareCacheFolder() {
$path = "c:\cachefolder"
$name = "cachefolder"
$type = 0
$password = ""
$description = ""
$max = 100
$access = $null
  if (!(Get-WmiObject Win32_Share -Filter "name='$Sharename'")) {
Invoke-WmiMethod -Class Win32_Share -Name Create -ArgumentList $access, $description, $max, $name, $password, $path, $type
  }
}
I'm using PowerShell version 3.
As documented the return code 8 means "unknown error". The command is syntactically correct and works on other computers, so the issue is not with your code. The problem is also unlikely to be caused by a share name conflict, missing folder, permission issue, etc., as those would cause different errors/return codes.
I suspect that on your system the Server service is not running. Verify that with the following command:
Get-Service 'Server' | Select-Object StartType, Status | Format-List
The start type should be "Automatic", and the status should be "Running". If they're not, change the start type and start the service like this:
Get-Service 'Server' | Set-Service -StartupType 'Automatic'
Start-Service 'Server'

uninstalling Office 2007 with PowerShell

I'm trying to write a script which uninstalls Microsoft Office 2007 Enterprise by grabbing the IdentifyingNumber using Get-WmiObject -Class Win32_Product. I'm able to grab the IdentifyingNumber, but when I attempt to uninstall PowerShell outputs some information that I'm not sure what to do with. Is this not a proper way to utilize Uninstall()?
$2k7 = Get-WmiObject -Class Win32_Product | Where-Object { $_.IdentifyingNumber -match "{90120000-0030-0000-0000-0000000FF1CE}" }
if ($2k7 -ne $null) {
$2k7.Uninstall()
}
else {
write-host "nothing to see here"
}
Output...
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 1603
Error 1603 is a catch-all error used by Microsoft Installer when an unexpected failure is encountered.
I would verify that you're running your Powershell window with elevated privileges and that the program you intend to uninstall doesn't have any processes currently running.

how to get return code when using invoke-command against multiple computers?

i'm trying to know if my scipt was effectively executed on all the remote hosts when using invoke-command like this :
Invoke-Command -ComputerName "test1","test2" -ScriptBlock {$env:computername}
when it runs interactively it's OK i can see error messages like this :
CategoryInfo : OpenError: (test1:String) [], PSRemotingTransportException
FullyQualifiedErrorId : NetworkPathNotFound,PSSessionStateBroken
but how to do when running the script in 'batch mode' ?
I tried the try{} catch{} statement but it doesnt seem to work,
then I tried to handle the result in a variable, didnt work either :
PS>$result=Invoke-Command -ComputerName "test1","test2","rodc1" -ScriptBlock {$env:computername}
PS>$result
rodc1
I have ended up to use new-pssession for each host and test it like this
$computers=#("test1","test2","rodc1")
$computers|%{
$s=new-PSSession -ComputerName $_
if($s -eq $null){
$errs +="$_ : cant connect to host `n<br/>"
}
else{
$sess+=$s
}
}
invoke-Command -Session $sess -ScriptBlock {$env:computername} -asJob -jobName "test"
now, i can use $errs to know which computers failed
Is there a better/simplier way to do this ?
thank you
Some errors were still not catched here is the part to modify :
$computers=#("test1","test2","rodc1")
$computers|%{
try{
$s=new-PSSession -ComputerName $_
if($s -eq $null){
$rapport+="$_ : cant connect to host`n<br/>"
}
else{
$sess+=$s
}
}
catch{
$rapport+="$_ : cant connect to host`n<br/>"
}
}
You can just compare your input list and your output list :
Compare-Object $computers $result
InputObject SideIndicator
----------- -------------
test1 <=
test2 <=
or directly
(Compare-Object $computers $result).InputObject