I'm trying to generate a list of computers owned by a particular PDL and I'm encountering some syntax issues:
$group = Get-ADGroupMember -Identity "pdl" | Select-Object -ExpandProperty DistinguishedName
Foreach($item in $group) { Get-ADComputer -Filter "ManagedBy -eq "$item"" -Property managedby | Select Name }
The second part is based on another code snippet that I found elsewhere (I think on StackOverflow as well) which worked just fine:
Get-ADComputer -Filter "ManagedBy -eq 'CN=user#company.com,OU=US,OU=Users,OU=Accounts,DC=americas,DC=company,DC=com'" -Property ManagedBy
But the difference is I could use '' in this one, but adding in $item prevents me from using that.
The syntax error I get back with the first snippet:
Get-ADComputer : A positional parameter cannot be found that accepts argument 'CN=user#company.com,OU=US,OU=Users,OU=Accounts,DC=americas,DC=company,DC=com'.
At D:\Documents\Scripts\uatgroup.ps1:2 char:31
+ Foreach($item in $UATgroup) { Get-ADComputer -Filter "ManagedBy -eq "$item"" -Pr ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADComputer], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.ActiveDirectory.Management.Commands.GetADComputer
Anyone know a way to fix the syntax here? Or an alternate method of running this?
This:
"ManagedBy -eq "$item""
Is parsed as three separate strings. Only the first one (ManagedBy -eq) will be bound to the -Filter parameter, the rest will be treated as separate tokens, causing PowerShell to complain that you can't just leave the string CN=... there in the middle of everything.
You can either use single-quotes inside the double-quoted string, to avoid terminating the string early:
Get-ADComputer -Filter "ManagedBy -eq '$item'"
Escape the inline double-quotes with a backtick ( ` ):
Get-ADComputer -Filter "ManagedBy -eq `"$item`""
Or escape them by doubling them:
Get-ADComputer -Filter "ManagedBy -eq ""$item"""
Related
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.
I have a text file test.txt which contains a list of OUs where I need to count the number of users found within each OU.
test.txt:
"ou=MyOU1,dc=Mydomain,dc=net"
"ou=MyOU2,dc=Mydomain,dc=net"
"ou=MyOU3,dc=Mydomain,dc=net"
I am passing this to command in PowerShell:
Get-Content .\test.txt | Out-String | ForEach-Object {
(Get-ADUser -Filter * -SearchBase "$_").Count
}
I'm getting the following error:
Get-ADUser : The supplied distinguishedName must belong to one of the
following partition(s): 'DC=Mydomain,DC=net ,
CN=Configuration,DC=Mydomain,DC=net ,
CN=Schema,CN=Configuration,DC=Mydomain,DC=net ,
DC=ForestDnsZones,DC=Mydomain,DC=net ,
DC=DomainDnsZones,DC=Mydomain,DC=net'.
At line:1 char:62
+ ... ing) | ForEach-Object {(Get-ADUser -Filter * -SearchBase "$_").Count}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADUser], ArgumentException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDirectory.Management.Commands.GetADUser
However, when I run the OU individually, it works.
PS> (Get-ADUser -Filter * -SearchBase "ou=MyOU1,dc=Mydomain,dc=net").Count
10782
Note: Use of Out-String is not only unnecessary in your code, but actually creates a single output string, which causes your command to malfunction, because ForEach-Object is then only called once, with a multi-line string.
Get-Content by itself sends the lines of a text file individually through the pipeline, which is what you want:
Get-Content .\test.txt | foreach-object {
(get-aduser -filter * -searchbase $_).count
}
Note that $_ already is a string, so you needn't enclose it in "...".
Aside from that, if the lines in your file really contain "..."-enclosed strings, as your sample input suggests (probably not, because the error message does not reflect them), and you cannot fix the file itself, you'd have to remove these double quotes, as they otherwise become part of the string that is passed to -SearchBase:
Get-Content .\test.txt | foreach-object {
(get-aduser -filter * -searchbase ($_ -replace '"')).count
}
I am trying to write a script that will import a csv file and update a set of custom attributes that were built into our AD Schema.
Here is the basic code:
Import-Module ActiveDirectory
$USERS = Import-Csv c:\temp\test2.csv
foreach ($user in $users) {
Get-ADComputer -filter {dnsname -eq $user.ComputerName} |
Set-ADComputer -replace #{bSBPrimaryUser = $user.bSBPrimaryUser}
}
Here is my Error Message:
Set-ADComputer : Cannot bind parameter 'Replace' to the target. Exception setting "Replace": "Object reference not set to an instance of an object."
At C:\Users\nwatson\Documents\Update Computers.ps1:7 char:24
Set-ADComputer -replace <<<< #{bSBPrimaryUser = $user.bSBPrimaryUser}}
CategoryInfo : WriteError: (:) [Set-ADComputer], ParameterBindingException
FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.ActiveDirectory.Management.Commands.SetADComputer
For some reason if I write a basic command like below it works, but not in the array.
Set-ADComputer as-001 -replace #{ bSBPrimaryUser = "Joe Smith";}
First, the property you are looking for isn't dnsname but dnshostname or name. (If just using name, then skip using filter and pass it in as the identity)
Second, the filters on the AD cmdlets aren't straight forward. If using curly braces, then you can't use an expression. Double quotes then single quotes seems to work fine though.
Get-ADComputer -filter "dnshostname -eq '$($user.ComputerName)'"
Alternatively, define the expression as a variable.
$ComputerName = $user.ComputerName
Get-ADComputer -filter {dnshostname -eq $Computername}
I am trying to pull together a PS script to automatically add computers to a security group that are not part of another group.
In this case, add all computers to group_b that are not part of group_a.
This is what I tried..
#get list of computers from group_a
$tpmobjects = Get-ADGroupMember -Identity "group_a" | Select name
#add computers to group_b that are not in group_a
Get-ADComputer -Filter {SamAccountName -notlike $tpmobjects} | Foreach-Object { Add-ADPrincipalGroupMembership -Identity $_.SamAccountName -MemberOf "group_b" }
The error I get is...
Get-ADComputer : Type: 'System.Object[]' is not supported for extended attribute 'SamAccountName'.
At line:2 char:1
+ Get-ADComputer -Filter {SamAccountName -notlike $tpmobjects}...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADComputer], ArgumentException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDirectory.Management.Commands.GetADComputer
Anyone have a way to do this?
Thanks.
What happens is that Get-ADGroupMember returns multiple objects and the -Filter parameter doesn't support matching against multiple objects.
There are multiple ways around this, but the easiest is to simply filter the output from Get-ADGroupMember with Where-Object:
$Computers = Get-ADGroupMember group_a |Where-Object {$_.objectClass -eq 'computer'}
You also don't need to wrap Add-ADPrincipalGroupMembership in ForEach-Object, it accepts pipeline input, and an ADComputer object can be bound to the -Identity parameter directly without problems:
$Computers |Add-ADPrincipalGroupMembership -MemberOf group_a
I have a powershell question that has to do with importing a csv file, then going through a foreach through the csv file.
I have something like the following:
$infile = "c:\temp\infile.csv"
$outfile = "c:\temp\outfile.csv"
$csv = Import-csv -path $infile
foreach ($line in $csv)
{
$data = Get-ADUser -Filter {EmailAddress -eq $line.email} -Property Mail | Select-Object -ExpandProperty SamAccountName
}
When I do something like that, I get the following error:
Get-ADUser : Property: 'email' not found in object of type: 'System.Management.Automation.PSCustomObject'.
At C:\Temp\program1.ps1:11 char:24
+ $ad_data = Get-ADUser <<<< -Filter {EmailAddress -eq $line.email} -Property Mail | Select-Object -ExpandProperty SamAccountName
+ CategoryInfo : InvalidArgument: (:) [Get-ADUser], ArgumentException
+ FullyQualifiedErrorId : Property: 'email' not found in object of type: 'System.Management.Automation.PSCustomObject'.,Microsoft.ActiveDirectory.Management.Commands.GetADUser
But if I do something like:
$var = $line.email
$data = Get-ADUser -Filter {EmailAddress -eq $var} -Property Mail | Select-Object -ExpandProperty SamAccountName
Why does the second method works but the first method throws an error?
Thanks,
Alright, I had a discussion with some of my fellow PowerShell MVPs, and the answer as to why is really quite interesting.
For the quick answer, this is how you do get the AD User while preserving the structure of your code:
Get-ADUser -Filter "Emailaddress -eq '$($line.email)'"
You can quickly test to see what is happening by just running the quoted code on its own:
"Emailaddress -eq '$($line.email)'"
>Emailaddress -eq 'Jim.Adkison#foxdeploy.com'
As to why, well, the outside set of quotes always wins in PowerShell, and the *-ADUser -Filter Cmdlets expect the value to be provided in single quotes.
According to Dave Wyatt, PowerShell MVP and all around cool guy and Mike Robbins, also MVP and well-respected around the community, the way that the ADUser Cmdlets expand variables is somewhat unstandard when compared to the rest of PowerShell's code base. They described the action of Variable expansion as 'strange voodoo', which seems about right.
If you'd like to learn a little bit more, follow up on Mike's awesomely detailed blog post on just this type of scenario PowerShell: When Best Practices and Accurate Results Collide
What if you use a subexpression in the filter?
Get-ADUser -Filter {EmailAddress -eq $($line.email)}
From the error, it isn't properly calling your object inside the filter.
For more testing, what is the object type of $line?
$line | Get-Member