How can I show the value of the attribute LastLogonTime?
function Get-MailboxesNotLoggedOnTo {
param(
[int]$days = 90
)
$mailboxes = Get-Mailbox -ResultSize 500
$mailboxes | Where-Object {
(Get-MailboxStatistics $_).LastLogonTime -and
(Get-MailboxStatistics $_).LastLogonTime -le (Get-Date).AddDays(-$days)
} | FT DisplayName, Alias, ServerName, LastLogonTime
}
This is happening because Get-Mailbox does not return a property called LastLogonTime. Get-MailboxStatistics does. What you need to do is add the timestamp as a property of your output
$mailboxes = Get-Mailbox -ResultSize 200
$mailboxes | Where-Object {
(Get-MailboxStatistics $_).LastLogonTime -and
(Get-MailboxStatistics $_).LastLogonTime -le (Get-Date).AddDays(-$days)
} | ForEach-Object {Add-Member -InputObject $_ -MemberType NoteProperty -Name LastLogonTime -Value (Get-MailboxStatistics $_).LastLogonTime -PassThru} |
Select DisplayName, Alias, ServerName, LastLogonTime
Using Add-Member we can fill in the missing piece. The one issue I have with this is the multiple calls to Get-MailboxStatistics which im working on improving now. Should be something closer to this.
$checkDate = (Get-Date).AddDays(-90)
$mailboxes = Get-Mailbox -ResultSize 200
$mailboxes | ForEach-Object{
$stats = Get-MailboxStatistics $_
If ($stats.LastLogonTime -and ($stats.LastLogonTime -le $checkDate)){
Add-Member -InputObject $_ -MemberType NoteProperty -Name LastLogonTime -Value $stats.LastLogonTime -PassThru
}
} | Select DisplayName, Alias, ServerName, LastLogonTime
The extra calls to Get-MailboxStatistics would make it slower. Reduced the call to only the one. Still using Add-Member with -PassThru which just pipes out to a select statement. This should be a more efficient approach.
Related
I need to list users of a connected drive and it's serial # in an output file. I'll be connecting between 12-24 drives in arrays at a time. I would like to be able to put the assigned drive letters into a variable. And then have the entire script loop for each connected drive. dumping serial + linking it to the users of that drive in a CSV output file
How can I put the assigned drive letters into an array?
$(get-physicaldisk; get-childitem -path (array variable):\Users) | add-content C:\path\to\my\output.csv
almost gets the output I need when I try this on a single drive. But I'd really like to clean it up and only display the important info (PSChildName) excluding all default, public admin accounts to reduce duplicate un-needed info.
I wanted this to work
$(get-physicaldisk | select-object FriendlyName, SerialNumber)-$(get-childitem -path L:\Users| select-object PSChildName)
but it did not
I need it to grab the serial for each drive - and output the users associated with that drive … i'm struggling with making the output look the way I want.
For each - drive in array - output ((serial #) + (users on the drive)) amending my .csv
After much plugging and chugging i'm now here, thanks to everyone's help
function Get-UsersOnDrive([string[]]$DriveLetters){
if (!$DriveLetters){
$DriveLetters = Get-WmiObject Win32_Logicaldisk | %{$_.Name -replace ":", ""}
}
foreach($DriveLetter in $DriveLetters)
{
$SerialNumber = get-partition -DriveLetter $DriveLetter -ErrorAction Ignore | get-disk | select -ExpandProperty SerialNumber
$path = $DriveLetter + ":\Users"
$Users = get-childitem -path $path | select-object PSChildName
$Users | %{
$OutPut = new-object PsCustomObject
$OutPut | Add-Member -MemberType NoteProperty -Name SerialNumber -Value $SerialNumber -PassThru |
Add-Member -MemberType NoteProperty -Name Username -Value $_
return $OutPut
}
}
}
Get-UsersOnDrive -DriveLetters #("C") | Export-Csv -Path C:\sample\Test.csv -NoTypeInformation
Ok so here is what i came up with and its rough
Get-WmiObject Win32_Logicaldisk | %{
$DriveLetter = $_.Name -replace ":", ""
$SerialNumber = get-partition -DriveLetter $DriveLetter | get-disk | select -ExpandProperty SerialNumber
$Users = Get-WmiObject Win32_UserProfile | select -ExpandProperty LocalPath | ?{$_ -like "$DriveLetter*"} | %{
$_ -replace '.*\\'
}
$Users | %{
$OutPut = new-object PsCustomObject
$OutPut | Add-Member -MemberType NoteProperty -Name SerialNumber -Value $SerialNumber -PassThru |
Add-Member -MemberType NoteProperty -Name Username -Value $_
return $OutPut
}
} | Export-Csv -Path C:\sample\Test.csv -NoTypeInformation
A. Get WMI LogicalDisk (gets you the drive letters)
B. Pass the $DriveLetter into a get-partition and get the SerialNumber property value.
C. Get Users Profile path, then find the ones on the current drive and replace everything except for the last slash, which is the username
D. Foreach user on drive we create a Custom Object and add the properties SerialNumber and Username, then return output and export to CSV
Here is a function that you can call to get users on drive as well
function Get-UsersOnDrive([string[]]$DriveLetters){
if (!$DriveLetters){
$DriveLetters = Get-WmiObject Win32_Logicaldisk | %{$_.Name -replace ":", ""}
}
foreach($DriveLetter in $DriveLetters){
$SerialNumber = get-partition -DriveLetter $DriveLetter -ErrorAction Ignore | get-disk | select -ExpandProperty SerialNumber
$Users = Get-WmiObject Win32_UserProfile | select -ExpandProperty LocalPath | ?{$_ -like "$DriveLetter*"} | %{
$_ -replace '.*\\'
}
$Users | %{
$OutPut = new-object PsCustomObject
$OutPut | Add-Member -MemberType NoteProperty -Name SerialNumber -Value $SerialNumber -PassThru |
Add-Member -MemberType NoteProperty -Name Username -Value $_
return $OutPut
}
}
}
Get-UsersOnDrive -DriveLetters #("C","V","F") | Export-Csv -Path C:\sample\Test.csv -NoTypeInformation
If you remove -DriveLetters parameter and the drives then it will check all drives
The following code gets the disk serial number. I am not sure why that is needed. Will this give you a start?
function Get-DiskSerialNumber {
param(
[Parameter(Mandatory = $true,Position=0)]
[string] $DriveLetter
)
Get-CimInstance -ClassName Win32_DiskDrive |
Get-CimAssociatedInstance -Association Win32_DiskDriveToDiskPartition |
Get-CimAssociatedInstance -Association Win32_LogicalDiskToPartition |
Where-Object DeviceId -eq $DriveLetter |
Get-CimAssociatedInstance -Association Win32_LogicalDiskToPartition |
Get-CimAssociatedInstance -Association Win32_DiskDriveToDiskPartition |
Select-Object -Property SerialNumber
}
& openfiles /query /fo csv |
Select-Object -Skip 5 |
ConvertFrom-Csv -Header #('ID','USER','TYPE','PATH') |
Select-Object -Property USER,#{name='DRIVE';expression={$_.PATH.Substring(0,2)}} |
Sort-Object -Property DRIVE,USER -Unique |
Select-Object -Property *,
#{name='SERIALNUMBER';expression={(Get-DiskSerialNumber -Drive $_.DRIVE).SerialNumber}}
For a given mailbox, I want to list of any users who have any of the following permissions:
send as
send on behalf of
full access
I haven't been able to find a simple way to get all 3 at once, so I have been going at it on a per permission basis...
get-exolmailbox -identity "example#example.com" | get-exolmailboxpermission | where { ($_.AccessRights -eq "FullAccess") -and ($_.IsInherited -eq $false) -and -not ($_.User -like "NT AUTHORITY\SELF") }
get-exolmailbox -Identity "example#example.com" | Get-ADPermission | ? { ($_.ExtendedRights -like "*send*") -or ($_.ExtendedRights -like "*full*") -and -not ($_.User -like "*\self*") } | FT -auto User,ExtendedRights
get-exolmailbox -identity "example#example.com" | fl displayname, grantsendonbehalfto
Is there was a more elegant way to get that same info before I put some time into figuring out how to format the results the way I want?
I would prefer to end up with an excel file that lists each user by display name and which permissions they have to the mailbox.
Something like this should do what you want, it creates a custom object and assigns the info from your commands to its properties.
$emailaddress = "user1#example.com","user2#example.com"
$MailboxPermissions = #()
foreach ($email in $emailaddress)
{
$exolmailbox = get-exolmailbox -identity $email
$FullAccess = $exolmailbox | where { ($_.AccessRights -eq "FullAccess") -and ($_.IsInherited -eq $false) -and -not ($_.User -like "NT AUTHORITY\SELF") }
$SendAs = $exolmailbox | Get-ADPermission | ? { ($_.ExtendedRights -like "*send*") -or ($_.ExtendedRights -like "*full*") -and -not ($_.User -like "*\self*") }
$MailboxInfo = New-Object System.Object
$MailboxInfo | Add-Member -type NoteProperty -name DisplayName -value $exolmailbox.displayname
$MailboxInfo | Add-Member -type NoteProperty -name FullAccess -value $FullAccess
$MailboxInfo | Add-Member -type NoteProperty -name SendAsUser -value $SendAs.User
$MailboxInfo | Add-Member -type NoteProperty -name SendAsExtendedRights -value $SendAs.ExtendedRights
$MailboxInfo | Add-Member -type NoteProperty -name GrantSendOnBehalfTo -value $exolmailbox.grantsendonbehalfto
$MailboxPermissions += $MailboxInfo
}
$MailboxPermissions
Note: I can't test this as I can't find anything online that references get-exolmailbox, and I've only ever seen/used get-mailbox before.
I need to create a report for exchange server 2010.
Where I need the users Display name, lastlogontime and account status ie enabled or disable.
get-mailbox statistics shows lastlogon and get-user can show account control status.
So I tried this not working anyhow.
Get-User -ResultSize Unlimited | Where { $_.RecipientType -eq ‘UserMailbox’ } | ForEach { $Users = #{} } { $Users[$_.SamAccountName] = $_ }
get-mailboxstatistics -server 00-exchbx01 |
ForEach {
New-Object psobject |
Add-Member -PassThru NoteProperty name $_.name |
Add-Member -PassThru NoteProperty lastlogontime $_.lastlogontime |
Add-Member -PassThru NoteProperty UserAccountControl $Users[$_.SamAccountName].UserAccountControl
} |select name,lastlogontime,useraccountcontrol |sort-lastlogontime -descending | export-csv c:\ussersxx.csv -nti
also tried No luck Yet any Help?
Get-User -ResultSize Unlimited | Where { $_.RecipientType -eq ‘UserMailbox’ } | ForEach { $Users = #{} } { $Users[$_.SamAccountName] = $_ } | get-mailboxstatistics -server 00-exchbx01 | select Name,useraccountcontrol, lastlogontime|sort-lastlogontime -descending | Export-csv c:\report.csv
`
This should do it.
$outtbl = #()
$users = Get-User -ResultSize Unlimited | Where { $_.RecipientType -eq ‘UserMailbox’ }
$users | % {
$x = Get-MailboxStatistics $_ | Select LastLogonTime
$t = New-Object PSObject -Property #{
Name = $_.Name
LastLogonTime = $x.LastLogontime
UserAccountControl = $_.UserAccountControl
}
$outtbl += $t
}
This is the way I've always done these "combining results of different commands" type scenarios.
You can then do $outtbl | Sort LastLogonTime -Descending | Export-Csv c:\ussersxx.csv -nti to export the data
There's a couple of things here, most of that looks fine except for your last line:
||sort-lastlogontime -descending |
This should become:
| sort -property lastlogontime -descending |
What you'll also run into is that you might end up with things coming down the pipeline from Get-MailboxStatistics that aren't in your $Users hash table. This will results in getting errors when using your hash table to fill out a property the psobject.
You could adjust this to iterate through the hash table, passing the SamAccountName as the value for the Identity property (but this will likely be slower), or add in some error handling so that you just end up with an empty property rather than it completely erroring out.
I'm working on a basic PowerShell script that inputs a pair of dates then gets all accounts with passwords expiring between those times. I'd like to output the data to the console in a way that is compatible with Export-Csv. That way the person running the script can either just view in the console, or get a file.
Here is my script:
[CmdletBinding()]
param(
[string]$StartDate = $(throw "Enter beginning date as MM/DD/YY"),
[string]$EndDate = $(throw "Enter end date as MM/DD/YY")
)
$start = Get-Date($StartDate)
$end = Get-Date($EndDate)
$low = $start.AddDays(-150)
$high = $end.AddDays(-150)
$passusers = Get-ADUser -Filter { PasswordLastSet -gt $low -and PasswordLastSet -lt $high -and userAccountControl -ne '66048' -and userAccountControl -ne '66080' -and enabled -eq $true} -Properties PasswordLastSet,GivenName,DisplayName,mail,LastLogon | Sort-Object -Property DisplayName
$accts = #()
foreach($user in $passusers) {
$passLastSet = [string]$user.PasswordLastSet
$Expiration = (Get-Date($passLastSet)).addDays(150)
$obj = New-Object System.Object
$obj | Add-Member -MemberType NoteProperty -Name Name -Value $user.DisplayName
$obj | Add-Member -MemberType NoteProperty -Name Email -Value $user.mail
$obj | Add-Member -MemberType NoteProperty -Name Expiration -Value $expiration
$accts += $obj
}
Write-Output ($accts | Format-Table | Out-String)
This prints to the console perfectly:
Name Email Expiration
---- ----- ----------
Victor Demon demonv#nsula.edu 1/3/2016 7:16:18 AM
However when called with | Export-Csv it doesn't:
#TYPE System.String
Length
5388
I've tried multiple variations using objects, and data tables, however it seems like I can only get it to work for console or for CSV, not for both.
Replace
Write-Output ($accts | Format-Table | Out-String)
with
$accts
That way your users can run your script any way they like, e.g.
.\your_script.ps1 | Format-Table
.\your_script.ps1 | Format-List
.\your_script.ps1 | Export-Csv
.\your_script.ps1 | Out-GridView
...
Format-Table | Out-String converts your output to a single string whereas Export-Csv expects a list of objects as input (the object properties then become the columns of the CSV). If Export-Csv is fed a string, the only property is Length, so you get a CSV with one column and one record.
$accts | ConvertTo-Csv | Tee -File output.csv | ConvertFrom-Csv
i wrote a script that gonna disabled old users...
and i need to do an exclude list to it...
the exclude list should be .csv, with 3 columns "Name","SamaccountName","Reason"...
i'm kind of stuck with the exclude list filtering...
i tried to do -notmatch and -notcontains and nothing worked for me...
i even try to do a foreach with if but the same...
Function Get-ADLockOldUsers {
param ()
begin{
[datetime]$myDate = '01/01/1601 02:00:00'
$colObj = #()
$AllUsers = (Get-ADUser -Filter * -Properties lastLogonTimestamp | ? {$_.Enabled} | Select-Object Name,SamAccountName,#{N="LastLogon";E={[datetime]::FromFileTime($_.lastLogonTimestamp)}})
$AllUsers = $AllUsers | ? {(Get-Date).AddDays(-30) -gt $_.LastLogon -and -not ($_.LastLogon -eq $myDate)}
}
process {
$AllUsers | % {
$obj = New-Object psobject
$obj | Add-Member noteproperty 'Name' $_.Name -Force
$obj | Add-Member noteproperty 'SamAccountName' $_.SamAccountName -Force
$obj | Add-Member noteproperty 'LastLogon' $_.LastLogon -Force
$obj | Add-Member noteproperty 'NeedDisabled' $true -Force
$colObj += $obj
}
}
end { return $colObj }
}
Function Set-ADLockUser {
param()
begin{
if (Test-Path '.\excludeusers.csv') {
$excludeUsers = Import-Csv '.\excludeusers.csv'
$DUser = #()
$colUsers = Get-ADLockOldUsers
$colUsers | ? {$_.SamAccountName -notcontains $excludeUsers} | % {Set-ADUser -Identity $_.SamAccountName -Enabled $false -WhatIf }
}
else { Write-Output "Error! excludeusers.csv cannot be found, stop script"; break }
}
process {
}
end{}
}
Set-ADLockUser
A string value can never contain an array, so
$_.SamAccountName -notcontains $excludeUsers
will always evaluate to $true. You need to reverse the check and make the reference an array of strings (the CSV import produces an array of custom objects). Selecting only the field SamaccountName from the imported CSV and switching the arguments should do what you want:
$excludeUsers = Import-Csv '.\excludeusers.csv' | % { $_.SamaccountName }
...
$colUsers | ? { $excludeUsers -notcontains $_.SamAccountName } | ...
As a side note, you could simplify the the code for finding obsolete accounts like this:
$myDate = Get-Date '01/01/1601 02:00:00'
$limit = (Get-Date).AddDays(-30)
$colObj = Get-ADUser -Filter * -Properties * `
| ? { $_.Enabled } `
| select Name,SamAccountName,#{n="NeedDisabled";e={$true}},
#{n="LastLogon";e={[datetime]::FromFileTime($_.lastLogonTimestamp)}} `
| ? { $limit -gt $_.LastLogon -and $_.LastLogon -ne $myDate }
This is the final solution...
<#
.Synopsis
Get All Users in the Domain and check the last logon Date
.Example
Set-ADLockUser -ReportOnly:$true
Get all users that didn't logon for a 30 days and write a report to the current directory
.Example
Set-ADLockUser -ReportOnly:$false
Get all users that didn't logon for a 30 days and disabled them
.Description
Get All Users in the Domain and check the last logon Date, and exclude some users from a list .\excludeusers.csv
.Parameter ReportOnly
Specifies if the script is in reportmode or active mode if ReportOnly=$false all the relevant users will lock
.Outputs
PSObject[]
.Notes
Name: Set-ADLockUser
Author: Ohad Halali
Date: 14.07.2013
.Link
#>
Function Get-ADLockOldUsers {
param ()
begin{
[datetime]$myDate = '01/01/1601 02:00:00'
$colObj = #()
$AllUsers = (Get-ADUser -Filter * -Properties lastLogonTimestamp | ? {$_.Enabled} | `
Select Name,SamAccountName,#{N="LastLogon";E={[datetime]::FromFileTime($_.lastLogonTimestamp)}}) | `
? {(Get-Date).AddDays(-30) -gt $_.LastLogon -and -not ($_.LastLogon -eq $myDate)}
}
process {
$AllUsers | % {
$obj = New-Object psobject
$obj | Add-Member noteproperty 'Name' $_.Name -Force
$obj | Add-Member noteproperty 'SamAccountName' $_.SamAccountName -Force
$obj | Add-Member noteproperty 'LastLogon' $_.LastLogon -Force
$obj | Add-Member noteproperty 'NeedDisabled' $true -Force
$colObj += $obj
}
}
end { return $colObj }
}
Function Set-ADLockUser {
param([bool]$ReportOnly=$true)
begin{
if (Test-Path '.\excludeusers.csv') {
$excludeUsers = Import-Csv '.\excludeusers.csv'
$colUsers = Get-ADLockOldUsers | ? {$excludeUsers.SamAccountName -notcontains $_.SamAccountName}
if ($ReportOnly) {
$colUsers | Export-Csv '.\Report.csv' -NoClobber -NoTypeInformation -Encoding ASCII -Force
}
else {
$colUsers.SamAccountName | Set-ADUser -SamAccountName $_ -Enabled:$False -Replace #{info="Disabled after no login for 30 days (Script)"} -WhatIf
}
}
else { Write-Output "Error! excludeusers.csv cannot be found, stop script"; break }
}
process {}
end{}
}
Set-ADLockUser