I'm trying to run a PowerShell command in a batch script. Im trying to remove all traces of an old RMM tool from client PCs and for the life of me can't get this line to run correctly.
The idea is that this searches for software that has N-Able in the vendor name and passes the GUID to the $nableguid
variable and then msiexec.exe
against the GUIDs found above.
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {$nableguid = (Get -WmiObject Win32_Product -Filter "vendor LIKE '%N-able%'" | Select -ExpandProperty IdentifyingNumber); foreach ($nguid in $nableguid){ & MsiExec.exe /X$nguid /quiet} }";
The current error is as follows
Get-WmiObject : A positional parameter cannot be found that accepts argument ''.
At line:1 char:18
+ & {$nableguid = (Get-WmiObject Win32_Product -Filter vendor LIKE '' | Select -Ex ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-WmiObject], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetWmiObjectCommand
I know that this boils down to orders of operations and the current organization of quotations, but after messing around with the ordering for an hour I still cant get it to work correctly.
Check this snippet, it is using WMI but in another way, and has almost never failed me :
function Uninstall-Application($computer, $target) {
$productInfo = Get-WmiObject Win32_Product -Filter "Name LIKE '%$target%'" -ComputerName $computer
$pin = $productInfo.IdentifyingNumber
$pn = $productInfo.Name
$pv = $productInfo.Version
if($pn -ne $null) {
$classKey = "IdentifyingNumber=`"$pin`",Name=`"$pn`",version=`"$pv`""
$uninstallReturn = ([wmi]"\\$computer\root\cimv2:Win32_Product.$classKey").uninstall()
if($uninstallReturn.ReturnValue -ge 0) { Write-Host "Uninstall complete" }
else { $uninstallReturn | Out-Host }
} else {
Throw "Product not found"
}
}
Example usage :
Uninstall-Application "127.0.0.1" "firefox"
You're getting that error, because you're using unescaped percent characters and double quotes inside a double-quoted string:
"& {... -Filter "vendor LIKE '%N-able%'" ...}"
The above evaluates to -Filter vendor LIKE ''
when the PowerShell command is executed, i.e. only the token vendor
is passed as an argument to the parameter -Filter
. LIKE
and ''
are passed as separate positional parameters.
You must escape the nested double quotes to preserve them for the PowerShell command:
"& {... -Filter \"vendor LIKE '%N-able%'\" ...}"
You must also double the %
characters (that's how they are escaped in batch/CMD), otherwise %N-able%
would be interpreted as a batch variable and expanded to an empty string before the execution of the powershell
commandline.
"& {... -Filter \"vendor LIKE '%%N-able%%'\" ...}"
With that said, in general it would be far simpler to implement the PowerShell code in a PowerShell script:
$nableguid = Get -WmiObject Win32_Product -Filter "vendor LIKE '%N-able%'" |
Select -ExpandProperty IdentifyingNumber)
foreach ($nguid in $nableguid) {
& MsiExec.exe /X$nguid /quiet
}
and run that script via the -File
parameter (if you must run it from a batch file in the first place):
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\path\to\script.ps1"
An even better approach would be to drop the batch script entirely and implement everything in PowerShell.