run powershell command over cmd - powershell

I'm trying to run this powershell command over cmd.. it worked when i run it directly from powershell.. but when i try to run if from cmd i get errors
Powershell Command:
(Get-WmiObject -Class Win32_Product -Filter "Name='Symantec Endpoint Protection'" -ComputerName localhost. ).Uninstall()
How I run it (cmd):
powershell.exe -Command (Get-WmiObject -Class Win32_Product -Filter Name='Symantec Endpoint Protection' -ComputerName localhost. ).Uninstall()
Output:
Get-WmiObject : Invalid query "select * from Win32_Product where Name=Symantec
Endpoint Protection"
At line:1 char:2
+ (Get-WmiObject -Class Win32_Product -Filter Name='Symantec Endpoint P ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-WmiObject], Management
Exception
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.C
ommands.GetWmiObjectCommand
You cannot call a method on a null-valued expression.
At line:1 char:1
+ (Get-WmiObject -Class Win32_Product -Filter Name='Symantec Endpoint P ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

The other answers already answer your question of running powershell over CMD. I'd like to recommend you stop using the Win32_Product wmi class. You can read any of the never ending articles explaining why. As for building commands with arguments, I recommend splatting. As a bonus specifically regarding removing SEP, here is a snippet from a production script used to remove Symantec Endpoint using MSIexec and the guid.
$DateStamp = get-date -Format yyyyMMddTHHmmss
$logFile = '{0}-{1}-{2}.log' -f 'SymantecUninstall',$PC,$DateStamp
$locallog = join-path 'c:\windows\temp' -ChildPath $logFile
$uninstalljobs = Foreach($PC in $SomeList){
start-job -name $pc -ScriptBlock {
Param($PC,$locallog)
$script = {
Param($locallog)
$MSIArguments = #(
"/x"
('"{0}"' -f '{A0CFB412-0C01-4D2E-BAC9-3610AD36B4C8}')
"/qn"
"/norestart"
"/L*v"
$locallog
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow
}
Invoke-Command -ComputerName $pc -ArgumentList $locallog -ScriptBlock $script
} -ArgumentList $PC,$locallog
}
Just update the guid to match your product. If you want to pull the uninstall string from the registry and use that, it would also be preferable to Win32_Product.
Here are a couple of ways you can find the uninstallstring.
$script = {
$ErrorActionPreference = 'stop'
"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | foreach{
try
{
$key = reg query $_ /f "Symantec Endpoint" /s | select -skip 1 -first 1
$key = $key -replace 'HKEY_LOCAL_MACHINE','HKLM:'
(Get-ItemProperty $key -Name UninstallString).UninstallString
}
catch{}
}
}
powershell.exe -command $script
or
$script = {
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | foreach{
Get-childitem $_ |
Where {($_ | get-itemproperty -Name displayname -ea 0).displayname -like 'Symantec Endpoint*'} |
Get-ItemPropertyValue -name UninstallString
}
}
powershell.exe -command $script

Try this:
powershell.exe -Command "& {(Get-WmiObject -Class Win32_Product -Filter """Name='Symantec Endpoint Protection'""" -ComputerName XOS-MS182. ).Uninstall()}"

Try these. The parentheses mean something special to cmd. The filter would require two sets of quotes. Since the pipe is inside the double quotes, cmd ignores it.
powershell "(Get-WmiObject -Class Win32_Product -ComputerName localhost | where name -eq 'symantec endpoint protection').Uninstall()"
powershell "Get-WmiObject win32_product -cn localhost | ? name -eq 'symantec endpoint protection' | remove-wmiobject"

You don't need to use powershell for this task, from an elevated Windows Command Prompt, (cmd), you could use wmic instead:
WMIC.exe Product Where "Name='Symantec Endpoint Protection'" Call Uninstall

Related

Passing Variable to Remote Computer with Invoke-Command and Get-CimInstance

I've been attempting to pass a variable in Powershell using Invoke-Command, however, every example I've found doesn't seem to work when using Get-CimInstance. This is the basic code I'm using is:
$Computer = (Read-Host "Enter Computer Name")
$User = (Read-Host "Enter User Name")
$Cred = (Get-Credential -Message "Enter Credentials" )
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {(Get-CimInstance -Class Win32_UserProfile -Filter 'LocalPath like "%$User"').LocalPath.split('\')[-1] | Remove-CimInstance}
When I run that I get a null value:
You cannot call a method on a null-valued expression.
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
+ PSComputerName : DBServer
I've also tried using the -ArgumentList flag, but that doesn't work either and I get the null value error again:
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {(Get-CimInstance -Class Win32_UserProfile -Filter 'LocalPath like "%$using:User"').LocalPath.split('\')[-1] | Remove-CimInstance} -ArgumentList $User
or:
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {(Get-CimInstance -Class Win32_UserProfile -Filter 'LocalPath like "%$args[0]"').LocalPath.split('\')[-1] | Remove-CimInstance} -ArgumentList $User
My best guess is that the -Filter flag is causing the issue. Though it works just fine if run locally. Also in my test case some usernames start with a dollar sign (ie $fredsmith) which may be an issue as well.
The doublequotes have to be on the outside to interpret the variable.
$user = 'joe'
"localpath like '%$user%'"
localpath like '%joe%'
This worked for me at an elevated prompt with the winrm service running:
invoke-command localhost {
get-wmiobject win32_userprofile -filter "localpath like '%$using:user%'" }
Or with no quoting issues:
invoke-command localhost {
get-ciminstance win32_userprofile | where localpath -match $using:user |
remove-ciminstance -whatif }
invoke-command localhost { param($user)
get-wmiobject win32_userprofile | where localpath -match $user } -args $user
invoke-command localhost {
get-wmiobject win32_userprofile | where localpath -match $args[0] } -args $user

Powershell Remote Stop and Disable Service

SO Braintrust. I'm not a Powershell person, but I'm working on it. Trying to address yet another zero-day, I'm trying to build a reuseable script to remotely stop and disable the affected service. It is based on a script I got from a Microsoft MVP at (ultimately): http://portal.sivarajan.com/2010/07/stopstart-or-enabledisable-service_26.html
The prompt for the service name was added by me as well as the output information (Write-host & Add-Content lines), so I could get a results summation (the output part's not working fully, but it's the least of my concerns at the moment.).
$output = "c:\scripts\results.csv"
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output Start"
cls
$Cred = Get-Credential
$service = Read-Host -Prompt 'Enter Service Name" '
Import-CSV C:\Scripts\computers.csv | %
{
$computer = $_.ComputerName
Write-Host "Working on $computer"
Add-content -path $output "$computer"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).stopservice()
Add-content -path $output " Stop - $result"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).ChangeStartMode("Disabled")
Add-content -path $output " Disable - $result"
}
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output End"
when I run it, I get an error on the computer name
Get-WmiObject : Cannot validate argument on parameter 'ComputerName'.
The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Scripts\StopAndDisableService.ps1:12 char:54
+ ... result = (Get-WmiObject win32_service -computername $computer -filter ...
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Get-WmiObject : Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Scripts\StopAndDisableService.ps1:14 char:54
+ ... result = (Get-WmiObject win32_service -computername $computer -filter ...
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Computer.csv contains one computer name per line, no punctuation, no FQDN, just the computer name
Special thanks to #Mathias R. Jessen for his help on this. Final working code. you will have to analyze the screen output to catch any errors and see which machines it did not catch due to being offline # time of running (some output file items have been commented out since they don't work as intended)
$output = "c:\scripts\results.csv"
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output Start"
cls
$Cred = Get-Credential
$service = Read-Host -Prompt 'Enter Service Name" '
Import-CSV C:\Scripts\computers.csv -Header ComputerName | % {
$computer = $_.ComputerName
Write-Host "Working on $computer"
Add-content -path $output "$computer"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).stopservice()
#Add-content -path $output " Stop - $result"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).ChangeStartMode("Disabled")
#Add-content -path $output " Disable - $result"
}
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output End"
Analyzing results on the screen output, any results with
Just the machine name - means it's processed without error on that machine (success)
RPC server is unavailable means machine is offline
Cannot call a method on Null-Valued expression on line 12 or line 14 means that service doesn't exist on that machine
The results.csv output file will contain list of names of the machines this script was run against

Calling another powershell script with Get-Credentials - Odd result

Edited:
I have a powershell script that calls another script as elevated domain admin which returns an access denied error as follows:
Exception calling "Add" with "1" argument(s): "Access is denied.
"
At \\server\software$\!SystemSetup\PS_Scripts\LocalAdmin.ps1:16 char:5
+ $AdminGroup.Add($User.Path)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : CatchFromBaseAdapterMethodInvokeTI
Using this method to call the script produces the error:
$Cred = Get-Credential
Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile -NoExit -ExecutionPolicy Bypass -File $ScriptLocation" -Credential $Cred
However, If I just right click and run as administrator and enter my domain credentials to call the script (without using $Cred) works fine:
Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile -NoExit -ExecutionPolicy Bypass -File $ScriptLocation"
The script that I am calling looks like this:
$WindowsVersion = Get-WmiObject -Class Win32_OperatingSystem | ForEach-Object -MemberName Caption
If ($WindowsVersion -match 'Microsoft Windows 10 Enterprise') {
$DomainName = "DOMAIN.COM"
$ComputerName = (hostname)
$Username = (Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -ExpandProperty UserName).Split('\')[1]
$AdminGroup = [ADSI]"WinNT://$ComputerName/Administrators,group"
$User = [ADSI]"WinNT://$DomainName/$UserName,user"
$AdminGroup.Add($User.Path)
Write-Host "$Username added to Administrators"
} Elseif ($WindowsVersion -match 'Microsoft Windows 7 Enterprise' -or $WindowsVersion -match 'Microsoft Windows 7 Professional') {
$DomainName = "DOMAIN.COM"
$ComputerName = (hostname)
$Username = (Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty UserName).Split('\')[1]
$AdminGroup = [ADSI]"WinNT://$ComputerName/Administrators,group"
$User = [ADSI]"WinNT://$DomainName/$UserName,user"
$AdminGroup.Add($User.Path)
Write-Host "$Username added to Administrators"
} Else {
Write-Host "Could not determine OS version"
}
I cannot figure out why storing my domain admin credentials in $Cred and passing it to the script gives me the access denied once it gets to $AdminGroup.Add($User.Path)
Going off of TheIncorrigible1's comment, You can add this to your script at the beginning to check if it is running as admin. If it is not, it will relaunch as admin
If (-Not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
$Arguments = "& '" + $MyInvocation.MyCommand.Definition + "'"
Start-Process Powershell -Verb RunAs -ArgumentList $Arguments
Break
}
Then depending on your UAC setting you may be prompted to allow it to run with elevated privilege.

Connect remote server and execute script

I'm trying to connect a remote server and stop a process on it using this PowerShell command
Invoke-Command -ComputerName \\srvwebui3 -ScriptBlock {
Get-Process | Where-Object {
$_.Path -like "\\abd\net$\abd\versions\Bin\HttpServer.exe"
} | Stop-Process
}
but I got this error message after executing it:
Invoke-Command : One or more computer names is not valid. If you are trying to
pass a Uri, use the -ConnectionUri parameter or pass Uri objects instead of
strings.
At C:\powerShell\stop-process.ps1:4 char:15
+ Invoke-Command <<<< -ComputerName \\srvwebui3 -ScriptBlock { Get-Process | Where-Object {$_.Path -like "\\gaia\netlims$\Autolims\MainRls\Bin\HttpServer.exe"} | Stop-Process }
+ CategoryInfo : InvalidArgument: (System.String[]:String[]) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : PSSessionInvalidComputerName,Microsoft.PowerShell.Commands.InvokeCommandCommand
Here a PowerShell code that worked:
Invoke-Command -ComputerName <computerName> -ScriptBlock {
Get-Process | Where-Object {
$_.Path -like \\bbb\abab$\bs\MainRls\Bin\HttpServer.exe"
} |
Stop-Process -Force
}

Powershell Kill all processes except system

In powershell, I would like to kill all processes for all users, except explorer and processes used by the system
This is where I am including the errors that are given:
$Cred = Get-Credential;
Invoke-Command -ComputerName localhost -Credential $Cred -ScriptBlock { Get-Process $env:ALLUSERSPROFILE | Where-Object -FilterScript {$_.Name -ne "SYSTEM, NETWORK SERVICE, LOCAL SERVICE"} | Where-Object -filterscript {$_.Name -ne "explorer"} | Stop-Process -WhatIf }
Cannot find a process with the name "C:\ProgramData". Verify the process name and call the cmdlet again.
+ CategoryInfo : ObjectNotFound: (C:\ProgramData:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
+ PSComputerName : localhost
Here, this should work for you.
Function Stop-UserProcesses{
Param([string]$Computer = "localhost")
$Cred = Get-Credential
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {
Get-Process -IncludeUserName | Where{!($_.UserName -match "NT AUTHORITY\\(?:SYSTEM|(?:LOCAL|NETWORK) SERVICE)") -and !($_.ProcessName -eq "explorer")}|Stop-Process -WhatIf
}
}
Once you are convinced that it is functional remove the -WhatIf. Then just call it as Stop-UserProcesses to end everything locally, or Stop-UserProcesses SomeComputer01 to end everything on a remote system (assuming you have remote sessions enabled in your environment).
Edit: Well then, evidently the -IncludeUserName switch is new in v4. So, in order to do what you want we have to jump through hoops and use Get-WMIObject on the win32_process class, then execute the GetOwner() method for each process. Probably want to filter it so we don't end up with things like Idle throwing errors when they don't have an owner, so we'll make sure that the CommandLine property exists.
Function Stop-UserProcesses{
Param([string]$Computer = "localhost")
$Cred = Get-Credential
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {
#Get all processes
$Processes = get-wmiobject win32_process|Where{![string]::IsNullOrEmpty($_.commandline)}|Select *,#{l='Owner';e={$_.getowner().user}}
#Filter out System and service processes
$Processes = $Processes | Where { !($_.Owner -match "(?:SYSTEM|(?:LOCAL|NETWORK) SERVICE)") }
#Get processes and filter on the Process ID and name = explorer, then pipe to stop-process
Get-Process | Where { $Processes.ProcessID -contains $_.id -and $_.name -ne "explorer" } | Stop-Process -WhatIf
}
}