PowerShell Active Directory Compare with Text file - powershell

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

Related

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.

Passing results to a -like filter in PowerShell

I am trying to create a script to take care of a repetitive task I have. Basically I need to get the person's ID that manages a particular folder.
My first script tells me the various security groups assigned to a specified folder. The second script takes a specified AD group and tells me who manages it. Ideally I want to just run the script, input my folder name and have it tell me who manages the various AD groups assigned. I can then go and do the rest. But I am having an issue with the output of the first script. I have it so it displays in the console correctly, but I cannot figure out how to get those results into the filter in the second script.
Script one:
$FN = Read-Host -Prompt "Please enter Folder name"
$ADG = (Get-Acl $FN).Access |
Select IdentityReference |
Where-Object IdentityReference -like '*SL*'
foreach ($ACL in $ADG) {
$Group.Fullname + ($ACL.IdentityReference.Value.Split('\'))[1] | Out-String
}
Script two:
Get-ADGroup -Filter {Name -like "use output here"} -Properties managedby |
Select managedby
I would be most appreciative of any assistance. ESPECIALLY if I am barking up the wrong PowerShell command! My first foray into using multiple queries in a script.
It's not quite clear to me what the $Group.Fullname + (...)[1] | Out-String is supposed to do, but assuming that you want to run the second command for each identity reference from your first command you could do something like this:
Get-Acl $FN |
Select-Object -Expand Access |
Select-Object -Expand IdentityReference |
Where-Object { $_.Value -like '*SL*' } |
ForEach-Object {
$name = $_.Value.Split('\', 2)[-1]
Get-ADGroup -Filter "Name -like '*${name}*'" -Property ManagedBy
} |
Select-Object -Expand ManagedBy |
Get-ADUser

Using a text file to loop through PowerShell command

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
}

Get-ADUser -Filter fails when comparing to an object's property

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

powershell, Variable: '_' found in expression: $_

I am fairly new to powershell and I am currently employing it to work around a few administration tasks for the Helpdesk.
I have a problem with trying to move an AD object (forgive me if the following terminology is used incorrectly) based on the property of on object from an imported CSV.
The CSV is:
UserPrincipalname,UserToAccess,DaysToLive
joe#company.com,dave#company.com,90
and so on...
I then pass the array through a ForEach loop to move the AD account:
foreach ($line in $import) {Get-ADUser -filter {userPrincipalName -eq $_.UserToAccess} -SearchBase "DistinguishedName of OU" | Move-ADObject -TargetPath 'DistinguishedName of OU'}
Subsequently I am getting the following error:
Get-ADUser : Variable: '' found in expression: $.UserToAccess is not
defined. At D:\jason\EnableArchiveAccess.ps1:17 char:29
+ foreach ($line in $import) {Get-ADUser -filter {userPrincipalName -eq $.UserToA ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADUser], ArgumentException
+ FullyQualifiedErrorId : Variable: '' found in expression: $_.UserToAccess is not defined.,Microsoft.ActiveDirec
tory.Management.Commands.GetADUser
I have been able to use the above logic to unhide users from the GAL and I have checked the array and the properties are there as noteproperties.
I assume it's because I am using not AD variables in the command but any help would be much appreciated but if I find the answer sooner I will post back.
Just looking at that, I think you need to change
$_.UserToAccess
to
$line.UserToAccess
The other alternative would be:
$import | foreach{
Get-ADUser -filter {userPrincipalName -eq $_.UserToAccess} `
-SearchBase "DistinguishedName of OU" `
| Move-ADObject -TargetPath 'DistinguishedName of OU'}
This is one of the common mixups in PowerShell. There are in fact two foreach "keywords". One is alias of the Foreach-Object cmdlet and is used as such:
$Items = 1,2,3
$Items | foreach { $_ }
The $_ in the example means the current object. That is 1 on first pass, 2 on second pass and 3 on the third.
The second foreach is keyword and is used as such
$Items = 1,2,3
foreach ($item in $items) {
$item
}
In this example the $item represents the current object.
So in your example you have to use $list instead of $_.