Retrieving Bitlocker Recovery Keys from AD - powershell

Fairly new to Powershell, I managed to get the following code to retrieve the Bitlocker key for computers in the domain, however, I have an issue with it:
Clear-Host
$TestOU = "OU=ABC,DC=XYZ,DC=com"
$PCs = Get-ADComputer -Filter * -SearchBase $TestOU
$Results = ForEach ($Computer in $PCs)
{
New-Object PSObject -Property #{
ComputerName = $Computer.Name
RecoveryPassword = Get-ADObject -Filter 'objectclass -eq "msFVE-
RecoveryInformation"' -SearchBase $computer.DistinguishedName -Properties
msFVE-RecoveryPassword,whencreated | sort whencreated -Descending | select
msfve-recoverypassword
}
}
$Results
My output for each password begins with {a{msfve-recoverypassword= and I'm not sure how to remove this.

The following code gives useful output for human consumption in the shell, but may also be used in a script:
$computer = Get-ADComputer $computerName
Get-ADObject -Filter 'objectClass -eq "msFVE-RecoveryInformation"' -SearchBase $computer.DistinguishedName -Properties whenCreated, msFVE-RecoveryPassword | `
Sort whenCreated -Descending | Select whenCreated, msFVE-RecoveryPassword

Related

How to select a substring in select/group command- Powershell

In the code below, the userprinciplename will output strings like "LLL_John.Smith#email.com" and XXXX_Jane.Doe#email.com" but i am hoping to extract a substring from that, that being the codes before the "_" character, so LLL and XXXX.
There may be some which do not have an underscore character however and so these would need to be ignored / have the original string it would have returned.
##Check bottom of script for setting specific OU
Function Get-LastLogon {
param(
[string]$OUName
)
# Get all matching OUs on any level
$OUs = Get-ADOrganizationalUnit -Filter "Name -like '$OUName'"
$DCs = Get-ADDomainController -Filter *
# Get all users from each OU from each DC
$ADUsers = Foreach ($OU in $OUs) {
Foreach ($DC in $DCs.HostName) {
Get-ADUser -SearchBase $OU.DistinguishedName -Filter * -Properties LastLogon -server $dc |
Select-Object Name,userPrincipalName, #{n='LastLogon';e={[DateTime]::FromFileTime($_.LastLogon)}}
}
}
# return most recent LastLogon date for each user
$ADUsers |
Group Name,userPrincipalName |
Select Name,userprinciplename, #{n='LastLogon';e={$_.Group.LastLogon | sort -desc | select -First 1}}
} ## End function
##Enter the OU here
Get-LastLogon -OUName 'Clients'
##Un-comment below to export to csv
## | Export-Csv -Path 'C:\temp\UserExport.csv'
Here is what the script looks like now in full:
##Check bottom of script for setting specific OU
Function Get-LastLogon {
param(
[string]$OUName
)
# Get all matching OUs on any level
$OUs = Get-ADOrganizationalUnit -Filter "Name -like '$OUName'"
$DCs = Get-ADDomainController -Filter *
$ADUsers = foreach ($OU in $OUs) {
foreach ($dc in $DCs.HostName) {
Get-ADUser -SearchBase $OU.DistinguishedName -Filter * -Properties lastLogonTimeStamp -Server $dc |
Select-Object Name,UserPrincipalName,
#{Name = 'LastLogon';Expression = {[DateTime]::FromFileTime($_.lastLogonTimeStamp)}},
#{Name = 'UserCode'; Expression = {([regex]'^([^_]+)_.*').Match($_.UserPrincipalName).Groups[1].Value}}
}
} }
# return the most recent LastLogon date for each user
# (only the users with a code prefix in the UserPrincipalName)
$ADUsers | Where-Object { ![string]::IsNullOrWhiteSpace($_.UserCode) } |
Group-Object UserPrincipalName | ForEach-Object {
[PsCustomObject]#{
Name = $_.Group[0].Name
UserCode = $_.Group[0].UserCode
LastLogon = $_.Group.LastLogon | Sort-Object -Descending | Select-Object -First 1
}
}
## End function
$OUcustom = Read-Host -prompt 'Enter OU here or "Clients" for all'
##Enter the OU here
Get-LastLogon -OUName $OUcustom |
##export csv
Export-Csv -path "C:\temp\UserExport_$((Get-Date).ToString("ddMM_HHmm")).csv" -NoTypeInformation
".csv extracted to C:\temp"
pause
Just add another calculated property to the code you have to get the array of user objects:
$ADUsers = foreach ($OU in $OUs) {
foreach ($dc in $DCs.HostName) {
Get-ADUser -SearchBase $OU.DistinguishedName -Filter * -Properties lastLogonTimeStamp -Server $dc |
Select-Object Name,UserPrincipalName,
#{Name = 'LastLogon';Expression = {[DateTime]::FromFileTime($_.lastLogonTimeStamp)}},
#{Name = 'UserCode'; Expression = {if ($_.UserPrincipalName -like '*_*#*') {($_.UserPrincipalName -split '_')[0]} else { $null }}}
# or use regex like:
# #{Name = 'UserCode'; Expression = {([regex]'^([^_]+)_.*').Match($_.UserPrincipalName).Groups[1].Value}}
}
}
Then you can filter out the users that do have such a code:
# return the most recent LastLogon date for each user
# (only the users with a code prefix in the UserPrincipalName)
$ADUsers | Where-Object { ![string]::IsNullOrWhiteSpace($_.UserCode) } |
Group-Object UserPrincipalName | ForEach-Object {
[PsCustomObject]#{
Name = $_.Group[0].Name
UserCode = $_.Group[0].UserCode
LastLogon = $_.Group.LastLogon | Sort-Object -Descending | Select-Object -First 1
}
}
If you want to rule out all users that do not have some code followed by an underscore in their UserPrincipalName property straight away, you can use the filter parameter:
Get-ADUser -SearchBase $OU.DistinguishedName -Filter "UserPrincipalName -like '*_*#*'" -Properties lastLogonTimeStamp -Server $dc
This however will not give you the opportunity to use the collected users for some other purpose, like outputting users who do not have a code prefixed, as would be easy to do with the code above.
P.S. Did you know PowerShell also provides an attribute LastLogonDate, which is the LDAP property lastLogonTimeStamp, converted to local time.
So this was actually more simple than I realised.
I just needed to add in:
#{N='userPrincipalName';E={$_.userPrincipalName.Split("_")[0]}}
To the first and second blocks where UserPrincipleName was being selected.
Will post the full working code below for relevance.
##Check bottom of script for setting specific OU
Function Get-LastLogon {
param(
[string]$OUName
)
# Get all matching OUs on any level
$OUs = Get-ADOrganizationalUnit -Filter "Name -like '$OUName'"
$DCs = Get-ADDomainController -Filter *
# Get all users from each OU from each DC
$ADUsers = Foreach ($OU in $OUs) {
Foreach ($DC in $DCs.HostName) {
Get-ADUser -SearchBase $OU.DistinguishedName -Filter * -Properties LastLogon -server $dc |
Select-Object Name,#{N='userPrincipalName';E={$_.userPrincipalName.Split("_")[0]}}, #{n='LastLogon';e={[DateTime]::FromFileTime($_.LastLogon)}}
}
}
# return most recent LastLogon date for each user
$ADUsers |
Group Name,userPrincipalName |
Select Name,#{N='userprinciplename';E={$_.userprinciplename.Split("_")[0]}}, #{n='LastLogon';e={$_.Group.LastLogon | sort -desc | select -First 1}}
} ## End function
$OUcustom = Read-Host -prompt 'Enter OU here or "Clients" for all'
##Enter the OU here
Get-LastLogon -OUName $OUcustom |
##export csv
Export-Csv -path "C:\temp\UserExport_$((Get-Date).ToString("ddMM_HHmm")).csv" -NoTypeInformation
".csv extracted to C:\temp"
pause

Export computer name from after .ntSecurityDescriptor output

I have the following code, I'm just trying to export what security groups are attached to each Domain Controller.
I have so far made this, however! I cannot seem to export the computer names along side the Groups in the output! Can someone potentially help! I've been going round in circles for hours
$ou = "OU=Domain Controllers,DC=example,DC=com"
$user = Get-ADComputer -SearchBase $ou -Filter * -properties * | Select ntSecurityDescriptor, Name
$user2 = $user.ntSecurityDescriptor.Access |
select-object -expandproperty IdentityReference |
sort-object -unique
if ($user2-eq "example\user") {
#They Match
Write-Host "Oh Sugar"
$user.ntSecurityDescriptor.Access |
Select-Object -expandproperty IdentityReference |
sort-object -unique
} else {
Write-Host "Phew"
}
Update 20th August. I updated my code to loop around and show the computer name in the output.
$ou = "OU=Domain Controllers,DC=example,DC=com"
$computers = Get-ADComputer -SearchBase $ou -Filter * -properties ntSecurityDescriptor, Name
$code = foreach ($computer in $computers)
{
Get-ADComputer $computer -properties ntSecurityDescriptor
$owner = $computer.ntSecurityDescriptor.Access |
Select-Object -expandproperty IdentityReference |
sort-object -unique
$export = if ($owner-eq "example\user") {
#Problem found
$computer.Name
} else {
}
$export | Out-File 'C:\Temp\output.csv' -Append
}

Password change notification problem exclude OU powershell

We are using a good script that we would like to extend to search for users everywhere except one OU. How can I do this?
Thanks in advance for your help!
PasswordChangeNotification
How to instert this code?
Get-ADOrganizationalUnit -filter * -SearchBase 'OU=test,DC=test,DC=com' | foreach {
if($_.distinguishedname -ne "OU=not,OU=that,OU=orgUnit,OU=test,DC=test,DC=com"){
$users=Get-ADUser -filter * -searchbase $_.distinguishedname -ResultPageSize 2000 -resultSetSize 500 -searchscope Onelevel | where-object enabled -eq true
$total=($users | measure-object).count
New-Object psobject -Property #{
OU=$_.Name;
A=$Total
}
}
}
On line 132 of the file you've linked to, you'll find the statement that actually queries Active Directory for the users:
$users = get-aduser -filter {(Enabled -eq $true) -and (PasswordNeverExpires -eq $false)} -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress | where { $_.passwordexpired -eq $false }
Add the following statement to the next line:
$users = $users |Where-Object distinguishedname -notlike "*,OU=not,OU=that,OU=orgUnit,OU=test,DC=test,DC=com"
... and leave the rest of the script as-is

get OU Permissions for specific domain

I found a script that give you OU permissions for the domain the script is run on.
I want to use the same script from a single domain but scan other domains I specify.
The problem I think is with $schemaIDGUID = #{}
When run It's always for the domain the script is running on which is different from the domain I want to run the script on.
Here's the script I modified it to pickup specific domain.
$schemaIDGUID = #{}
$domain = "My specific domain name"
$report = #()
$schemaIDGUID = #{}
$ErrorActionPreference = 'SilentlyContinue'
Get-ADObject -Server $domain -SearchBase (Get-ADRootDSE -Server $domain).schemaNamingContext -LDAPFilter '(schemaIDGUID=*)' -Properties name, schemaIDGUID |
ForEach-Object {$schemaIDGUID.add([System.GUID]$_.schemaIDGUID,$_.name)}
Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE -Server $domain).configurationNamingContext)" -LDAPFilter '(objectClass=controlAccessRight)' -Properties name, rightsGUID |
ForEach-Object {$schemaIDGUID.add([System.GUID]$_.rightsGUID,$_.name)}
$ErrorActionPreference = 'Continue'
$OUs = #(Get-ADDomain -Server $domain | Select-Object -ExpandProperty DistinguishedName)
$OUs += Get-ADOrganizationalUnit -Server $domain -Filter * | Select-Object -ExpandProperty DistinguishedName
$OUs += Get-ADObject -Server $domain -SearchBase (Get-ADDomain -Server $domain).DistinguishedName -SearchScope OneLevel -LDAPFilter '(objectClass=container)' | Select-Object -ExpandProperty DistinguishedName
ForEach ($OU in $OUs) {
$report += Get-Acl -Path "AD:\$OU" |
Select-Object -ExpandProperty Access |
Select-Object #{name='organizationalUnit';expression={$OU}}, `
#{name='objectTypeName';expression={if ($_.objectType.ToString() -eq '00000000-0000-0000-0000-000000000000') {'All'} Else {$schemaIDGUID.Item($_.objectType)}}}, `
#{name='inheritedObjectTypeName';expression={$schemaIDGUID.Item($_.inheritedObjectType)}}, `
*
}
$report | Export-Csv -Path ".\$domain.OU_Permissions.csv" -NoTypeInformation
#Start-Process ".\$domain.OU_Permissions.csv"
break
$report |
Where-Object {-not $_.IsInherited} |
Select-Object IdentityReference, OrganizationalUnit -Unique |
Sort-Object IdentityReference
$filter = Read-Host "Enter the user or group name to search in OU permissions"
$report |
Where-Object {$_.IdentityReference -like "*$filter*"} |
Select-Object IdentityReference, OrganizationalUnit, IsInherited -Unique |
Sort-Object IdentityReference
Your problem has nothing to do with the $schemaIDGUID variable.
The problem is this line:
$report += Get-Acl -Path "AD:\$OU"
The AD: drive is mapped to ADWS on a DC in your home domain, on module import, so you'll need to explicitly create another drive that maps to the target domain instead:
$domain = "other.domain.tld"
# discover naming context + find a DC to query
$defaultNC = (Get-ADRootDSE -Server $domain).defaultNamingContext
$DC = Get-ADDomainController -Server $domain
# map new ADTemp:\ drive
New-PSDrive -Name ADTemp -PSProvider ActiveDirectory -Root $defaultNC -Server $DC
For the rest of the script, the only thing you need to change is the previously mentioned line, to:
$report += Get-Acl -Path "ADTemp:\$OU"

Custom Object multiple lines

I created a script to pull some info from AD, the problem I'm having is the Secondary SMTP address field has more then one line. I'd like to show each secondary SMTP in a new line. My Script output looks like {smtp:joe.rodriguez#con...
$searchBase = 'OU=Users,DC=Contoso,DC=LOCAL'
$users = Get-ADUser -filter 'enabled -eq $true' -SearchBase $searchBase |select -expand samaccountname
Foreach ($user in $users){
$Secondary = get-recipient -Identity $user -ErrorAction SilentlyContinue| select Name -ExpandProperty emailaddresses |? {$_.Prefix -like "SMTP" -and $_.IsPrimaryAddress -like "False"} |select -ExpandProperty $_.Smtpaddress
New-Object -TypeName PSCustomObject -Property #{
Name = Get-ADUser -Identity $user -Properties DisplayName |select -ExpandProperty DisplayName
"Login ID" = Get-ADUser -Identity $user -Properties SamAccountName |select -ExpandProperty SamAccountName
Primary = get-recipient -Identity $user -ErrorAction SilentlyContinue| select Name -ExpandProperty emailaddresses |? {$_.Prefix -like "SMTP" -and $_.IsPrimaryAddress -like "True"} |select -ExpandProperty Smtpaddress
Secondary = $Secondary
}
}
Personally I'd make an array, pull your user list, and then iterate through the secondary SMTP addresses for each user adding your custom object to the array for each entry.
$Userlist = #()
$searchBase = 'OU=Users,DC=Contoso,DC=LOCAL'
$users = Get-ADUser -filter 'enabled -eq $true' -SearchBase $searchBase -Properties DisplayName
Foreach ($user in $users){
$Recip = get-recipient -Identity $user.samaccountname -ErrorAction SilentlyContinue| select Name -ExpandProperty emailaddresses |? {$_.Prefix -like "SMTP"}
$Recip|? {$_.IsPrimaryAddress -like "False"} |select -ExpandProperty Smtpaddress |%{
$UserList += New-Object -TypeName PSCustomObject -Property #{
Name = $User.DisplayName
"Login ID" = $User.SamAccountName
Primary = $Recip|? {$_.IsPrimaryAddress -like "True"} |select -ExpandProperty Smtpaddress
Secondary = $_
}
}
}
This script (based off your script above) also reduces the number of server queries by 3 per user I think, so it should run a ton faster.