Using a text file to loop through PowerShell command - powershell

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
}

Related

Cannot Search AD from CSV using Powershell

Trying to search AD account properties pulling from a CSV. The Import-CSV line works by itself. I cannot for the life of me figure out why it is asking for a filter. I took this from another script I found where they said it worked. Others were using a For-Each statement.
PS C:\Users\XXXXX> Import-CSV .\listofnames.csv | Get-ADUser $_.DisplayName -properties displayname
Get-ADUser : Cannot validate argument on parameter 'Identity'. The argument is null or an element of the argument
collection contains a null value.
At line:1 char:43
+ Import-CSV .\listofnames.csv | Get-ADUser $_.DisplayName -properties ...
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-ADUser], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.GetADUser
Its prompting you for the 'Identity' because that is how it identifies what user you are searching for.
Try this:
$users = get-content C:\Temp\test.csv
foreach ($user in $users){Get-ADUser -Identity $user -Properties displayname}
The CSV file just has the user IDs for the users who you would like to find info for.
Or if you can try the following:
Import-Csv C:\Temp\users.csv | ForEach-Object { Get-ADUser -identity $_.Name -Properties displayname }

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 use the variable to replace the Object/OU Path with LDAPFilter in Powershell

I am trying to retrieve the membership for a specific office of one specific security group in our working environment, instead of Get-ADGroupMember which is slow and always get time-out when there is a huge user list.
My code is as below:
Import-module ActiveDirectory
**$groupinfo** = Get-ADGroup -identity "vip"
Get-ADuser -LDAPFilter '(&(objectcategory=user)(memberof='**$groupinfo.DistinguishedName**'))' -Properties office,title | where {$_.office -like 'New York'} | select name,samaccountname,office,title |Export-csv -NoTypeInformation c:\tmp\NY.csv -Delimiter ";"
I get the following error
Get-ADUser : A positional parameter cannot be found that accepts argument '**CN=vip,OU=Groups,DC=contoso,DC=com**'.
At line:2 char:2
+ Get-ADuser -LDAPFilter '(&(objectcategory=user)(memberof='$group.Dis ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADUser], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.ActiveDirectory.Management.Commands.GetADUser
Can anyone advise me how to use this variable $groupinfo in LDAPFilter?
Do I need a junction?
Get-ADuser -LDAPFilter '(&(objectcategory=user)(memberof=**CN=vip,OU=Groups,DC=contoso,DC=com**))' -Properties office,title | where {$_.office -like 'New York'} | select name,samaccountname,office,title |Export-csv -NoTypeInformation c:\tmp\NY.csv -Delimiter ";"
This one does work when no variable.
If you use double-quotes around the LDAPFilter, the content of the variable is used instead of the variable name literal.
Try:
Get-ADuser -LDAPFilter "(&(objectCategory=person)(objectClass=user)(memberOf=$($groupinfo.DistinguishedName)))" -Properties office,title |
Where-Object {$_.office -like '*New York*'} |
Select-Object name,samaccountname,office,title |
Export-Csv -NoTypeInformation c:\tmp\NY.csv -Delimiter ";"
Note: I have not tried to put all this in a single ling, because doing that just askes for mistakes that are hard to spot. Also, I changed (objectcategory=user) to (objectCategory=person)(objectClass=user) to make sure only user objects are returned. See Filter on objectCategory and objectClasO

PowerShell Active Directory Compare with Text file

I am trying to make a script that compares a list of asset tags in a text file with the computer names in AD, and generate the Description. Exporting it to CSV will come later. As of now though, while the code does work, it gives the following error message. Our computers in AD starts with either L or D, which states whether it's a laptop or desktop, but the list we receive does not contain the L or D in it, which is why you see me putting the "L" + "D" at the front. Is there a better way of doing this?
Code:
Import-Module ActiveDirectory
foreach ($line in Get-Content ComputerNames.txt) {
if($line -match $regex) {
$laptop = "L" + $line
$desktop = "D" + $line
get-ADComputer $laptop -Properties * |select Description
#get-ADComputer $desktop -Properties * |select Description -ErrorAction Ignore }
}
Error:
get-ADComputer : Cannot find an object with identity: 'LD7MWQ12' under: 'DC=ap,DC=o-i,DC=intra'.
At line:9 char:9
+ get-ADComputer $laptop -Properties * |select Description
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (LD7MWQ12:ADComputer) [Get-ADComputer], ADIdentityNotFoundException
+ FullyQualifiedErrorId : Cannot find an object with identity: 'LD7MWQ12' under: 'DC=ap,DC=o-i,DC=intra'.,Microsoft.ActiveDirectory.Management.Com
mands.GetADComputer
Probably a more efficient way to do this But the below works:
Import-Module ActiveDirectory
foreach ($line in Get-Content ComputerNames.txt) {
Get-ADComputer -Filter * -Property Description | Where {$_.samaccountname -Like "*$line"} | select Description
}
For every line in the computernames.txt object it will go and find the AD Object that is like the $line variable and then select the Description for that object
The slow bit is going to be the network link to AD, you really only want to do that once if possible. Unless you have huge numbers of computers in AD, it would be better to pull down all the computers and then compare them locally against the text file.
Also if you're pulling information from AD, don't bring any more than you need, the network traffic and memory overhead is wasted, so instead of Properties *, just add in the description
Import-Module ActiveDirectory
# AD query which will get all computers with names starting D or L
$ADFilter = "Name -like 'D*' -or Name -like 'L*'"
$ADComputers = Get-ADComputer -filter $ADFilter -Properties Description | Select Name, Description
$NamesFromFile = Get-Content ComputerNames.Txt
# Filter the AD Computers where the name without the first character is
# mentioned in the file
$ADComputers | Where-Object { $_.Name.SubString(1) -in $NamesFromFile } | Export-Csv -NoTypeInformation out.csv

How to query ManagedBy property of ADComputer in a Foreach loop?

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"""