I have this great powershell script I wrote a while back which copy's the users from one Active Directory Group to Another. I need to log the results of each screen output so I have a log of what the script did should there ever be a problem. I would like to write the output to C:\Temp\CopyLog.txt but I can't figure out how to get it to work correctly. I have tried Add-Content and out-file but they don't seem to like me.
Import-Module activedirectory
$string = Get-Content C:\Temp\GroupsToCopy.txt
foreach($i in $string)
{
$split = $i.split(";")
$Source_Group = $split[0]
$Destination_Group = $split[1]
"***Results before script***"
"Current Member's of: $Source_Group"
Get-ADGroupMember $Source_Group | select name | ft -hide
"`n"
"Current Member's of: $Destination_Group"
$Source = Get-ADGroupMember $Source_Group | select name | ft -hide
$DST = Get-ADGroupMember $Destination_Group
if ($DST -eq $null)
{
"Group has no members"
}
else
{
Get-ADGroupMember $Destination_Group | select name | ft -hide
}
$Target = Get-ADGroupMember $Source_Group
foreach ($Person in $Target)
{
Add-ADGroupMember $Destination_Group -Members $Person.distinguishedname
}
"`n"
"***Results after script***"
"`n"
"Current Member's of: $Source_Group"
Get-ADGroupMember $Source_Group | select name | ft -hide
"`n"
"Current Member's of: $Destination_Group"
Get-ADGroupMember $Destination_Group | select name | ft -hide
"`n"
}
Use Start-Transcript:
Start-Transcript -Path C:\Temp\CopyLog.txt -Append
# Rest of script goes here
Stop-Transcript
Related
Using PowerShell I retrieve information from multiple ActiveDirectory groups and output it to a single CSV file. To each row I want to add the name of the group, in addition to the information retrieved. How can I achieve this?
Desired Result:
"CN","Department","co","Company","Group"
"ABCDEF","Media","UK","Global Entertainment","XXX"
Current Result:
"CN","Department","co","Company"
"ABCDEF","Media","UK","Global Entertainment"
My PowerShell code:
#Roles to check membership for
$Roles= #(
'XXX'
'YYY'
)
$FolderName = "C:\"
$OutputAD = #()
foreach ($role in $Roles) {
$GroupMembers = Get-ADGroupMember -identity $role | select name
$GroupMembersArray = $GroupMembers | Foreach {"$($_.Name)"}
$GroupMembersArray | ForEach-Object {
$UserLookup = Get-ADUser -Filter "Name -eq '$_'" -Properties CN,Department,co,Company | Select-Object CN,Department,co,Company
$OutputAD += $UserLookup
}
}
$OutputAD | Export-Csv "$FolderName\Membership $(get-date -Format yyyy-MMM-dd-HH-mm-ss).csv" -NoTypeInformation
Found the solution. In Select-Object you can add a calculated property.
Example: Select-Object CN,Department,co,Company,#{n='Role';e={$role}}
I am running the below script and it is causing exception of type 'system.outofmemoryexception' was thrown
I believe that it is due to the #Results array growing past the 2gb allocated to windows shell. Is there possibly a way to iterate through the results, or am I stuck with allocating more memory (which could ultimately be a lot...)?
$Path = "path to output"
### Get all PF
$publicFolders = Get-PublicFolder "Public Folder Name" -Recurse -resultsize unlimited | Select-Object *
### Array to contain results
$results = #()
###Begin looping through each PF and grab each user/group with AccessRights to that folder
$final = ForEach($pf in $publicFolders){
$perms = Get-PublicFolderClientPermission -Identity $pf.Identity | Where-Object {$_.User -notmatch "Default|Anonymous|S-X-X-XX"}
Foreach($perm in $perms){
$temp = [PSCustomObject]#{
MailFolderName = $pf.Identity
UserWithPerms = $perm.User
AccessRights = $perm | Select-Object -ExpandProperty AccessRights
}
$results += $temp
}
}
$final | Export-Csv $path -NoTypeInformation
Am I barking up the wrong tree?
Thanks in advance.
Use the ForEach-Object cmdlet instead of a foreach(){} loop statement for the outer loop - this way you can start piping the output to Export-Csv immediately instead of buffering it in an array:
$publicFolders |ForEach-Object {
$pf = $_
$perms = Get-PublicFolderClientPermission -Identity $pf.Identity | Where-Object {$_.User -notmatch "Default|Anonymous|S-X-X-XX"}
Foreach($perm in $perms){
[PSCustomObject]#{
MailFolderName = $pf.Identity
UserWithPerms = $perm.User
AccessRights = $perm | Select-Object -ExpandProperty AccessRights
}
}
} | Export-Csv $path -NoTypeInformation
Alternatively, flush the partial set of results to file after enumerating the permissions for each folder:
ForEach($pf in $publicFolders){
$perms = Get-PublicFolderClientPermission -Identity $pf.Identity | Where-Object {$_.User -notmatch "Default|Anonymous|S-X-X-XX"}
$results = Foreach($perm in $perms){
[PSCustomObject]#{
MailFolderName = $pf.Identity
UserWithPerms = $perm.User
AccessRights = $perm | Select-Object -ExpandProperty AccessRights
}
}
# flush the buffer before moving to the next set of permissions
$results |Export-Csv $path -NoTypeInformation -Append
}
I am trying to fetch the AD group members information through power shell. But I am getting the messages as
Export-Csv : Cannot bind argument to parameter 'InputObject' because it is null.
Import-Module ActiveDirectory
$Path = Get-Location
$GroupName = Read-Host "Type the Group Name to check the members in it`t "
foreach ($group in $GroupName) {
$users = #{}
Get-ADUser -Filter '*' -Property Name, DisplayName | ForEach-Object {
$users[$_.DistinguishedName] = $_
}
$MemberCount = (Get-ADGroup $group -Properties Member | Select-Object -Expand Member).Count
Write-Host "`t Total Number of Users/Groups added on this Group : $MemberCount" -BackgroundColor DarkCyan
$Info = Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
ForEach-Object { $users[$_] }
$Info | Export-Csv -NoTypeInformation -Append -Force $Path\new.csv
The error means that $Info contains empty/null values. The most likely reason for their presence is that the group has members that aren't returned by Get-ADUser.
You can avoid the issue by checking for the presence of the key in the $users hashtable:
$Info = Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
ForEach-Object { if ($users.ContainsKey($_) {$users[$_]} }
If you want to further investigate the missing distinguished names you could collect them like this:
$missing = Get-ADGroup $group -Properties Member |
Select-Object -Expand Member |
ForEach-Object { if (-not $users.ContainsKey($_) {$_} }
I want to specify a source user and capture the list of the groups that user belongs to. I want to then specify a second user and have the original captured groups added to the new users account.
If user1 is a member of GroupA, GroupB, GroupC I want the script to capture that and add it to user3 when I type his name.
Import-Module ActiveDirectory
$SourceUser = Read-Host -Prompt 'Enter the username of the user whos groups you would like to copy'
$DestUser = Read-Host -Prompt "Enter the username of the user who will get: $SourceUser groups"
$SourceGroups = Get-ADUser $SourceUser -Property MemberOf | % {
$_.MemberOf | Get-ADGroup | select Name | sort name
}
"List of groups for user $DestUser BEFORE script: "
Get-ADUser $DestUser -Property MemberOf | % {
$_.MemberOf | Get-ADGroup | select Name | sort name
}
# ***Where my problem is***
#Add-ADGroupMember $SourceGroups –Member $DestUser
"List of groups for user $DestUser AFTER script: "
Get-ADUser -Identity $DestUser -Property MemberOf | % {
$_.MemberOf | Get-ADGroup | select Name | sort name
}
When in doubt, read the documentation.
Syntax
Add-ADGroupMember [-Identity] <ADGroup> [-Members] <ADPrincipal[]> ...
The -Identity parameter (the first argument) takes a single group identity, not a list of identities. To add a user to a list of groups you need a loop:
$SourceGroups | ForEach-Object { Add-ADGroupMember $_ –Member $DestUser }
Here is the corrected code that now works.
$T2FolderExists = Test-Path "C:\T2\"
$LogsFolderExists = Test-Path "C:\T2\Logs\"
IF ($T2FolderExists -eq $False)
{
New-Item C:\T2\ -type directory
IF ($LogsFolderExists -eq $False)
{
New-Item C:\T2\Logs\ -type directory
}
ELSE
{
}
"`n"
Start-Transcript -Path C:\T2\Logs\CopyMembershipFromADAccount.txt -Append
"`n"
}
ELSE
{
"`n"
Start-Transcript -Path C:\T2\Logs\CopyMembershipFromADAccount.txt -Append
"`n"
}
<#*****Session Paramaters*****>
Set-ExecutionPolicy Unrestricted -force
Import-Module ActiveDirectory
Clear-Host
Write-Host "Enter the username of the user whos groups you would like to copy" -foregroundcolor Green -backgroundcolor Black
$SourceUser = Read-Host
"`n"
Write-Host "Enter the username of the user who will get: $SourceUser groups" -foregroundcolor Green -backgroundcolor Black
$DestUser = Read-Host
"`n"
$SourceGroups = Get-ADUser $SourceUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n`n"
Write-Host "List of groups for user $SourceUser BEFORE script: "
Get-ADUser $SourceUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n`n"
Write-Host "List of groups for user $DestUser BEFORE script: "
Get-ADUser $DestUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n`n"
ForEach ($Group in $SourceGroups)
{
Add-ADGroupMember $Group –Member $DestUser
Write-Host "Adding $Group to $DestUser 's Account" -foregroundcolor Cyan -backgroundcolor Black
}
"`n`n"
Write-Host "List of groups for user $SourceUser BEFORE script: "
Get-ADUser $SourceUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n`n"
Write-Host "List of groups for user $DestUser AFTER script: "
Get-ADUser $DestUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n"
Stop-Transcript
Exit
This is what I did:
Import-Module ActiveDirectory
Import-CSV "data.csv" -Delimiter ";" |
ForEach {`
$_.Group1,$_.Group2,$_.Group3,$_.Group4,$_.Group5,$_.Group6 |
Add-ADGroupMember `
-Members $_.Alias`
}
You can have more groups in the script without using them.
And in the "data.csv", you put this (for example):
Alias;Group1;Group2;Group3;Group4
l.salvador;Spanish;Republic;Central;WWW
Although I had an error with "Identity" could not be checked, it worked.
I've imported a CSV file into an array and grouped it by email address. I'd like to be able to call the group by name in another ForEach loop so that I can send an email to each email address with a table of the $ServerID(s) and $DateTime(s) associated with them. Was Group-Object the best way to start this?
In the CSV file, one email address can be associated with many servers, but one server is only associated with one email address. The values in the file will be updated constantly - thus the need for dynamic variables for almost all objects.
$csv = import-csv "C:Example.csv"
$array = #()
ForEach ($server in $csv) {
$object = New-Object PSObject -Property #{"Email"= $server.Email; "ServerID" = $server.ServerID; "DateTime" = $server.DateTime}
$array += $object}
$array | Group-Object Email
Count Name Group
2 A#gmail.com {#{PG_Email=A#gmail.com; ServerID=333; Lease_End=10/10/15}, #{PG_Email=A#gmail.com; ServerID=111; Lease_End=12/12/15}}
1 B#gmail.com {#{PG_Email=B#gmail.com; ServerID=222; Lease_End=09/09/15}}
Yes, you should use Group-Object. I'm not sure what you mean with "call the group by name". If you want to select a group based by the name you would have to save the result from Group-Object and search for your group like:
$groups = $array | Group-Object Email
$selectedmail = "B#gmail.com"
$groups | Where-Object { $_.Name -eq $selectedmail }
Or you could save the groups in a hashtable:
#Create hashtable
$ht = #{}
#Fill hashtable with groups (email as key/ID)
$array | Group-Object Email | ForEach-Object { $ht[$_.Name] = $_.Group }
$selectedmail = "B#gmail.com"
#Get objects for selected mail
$ht[$selectedmail]
If you are going to mail everyone, I would simplify this to:
Import-Csv "C:\Example.csv" |
Group-Object Email |
ForEach-Object {
$to = $_.Name
#Get table of ServerID + Lease_End as string to send as mailbody
$mailbody = $_.Group | Format-Table -Property ServerID, Lease_End -AutoSize | Out-String
#You could also create a HTML-table with:
$htmlbody = $_.Group | Select-Object -Property ServerID, Lease_End | ConvertTo-HTML -Property Name, Length
#Send mail
#Send-MailMessage -To $to -Subject "Lease-status" -Body $mailbody -From "mysupersecret#mail.com"
}