List computers in AD with LastLoginTimestamp

List Workstation OS computers,

get-adcomputer -filter {OperatingSystem -notlike '*server*'} -Properties OperatingSystem,LastLogonTimestamp | Sort LastLogonTimestamp | Select Name,OperatingSystem,@{Name='LastLogonTimestamp'; Expression={[DateTime]::FromFileTime($_.LastLogonTimestamp).ToString("dd/MM/yyyy")}}

List Server OS computers,

get-adcomputer -filter {OperatingSystem -notlike '*server*'} -Properties OperatingSystem,LastLogonTimestamp | Sort LastLogonTimestamp | Select Name,OperatingSystem,@{Name='LastLogonTimestamp'; Expression={[DateTime]::FromFileTime($_.LastLogonTimestamp).ToString("dd/MM/yyyy")}}
Advertisements

Download wallpapers from InterfaceLift

The following code will automatically scrape the latest wallpapers from InterfaceLift. This code could be scheduled to run at startup and automatically update the target folder to be used as a wallpaper slideshow. A second script is to download to a static image file that will update as InterfaceLift releases a new image.

Shout out to InterfaceLift which have some of the most beautiful wallpapers out there.  If you use AdBlock be sure to support the site by excluding it and allowing the ads to download.

# Written by Ben Penney https://sysadminben.wordpress.com # Change this line to match the resolution of the image to download. It must be in the same string format used by InterfaceLift $Resolution = "1920x1200" # Folder where the images will download to $TargetPath = "$($env:USERPROFILE)\Pictures\InterfaceLift" # If folder InterfaceLift does not exist in the users Pictures folder it creates it If (!(Test-Path $TargetPath)) {New-Item -ItemType Directory $TargetPath} # The following string is used to match the urls of the preview images in the main page. These names are used in the full resolution images [regex]$regex = "(?<=\/wallpaper\/previews\/).*?(?=_672x420.jpg)" # This line downloads the web page and looks for the above string matches $regex.Matches((Invoke-WebRequest "https://interfacelift.com/wallpaper/downloads/date/any").Content) | foreach-object { # Generate the final image name from the matched strings above $FileName = "$($_)_$Resolution.jpg" # Check the image has not already been downloaded If (Test-Path "$TargetPath\$FileName") { # Skip if the file exists "'$FileName' exists. Skipping." } Else { # Download the file "Downloading file '$FileName'" Invoke-WebRequest "http://interfacelift.com/wallpaper/7yz4ma1/$FileName" -OutFile "$TargetPath\$FileName" } }

Second script that overwrites a single image file. Once the script is run for the first time point your wallpaper to the InterfaceLift.jpg file in your Pictures folder.

# Written by Ben Penney https://sysadminben.wordpress.com # Change this line to match the resolution of the image to download. It must be in the same string format used by InterfaceLift $Resolution = "1920x1200" # Folder where the images will download to $TargetPath = "$($env:USERPROFILE)\Pictures\InterfaceLift.jpg" # The following string is used to match the urls of the preview images in the main page. These names are used in the full resolution images [regex]$regex = "(?<=\/wallpaper\/previews\/).*?(?=_672x420.jpg)" # Grab the name of the latest image $LatestImage = (Invoke-WebRequest "https://interfacelift.com/wallpaper/downloads/date/any/index$int.html").Content)[0] # Generate the final filename of the full resolution image $FileName = "$($regex.Matches($LatestImage)_$Resolution.jpg" # Download the file "Downloading file '$FileName'" Invoke-WebRequest "http://interfacelift.com/wallpaper/7yz4ma1/$FileName" -OutFile "$TargetPath"

Read email in folder in O365

Earlier I posted how to read email in your inbox in O365. After having to write code to read email in a specific folder I thought I would add it here for everyone to use.

This specific code reads through all the emails in the specified folder and outputs who the email was sent to (yes weird I know but I was cc’ed on these specific emails so I wanted to know who really was the recipient)

# Written by Ben Penney https://sysadminben.wordpress.com $mail="ben.penney@domain.com" $password="password" $FolderName = "foldername" # Set the path to your copy of EWS Managed API $dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll" # Load the Assemply [void][Reflection.Assembly]::LoadFile($dllpath) # Create a new Exchange service object $service = new-object Microsoft.Exchange.WebServices.Data.ExchangeService #These are your O365 credentials $Service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($mail,$password) # this TestUrlCallback is purely a security check $TestUrlCallback = { param ([string] $url) if ($url -eq "https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml") {$true} else {$false} } # Autodiscover using the mail address set above $service.AutodiscoverUrl($mail,$TestUrlCallback) # create Property Set to include body and header of email $PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) # set email body to text $PropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text; # Set how many emails we want to read at a time $numOfEmailsToRead = 100 # Index to keep track of where we are up to. Set to 0 initially. $index = 0 $folderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(20) $folderView.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly) $folderView.PropertySet.Add([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName) $searchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$FolderName) $findFolderResults = $service.FindFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$searchFilter,$folderView) $findFolderResults.Folders.ID.UniqueID # Do/while loop for paging through the folder do { # Set what we want to retrieve from the folder. This will grab the first $pagesize emails $view = New-Object Microsoft.Exchange.WebServices.Data.ItemView($numOfEmailsToRead,$index) # Retrieve the data from the folder $findResults = $findFolderResults.Folders[0].FindItems($view) foreach ($item in $findResults.Items) { # load the additional properties for the item $item.Load($propertySet) # Output the results "$($item.ToRecipients.Address)" } # Increment $index to next block of emails $index += $numOfEmailsToRead } while ($findResults.MoreAvailable) # Do/While there are more emails to retrieve

Simple Robocopy Backup Script

This simple backup script will copy a folder to another server using dated folders and delete old backup folders older than the specified number of days (15 in this example). Add this script to the task scheduler. In an AD environment, assign rights to the target location to the computer object and run the task as SYSTEM to avoid pesky service accounts.

# Written by Ben Penney https://sysadminben.wordpress.com $limit = (Get-Date).AddDays(-15) $SourcePath = "c:\folder" $TargetPath = "\\backupnas\Backup\servername" $SMTPRecipients = "user1@email.com","user2@email.com" $SMTPFrom = "smtp@email.com" $SMTPServer = "smtp.domain.com" $SMTPSubject = "Server backup" $EmailBody = "Starting process $(Get-Date)`n" # Delete folders older than the $limit. Get-ChildItem -Path $path -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit } | ForEach { $EmailBody += "Deleting folder "+($_.Name) Remove-Item -Force -recurse } $DateString = (Get-Date).ToString("yyyyMMdd") $RobocopyOutput = RoboCopy $SourcePath $TargetPath\$DateString /COPY:DAT /E /R:2 /W:2 /NFL /NDL /NP # OPTIONAL CODE TO TRUNCATE THE ROBOCOPY OUTPUT If ($RobocopyOutput.Count -gt 200) { $RobocopyOutput = $RobocopyOutput[0..200] $RobocopyOutput[0] = "********** ROBOCOPY LOG TRUNCATED ************" } $EmailBody += [system.string]::join("`n",$RobocopyOutput) If ($EmailBody.Contains("ERROR")) {$SMTPSubject += " ***ERRORS***"} $EmailBody += "`n`nFinished process $(Get-Date)" Send-MailMessage -To $SMTPRecipients -From $SMTPFrom -Subject $SMTPSubject -SMTPServer $SMTPServer -Body $EmailBody

Using Powershell to read and write MSSQL

These examples are using a test database called EmailList with a table called Table1 which has three fields ‘username’,’email’ and ‘display name’.

This sample code will log in to MSSQL with your current logged in credentials,

$dataSource = "TESTSQLSERVER" $database = "EmailList" $connectionString = "Server=$dataSource;Database=$database;Integrated Security=True;" $connection = New-Object System.Data.SqlClient.SqlConnection $connection.ConnectionString = $connectionString $connection.Open() $command = $connection.CreateCommand()


This code will return the number of records with the specified email address,

$command.CommandText = "Select Count(*) FROM Table1 Where Email='testemail@test.com'" $command.ExecuteScalar()



This code with write a record to the database,

$command.CommandText = "INSERT INTO Table1 VALUES ('username','testemail@test.com','Users Name')" $command.ExecuteNonQuery()


This code will read records from the database,

$command.CommandText = "SELECT * FROM Table1 WHERE Email='testemail@test.com'" $reader = $command.ExecuteReader() While ($reader.Read()) {$reader[0];$reader[1];$reader[2]} $reader.Close()


Don’t forget to close your connection once you have finished,

$connection.Close()

Powershell – Removing data in brackets in string

I was given a task to auto generate email addresses based on first name and last name. Given that some people like to put data in their names in brackets to denote nicknames or maiden names one of the tasks was to reliably remove this data before working out the email address.

Trusty Google comes up with the following solution from this blog,

"string" -replace "\([^\)]+\)",""

This is a pretty elegant solution that produces the following results,

TEST 1
PS> "test(adsf)" -replace "\([^\)]+\)",""
test
TEST 2
PS> "test(adsf)(test)" -replace "\([^\)]+\)",""
test
TEST 3
PS> "test(adsf) (test)" -replace "\([^\)]+\)",""
test
TEST 4
PS> "test(adsf)xx(test)" -replace "\([^\)]+\)",""
testxx
TEST 5
PS> "test()" -replace "\([^\)]+\)",""
test()
TEST 6
PS> "test(a(dsf) (t)est)" -replace "\([^\)]+\)",""
test est)
TEST 7
PS> "test(adsf" -replace "\([^\)]+\)",""
test(adsf
TEST 8
PS> "test)" -replace "\([^\)]+\)",""
test)

Since I want a solution that removes every bracket no matter what I needed to take this a little further.

By replacing the + from the RegEx string with a * this will allow empty strings between the bracket start and end which resolves TEST 5,

TEST 5
PS> "test()" -replace "\([^\)]*\)",""
test

This works because the + symbol says I should have one or more of the character before me in the string which is [^/)] meaning not end bracket. By replacing it with the * symbol I am saying you can have none or more of those characters.

By adding a * character to the end of the RegEx string we can also accommodate the string with the missing closing bracket making the assumption that there should have been a closing bracket at the end of the string (ignore this if you do not want to make this assumption),

TEST 7
PS> "test(adsf" -replace "\([^\)]*\)*",""
test

As for the other two failures, we will just have to take it on the chin and accept that we can’t resolve everything and simply remove the extra characters with an additional replace statement,

"string" -replace "\([^\)]*\)*","" -replace "[\(\)]",""

Which provides the following results,

TEST 1
PS> "test(adsf)" -replace "\([^\)]*\)*","" -replace "[\(\)]",""
test
TEST 2
PS> "test(adsf)(test)" -replace "\([^\)]*\)*","" -replace "[\(\)]",""
test
TEST 3
PS> "test(adsf) (test)" -replace "\([^\)]*\)*","" -replace "[\(\)]",""
test
TEST 4
PS> "test(adsf)xx(test)" -replace "\([^\)]*\)*","" -replace "[\(\)]",""
testxx
TEST 5
PS> "test()" -replace "\([^\)]*\)*","" -replace "[\(\)]",""
test
TEST 6
PS> "test(a(dsf) (t)est)" -replace "\([^\)]*\)*","" -replace "[\(\)]",""
test est
TEST 7
PS> "test(adsf" -replace "\([^\)]*\)*","" -replace "[\(\)]",""
test
TEST 8
PS> "test)" -replace "\([^\)]*\)*","" -replace "[\(\)]",""
test

As always let me know if I have forgotten anything or you have any questions.
Thanks

All users who have logged in to AD in the past x hours

This query grabs all the users who have a last logon timestamp shorter than 15 days ago and then for each of those users checks each of the Domain Controllers for the latest logon and reports the user if they have logged in in the past 8 hours.

$dcs = Get-ADDomainController -Filter *
$FileDate = [DateTime]::Now.AddDays(-15).ToFileTime()
Get-AdUser -filter {LastLogonTimestamp -gt $FileDate} | ForEach {
    $time = 0
    foreach($dc in $dcs)
    { 
        $user = Get-ADUser $_.Name -Server $dc.HostName -Properties lastLogon 
        if($user.LastLogon -gt $time) 
        {
            $time = $user.LastLogon
        }
    }
    $dt = [DateTime]::FromFileTime($time)
    If ($dt -gt [DateTime]::Now.AddHours(-8)) {"$($_.Name) last logged on at: $dt"}
}

Migrate FSRM Quotas using PowerShell to 2012 R2 – Simple Version

UPDATE 1.05
– Remove commas from size value
– Added handle for “The requested object was not found” result from dirquota.exe

UPDATE 1.04
– Updated code for folders that have no share path or multiple share paths

UPDATE 1.03
– Updated E-mail notification to handle ‘from’ field
– Updated notification section to handle empty notifications (threshold but no actions)

UPDATE: 1.02
– Added code to fix paths with dollar signs

UPDATE: 1.01
– Updated code to handle path not found if no quota exists.
– Updated example to include how to handle paths with dollar signs

This is an updated version of my previous script to migrate quotas from Windows 2008 R2 to Windows 2012 R2

Previous version that takes into account already applied auto quotas to limit the output to only quotas that need to be updated.

This version simply sets all of the quotas and ignores auto quotas. If you use auto quotas then the best method is the use the output from this script to duplicate the quotas then add the auto quotas manually afterwards.

This script makes the following assumptions,
1) The quota templates needed to be applied have been migrated to the new server. This is a native command using dirquota.exe template export /File:PATH
2) There are currently no quotas on the new server. All Auto Quotas are to be assigned after this scripts output has been run on the new server.
3) DIRQUOTA LIMITATION: Commands are set with a KillTimeOut of 10 minutes. You can change this manually in either the script or the output.
4) DIRQUOTA LIMITATION: dirquota.exe does not output if the Report ‘Files By Property’ so due to this it is assumed that this report is ticked on for all instances of report actions.

# Written by Ben Penney https://sysadminben.wordpress.com # Version 1.05 # This script has been written to be run on the old/source FSRM server and the output generated to be executed on the target server. # This script has been tested on 2008 R2 and 2012 R2 source servers and 2012 R2 target servers. # SourcePath is the local path on the old server of the folder you want to export the quotas from. # TargetPath is the local path on the new server where you will execute the generated PowerShell commands # Example: # .\ExportQuotas -SourcePath "O:\StaffShared" -TargetPath "C:\TEST" > ImportQuotas.ps1 # DOLLAR SIGNS IN PATH? - Don't forget to escape the dollar signs with a ` character Param([Parameter(Mandatory = $true)] $SourcePath,$TargetPath) Function processDirQuotaOutput ($QuotaOutput) { If ($QuotaOutput -like '*The specified path is invalid.*') {Return} If ($QuotaOutput -like "*not found*" -Or $QuotaOutput -like "*No quotas exist*") {Return} [int]$LineNum = 2 If ($QuotaOutput[1] -like 'This tool is deprecated*') {$LineNum += 2} # For 2012 output While ($LineNum -lt $QuotaOutput.Length) { # ---------- Quota Path Line ---------- $QuotaPath = $QuotaOutput[$LineNum].Substring(24,$QuotaOutput[$LineNum].Length-24) $QuotaPathNew = $($QuotaPath -iReplace(($SourcePath -replace "\\","\\" -replace "\$","\$"),$TargetPath)) $QuotaPathParent = $QuotaPath.SubString(0,$QuotaPath.LastIndexOf("\")) $LineNum++ # ---------- Share Path (2008) or Description (2012) Line ---------- # Skipped While ($QuotaOutput[$LineNum].Substring(0,15) -ne "Source Template") {$LineNum++} # ---------- Source Template Line ---------- If ($QuotaOutput[$LineNum] -like '*(Does not match template)') { $SourceTemplateMatches = $false $SourceTemplate = $QuotaOutput[$LineNum].Substring(24,$QuotaOutput[$LineNum].Length-50) } ElseIf ($QuotaOutput[$LineNum] -like '*(Matches template)') { $SourceTemplateMatches = $true $SourceTemplate = $QuotaOutput[$LineNum].Substring(24,$QuotaOutput[$LineNum].Length-43) } $LineNum++ # ---------- Quota Status Line ---------- If ($QuotaOutput[$LineNum] -like '*Disabled') {$QuotaStatus = "-Disabled "} $LineNum++ # ---------- Limit Line ---------- $Limit = $QuotaOutput[$LineNum].Substring(24,$QuotaOutput[$LineNum].Length-31).Replace(' ','').Replace(',','') If ($QuotaOutput[$LineNum].Substring($QuotaOutput[$LineNum].Length-5,4) -eq 'Soft') { $LimitType = "-SoftLimit" } $LineNum++ # ---------- Used, Available, Peak Usage Line ---------- # Skipped $LineNum += 3 # ---------- START: Generate Quota commands ---------- # Before thresholds line generate command to create quota $FRSMCommand = "New-FsrmQuota -Path '$QuotaPathNew' -Size $Limit $LimitType $QuotaStatus" If ($SourceTemplate -ne $Null) { $FRSMCommand += " -Template '$SourceTemplate'" } $FRSMCommand # ----------- END: Generate Quota commands ----------- # ---------- Thresholds Line ---------- $LineNum += 2 If ($QuotaOutput[$LineNum-2] -notlike '*None') { $Thresholds = "" While ($LineNum -lt $QuotaOutput.Length -And ` $QuotaOutput[$LineNum] -notlike 'Quota Path:*') { $Actions = "" [int]$NotificationLimit = $QuotaOutput[$LineNum].SubString($QuotaOutput[$LineNum].IndexOf("(")+1,3).Trim() $LineNum += 2 While ($LineNum -lt $QuotaOutput.Length -And ` $QuotaOutput[$LineNum] -notlike 'Quota Path:*' -And ` $QuotaOutput[$LineNum] -notlike 'Notifications for *') { $NotificationType = "Error" If ($QuotaOutput[$LineNum].Length -gt 32) {$NotificationType = $QuotaOutput[$LineNum].SubString(32,$QuotaOutput[$LineNum].Length-32)} Switch ($NotificationType) { 'Error' {$LineNum += 2} 'Event Log' { [int]$RunLimitInterval = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-39) $EventType = $QuotaOutput[$LineNum+2].SubString(32,$QuotaOutput[$LineNum+2].Length-32) $MessageBody = $QuotaOutput[$LineNum+3].SubString(32,$QuotaOutput[$LineNum+3].Length-32) $LineNum += 5 While ($LineNum -lt $QuotaOutput.Length -And ` $QuotaOutput[$LineNum] -notlike 'Quota Path:*' -And ` $QuotaOutput[$LineNum] -notlike '*Notification Type:*' -And ` $QuotaOutput[$LineNum] -notlike 'Notifications for *') { $MessageBody += "`r`n" + $QuotaOutput[$LineNum-1] $LineNum++ } $Actions += ",(New-FsrmAction Event -EventType $EventType -Body '$MessageBody')" } 'E-mail' { [int]$RunLimitInterval = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-39) $MailTo = $QuotaOutput[$LineNum+2].SubString(32,$QuotaOutput[$LineNum+2].Length-32) $LineNum += 3 $MailSubject = "" If ($QuotaOutput[$LineNum] -like '*Mail Subject:*') { $MailSubject = $QuotaOutput[$LineNum].SubString(32,$QuotaOutput[$LineNum].Length-32) $LineNum++ } If ($QuotaOutput[$LineNum] -like '*Mail From:*') {$LineNum++} $MessageBody = $QuotaOutput[$LineNum].SubString(32,$QuotaOutput[$LineNum].Length-32) $LineNum += 2 While ($LineNum -lt $QuotaOutput.Length -And ` $QuotaOutput[$LineNum] -notlike 'Quota Path:*' -And ` $QuotaOutput[$LineNum] -notlike '*Notification Type:*' -And ` $QuotaOutput[$LineNum] -notlike 'Notifications for *') { $MessageBody += "`r`n" + $QuotaOutput[$LineNum-1] $LineNum++ } $Actions += ",(New-FsrmAction Email -MailTo '$MailTo' -Subject '$MailSubject' -Body '$MessageBody'" $Actions += " -RunLimitInterval $RunLimitInterval)" } 'Command' { [int]$RunLimitInterval = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-39) $Command = $QuotaOutput[$LineNum+2].SubString(32,$QuotaOutput[$LineNum+2].Length-32) $Arguments = $QuotaOutput[$LineNum+3].SubString(32,$QuotaOutput[$LineNum+3].Length-32) $WorkingDirectory = $QuotaOutput[$LineNum+4].SubString(32,$QuotaOutput[$LineNum+4].Length-32) Switch ($QuotaOutput[$LineNum+5].SubString(32,$QuotaOutput[$LineNum+5].Length-32)) { 'NT AUTHORITY\LOCAL SERVICE' {$RunAs = 'LocalService'} 'NT AUTHORITY\SYSTEM' {$RunAs = 'LocalSystem'} 'NT AUTHORITY\NETWORK SERVICE' {$RunAs = 'NetworkService'} } $LineNum += 7 $Actions += ",(New-FsrmAction Command -Command '$Command' -CommandParameters '$Arguments' -WorkingDirectory '$WorkingDirectory'" $Actions += " -SecurityLevel $RunAs -RunLimitInterval $RunLimitInterval -Killtimeout 10)" } 'Report' { #---Do nothing for now--- [int]$RunLimitInterval = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-39) $LineNum += 2 $Reports = "FilesByProperty" While ($QuotaOutput[$LineNum] -notlike '*Reports saved to:*') { Switch ($QuotaOutput[$LineNum].SubString(6,10)) { 'Duplicate ' {$Reports += ",DuplicateFiles"} 'File Scree' {$Reports += ",FileScreen"} 'Files by F' {$Reports += ",FilesByFileGroup"} 'Files by O' {$Reports += ",FilesByOwner"} 'Large File' {$Reports += ",LargeFiles"} 'Least Rece' {$Reports += ",LeastRecentlyAccessed"} 'Most Recen' {$Reports += ",MostRecentlyAccessed"} 'Quota Usag' {$Reports += ",QuotaUsage"} } $LineNum++ } $SendReportsTo = "" If ($QuotaOutput[$LineNum+1].Length -gt 32) { $SendReportsTo = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-32) } $LineNum += 3 $Actions += ",(New-FsrmAction Report -ReportTypes $Reports -MailTo '$SendReportsTo')" } } } If ($Actions -ne '') {$Thresholds += ",(New-FsrmQuotaThreshold -Percentage $NotificationLimit -Action $($Actions.SubString(1)))"} } If ($Thresholds -ne '') {"Set-FsrmQuota -Path '$QuotaPathNew' -Threshold $($Thresholds.SubString(1))"} } # ----------- END: Generate Threshold commands ----------- # ---------- START: Reset variables ---------- $QuotaPath = $null $QuotaPathNew = $null $QuotaPathParent = $null $SourceTemplate = $null $SourceTemplateMatches = $null $QuotaStatus = $null $Limit = $null $LimitType = $null # ----------- END: Reset variables ----------- } } # ---------- START: Process Quotas ---------- processDirQuotaOutput (dirquota quota list /path:$SourcePath\* -List-Notifications) processDirQuotaOutput (dirquota quota list /path:$SourcePath\ -List-Notifications) # ----------- END: Process Quotas -----------

Convert all group types in OU with Powershell

Using the following command will convert every group in that OU (and sub OUs unless you add the -SearchScope OneLevel switch) to type Distribution with Scope Global.

get-adgroup -filter * -SearchBase "OU=Groups,DC=work,DC=com" | ForEach {$x=[ADSI]"LDAP://CN=$($_.Name),OU=Groups,DC=work,DC=com"; $x.Put("groupType","2"); $x.setInfo()}

To change to the following group types/scopes use the following values for “groupType”,

Distribution – Universal = 8
Distribution – Domain Local = 4
Distribution – Global = 2

**STILL CANNOT GET THE FOLLOWING TO WORK**
Security – Universal = -2147483640
Security- Domain Local = -2147483644
Security- Global = -2147483646

Audit all users in Active Directory

This will output all users in the domain with their last login timestamp converted to dd/mm/yyyy format, creation date, and enabled value.

get-aduser -Filter * -Property whenCreated, LastLogonTimeStamp, AccountExpirationDate | Select Distinguishedname, whenCreated,@{Name='LastLogonTimestamp'; Expression={[DateTime]::FromFileTime($_.LastLogonTimestamp).ToString("dd/MM/yyyy")}}, AccountExpirationDate, Enabled | Export-CSV output.csv

Add the following switch to the get-aduser command to limit the search,

-SearchBase "OU=staff,ou=users,ou=business,dc=work,dc=com"

Add the following command to exclude any objects in the sub OU ‘Archive’,

| Where {$_.DistinguishedName -notlike '*Archive*'}

Add the following switch to get-aduser command to not search sub OUs,

-SearchScope OneLevel

Example below with all options,

get-aduser -filter * -SearchBase "OU=staff,ou=users,ou=business,dc=work,dc=com" -SearchScope OneLevel -Property whenCreated, LastLogonTimeStamp, AccountExpirationDate | Select Distinguishedname, whenCreated, @{Name='LastLogonTimestamp'; Expression={[DateTime]::FromFileTime($_.LastLogonTimestamp).ToString("dd/MM/yyyy")}}, AccountExpirationDate, Enabled | Export-CSV output.csv