Powershell ForEach-Object : Cannot bind parameter - powershell

I am trying to get the OWNER of a process, code :
(Get-WmiObject -class win32_process | where{$_.ProcessName -eq 'explorer.exe'}).getowner() | Foreach-Object user | out-string**
This works great under win8 but in win7 I get this msg :
ForEach-Object : Cannot bind parameter 'Process'. Cannot convert the "user" val
ue of type "System.String" to type "System.Management.Automation.ScriptBlock".
At C:\Program Files (x86)\Advanced Monitoring Agent GP\scripts\9660.ps1:1 char:
108
+ (Get-WmiObject -class win32_process | where{$_.ProcessName -eq 'explorer.exe'
}).getowner() | Foreach-Object <<<< user | out-string
+ CategoryInfo : InvalidArgument: (:) [ForEach-Object], Parameter
BindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerSh
ell.Commands.ForEachObjectCommand
Help please! Thank you for the time.

Instead of foreach-object user, use select -expand user. This is equivalent to doing foreach-object { $_.user } which is probably what you meant to do. Improvements to flexibility in the grammar allow your first attempt in later versions of powershell.

The older version of Powershell won't work with the simplified syntax. This should work on either one:
(Get-WmiObject -class win32_process |
where{$_.ProcessName -eq 'explorer.exe'}).getowner() |
Foreach-Object { $_.user | out-string }

(Get-WmiObject -class win32_process | where{$_.ProcessName -eq 'explorer.exe'}).getowner() | select user

I had a similar problem but in my case, there was a non-printable character in my script that appeared after one of the }'s. ASCII code 03. I found that by opening the script in a binary editor (Textpad8). I deleted this character and it fixed the problem for me.

Related

PowerShell Script to pull servers in AD and then search SERVICES running under the Local Administrator account

New to PowerShell, attempting to cobble scripts together to:
Pull a list of Servers in Active Directory (done).
Query each server for a list of SERVICE accounts running under ADMINISTATOR credentials.
Can anyone guide me...prefer to export out to a CSV file, etc.
THANK YOU!
THIS IS WHAT I HAVE:
Import-Module ActiveDirectory
$Serverlist = Get-ADComputer -Filter 'operatingsystem -like "*server*" -and enabled -eq "true"' `
-Properties Name
Sort-Object -Property Name |
foreach ($Server in $Serverlist) {
$Server
Get-WmiObject Win32-Service | Select DisplayName, StartName | Where-Object {$_.StartName -eq "administrator"}
GETTING THESE ERRORS:
At line:5 char:18
+ foreach ($Server in $Serverlist) {
+ ~~
Unexpected token 'in' in expression or statement.
At line:5 char:17
+ foreach ($Server in $Serverlist) {
+ ~
Missing closing ')' in expression.
At line:5 char:32
+ foreach ($Server in $Serverlist) {
+ ~
Unexpected token ')' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
Assuming you have permissions to remotely query those hosts you can try the following:
$computers = (Get-ADComputer -Filter 'operatingsystem -like "*server*" -and enabled -eq "true"').DNSHostName
Get-CimInstance Win32_Service -Filter "StartName LIKE '%Administrator%'" -ComputerName $computers
| Select-Object DisplayName, StartName, PSComputerName
Notes
Get-CimInstance and Get-WmiObject (replaced in this example, since its no longer maintained in new PowerShell versions) can invoke queries in parallel, hence no loop is required.
Both cmdlets allow queries with WQL. Faster filtering this way than with powershell.
Only real reason to use Get-WmiObject instead of Get-CimInstance could be if using DCOM as your remoting protocol. At which point you could use New-CimSessionOption -Protocol DCOM and connect using a CimSession. Functionality for both cmdlets is mostly the same.
You should include PSComputerName in your Select-Object statement to understand from which computer the object is coming from.

Powershell invoke-expression doesn't work with filter switch

I'm trying to write a program that lets users to do different kinds of queries on Active Directory. I want to make it in a way that lets them to chose which attributes they want to show in the output, and also filter the output in several ways.
As I don't know during writing the code how many attributes they will chose, it seemd the easiest way to produce a string out of the attributelist, and invoke the string with invoke-expression. This way works perfectly with attributes, but not at all with filters.
I've found several kinds of filter syntaxes but neither works when I put them in a string and try to invoke that with "Invoke-expression"
This:
$time = (Get-Date).Adddays(-(19))
Get-ADUser -Filter {LastLogonTimeStamp -gt $time} -SearchBase 'CN=Users,DC=home,DC=local' -Properties samAccountname, LastLogonDate | Select-Object #{n='Felhasználónév'; e='samAccountName'}, #{n='Utolsó bejelentkezés'; e='LastLogonDate'} | Out-String
Gives me the result I want.
While this:
$time = (Get-Date).Adddays(-(19))
$out = "Get-ADUser -Filter {LastLogonTimeStamp -gt $time} -SearchBase 'CN=Users,DC=home,DC=local' -Properties samAccountname, LastLogonDate | Select-Object #{n='Felhasználónév'; e='samAccountName'}, #{n='Utolsó bejelentkezés'; e='LastLogonDate'} | Out-String"
Write-Host $out
Invoke-Expression $out
Gives me the following result:
Get-ADUser -Filter {LastLogonTimeStamp -gt 05/05/2019 19:05:46} -SearchBase 'OU=Testing,DC=home,DC=local' -Properties samAccountname, LastLogonDate | Select-Object #{n='Username'; e='samAccountName'}, #{n='Last Logon'; e='LastLogonDat
e'}
Get-ADUser : Error parsing query: 'LastLogonTimeStamp -gt 05/05/2019 19:05:46' Error Message: 'Operator Not supported: ' at
position: '26'.
At line:1 char:1
+ Get-ADUser -Filter {LastLogonTimeStamp -gt 05/05/2019 19:05:46} -Sear ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ParserError: (:) [Get-ADUser], ADFilterParsingException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADFilterParsingException,Microsoft
.ActiveDirectory.Management.Commands.GetADUser
Why does every other command works perfectly when invoking them from a string, but not this one? Is there any other way to filter the result? At first I wanna stick to filtering before the query, and not with the where clause, but I'm gonna try that too, if filtering won't work.
It feels stupid to answer my own question, but I think I found the answer.
Placing escape character before the variable did the trick.
$time = (Get-Date).Adddays(-(19))
$out = "Get-ADUser -Filter {lastlogontimestamp -gt `$time} -SearchBase 'CN=Users,DC=home,DC=local' -Properties samAccountname, LastLogonDate | Select-Object #{n='Felhasználónév'; e='samAccountName'}, #{n='Utolsó bejelentkezés'; e='LastLogonDate'} | Out-String"
Write-Host $out
$expr = Invoke-Expression $out
$expr
Returns
Felhasználónév Utolsó bejelentkezés
-------------- --------------------
Administrator 2019. 05. 24. 18:18:28
I had a similar situation, but mine was specific to $true $false parameters that are $true if present, $false if absent for [switch] type [params]. I had never needed to override the default params, because those were originally intended for single-use/manual invocation from the command line.
Invoke-Expression simplified calling .ps1 files as subroutines, but this would work directly from the command line console
\temp\00405-LoadW.ps1 -skipinit -showbanner:$false | Out-File -filepath 'c:\temp\today\00405-LoadW.log'
while this would not work when called inside a .ps1 file:
Invoke-Expression "\temp\00405-LoadW.ps1 -skipinit -showbanner:$false | Out-File -filepath 'c:\temp\today\00405-LoadW.log'"
This post (directly above) has the solution, the back-tick
`
This works both on the command console and from inside a .ps1:
Invoke-Expression "\temp\00405-LoadW.ps1 -skipinit -showbanner:`$false | Out-File -filepath 'c:\temp\today\00405-LoadW.log'"
PS: More time spent on figuring out how to escape the back-tick here than the actual answer.

How To Ignore Error In Powershell Script (ErrorAction: SilentlyContinue not suppressing error)

I have a Powershell script that lists all the users/groups in the local administrators group for all computers in a designated OU in Active Directory.
The script works perfectly locally (if I run it against the local machine only) but when I run it against remote machines, it technically works but it throws a consistent error that I don't know how to filter out.
Here is the script (NOTE: must be running from ActiveDirectory PS console to use Get-ADComputer):
Get-ADComputer -SearchBase 'OU=ou01,dc=domain,dc=local' -Filter 'ObjectClass -eq "Computer"' `
| ForEach-Object {
Get-WmiObject win32_groupuser -cn $_.name -ErrorAction SilentlyContinue `
| Where-Object { $_.groupcomponent -match 'administrators' } `
| ForEach-Object -ErrorAction SilentlyContinue {[wmi]$_.partcomponent } `
| Select-Object __SERVER,Caption
} | Format-Table -Property * -AutoSize
Here are the results (correct result is in first line, error below that):
__SERVER Caption
-------- -------
workstation_name workstation_name\Administrator
Cannot convert value "\\workstation_name\root\cimv2:Win32_Group.Domain="DOMAIN",Name="Domain Admins"" to type "System.Management.ManagementObject". Error: "Not found "
At line:1 char:306
+ Get-ADComputer -SearchBase 'OU=ou01,dc=domain,dc=local' -Filter 'ObjectClass -eq "Computer"' | ForEach-Object { Get-WmiObject win32_groupuser -cn $_.name -ErrorAction SilentlyContinue | Where-Object { $_.groupcomponent -match 'administrators' } | ForEach-Object -ErrorAction SilentlyContinue {[wmi]$_. <<<< partcomponent } | Select-Object __SERVER,Caption } | Format-Table -Property * -AutoSize
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
I have unsuccessfully tried to use -ErrorAction SilentlyContinue, is there another way to suppress this message? Not sure what I am missing.

Running a powershell script against all the computers in Active Directory

I have written a script that generates some information but I need to run it on over 160 computers in an active directory. I don't want to run this script on each machine individually, is there any way of executing this script all all the machines from one centralized location?
invoke-command -ComputerName test-pc -ScriptBlock {gwmi win32_service | Select-object Name, PathName | where-object {$_.PathName -notlike '"*' -and $_.PathName -like "*\* *\*"}}
I don't want to be logging on to each machine individually. Is there quicker way? There must be.
Any help will be much appreciated.
Sohail.
Updated version:
invoke-command -ComputerName #(Get-ADComputer -Filter {Name -like "GBST*"} | Select-Object Name) -ScriptBlock {gwmi win32_service | Select-object Name, PathName | where-object {$_.PathName -notlike '"*' -and $_.PathName -like "*\* *\*"}}
Error message:
invoke-command : One or more computer names are not valid. If you are trying to pass a URI, use the -ConnectionUri parameter, or pass URI objects
instead of strings.
At line:1 char:2
+ invoke-command -ComputerName #(Get-ADComputer -filter {Name -like "GBSU1*"} | S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.String[]:String[]) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : PSSessionInvalidComputerName,Microsoft.PowerShell.Commands.InvokeCommandCommand
Just to make it shorter :
(Get-ADComputer -Filter 'Name -like "GBSU*"').Name | % {
Get-WMIObject Win32_Service |
Select-Object Name, PathName |
Where-Object { $_.PathName -notlike '"*' -and $_.PathName -like "** **" }
}
As pointed out by #bluuf :
This is actually not a 'good' solution since Get-WmiObject supports
the ComputerName parameter : Invoke-Command shouldn't be used at all
in this case.
There is a syntax error in your revised example where you kept the "*" in the Filter. You can't filter for all then narrow your results. Asterisk is implied when filtering based on properties.
I also added the ".Name" property to the computer search to only pass that to the invoke-command section. I tried the following code and it seemed to work.
invoke-command -ComputerName #((Get-ADComputer -Filter 'Name -like "GBST*"').Name) -ScriptBlock {gwmi win32_service | Select-object Name, PathName | where-object {$_.PathName -notlike 'C:\Windows\system32\*' -and $_.PathName -like 'C:\Program Files\*'}}

Error on win32_userprofile delete method?

I'm attempting to create a script that cleans up temporary profiles on a 2008-R2 server.
Weird thing is I'm positive I had this working fine before our holiday, now the script doesn't work after said holiday :(.
The script:
$keys = ls "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*.bak"
foreach ($key in $keys){
$sid = $key.name | select-string -Pattern 'S-\d-\d+-(\d+-){1,14}\d+' | out-string
$sid = ($sid).Split('\')[6]
$sid = ($sid).Split('.')[0]
$profile = get-wmiobject win32_userprofile -computername localhost | where-object {$_.SID -eq $sid}
$profile.Delete()
}
If I run that, or any form of modification of that delete method, I get:
Exception calling "Delete" with "0" argument(s): ""
At C:\temp\remove_temp_profiles.ps1:7 char:18
($profile).Delete <<<< ()
CategoryInfo : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : DotNetMethodException
If I run a:
get-wmiobject win32_userprofile | get-member
I can see that the delete method is not there. It's supposedly "hidden" whatever that means.
Apart from the delete not working, the rest of the script works perfectly (regex is another battle haha!)
I've also instead attempted to use remove-wmiobject instead. However it causes errors with:
Remove-WmiObject :
At C:\temp\remove_temp_profiles.ps1:7 char:28
+ $profile | remove-wmiobject <<<<
+ CategoryInfo : InvalidOperation: (:) [Remove-WmiObject], COMException
+ FullyQualifiedErrorId : RemoveWMICOMException,Microsoft.PowerShell.Commands.RemoveWmiObject
I've spent ages and ages googling and trying different things, and all of the solutions appear to be "use the $variable.Delete() and it works fine". I don't know how to program (only basic scripting) so apologies for my newness.
This could be because the profile is still considered to be loaded. You can verify this by looking at the loaded property. You should also look at using the -Filter parameter instead of piping everything to Where-Object.
$keys = ls "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*.bak"
foreach ($key in $keys){
$sid = $key.name | select-string -Pattern 'S-\d-\d+-(\d+-){1,14}\d+' | out-string
$sid = ($sid).Split('\')[6]
$sid = ($sid).Split('.')[0]
$profile = get-wmiobject win32_userprofile -computername localhost -Filter "SID -eq '$sid' AND NOT Loaded='True'"
$profile.Delete()
}
If you just want to see if profiles are still loaded:
Get-WMIObject win32_userprofile -computername localhost -Filter "Loaded='True'" |
Select SID,LocalPath,Loaded