Skip to content

Commit 79176d7

Browse files
RodriguezRodriguez
Rodriguez
authored and
Rodriguez
committed
New script to get cool report on AD user group memberships. Other minor stuffs.
1 parent c137f01 commit 79176d7

6 files changed

+475
-12
lines changed

AD/Get-ADGroupReport.ps1

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
function Get-ADGroupReport {
2+
[CmdletBinding()]
3+
Param(
4+
[Parameter(Mandatory = $true)]
5+
[ValidateNotNullorEmpty()]
6+
[string]$SaveToCsv,
7+
8+
[Parameter(Mandatory = $false)]
9+
[ValidateNotNullorEmpty()]
10+
[string]$ADGroupFilter = 'GroupCategory -eq "Distribution"'
11+
)
12+
13+
begin {
14+
Import-Module ActiveDirectory
15+
16+
Write-Progress -Id 1 -Activity "Getting AD groups using filter $ADGroupFilter..."
17+
$Groups = Get-ADGroup -Filter $ADGroupFilter
18+
$Users = @{}
19+
}
20+
21+
process {
22+
$GroupCount = $Groups.Count
23+
$GroupCounter = 0
24+
25+
foreach ($Group in $Groups) {
26+
$GroupCounter++
27+
28+
$GroupName = $Group.Name
29+
30+
$GroupProgressParams = @{
31+
'Id' = 1
32+
'Activity' = "Processing group $GroupCounter of $GroupCount"
33+
'Status' = $GroupName
34+
'PercentComplete' = ($GroupCounter / $GroupCount) * 100
35+
}
36+
Write-Progress @GroupProgressParams
37+
38+
$Members = Get-ADGroupMember $Group -Recursive
39+
40+
$MemberCount = $Members.Count
41+
$MemberCounter = 0
42+
43+
foreach ($Member in $Members) {
44+
$MemberCounter++
45+
46+
$MemberName = $Member.SamAccountName
47+
48+
$MemberProgressParams = @{
49+
'Id' = 2
50+
'ParentId' = 1
51+
'Activity' = "Processing member $MemberCounter of $MemberCount"
52+
'Status' = $MemberName
53+
}
54+
if ($MemberCount.GetType() -eq [int]) {
55+
$MemberProgressParams.Add('PercentComplete', ($MemberCounter / $MemberCount) * 100)
56+
}
57+
Write-Progress @MemberProgressParams
58+
59+
if ($Member.objectClass -eq 'user') {
60+
Write-Verbose "$MemberName is a user"
61+
62+
if (-not $Users.ContainsKey($MemberName)) {
63+
Write-Verbose "Adding $MemberName to users list"
64+
$Users.Add($MemberName, @{})
65+
}
66+
67+
Write-Verbose "Adding $($GroupName) to $MemberName's group list"
68+
$Users.($MemberName).Add($GroupName, $true)
69+
} else {
70+
Write-Verbose "$MemberName is not a user"
71+
}
72+
}
73+
74+
Write-Progress -Id 2 -ParentId 1 -Activity "Processing members" -Completed
75+
}
76+
77+
$ReportProgressParams = @{
78+
'Id' = 1
79+
'Activity' = 'Building report...'
80+
}
81+
Write-Progress @ReportProgressParams
82+
83+
$Results = @()
84+
85+
foreach ($User in $Users.GetEnumerator()) {
86+
$ADUser = Get-ADUser -Identity $User.Name -Properties @(
87+
'physicalDeliveryOfficeName', 'Office', 'Department', 'Company', 'City', 'telephoneNumber'
88+
)
89+
90+
$UserObject = New-Object psobject -Property @{
91+
UserId = $User.Name
92+
Email = $ADUser.UserPrincipalName
93+
Phone = $ADUser.telephoneNumber
94+
FullName = $ADUser.Name
95+
Enabled = $ADUser.Enabled
96+
PhysicalOffice = $ADUser.physicalDeliveryOfficeName
97+
Office = $ADUser.Office
98+
Department = $ADUser.Department
99+
Company = $ADUser.Company
100+
City = $ADUser.City
101+
}
102+
103+
foreach ($Group in $Groups) {
104+
$UserObject | Add-Member -MemberType NoteProperty -Name $Group.Name -Value ''
105+
106+
if ($User.Value.ContainsKey($Group.Name)) {
107+
$UserObject.($Group.Name) = 'x'
108+
}
109+
}
110+
111+
$Results += $UserObject
112+
}
113+
}
114+
115+
end {
116+
if ($SaveToCsv) { $Results | Export-Csv -Path $SaveToCsv -NoTypeInformation }
117+
$Results
118+
}
119+
}

AD/Test-Credential.ps1

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<#
2+
.DESCRIPTION
3+
Simulates an Authentication Request in a Domain envrionment using a PSCredential Object. Returns $true if both Username and Password pair are valid.
4+
.VERSION
5+
1.3
6+
.GUID
7+
6a18515f-73d3-4fb4-884f-412395aa5054
8+
.AUTHOR
9+
Thomas Malkewitz @dotps1
10+
.TAGS
11+
PSCredential, Credential
12+
.RELEASENOTES
13+
Updated $Domain default value to $Credential.GetNetworkCredential().Domain.
14+
Added support for multipul credential objects to be passed into $Credential.
15+
.PROJECTURI
16+
http://dotps1.github.io
17+
.NOTES
18+
Slight modifications by Nick
19+
#>
20+
21+
Function Test-Credential {
22+
[OutputType([Bool])]
23+
24+
Param (
25+
[Parameter(
26+
Mandatory = $true,
27+
ValueFromPipeLine = $true,
28+
ValueFromPipelineByPropertyName = $true
29+
)]
30+
[Alias('PSCredential')]
31+
[ValidateNotNull()]
32+
[System.Management.Automation.PSCredential]
33+
[System.Management.Automation.Credential()]
34+
$Credential,
35+
36+
[Parameter()]
37+
[String]
38+
$Domain = $Credential.GetNetworkCredential().Domain
39+
)
40+
41+
Begin {
42+
[System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.AccountManagement") |
43+
Out-Null
44+
45+
$principalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext(
46+
[System.DirectoryServices.AccountManagement.ContextType]::Domain, $Domain
47+
)
48+
}
49+
50+
Process {
51+
foreach ($item in $Credential) {
52+
$networkCredential = $Credential.GetNetworkCredential()
53+
54+
Write-Output -InputObject $(
55+
$principalContext.ValidateCredentials(
56+
$networkCredential.UserName, $networkCredential.Password
57+
)
58+
)
59+
}
60+
}
61+
62+
End {
63+
$principalContext.Dispose()
64+
}
65+
}

Exchange/Set-MSOMailboxAuditing.ps1

+66-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1+
# Start a transcript of everything we do
2+
$LogDirectory = (New-Item -ItemType Directory "$PSScriptRoot\Logs" -Force).FullName
3+
$Date = (Get-Date).ToString('yyyyMMdd-HHmm')
4+
$LogPath = "$LogDirectory\$($MyInvocation.MyCommand.Name)-$Date.log"
5+
$ResultsPath = "$LogDirectory\$($MyInvocation.MyCommand.Name)-$Date.csv"
6+
17
# Connect to Exchange Online
2-
Import-Module ..\OneDrive\OneDrive.psm1
3-
$Creds = Get-OneDriveCredential
8+
$Creds = Get-Credential
49
$ExchangeOnlineSession = New-PSSession -ConfigurationName Microsoft.Exchange `
510
-ConnectionUri https://outlook.office365.com/powershell-liveid/ `
611
-Credential $Creds -Authentication Basic -AllowRedirection
712
Import-PSSession $ExchangeOnlineSession
813

14+
Start-Transcript -Path $LogPath
15+
916
# Audit options
1017
$AuditOwnerOptions = @(
1118
'Create', 'HardDelete', 'MailboxLogin', 'Move', 'MoveToDeletedItems',
@@ -22,10 +29,63 @@ $AuditDelegateOptions = @(
2229
'SendAs', 'SendOnBehalf', 'SoftDelete', 'Update'
2330
)
2431

32+
# Keep track of how many accounts we fix
33+
$BadAccounts = 0
34+
2535
# Get all users and enable auditing options for their mailboxes
26-
Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox |
27-
Set-Mailbox -AuditEnabled $true -AuditOwner $AuditOwnerOptions `
28-
-AuditAdmin $AuditAdminOptions -AuditDelegate $AuditDelegateOptions
36+
Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox | ForEach-Object {
37+
$Params = @{ 'Identity' = $_.UserPrincipalName }
38+
39+
# Verify audit options are enabled
40+
if (-not $_.AuditEnabled) {
41+
Write-Output "$($_.UserPrincipalName) - enabling audit."
42+
$Params.Add('AuditEnabled', $true)
43+
}
44+
45+
# Verify audit owner options are correct
46+
if (Compare-Object -ReferenceObject $_.AuditOwner -DifferenceObject $AuditOwnerOptions) {
47+
Write-Output "$($_.UserPrincipalName) - resetting Audit Owner options."
48+
$Params.Add('AuditOwner', $AuditOwnerOptions)
49+
}
50+
51+
# Verify audit admin options are correct
52+
if (Compare-Object -ReferenceObject $_.AuditAdmin -DifferenceObject $AuditAdminOptions) {
53+
Write-Output "$($_.UserPrincipalName) - resetting Audit Admin options."
54+
$Params.Add('AuditAdmin', $AuditAdminOptions)
55+
}
56+
57+
# Verify audit delegate options are correct
58+
if (Compare-Object -ReferenceObject $_.AuditDelegate -DifferenceObject $AuditDelegateOptions) {
59+
Write-Output "$($_.UserPrincipalName) - resetting Audit Delegate options."
60+
$Params.Add('AuditDelegate', $AuditDelegateOptions)
61+
}
62+
63+
# Update user options if any don't match out settings
64+
if ($Params.Count -gt 1) {
65+
Write-Output "$($_.UserPrincipalName) - setting mailbox options."
66+
try { Set-Mailbox @Params -WhatIf } catch { $_ }
67+
$BadAccounts++
68+
}
69+
}
70+
71+
Write-Output "Audit options were set on $BadAccounts mailboxes."
72+
73+
# Save resulting audit rules of all users to csv
74+
Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox |
75+
Select-Object PrimarySmtpAddress, Name, Audit* |
76+
Export-Csv -Path $ResultsPath -NoTypeInformation
2977

3078
# Disconnect from Exchange Online
31-
Remove-PSSession $ExchangeOnlineSession
79+
Remove-PSSession $ExchangeOnlineSession
80+
Stop-Transcript
81+
82+
# Send results via email
83+
$Params = @{
84+
'Body' = Get-Content -Path $LogPath | Out-String
85+
'From' = '[email protected]'
86+
'SmtpServer' = 'smtp.company.local'
87+
'Subject' = 'Enable Mailbox Auditing'
88+
89+
'Attachments' = $ResultsPath
90+
}
91+
Send-MailMessage @Params

Google/Get-GoogleHangoutsData.ps1

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
2+
$HangoutsFilePath = '~\downloads\hangouts.json'
3+
$HangoutsRaw = Get-Content $HangoutsFilePath
4+
$HangoutsData = Get-Content $HangoutsFilePath | ConvertFrom-Json
5+
6+
$Conversations = @()
7+
$AllParticipants = @()
8+
9+
function Process-GoogleHangoutsData {
10+
# First we want to get all participants, so we loop fully once
11+
foreach ($Key in $HangoutsData.conversation_state) {
12+
$Conversation = $HangoutsData.conversation_state.$Key.'conversation_state'.'conversation'
13+
14+
# Get all participants
15+
foreach ($PersonData in $Conversation.'participant_data') {
16+
$Person = $Conversation.'participant_data'.$PersonData
17+
$Gaia_id = $Person.'id'.'gaia_id'
18+
if (-not $person.'fallback_name' -or $Person.'fallback_name' -eq $null) { break }
19+
if (-not $AllParticipants.$Gaia_id) {
20+
$AllParticipants.$gaia_id = $Person.'fallback_name'
21+
}
22+
}
23+
}
24+
foreach ($Key in $HangoutsData.'conversation_state') {
25+
$conversation_state = $HangoutsData.'conversation_state'.$key
26+
$id = $conversation_state.'conversation_id'.'id'
27+
$conversation = $conversation_state.'conversation_state'.'conversation'
28+
29+
# Find participants
30+
$participants = @()
31+
$participants_obj = @{}
32+
foreach ($person_key in $conversation.'participant_data') {
33+
$person = $conversation.'participant_data'.$person_key
34+
$gaia_id = $person.'id'.'gaia_id'
35+
$name = 'Unknown'
36+
if ($person.'fallback_name') {
37+
$name = $person.'fallback_name'
38+
} else {
39+
$name = $AllParticipants.$gaia_id
40+
}
41+
$participants.push($name)
42+
$participants_obj.$gaia_id = $name
43+
}
44+
$participants_string = $participants.join(", ")
45+
# Add to list
46+
#$(".convo-list").append("<a href=\"javascript:void(0)\" onclick=\"switchConvo('"+id+"')\" class=\"list-group-item\">" + participants_string + "</a>")
47+
# Parse events
48+
$events = @()
49+
for (event_key in conversation_state.'conversation_state'.'event'){
50+
$convo_event = conversation_state.'conversation_state'.'event'.event_key
51+
$timestamp = convo_event.'timestamp'
52+
$msgtime = formatTimestamp(timestamp)
53+
$sender = convo_event.'sender_id'.'gaia_id'
54+
$message = ""
55+
if(convo_event.'chat_message'){
56+
# Get message
57+
for(msg_key in convo_event.'chat_message'.'message_content'.'segment'){
58+
$segment = convo_event.'chat_message'.'message_content'.'segment'.msg_key
59+
if(segment.'type' == 'LINE_BREAK') $message += "\n"
60+
if(!segment.'text') continue
61+
message += twemoji.parse(segment.'text')
62+
}
63+
# Check for images on event
64+
if(convo_event.'chat_message'.'message_content'.'attachment'){
65+
foreach ($attach_key in convo_event.'chat_message'.'message_content'.'attachment'){
66+
$attachment = convo_event.'chat_message'.'message_content'.'attachment'.attach_key
67+
console.log(attachment)
68+
if(attachment.'embed_item'.'type'.0 == "PLUS_PHOTO"){
69+
message += "\n<a target='blank' href='" + attachment.'embed_item'.'embeds.PlusPhoto.plus_photo'.'url' + "'><img class='thumb' src='" + attachment.'embed_item'.'embeds.PlusPhoto.plus_photo'.'thumbnail'.'image_url' + "' /></a>"
70+
}
71+
}
72+
}
73+
events.push({msgtime: msgtime, sender: participants_obj.sender, message: message, timestamp: timestamp})
74+
}
75+
}
76+
<# Sort events by timestamp
77+
$events.sort(function($a, $b){
78+
$keyA = $a.timestamp,
79+
$keyB = $b.timestamp
80+
if($keyA < $keyB) return -1
81+
if($keyA > $keyB) return 1
82+
return 0
83+
})#>
84+
# Add events
85+
$Conversations.$id = $events
86+
}
87+
}
88+
89+
function switchConvo($id) {
90+
$('.txt').text('')
91+
foreach ($event_id in Conversations.id){
92+
$convo_event = Conversations.id.event_id
93+
$('.txt').append($convo_event.msgtime + ": " + $convo_event.sender + ": " + $convo_event.message + "\n")
94+
}
95+
}
96+
97+
function zeroPad($string) {
98+
return ($string < 10) ? "0" + $string : $string
99+
}
100+
101+
function formatTimestamp($timestamp) {
102+
$d = new Date($timestamp/1000)
103+
$formattedDate = $d.getFullYear() + "-" +
104+
zeroPad($d.getMonth() + 1) + "-" +
105+
zeroPad($d.getDate())
106+
$hours = zeroPad($d.getHours())
107+
$minutes = zeroPad($d.getMinutes())
108+
$formattedTime = $hours + ":" + $minutes
109+
return $formattedDate + " " + $formattedTime
110+
}

0 commit comments

Comments
 (0)