Folder Compare against AD Domain - powershell

I'm trying to clean up our storage from legacy users that no longer exist and getting misc results.
I have a share with all usernames as folder names (ex. \\storage\homedir\joeblow) AD username: Joeblow. Throughout various years users have been removed from the domain but the folders were never removed from the share. So I am walking the share and using that to query the domain to find if said user still exists. I seems to work most the time and fail randomly. Not sure why, because manually sometimes the code will execute fine. Any thoughts?
Here is the code:
Import-Module ActiveDirectory
$folders = dir \\storage.domain.edu\C$\homedir3 | where {$_.PSIsContainer -eq $true}
$folder4 = "\\storage.domain.edu\C$\homedir4"
function New-Folder($Name, $Size) {
$folderList = New-Object PSObject
$folderList | Add-Member -MemberType NoteProperty -Name Name -Value $Name
$folderList | Add-Member -MemberType NoteProperty -Name Size -Value $Size
$folderList | Add-Member -MemberType NoteProperty -Name User -Value $User
}
foreach ($i in $folders) {
Write-Host "Folder presently is folder $i"
#$ADuser=Get-ADUser -Filter {$i.sAMAccountName.ToUpper() -eq"$i"} -SearchBase "OU=Active,OU=UserAccounts,DC=ad,DC=domain,DC=edu"
#$ADuser=Get-ADUser -Filter {samaccountname -eq $i} -SearchBase "OU=Active,OU=UserAccounts,DC=ad,DC=domain,DC=edu" -Property samaccountname
$r = "\\STORAGE.domain.EDU\HOMEDIR\$i"
$r = $r.ToUpper()
$ADuser = Get-ADUser -Filter {sameaccountname -eq $i} -SearchBase "OU=Active,OU=UserAccounts,DC=ad,DC=domain,DC=edu" -Property homeDirectory, samaccountname
if (!$ADuser) {
Write-Host "Null yo"
$ADuser = Get-ADUser -Filter {homeDirectory -eq $r} -SearchBase "OU=Active,OU=UserAccounts,DC=ad,DC=domain,DC=edu" -Property homeDirectory, samaccountname
}
$ADname = $ADuser.samaccountname.ToUpper()
$ADuser = $ADuser.homeDirectory
$ADuser = $ADuser.toupper()
Write-Host "R be this: $r and equal $ADuser"
#Write-Host "The person's folder name is: $ADuser"
#$iUp = $i.ToUpper()
Write-Host "The folder's is: $i"
if ($ADuser -eq $r) {
Write-Host "User: $ADname is in HomeDir3 $ADuser"
} else {
#(Test-Path "$folder4\$ADuser".trim()) {
#$notFound = $i
$folderList = New-Folder -Name $ADuser -User
Write-Host "$ADname failed"
}
}
#}
Write-Host "$folderList"
#$leftOvers = Compare-Object $folder4 $notFound
#Write-Host " Here is whats left $leftOvers"
#$i | Out-File -append "C:\deadaccounts.txt"

Related

Optimize slow powershell script

I wrote this script and it works but its painfully slow, can you please point out why ? and provide some ideas on how to optimize its functionality. in can make simple Powershell scrips however I have a very had time looking up methodology on google not knowing what to look for
my script
$i=1;
foreach ($PC in $ComputerName) {
$per = ($i/$ComputerName.Length)*100
try {
# Get-ADComputer $pcs -properties name,enabled | select-object name,enabled
$status = Get-ADComputer -Identity $PC -Properties Enabled | select-object -ExpandProperty Enabled
if(Test-Connection -ComputerName $PC -Quiet -Count 1){
$quserOut = quser.exe /SERVER:$PC 2>&1
if ($quserOut -match "No user exists"){
"$PC>On Line>$status>No users loggedIn"; continue
}else{
$users = $quserOut -replace '\s{2,}', ',' |
ConvertFrom-CSV -Header 'username', 'sessionname', 'id', 'state', 'idleTime', 'logonTime' |
Add-Member -MemberType NoteProperty -Name ComputerName -Value $PC -PassThru
$users = $users[1..$users.count]
for ($i = 0; $i -lt $users.count; $i++){
if ($users[$i].sessionname -match '^\d+$'){
$users[$i].logonTime = $users[$i].idleTime
$users[$i].idleTime = $users[$i].STATE
$users[$i].STATE = $users[$i].ID
$users[$i].ID = $users[$i].SESSIONNAME
$users[$i].SESSIONNAME = $null
}
}
$users = $users | Sort-Object -Property idleTime
# $status = Get-ADComputer -Identity $PC -Properties Enabled | select-object -ExpandProperty Enabled
$Usr = $users | Where-Object { $_.state -eq 'Active' } | select-object -ExpandProperty username
"$PC>On Line>$status>$Usr"
}
} else {
"$PC>Not Online>$status>NoUserDataRetrieve"
}
}
catch {
"$PC>Not in AD>$status>NoUserDataRetrieve"
}
Write-Progress -Activity "Procesando Usuarios:" -Status "Usuario EN Proceso: $i -- $PC" -PercentComplete $per
Start-Sleep -Milliseconds 100
$i++
}
this displays the following data
basically script test if PC exist in Active Directory, it does a ping test , and gets back current logged in user
Machine Name > Ping Test pass? > AD status > current logged in user
PC1>Online>True>BazVic
PC2>NotOnLine>True>No Available Data
PC3>OnLine>True>ReyesDa
PC2>NotOnLine>FALSE>No Available Data

Fetching domain users from local groups with powershell

I want to migrate from one server to another one and because of that it is needed to add some local groups in the new server. In these local groups the users added belong to the domain.
Ex.:
Server | Members
---------------------------|------------------
Server\Group1 | Domain\User1, Domain\User2
Server\Group2 | Domain\User2, Domain\User3
The following link https://www.petri.com/use-powershell-to-find-local-groups-and-members seems to resolve this, but I am getting an unexpected result
This is the PowerShell script
# set variables
$server = $env:COMPUTERNAME
$localgroup = "Administrators"
$Group= [ADSI]"WinNT://$Server/$LocalGroup,group"
# get users name
$members = $Group.psbase.Invoke("Members")
$members | ForEach-Object
{
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}
Get-WMIObject win32_group -filter "LocalAccount='True'" -computername $Server | Select PSComputername,Name,#{Name="Members";Expression={$_.GetRelated("Win32_UserAccount").Name -join ";"}}
The shown output is a two columns(although it should be 3, but PSComputerName is not being displayed where the Members column is empty)
Well, this is how I achieved the output and also exported it to a *.csv file
# set variables
$server = $env:COMPUTERNAME
$tableOutput = New-Object System.Collections.ArrayList
# get members
Function Get-Members($groupName){
$testgroup = [ADSI]"WinNT://$Server/$tmpGroupName,group"
$members = New-Object System.Collections.ArrayList
$testgroup.psbase.Invoke("Members") | ForEach-Object{
$searchFilter = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) -replace "\."," "
$tmpUser = Get-ADUser -Filter {(Name -like $searchFilter) -or (SamAccountName -like $searchFilter)}
if($tmpUser){
[void]$members.Add($tmpUser.UserPrincipalName)
}
}
$members
}
Get-WMIObject win32_group -Filter { (LocalAccount='True') } -computername $Server | ForEach-Object{
$tmpGroup = $_
# get data
$tmpGroupName = $tmpGroup.Name
$members = Get-Members($tmpGroupName)
$tmpGroupDescription = $tmpGroup.Description
# save into object
$groupObject = New-Object -TypeName PSObject
$groupObject | Add-Member -MemberType NoteProperty -Name GroupName -Value $tmpGroupName
$groupObject | Add-Member -MemberType NoteProperty -Name GroupDescription -Value $tmpGroupDescription
$groupObject | Add-Member -MemberType NoteProperty -Name UsersList -Value $members
[void]$tableOutput.Add($groupObject)
}
$tableOutput | Select GroupName, GroupDescription, #{Name='Users';Expression={$_.UsersList -join ','}} | Export-CSV -Path 'C:\test\users.csv' -Delimiter ';' -NoTypeInformation
Any correction would be appreciated.

Powershell error adding to an array

Hi I am trying to run a script to get users in a network into an array so that it can be outputted to a csv file along with other data that I am going to get, such as distribution groups.
The code script I am running is giving an error:
Method invocation failed because [System.Management.Automation.PSObject] doesn't contain a method named 'op_Addition'.
The script is a simple for loop:
$ActiveDirectoryList=#()
$UserDetails = get-aduser -filter {enabled -eq $true} -properties * | Select DisplayName,EmailAddress, SAMAccountName
$counter = 0
foreach($User in $UserDetails){
$ActiveDirectoryList = New-Object PSObject
$Users = get-aduser $User.SAMAccountName -properties *
if(!$Users.EmailAddress -eq ""){
$counter++
$ActiveDirectoryList | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $Users.DisplayName
$ActiveDirectoryList | Add-Member -MemberType NoteProperty -Name "Email Address" -Value $Users.EmailAddress
write-host $Users.DisplayName
$ActiveDirectoryList+=$ActiveDirectoryList
}
}
Tried looking on the internet for a solution but they don't seem to solve anything.
Don't reuse the same variable name for the array, and the individual objects that you want to add to the array. Here I've renamed the PSObject variable to $ActiveDirectoryObject:
$ActiveDirectoryList=#()
$UserDetails = get-aduser -filter {enabled -eq $true} -properties * | Select DisplayName,EmailAddress, SAMAccountName
$counter = 0
foreach($User in $UserDetails){
$ActiveDirectoryObject = New-Object PSObject
$Users = get-aduser $User.SAMAccountName -properties *
if(!$Users.EmailAddress -eq ""){
$counter++
$ActiveDirectoryObject | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $Users.DisplayName
$ActiveDirectoryObject | Add-Member -MemberType NoteProperty -Name "Email Address" -Value $Users.EmailAddress
write-host $Users.DisplayName
$ActiveDirectoryList += $ActiveDirectoryObject
}
}
Additional Note: This can also occur if you don't declare the array as an array or mistype it when you declare it. Simple little error. But, maybe it will help someone that comes here and still can't get it resolved. Check your array variable name declaration carefully.
# Example 1 of how you could unintentionally fubar it.
$ActiveDirectoryList=$null
# Example 2 of how you could unintentionally fubar it.
$ActiveDirectoryList_ExaggeratedExampleWrongName=#()
# Example 3. Same as 2 above, but not as easily identifiable type error
$ActiveDirectoryLists=#()
$UserDetails = get-aduser -filter {enabled -eq $true} -properties * | Select DisplayName,EmailAddress, SAMAccountName
$counter = 0
foreach($User in $UserDetails){
$ActiveDirectoryObject = New-Object PSObject
$Users = get-aduser $User.SAMAccountName -properties *
if(!$Users.EmailAddress -eq ""){
$counter++
$ActiveDirectoryObject | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $Users.DisplayName
$ActiveDirectoryObject | Add-Member -MemberType NoteProperty -Name "Email Address" -Value $Users.EmailAddress
write-host $Users.DisplayName
$ActiveDirectoryList += $ActiveDirectoryObject
}
}
+= kills puppies. (the whole array is copied every time)
$UserDetails = get-aduser -filter {enabled -eq $true} -properties |
Select DisplayName,EmailAddress, SAMAccountName
$counter = 0
$ActiveDirectoryList = foreach($User in $UserDetails){
$Users = get-aduser $User.SAMAccountName -properties *
if(!$Users.EmailAddress -eq ""){
$counter++
New-Object PSObject -property #{
Displayname = $Users.DisplayName
'Email Address' = $Users.EmailAddress
}
write-host $Users.DisplayName
}
}
This can be simplified to:
$ActiveDirectoryList = get-aduser -filter {enabled -eq $true -and
EmailAddress -like '*'} -properties Displayname,EmailAddress |
select Displayname,#{n='Email Address';e={$_.EmailAddress}}

Powershell - Get-AdUser: Exclude users in array

I want to generate a list of users, with the exception of a list of names. This exclusion list changes from week to week.
$exclude = #('smith, bob', 'jones, tom', ...)
$csvmaster = #()
$uacct = 'User Account'
$UserID = 'User ID'
$lastname = 'Last Name'
... other attributes
$ulist = get-aduser -filter {enabled -eq 'true'} -properties * | ? {$_.Distinguishedname -like '*Standard User*' -and $_.title -ne $null -and $_.employeenumber -ne $null}
foreach ($u in $ulist)
{
if ($u.name -notmatch $exclude) {
$csvline = New-Object System.Object
$csvline | Add-Member -MemberType NoteProperty -name $UserID -value $u.EmployeeNumber
$csvline | Add-Member -MemberType NoteProperty -name $lastname -value $u.surname
...other attributes
$csvmaster += $csvline
}
}
...Output to csv
When I run this, the names I want to exclude still make it into the list. I also tried -notcontains and excluding them like this:
$ulist = get-aduser -filter {enabled -eq 'true'} -properties * | ? {$_.Distinguishedname -like '*Standard User*' -and $_.title -ne $null -and $_.employeenumber -ne $null -and $_.name -notmatch $exclude}
This behaves the same way.
Cheers.
So I think my problem was the way Get-ADUser accepts input value. And/Or my logic in general. I changed the code to this:
$exclude = #( ..list..of..names..)
$csvline = #()
$ulist = get-aduser ...
foreach ($u in $ulist)
{
if ($exclude -notcontains $u.name)
{
...
$csvline += $u.name
}
}
And it is doing what I need.

Disabled ActiveDirectory Users from specific date with exclude list

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