Powershell script assistance please [duplicate] - windows

This question already has an answer here:
Add a where-object on a table construct?
(1 answer)
Closed 3 years ago.
I'm currently stuck getting a PowerShell error when trying to run a script I have written (Read stolen from the internet)
What I am trying to achieve is to search for a specific users e-mail address within one of the multiple O365 distribution Groups and then remove that user from the group if the group is one that meets the criteria.
The groups are all prefixed with the text "EX_SIG" and I am able to identify the one group the user is a member of but I'm struggling to then translate this into remove the user from the identified group.
I am a complete PowerShell newbie so any help would be appreciated.
Code:
$UAC_email = "sarah.connor#skynet.com"
$UAC_EX_GROUP = Get-DistributionGroup -identity "EX_SIG*" | where { (Get-DistributionGroupMember $_.name | foreach {$_.PrimarySmtpAddress}) -contains "$UAC_email"} | FT name -HideTableHeaders
Remove-DistributionGroupMember -Identity $UAC_EX_GROUP -Member "$UAC_email"
Error:
Cannot bind argument to parameter 'Identity' because it is null.

The FT (Format-Table) cmdlet is likely causing most of your problems. You shouldn't try to use output from formatting cmdlets except with out-* commands.
Format- cmdlets output "typesetting" objects which the host uses to format the display, not usable objects for the pipeline.
$UAC_email = "sarah.connor#skynet.com"
$UAC_EX_GROUP = Get-DistributionGroup -identity "EX_SIG*" | where { (Get-DistributionGroupMember $.name | foreach {$.PrimarySmtpAddress}) -contains "$UAC_email"}
Remove-DistributionGroupMember -Identity $UAC_EX_GROUP -Member "$UAC_email"

Try this as it is a lot cleaner than the code you posted but should accomplish your goal.
$UAC_email = "sarah.connor#skynet.com"
#Get list of distribution groups where identity matches "EX_SIG*" and the email address your looking for is in the list of the group members's primary smtp addresses
$UAC_EX_GROUPS = (Get-DistributionGroup -Identity "EX_SIG*") | Where-Object{(Get-DistributionGroupMember -Identity $_.Name).PrimarySmtpAddress -contains $UAC_email}
#Iterate over returned groups and remove the member from the group. I put a WHATIF in there so you can verify the output before just running it. You can also pipe this directly before the closing '}' in the previous command but it's less readable that way
$UAC_EX_GROUPS | Remove-DistributionGroupMember -Identity $_.Name -Member $UAC_email -WhatIf

Related

How to format CCM_UserAffinity output to tyoe Microsoft.PowerShell.Commands.LocalPrincipal

I am trying to create a deployment script which adds freshly deployed workstation primary users to local admin group. I utilized CCM_userAffinity class to obtain username, however - Add-LocalGroupMember does not accept its output.
Ive tried creating task sequence variable to pass into powershell script which adds to group with no success either. Preferably the solution would be integrated within deployment TS, however due to no success i have reverted to ps package deployment.
$computer = "LocalHost"
$namespace = "root\ccm\Policy\Machine"
$query = "ConsoleUser"
$PrimaryUser = Get-WmiObject -class CCM_UserAffinity -computername $computer -namespace $namespace | select-object $query | format-wide
i expected the output from -class CCM_UserAffinity to be accepted by Add-LocalGroupMember, however i get this instead -
Add-LocalGroupMember : Cannot bind parameter 'Member'. Cannot convert the "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" value of type
"Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" to type "Microsoft.PowerShell.Commands.LocalPrincipal".
As you plan on using the value you retrieve and not displaying it there is no need to use something like "format-wide" which only makes the output human readable and is the reason for your FormatStartData datatype.
You can just use :
$PrimaryUser = (Get-WmiObject -class CCM_UserAffinity -computername $computer -namespace $namespace).ConsoleUser
which returns a string and that is taken by the -Member argument of Add-LocalGroupMember
One thing to keep in mind is that in theory there can be more than one ConsoleUser per machine. So the ConsoleUser might be an Array or not. If you can guarantee that there is always only one user in your environment per machine (at the point where the ts runs) you can just use it as is. Otherwise you would have to specify which user you want to use and I can of course not tell you what a good rule for that for your environment would be.
Also I hope you checked that the WMI class CCM_UserAffinity is already populated at the stage where you want to run this script, I could not tell you if this is the case.

Powershell script: List files with specific change date (Amount if possible)

For license porpuses I try to automate the counting process instead of having to login into every single server, go into directory, search a file name and count the results based on the change date.
Want I'm aiming for:
Running a powershell script every month that checks the directory "C:\Users" for the file "Outlook.pst" recursively. And then filters the result by change date (one month or newer). Then packing this into an email to send to my inbox.
I'm not sure if that's possible, cause I am fairly new to powershell. Would appreciate your help!
It is possible.
I dont know how to start a ps session on a remote computer, but I think the cmdlet Enter-PSSession will do the trick. Or at least it was the first result while searching for "open remote powershell session". If that does not work use the Invoke-Command as suggested by lit to get $outlookFiles as suggested below.
For the rest use this.
$outlookFiles = Get-ChildItem -Path "C:\Users" -Recurse | Where-Object { $_.Name -eq "Outlook.pst" }
Now you have all files that have this name. If you are not familiar with the pipe in powershell it redirects all objects it found with the Get-ChildItem to the next pipe section and here the Where-Object will filter the received objects. If the current object ($_) will pass the condition it is returned by the whole command.
Now you can filter these objects again to only include the latest ones with.
$latestDate = (Get-Date).AddMonths(-1)
$newFiles = $outlookFiles | Where-Object { $_.LastAccessTime -gt $latestDate }
Now you have all the data you want in one object. Now you only have to format this how you like it e.g. you could use $mailBody = $newFiles | Out-String and then use Send-MailMessage -To x#y.z -From r#g.b -Body $mailBodyto send the mail.

Adding bulk Msol Users to Msol Group

I am trying to add a bulk of users from a CSV file to a MsolGroup via PowerShell. I have only the username of the users. (User.name)
This is what I tried:
1. Read the CSV file with the userName and get the Msol user object from it:
$group | % {Get-MsolUser -UserPrincipalName $_.name}
2. Add these ObjectID's to the requested MsolGroup:
$group | % {Get-MsolUser -UserPrincipalName $_.name} | % {Add-MsolGroupMember -GroupObjectId 86bbcf6b-feb6-4fe3-a9db-eb1e0b81ed55 -GroupMemberObjectId $_.objectid
This is the Error I get:
Add-MsolGroupMember : You cannot update mail-enabled groups using this
cmdlet. Use Exchange Online to perform this operation.
Is there a better way to do it? What am I doing wrong?
As noted in the error message, this cmdlet will only work against "regular" security groups. For mail-enabled security groups, use the Exchange remote PowerShell and Add-DistributionGroupMember
Refer documentation
We could use
$group | % {Get-MsolUser -UserPrincipalName $.name} | % {Add-DistributionGroupMember -Identity "86bbcf6b-feb6-4fe3-a9db-eb1e0b81ed55" -Member $.objectid

Why am I getting no output when I try to search for a deleted user in Active Directory through PowerShell?

I am trying to search Active Directory for deleted users with PowerShell, but am unable to return any results even though I have used the -IncludeDeletedObjects parameter. Here is the command that I used:
get-adobject -filter{Name -like "$user"} -includedeletedobjects -properties *
The answer that worked for me is the command below will list all the users that were deleted from the Active Directory if your AD recycle bin is enabled and if you have sufficient privileges on Active Directory
Get-AdObject -Filter 'ObjectClass -eq "user" -and IsDeleted -eq $True' -IncludeDeletedObjects -Properties * | Ft Name,IsDeleted,WhenCreated
If you don't have the AD Recycle Bin enabled, you won't be able to find deleted objects.
If $user is expected to an exact match, you should also be using the -eq operator, not -like. If you want a fuzzy match, -like is correct but you should surround $user with * like so: *${user}*.
If $user is supposed to be the logon name, and not the friendly name of the user, then Name isn't the correct property to filter on, you will want to check against SamAccountName, not Name:
Get-ADObject -Filter "SamAccountName -eq '$user'"
If you are only interested in user objects, and not other AD object types, consider usingGet-ADUser in lieu of Get-ADObject. The syntax for what you specified above is the same, but will guarantee you only get ADUser objects, not ADComputer, ADGroup, etc.
Also, you should avoid using -Properties * and -Filter { ScriptBlock } arguments when using the AD cmdlets. Only use the Properties you need to process later, and use a string based filter like so:
Get-ADObject -Filter "Name -like '*$user*'"
See my answer here for best practices when using the -Filter parameter with AD cmdlets (also explains why not to use -Properties *), and this answer here for more details on why you should not use ScriptBlock parameters for AD filters.

Is there a way to check AD group membership for a computer?

I am trying to check computer group membership through Powershell. I want to be able to specify a certain computer name and find which groups that computer is in but from a Powershell script. I am planning on running the script on a computer, grabbing the hostname, and then printing out what AD groups that computer is in. Is there an easy way to do this?
EDIT:
So the plan here is to have a computer check to see what groups it is in, then assign a printer based on which group it is in. We have many printers that only 3 to 4 people use but due to the spread out nature of the users cannot downsize the amount of printers. I was looking at group policy but did not want to create 20 different GPOs. I wanted to do this with a logon/startup script. I'm not sure if this is doable or feasible.
Edit #2:
This edit it really late to the party but I figured if anyone found this it could help. We ended up using item level targeting on User>Preferences>Control Panel>Printers objects. We made an account in AD for each group of users needing access to the printers. This worked although it did create a long logon process for the first logon of the computer. We also enabled Point-to-Print restrictions so the drivers were loaded from the servers quietly.
This will give you the group membership (group names) of the local computer (requires powershell 2.0):
([adsisearcher]"(&(objectCategory=computer)(cn=$env:COMPUTERNAME))").FindOne().Properties.memberof -replace '^CN=([^,]+).+$','$1'
Apologies if I'm a bit late to the party on this but I needed to find a computer's group membership as well. After a lot of trial and error, this worked for me.
Get-ADComputer "mycomp" -Properties MemberOf | %{if ($_.MemberOf -like "*group name*") {Write-Host "found"} }
I noticed that if the string comparison is on a separate line, I needed to do the following
$g=Get-ADGroupMember -Identity "CN=myADgroup,OU=myOU,DC=corp,DC=com" -server corp.com
foreach($mbr in $g) {if($name.MemberOf -like "*mycomp*" -eq $true) {Write-Host "found"}}
Not sure but I imagine that testing the computer might be faster and easier than testing the group depending on the number of members.
the gpresult method seems to be the only way I can find that is accurate. Querying AD is not accurate since the computer may have been added to groups but not rebooted. I am sure someone could condense this but it worked well enough for what I needed to see.
# Get all active domain servers
$staledate = (Get-Date).AddDays(-90)
$computers = Get-ADComputer -Filter {(OperatingSystem -Like "*Server*") -and (Enabled -eq $True) -and (LastLogonDate -ge $staledate) -and (Modified -ge $staledate) -and (PasswordLastSet -ge $staledate) -and (whenChanged -ge $staledate) -and (Name -notlike "PHXVSSA101A")} | Select name -expandproperty name
$computers = $computers | Where {(Resolve-DNSName $_.name -ea 0) -and (Test-Connection -ComputerName $_.Name -Count 1 -ea 0)} | Sort
# Loop through all active domain servers
Foreach ($computer in $computers)
{
# Pull the gpresult for the current server
$Lines = gpresult /s $computer /v /SCOPE COMPUTER
# Initialize arrays
$cgroups = #()
$dgroups = #()
# Out equals false by default
$Out = $False
# Define start and end lines for the section we want
$start = "The computer is a part of the following security groups"
$end = "Resultant Set Of Policies for Computer"
# Loop through the gpresult output looking for the computer security group section
ForEach ($Line In $Lines)
{
If ($Line -match $start) {$Out = $True}
If ($Out -eq $True) {$cgroups += $Line}
If ($Line -match $end) {Break}
}
# Loop through all the gathered groups and check for Active Directory groups
ForEach ($group in $cgroups)
{
Try {
$check = Get-ADgroup $group -ErrorAction Stop
If ($check) {
$dgroups += $group
}
}
Catch {}
}
# Output server name and any Active Directory groups it is in
$computer
$dgroups
# End of computers loop
}
try running gpresult /V and check under "security GROUPS"
You can also try gpresult /scope computer /v under a command prompt (elevated to admin) for more specific results
Heres an LDAP query to find if a computer is in a group recursively:
(((objectClass=computer)(sAMAccountName=COMPUTERNAME$))(memberof:1.2.840.113556.1.4.1941:=DistinguishedNameOfGroup))
More info: http://justanotheritblog.co.uk/2016/01/27/recursively-check-if-a-usercomputer-is-a-member-of-an-ad-group-with-powershell-2-0/
To check the computer's own view of group membership, you can run:
(New-Object System.Security.Principal.WindowsPrincipal("$env:computername$")).IsInRole('Example Group')
True
Taking the computer out of Example Group doesn't affect the output of the above until the computer is rebooted.
Try this DOS Command, this will return all the local groups this computer belong to :
net localgroup

Resources