I am trying to create a powershell script that can export the members of a DL to an excel file. It should also check for nested groups, and it there are, list the members of that nested group in a new sheet named as that group. If it can also have the header as the nested group name, it will be good but is not ncessary.
Got a draft but its not working, obviously my reason for being here :)
can the pros please take a look and help me out?
$OutputFile = "DL-Members_$(Get-Date -Format ddMMMyyyy_hhmmss).xlsx"
$GroupName = "Test-DistributionList#contoso.com"
$Members = Get-DistributionGroupMember -Identity $GroupName -RecipientTypeDetails UserMailbox, MailUniversalDistributionGroup, DynamicDistributionGroup, SecurityDistributionGroup
$Excel = New-Object -ComObject Excel.Application
$Workbook = $Excel.Workbooks.Add()
$Sheet = $Workbook.Sheets.Item(1)
$Sheet.Name = "Distribution Group Members"
$Sheet.Cells.Item(1,1) = "Display Name"
$Sheet.Cells.Item(1,2) = "Primary Smtp Address"
$Sheet.Cells.Item(1,3) = "Recipient Type"
$Row = 2
foreach ($Member in $Members)
{
$Sheet.Cells.Item($Row,1) = $Member.DisplayName
$Sheet.Cells.Item($Row,2) = $Member.PrimarySmtpAddress
$Sheet.Cells.Item($Row,3) = $Member.RecipientTypeDetails
if ($Member.RecipientTypeDetails -eq "MailUniversalDistributionGroup" -or $Member.RecipientTypeDetails -eq "DynamicDistributionGroup" -or $Member.RecipientTypeDetails -eq "SecurityDistributionGroup")
{
$NestedMembers = Get-DistributionGroupMember -Identity $Member.PrimarySmtpAddress,RecipientTypeDetails UserMailbox, MailUniversalDistributionGroup, DynamicDistributionGroup, SecurityDistributionGroup
$NestedSheet = $Workbook.Sheets.Add()
$NestedSheet.Name = $Member.DisplayName
$NestedSheet.Cells.Item(1,1) = "Display Name"
$NestedSheet.Cells.Item(1,2) = "Primary Smtp Address"
$NestedSheet.Cells.Item(1,3) = "Recipient Type"
$NestedRow = 2
foreach ($NestedMember in $NestedMembers)
{
$NestedSheet.Cells.Item($NestedRow,1) = $NestedMember.DisplayName
$NestedSheet.Cells.Item($NestedRow,2) = $NestedMember.PrimarySmtpAddress
$NestedSheet.Cells.Item($NestedRow,3) = $NestedMember.RecipientTypeDetails
$NestedRow++
}
}
$Row++
}
$Workbook.SaveAs($OutputFile)
$Excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel) | Out-Null
Write-Host "Members of distribution group '$GroupName' have been exported to $OutputFile" -foregroundcolor Green
Related
I am having a script file to compare the my system login username and samaccountname. If the system login username and samaccountname is matched then my output is display popup message of my system login username. But the below script is working fine if the data is in excel file format. Due to some of user not having the ms office. Those used are doing browser based work. So i need to read the text file if the samaccountname matches contains in text file i want display the samaccountname and date.
Sample text file screenshot
$FilePath = 'd:\Alluserreport.xlsx'
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $false
$wb = $xl.Workbooks.Open($filepath)
# get data from columns 2 and 3
$sheet = $wb.Worksheets['Alluserreport']
$rowMax = $sheet.UsedRange.Rows.Count
$data = for ($row = 2; $row -le $rowMax; $row++) {
[PsCustomObject] #{
SamAccountName = $sheet.Cells.Item($row, 2).Value2
LastLogonDate = [datetime]::FromOADate($sheet.Cells.Item($row, 3).Value2) # convert to DateTime object
}
}
# cleanup
$wb.close()
$xl.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# filter for a specific username in the data
$user = $data | Where-Object { $_.SamAccountName -eq $env:USERNAME }
if ($user) {
$msgBody = "User: {0}`r`nLastLogon: {1}" -f $user.SamAccountName, $user.LastLogonDate
$msgTitle = "Test"
$msgButton = 'OK'
$msgImage = 'Asterisk'
$Result = [System.Windows.MessageBox]::Show($msgBody,$msgTitle,$msgButton,$msgImage)
}
else {
Write-Host "Not found"
}
Thanks for accepting the previous question.
Working with CSV files is even a lot easier than getting data from Excel.
Using your example:
# import the data from the file
$data = Import-Csv -Path 'd:\Alluserreport.csv'
# filter for a specific username in the data
$user = $data | Where-Object { $_.SamAccountName -eq $env:USERNAME }
if ($user) {
$msgBody = "User: {0}`r`nLastLogon: {1}" -f $user.SamAccountName, $user.'Expiration Date'
$msgTitle = "Test"
$msgButton = 'OK'
$msgImage = 'Asterisk'
$Result = [System.Windows.MessageBox]::Show($msgBody,$msgTitle,$msgButton,$msgImage)
}
else {
Write-Host "Not found"
}
I'm trying to convert my CSV file to Excel file with some Table format and style but I'm getting "Cannot index into a null array" for some reason. I'll be really appreciated if I can get any help or suggestion. Thanks
function Convert-to-Excel{
$params = #{
AutoSize = $true
TableStyle = 'Medium6'
BoldTopRow = $true
WorksheetName = 'Audit Log'
PassThru = $true
Path = "C:\AuditLogSearch\$((Get-Date).AddDays(-7).ToString('yyyy-MM-dd')) _ $(Get-Date -Format "yyyy-MM-dd") Audit-Log-Records11.xlsx"
}
$modifiedFile = Import-Csv "C:\AuditLogSearch\Modified-Audit-Log-Records.csv"
$actionReference = Import-Csv "C:\AuditLogSearch\Reference\Action.csv"
$xlsx = foreach ($u in $modifiedFile) {
$u.User = (Get-AzureADUser -ObjectId $u.User).DisplayName
New-Object PsObject -Property #{
User = $u.User
"Search Criteria" = $u."Search Criteria"
"Result Status" = $u."Result Status"
"Date & Time" = $u."Date & Time"
"Type of Action" = if (($actionReference | where-object { $_.Name -eq $u."Type of Action" }).Value -ne $null) { ($actionReference | where-object { $_.Name -eq $u."Type of Action" }).Value }
else { $u."Type of Action" }
} | Export-Excel #params
$ws = $xlsx.Workbook.Worksheets[$params.Worksheetname]
$ws.View.ShowGridLines = $false # => This will hide the GridLines on your file
Close-ExcelPackage $xlsx
}
}
You're closing the Excel Package on the first iteration of your loop hence why when it goes to the next it's trying to do something like this:
$null[$null] # => InvalidOperation: Cannot index into a null array
Try modifying your function so it looks like this instead:
First, construct the object[]:
$result = foreach ($u in $modifiedFile) {
$u.User = (Get-AzureADUser -ObjectId $u.User).DisplayName
New-Object PsObject -Property #{
User = $u.User
"Search Criteria" = $u."Search Criteria"
"Result Status" = $u."Result Status"
"Date & Time" = $u."Date & Time"
"Type of Action" = if (($actionReference.........
else { $u."Type of Action" }
}
}
Then export it to Excel:
$xlsx = $result | Export-Excel #params
$ws = $xlsx.Workbook.Worksheets[$params.Worksheetname]
$ws.View.ShowGridLines = $false # => This will hide the GridLines on your file
Close-ExcelPackage $xlsx
One thing to note, PassThru = $true on the $params means that instead of saving the Excel directly we want to save the object on a variable for "further manipulation" and by further manipulation what I mean is, in this case, hiding the GridLines of the worksheet ($ws.View.ShowGridLines = $false) and then closing the package (store it on the disk).
If you don't require to perform any modifications over the worksheet you can just remove the PassThru altogether and do:
$result | Export-Excel #params
Which will close the package and store the Excel on your disk.
I am having a bit of a tough time writing a script for exchange. I have an environment, that has a hybird environment. I am trying to make a power shell script to find all large distro groups and email the owners of the groups to clean them up. However, I am having issues with pulling the owner email and and name for the email portion of the script.
But, there are a few restrictions, I can't use AD powershell, exchange only. and I can't use the get-mailbox cmdlet.
add-pssnapin microsoft.exchange.management.powershell.e2010
set the scope of the search
Set-ADServerSettings -ViewEntireForest $true
$DistGroups = Get-DistributionGroup -ResultSize 2
ForEach ($Group in $DistGroups) {
#Get each group details
$MemberCount = (Get-DistributionGroupMember $Group).count
$GroupName = (Get-DistributionGroup $Group).DisplayName
$Owner = (Get-DistributionGroup $Group).ManagedBy
$OwnerEmail = Get-recipient -identity $Owner | select PrimarySmtpAddress
$OwnerFN = Get-Recipient -identity $Owner | Select FirstName
If ( $MemberCount > 50000) {
#define email stuff
$messageBody = "Hi, <b>$OwnerFN,</b><p>"
$messageBody += "We are auditing distribution groups in our environment and your group, $GroupName, was flagged as being
<font color=red>really large</font>. The current member count is <font color=red> $MemberCount</font>.<p>"
$messageBody += "Please take steps to update the group and clear out unnecessary or old group members… <p>"
$messageBody += "Thanks, <p>"
$messageBody += "The Exchange Admin Team"
#Send the mail
$email = New-Object System.Net.Mail.MailMessage
$email.From = "Email_Group_Admin_Report#Internal.Mail.company.com"
$email.To.Add("me#company.com")
#$email.To.Add("$OwnerEmail")
#$email.CC.Add("#company.com")
#$email.BCC.Add("admin#company.com")
$email.DeliveryNotificationOptions = [System.Net.Mail.DeliveryNotificationOptions]::OnSuccess
$email.IsBodyHtml = $True
$email.Priority = [System.Net.Mail.MailPriority]::High
$email.Subject = "Distribution Group Audit"
$email.Body = $messageBody | Out-String
$smtp = New-Object System.Net.Mail.SmtpClient
$smtp.Host = "mail.compnany.com"
$smtp.Send($email)
}
}
I am able to get the count, and the Distro name, I can't seem to get the managed by property or the other stuff, it spits out an entire list of primary emails and Firstnames and such... The managed by property doesn't seem to appear....
$OwnerEmail = Get-recipient -identity $Owner | select PrimarySmtpAddress
This will return an object, but when you send the email you're acting as if you have a string.
email.To.Add("$OwnerEmail")
Option A:
($OwnerEmail = Get-recipient -identity $Owner).PrimarySmtpAddress
email.To.Add($OwnerEmail)
Option B:
$OwnerEmail = Get-recipient -identity $Owner | select PrimarySmtpAddress
email.To.Add($OwnerEmail.PrimarySmtpAddress)
I had a tough time with the output formats, but I finally got it working as expected. Thought I would post the working script here... Maybe you will find it useful.
add-pssnapin microsoft.exchange.management.powershell.e2010
# Find all Distros
$DistGroups = Get-DistributionGroup -ResultSize unlimited
ForEach ($Group in $DistGroups) {
#Get each group details
if ($Group.managedby -ne $null) {
$t = $Group.Managedby
$t | foreach { $Owner = $_.Name }
}
else {
$Owner = "Unknown"
$DL_Name = $Group.displayname
}
$MemberCount = (Get-DistributionGroupMember $Group).count
if ($Owner -eq "Unknown") { echo "The owner is unknown!"
}
#set membercount catch here
elseIf ( $MemberCount -gt 2000) {
$OwnerEm = get-recipient $Owner | select PrimarySmtpAddress | ft -HideTableHeaders | out-string
#$OwnerEm = get-recipient me#company.com | select PrimarySmtpAddress | ft -HideTableHeaders | out-string
#define email stuff
$messageBody = "Hi, <b>$Owner,</b><p>"
$messageBody += "We are auditing distribution groups in our environment and your group, $DL_Name, was flagged as being <font color=red>really large</font>. The current member count is <font color=red> $MemberCount</font>.<p>"
$messageBody += "Please take steps to update the group and clear out unnecessary or old group members… <p>"
$messageBody += "Thanks, <p>"
$messageBody += "The Exchange Admin Team"
#Send the mail
$email = New-Object System.Net.Mail.MailMessage
$email.From = "Email_Group_Admin_Report#Internal.Mail.company.com"
#$email.To.Add("me#company.com")
$email.To.Add("$OwnerEm")
#$email.CC.Add("#company.com")
#$email.BCC.Add("admin#company.com")
$email.DeliveryNotificationOptions = [System.Net.Mail.DeliveryNotificationOptions]::OnSuccess
$email.IsBodyHtml = $True
$email.Priority = [System.Net.Mail.MailPriority]::High
#$attachment = "C:\myfile.txt"
#$email.Attachments.Add( $attachment )
$email.Subject = "Distribution Group Audit"
$email.Body = $messageBody | Out-String
$smtp = New-Object System.Net.Mail.SmtpClient
$smtp.Host = "mail.company.com"
$smtp.Send($email)
echo "the $DL_Name has a high member count. The member count is $MemberCount. The manager has been sent and email at $OwnerEm"
}
else {
echo "the $DL_Name seems fine! The member count is $MemberCount. The manager '$Owner' is doing great!"
}
}
I left the echo statements in so you can view the statuses via a console, or pipe them to a file.... or something...
I am trying to add read-only-permissions to a specific group called "Students" for a list I have created called "Quiz". I have to use PowerShell CSOM, but in every other tutorial I've been through, .NET server types have been used, which is not applicable to my code.
Code:
$ListName = "Quiz"
$PermissionLevel = "Read Only"
$web = $ctx.Web
$lists = $web.Lists
$ctx.Load($lists)
$ctx.ExecuteQuery()
foreach($list in $lists)
{
if($list.Title -eq $ListName)
{
$listId = $list.Id
}
}
$list = $lists.GetById($listId)
$ctx.Load($list);
$ctx.ExecuteQuery();
Write-Host "List:" $List.Title -foregroundcolor Green
if ($list -ne $null)
{
$groups = $web.SiteGroups
$ctx.Load($groups)
$ctx.ExecuteQuery()
foreach ($SiteGroup in $groups) {
if ($SiteGroup.Title -match "Students")
{
write-host "Group:" $SiteGroup.Title -foregroundcolor Green
$GroupName = $SiteGroup.Title
$builtInRole = $ctx.Web.RoleDefinitions.GetByName($PermissionLevel)
$roleAssignment = new-object Microsoft.SharePoint.Client.RoleAssignment($SiteGroup)
$roleAssignment.Add($builtInRole)
$list.BreakRoleInheritance($True, $False)
$list.RoleAssignments.Add($roleAssignment)
$list.Update();
Write-Host "Successfully added <$GroupName> to the <$ListName> list in <$site>. " -foregroundcolor Green
}
else
{
Write-Host "No Students groups exist." -foregroundcolor Red
}
}
}
My error is in
$roleAssignment = new-object Microsoft.SharePoint.Client.RoleAssignment($SiteGroup)
, where I'm recieving the error
Cannot find an overload for "RoleAssignment" and the argument count: "1".
Most tutorials use
$roleAssignment = new-object Microsoft.SharePoint.SPRoleAssignment($SiteGroup)
which I CAN NOT USE.
How can I complete my code?
P.S. I know my code is a bit messy, but I've been spending too much time trying to find a solution, and my code has greatly reduced in quality over the past hours. Sorry for that.
I dont have sharepoint to test but you are getting the error on roleassignments because the method you are calling takes 2 arguments.
anyway you can try something along these lines:
$roleAssignment = New-Object microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
$roleAssignment.Add($builtinRole)
$ctx.Load($list.RoleAssignments.Add($sitegroup, $roleAssignment))
Unnie on stackexchange helped me by providing the following code. I should have used microsoft.SharePoint.Client.RoleDefinitionBindingCollection instead of Microsoft.SharePoint.Client.RoleAssignment.
# Get the list by Title and load.
$web = $ctx.Web
$list = $web.Lists.GetByTitle("Quiz")
$ctx.Load($list)
# Load in list of groups on the current web.
$groups = $web.SiteGroups
$ctx.Load($groups)
$ctx.ExecuteQuery()
$listTitle = $list.Title
foreach($group in $groups)
{
if($group.Title -eq "Students")
{
$roleAssignment = $null
# Get the group and load into context to be used.
$StudentsGrp = $groups.GetById($group.Id)
$ctx.Load($StudentsGrp)
$ctx.ExecuteQuery()
# Break inheritance on the list and remove existing permissons.
$list.BreakRoleInheritance($false, $true)
# Get the permissions role for 'Read'
$reader = $web.RoleDefinitions.GetByName("Read")
# Create a role assignment and apply the 'read' role.
$roleAssignment = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
$roleAssignment.Add($reader)
# Apply the permission roles to the list.
$ctx.Load($list.RoleAssignments.Add($StudentsGrp, $roleAssignment))
$list.Update()
$ctx.ExecuteQuery()
}
}
This works! :-)
I am using a powershell script like the one below, it looks at AD Security group memberships and based on that it maps drives for the users. What I am trying to accomplish is that when it sees users log on from a certian IP or Subnet it maps a different set of drives in addition to the ones it grabs from AD group memberships, any insight will be appreciated.
# The section below determines what AD groups is the user member of
$strName = $env:username
function get-GroupMembership($DNName,$cGroup){
$strFilter = "(&(objectCategory=User)(samAccountName=$strName))"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.Filter = $strFilter
$objPath = $objSearcher.FindOne()
$objUser = $objPath.GetDirectoryEntry()
$DN = $objUser.distinguishedName
$strGrpFilter = "(&(objectCategory=group)(name=$cGroup))"
$objGrpSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objGrpSearcher.Filter = $strGrpFilter
$objGrpPath = $objGrpSearcher.FindOne()
If (!($objGrpPath -eq $Null)){
$objGrp = $objGrpPath.GetDirectoryEntry()
$grpDN = $objGrp.distinguishedName
$ADVal = [ADSI]"LDAP://$DN"
if ($ADVal.memberOf.Value -eq $grpDN){
$returnVal = 1
return $returnVal = 1
}else{
$returnVal = 0
return $returnVal = 0
}
}else{
$returnVal = 0
return $returnVal = 0
}
}
# The section below maps network drives based on users AD Security Group memberships
$result = get-groupMembership $strName "SecurityGrtoup1"
if ($result -eq '1') {
$(New-Object -ComObject WScript.Network).RemoveNetworkDrive("G:");
$(New-Object -ComObject WScript.Network).MapNetworkDrive("G:", "\\server1\Group");
$(New-Object -ComObject WScript.Network).RemoveNetworkDrive("P:");
$(New-Object -ComObject WScript.Network).MapNetworkDrive("P:", "\\server2\Common");
}
$result = get-groupMembership $strName "SecurityGroup3"
if ($result -eq '1') {
$(New-Object -ComObject WScript.Network).RemoveNetworkDrive("N:");
$(New-Object -ComObject WScript.Network).MapNetworkDrive("N:", "\\Server3\files");
}
This should get you the IPv4 address as a string object:
$ip = (Get-WmiObject -Class Win32_NetworkAdapterConfiguration | Where-Object {$_.IPAddress} | Select-Object -ExpandProperty IPAddress)[0]
You could then parse that anyway you need to, you could also instead use the .IPSubnet, or .DefaultIPGateway properties if that would get you what you need.
For other available properties try:
Get-WmiObject -Class Win32_NetworkAdapterConfiguration | Where-Object {$_.IPAddress} | Get-Member