Add or remove text from text file using PowerShell - powershell

I'm using PowerShell to add or remove text from file. I'm keep getting funny text in my file.
This only happens when I have removed the line from the text file and when I try to add new line I get funny text.
cls
IMPORT-MODULE ActiveDirectory
$fileLocation = "E:\Script\MatchCadTest\ptc.opt";
function addUser( $username=''){
$user = Get-ADUser -Identity $username -ErrorAction SilentlyContinue;
$userFullName = $user.Name;
$empty = [string]::IsNullOrEmpty($userFullName);
if ( !($empty) ){
$userExisted = Get-Content $fileLocation | Select-String "$username" -quiet
if( ! $userExisted ){
$newLocation = "E:\Script\MatchCadTest\backup\";
if((Test-Path -Path $fileLocation)) {
Copy-Item "$fileLocation" "$newLocation"
}
$date = Get-Date -Format "d-M-y Hms";
$newName = "ptc_$date.opt"
Rename-Item "$newLocation\ptc.opt" $newName
# Add-Content $fileLocation ""
Add-Content -Path $fileLocation -Value "# $userFullName";
Add-Content -Path $fileLocation -Value "INCLUDE MATHCAD USER $username";
Write-Host "User has been added to file. Please restart the service." -BackgroundColor Green -ForegroundColor Black
}
else{
Write-Host "User already existed" -BackgroundColor Red -ForegroundColor White
}
}
}
function removeUser( $username=''){
$user = Get-ADUser -Identity $username -ErrorAction SilentlyContinue;
# $user
$userFullName = $user.Name;
$empty = [string]::IsNullOrEmpty($userFullName);
if ( !($empty) ){
$userExisted = Get-Content $fileLocation | Select-String "$username" -quiet
if( $userExisted ){
$remove="# $userFullName";
$removeUser = (Get-Content $fileLocation);
$removeUser | where {$_ -ne $remove};
$remove="INCLUDE MATHCAD USER $username";
$removeUser | where {$_ -ne $remove}
$removeUser |Out-File $fileLocation;
#$removeUser = (Get-Content $fileLocation) | where {$_ -ne $remove} | Out-File $fileLocation;
#$content = Get-Content $fileLocation
#$content | Foreach {$_.TrimEnd()} | Set-Content $fileLocation
Write-Host "User removed" -BackgroundColor Green -ForegroundColor Black
}
else{
Write-Host "User does not existed" -BackgroundColor Red -ForegroundColor White
}
}
else{
Write-Host "User not found in ad" -BackgroundColor Red -ForegroundColor White
}
}
$option=''
while ( $option -ne 0){
Write-Host "What would you like to do?"
Write-Host "1= Add new user"
Write-Host "2= Remove user"
Write-Host "0= No (Exit)"
$option = Read-Host "Select option"
$username = Read-Host "Please enter Username"
if( $option -eq 0 ){
exit 1
}
elseif( $option -eq 1){
addUser($username);
}
elseif ( $option -eq 22){
removeUser ($username);
}
else{
cls
Write-Host
Write-Host " Invaild Choice " -BackgroundColor Red #-ForegroundColor White
Write-Host
}
#Reset
$option=444;
$username="";
$userFullName="";
$user="";
$empty="";
}
When I remove the line of text from file and add a new user, it's all a funny text string:
See below
‣潍慨浭摡䴠橡摩਍义䱃䑕⁅䅍䡔䅃⁄单剅洠ㅭ㘳㐰ല
I have a text file with following information.
- // Full name 1
- User ID of User 1
- // Full name 2
- User ID of User 2
* // Full name 3
* User ID of User 3
* // Full name 4
* User ID of User 4
* // Full name 5
* User ID of User 5
* // Full name 6
* User ID of User 6
* // Full name 7
* User ID of User 7
* // Full name 8
* User ID of User 8
If you see that user 5 and 6 or 7 and 8 has extra space which i wont to remove and ad just sinlge space.

I think you need to set the encoding for your Add-Content
Try: Add-Content -Encoding UTF8 -Path $fileLocation -Value "# $userFullName";

Related

My powershell script can't delete multiple users from csv file but can delete 1 user

This is the script which deletes user but only if 1 entry in there in csv file. however when I entered multiples entries in csv, the script takes values of all the rows as a single entry. How do I repair it? Thanks in advance!
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA SilentlyContinue
$CSVPath = "D:\Temp\userss.csv"
$CSVFile = Import-CSV $CSVPath
$web = Get-SPWeb -Identity https://................./
$DocLibsName = "Bilder der websitesammlung"
$folder = $web.Folders[$DocLibsName].SubFolders
foreach($Files in $CSVFile)
{
Write-Host "Retreiving user..." -ForegroundColor Blue
$user = $CSVFile.users
$items = $folder.Files | where {$_.Title -eq $user}
If($items.Title -contains $user)
{
$items.Delete()
Write-Host $user "deleted" -ForegroundColor DarkGreen
}
Else {
Write-Host $user"not found" -ForegroundColor DarkRed
}
}
Write-Host "Finished" -ForegroundColor Green
Please try to change the code "$user = $CSVFile.users" to "$user = $Files.users".Hope it can help you.
Try using this PowerShell code:
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA SilentlyContinue
$CSVPath = "D:\Temp\userss.csv"
$CSVFile = Import-CSV $CSVPath
$web = Get-SPWeb -Identity https://................./
$DocLibsName = "Bilder der websitesammlung"
$folder = $web.Folders[$DocLibsName].SubFolders
foreach($Files in $CSVFile)
{
foreach($loopItem in $Files.users) {
Write-Host "Retreiving user..." -ForegroundColor Blue
$user = $loopItem
$items = $folder.Files | where {$_.Title -eq $user}
If($items.Title -contains $user)
{
$items.Delete()
Write-Host $user "deleted" -ForegroundColor DarkGreen
}
Else {
Write-Host $user"not found" -ForegroundColor DarkRed
}
}
}
Write-Host "Finished" -ForegroundColor Green

Powershell - Move Mail

I'm newbie to powershell, and I have a challenge on process my script. It did everything perfectly, but it wont move the message to the target folder and I don't know why.
I thought maybe to process at end cycle, but the issue is that I can encour that will transfer also file that have not any reference, and I would avoid to process something that I have no info about.
I tried this
$MailboxName = "fatture#abc.com"
write-host "Now Processing" -ForegroundColor Yellow
write-host "Searching on Fatture" -ForegroundColor Yellow
$olFolderInbox = 6
$outlook = new-object -com outlook.application;
$namespace = $outlook.GetNameSpace("MAPI");
$recipient = $namespace.CreateRecipient($MailboxName)
$inbox = $namespace.GetSharedDefaultFolder($recipient,6)
$messages = $inbox.Folders.Item("Carriers").folders.Item("Gpac").folders.item("BLR")
$MoveTarget = $inbox.Folders.Item("Carriers").folders.Item("Gpac").folders.item("BLS")
$filepath = "C:\temp\FATTURE\Automation\"
$messages.Items | % {
Write-Host "New Message " $_.Subject
$msg = $_
$Ref = $_.Subject -replace ' ',''
$RefStr = $ref.split('#')
$SearchSTR = $RefStr[2]
write-host $SearchStr
# $invNbr = $body.Substring($body.IndexOf("INVOICE NO")+19,10)
#write-host "The Invoice Number is : $invNbr" -ForegroundColor Cyan
write-host "Querying for $SearchSTR" -ForegroundColor Green
$t = (Query_file($SearchSTR))[-1].CONSOL_REF
write-host "File Found : $t" -ForegroundColor Cyan
write-host $t
if ($t -ne $null) {
$filetype = $t.Substring(0,1)
$date = Get-Date -format "yyyyMMddhhmmss"
write-host "Today is Date is $date" -ForegroundColor Red
Switch($filetype.tostring())
{
{($_ -eq 1) -or ($_ -eq 2) -or ($_ -eq 7) -or ($_ -eq 7) -or ($_ -eq 8) }{($dept = "0001"), ($dept1 = "ZLAG")}
{($_ -eq "F") -or ($_ -eq "V") -or ($_ -eq "M")}{($dept = "0002"), ($dept1 = "Zero"), ($type = "MOR")}
{($_ -eq 3) -or ($_ -eq 5) -or ($_ -eq "J")} {($dept = "0028"), ($dept1 = "One"), ($type = "OBR") }
{($_ -eq 9)} {($dept = "0031"), ($dept1 = "CONSOLE")}
}
write-host "The KEY TYPE is $dept1 " -ForegroundColor Yellow
$fileStr = $t + "_INV_" + $dept + "_$date_.tsk"
write-host " FILE Path: " $fileStr -ForegroundColor Cyan
$msg.attachments | ?{$_.filename -like "*.pdf"} | %{
$file = $filestr
$_.saveasfile((Join-Path $filepath $filestr))
}
$msg.UnRead = $false
$msg.Move($MoveTarget)
}
#fine cycle messages
}
I tried to move from the cycle but the issue is that it goes for all of email, instead, I want to process only the email that should be. I would like when the attachment has being downloaded, that the email will be moved.

Subexpression printing out same strings? Powershell

I have this code which deletes User Profiles off a remote machine. The removal of profiles work just fine but, the Aesthetic of doing so doesn't. What do i mean?
I'm passing the user display names to an index and making a selection out of it, and that works fine in regards to assigning the proper names to the appropriate Index Number its associated to in C:\users.
The next line of code is it grabbing the selections i made, and running through them displaying the same name i did for the index, and then it goes off to delete the CIM instance.
So my question is, why is it not passing the subexpression $userinfo1 that is already made and not putting it into the next block of code, for example, the following works as in grabbing the proper Display Name and assigning it to the proper Number:
$menu = (get-childitem "\\$cn\c$\users" | sort LastWriteTime -Descending).Name
$userinfo1 = foreach ($user in $menu) {
Start-Sleep -Milliseconds 2
$userinfo = (net user $user /domain | Select-String "Full Name" -ErrorAction SilentlyContinue) -replace "Full Name ", "" 2>&1 | Out-String -Stream
if ($userinfo.Length -lt 4) {
"$user - NO DISPLAY NAME in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 2) {
"$user - account not in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 0){
$userinfo # output
}
}
}
}
Write-Warning "Ensure user profiles are no longer active and/or, have profiles be backed-up!"
Write-Host "RESULTS:" -BackgroundColor Black -ForegroundColor White
for ($i=0; $i -lt $userinfo1.Count; $i++) {
Write-Host "$($i): $($userinfo1[$i])"
} #END LIST OF POSSIBLE NAMES
Write-Host ""
Write-Host "For multiple users, seperate using a SPACE(1 2 3)"
$selection = Read-Host "ENTER THE NUMBER of the user(s) or Q to quit"
$selection = $selection -split " "
but, the next block doesn't associate the display name (that was captured in $userinfo1) with the number i select and it just continues to display the first display name with the rest of the profiles its reiterating through:
foreach($Profile in $menu[$selection]){
Write-Host "Deleting user: $(,$userinfo1[$selection]) `
ID:$Profile "}
Hopefully this makes sense, and if anyone can point me in the right direction id greatly appreciate it!
Heres the rest of the script, please feel free to use it as it does work for deleting the actual profile off the system and not just the files.
#Deletes a profile properly off remote machine. WARNING: DOES NOT BACK UP DATA! Use at your own peril. Delprofile
$cn = Read-Host -Prompt "Enter Computer Name"
$ping = Test-Connection -ComputerName $cn -Count 1 -Quiet
If($ping -eq $false){ Write-Host "Computer seems to be offline, please check name spelling." -ForegroundColor DarkYellow; Write-Host ""; &PFL-Delete } else {
$menu = (get-childitem "\\$cn\c$\users" | sort LastWriteTime -Descending).Name
$userinfo1 = foreach ($user in $menu) {
Start-Sleep -Milliseconds 2
$userinfo = (net user $user /domain | Select-String "Full Name" -ErrorAction SilentlyContinue) -replace "Full Name ", "" 2>&1 | Out-String -Stream
if ($userinfo.Length -lt 4) {
"$user - NO DISPLAY NAME in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 2) {
"$user - account not in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 0){
$userinfo # output
}
}
}
}
Write-Warning "Ensure user profiles are no longer active and/or, have profiles be backed-up!"
Write-Host "RESULTS:" -BackgroundColor Black -ForegroundColor White
for ($i=0; $i -lt $userinfo1.Count; $i++) {
Write-Host "$($i): $($userinfo1[$i])"
} #END LIST OF POSSIBLE NAMES
Write-Host ""
Write-Host "For multiple users, seperate using a SPACE(1 2 3)"
$selection = Read-Host "ENTER THE NUMBER of the user(s) or Q to quit"
$selection = $selection -split " "
foreach($Profile in $menu[$selection]){
Write-Host "Deleting user: $(,$userinfo1[$selection]) `
ID:$Profile "
$del = Get-CimInstance -ComputerName $cn -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $Profile }
If($del -eq $null){Write-Warning "No CIM instance found on system, profile has been deleted but files persist. Delete manually!"} else{
Get-CimInstance -ComputerName $cn -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $Profile } | Remove-CimInstance -WhatIf
Write-Host "user profile has been deleted" -ForegroundColor Red
Write-Host ""}
}
}
#CountPs $cn
12/31/2020 - EDIT:
Here is the finished result:
Function Delete-PFL{
#Deletes a profile properly off remote machine. WARNING: DOES NOT BACK UP DATA! Use at your own peril. Delprofile
$cn = Read-Host -Prompt "Enter Computer Name"
$ping = Test-Connection -ComputerName $cn -Count 1 -Quiet
If($ping -eq $false){ Write-Host "Computer seems to be offline, please check name spelling." -ForegroundColor DarkYellow; Write-Host ""; &Delete-PFL } else {
$menu = (get-childitem "\\$cn\c$\users" | sort LastWriteTime -Descending).Name
$userinfo1 = foreach ($user in $menu) {
Start-Sleep -Milliseconds 2
$userinfo = (net user $user /domain | Select-String "Full Name" -ErrorAction SilentlyContinue) -replace "Full Name ", "" 2>&1 | Out-String -Stream
if ($userinfo.Length -lt 4) {
"$user - NO DISPLAY NAME in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 2) {
"$user - ACCOUNT NOT in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 0){
$userinfo # output
}
}
}
}
Write-Warning "Ensure user profiles are no longer active and/or, have profiles be backed-up!"
Write-Host "RESULTS:" -BackgroundColor Black -ForegroundColor White
for ($i=0; $i -lt $userinfo1.Count; $i++) {
Write-Host "$($i): $($userinfo1[$i])"
} #END LIST OF POSSIBLE NAMES
Write-Host ""
Write-Host "For multiple users, seperate using a SPACE(1 2 3)"
$selection = Read-Host "ENTER THE NUMBER of the user(s) or Q to quit"
$selection = $selection -split " "
foreach($index in $selection) {
$Profile = $menu[$index]
Write-Host "Deleting user: $($userinfo1[$index]) `
ID:$Profile "
$del = Get-CimInstance -ComputerName $cn -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $Profile }
If($del -eq $null){Write-Warning "No CIM instance found on system, profile has been deleted but files persist."
Write-Host "Attempting to delete files, please wait. . ."
Remove-Item -Path "\\$cn\c$\users\$Profile" -Force -WhatIf
Write-Host ""
Start-Sleep -Seconds 2
Write-Host "Checking if Files are still there. . ."
$TestPath = Test-Path -Path "\\$cn\c$\users\$Profile"
If($TestPath -eq $false){ Write-Host "Profile Files have been deleted. `
Continuing. . . ." -ForegroundColor Green
}
} else{
Get-CimInstance -ComputerName $cn -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $Profile } | Remove-CimInstance -WhatIf
Write-Host "user profile has been deleted" -ForegroundColor Red
Write-Host ""
}
}
}
#CountPs $cn
}
Remember to remove the -whatif parameter. Enjoy!
$selection is an array of indices, so in your foreach loop you must refer to the single index at hand, not to $selection as a whole, to get the desired display output.
The conceptually clearest approach is probably to iterate over the indices contained in $selection:
foreach($index in $selection) {
$Profile = $menu[$index]
Write-Host "Deleting user: $($userinfo1[$index]) `
EDIPI:$Profile "
# ...
}

Send email to AD users when their password is about to expire

I've been working on a PowerShell script that sends an automated email out to AD users when their password is about to expire. My script has a ForEach statement in it but nothing within this actually runs. I've set it up so that it logs all activities in a .txt file so I can see when each step is being worked on. It's running on a Windows 2016 Essentials.
Script Below:
# VAR
$SMTPHost = "smtp.office365.com"
$FromEmail = "***"
$expireindays = 3
$Date = Get-Date
# Set DIR
$DirPath = "C:\TEMP"
# Check is DIR is present
$DirPathCheck = Test-Path -Path $DirPath
if (!($DirPathCheck)) {
try {
#Create DIR if not present
New-Item -ItemType Directory $DirPath -Force
}
catch {
$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
}
}
# CredObj
$CredObj = ($DirPath + "\" + "EmailExpiry.cred")
# Check if CredObj is Present
$CredObjCheck = Test-Path -Path $CredObj
If (!($CredObjCheck))
{
"$Date - INFO: creating cred object" | Out-File ($DirPath + "\" + "Log.txt") -Append
#If not present get O365 cred and store
$Credential = Get-Credential -Message "Please enter your Office 365 credentials."
#Export CredObj
$Credential | Export-Clixml -Path $CredObj
}
Write-Host "INFO | Importing Cred Object" -ForegroundColor Yellow
$Cred = (Import-Clixml -Path $CredObj)
"$Date - INFO: Importing AD Module" | Out-File ($DirPath + "\" + "Log.txt") -Append
Import-Module ActiveDirectory
"$Date - INFO: Getting Users" | Out-File ($DirPath + "\" + "Log.txt") -Append
Write-Host "INFO | Getting Users" -ForegroundColor Yellow
$users = Get-ADUser -properties Name, PasswordExpired, PasswordLastSet, EmailAddress -filter { (enabled -eq 'True') } | Where-Object { $_.PasswordExpired -eq 'False'}
# Process Each User for Password Expiry
ForEach ($User in $Users) {
$Name = (Get-ADUser $user | Get-ADUser -Property Name)
Write-Host "Working on $Name..." -ForegroundColor White
Write-Host "Getting email address for $Name..." -ForegroundColor Yellow
$emailaddress = $user.EmailAddress
if (!($emailaddress)) {
Write-Host "$Name has no E-Mail address listed, looking at their proxy address attributes..."
if (!($emailaddress)) {
Write-Host "$Name has no email address to send an e-mail to!" -ForegroundColor Red
"$Date - WARNING: No email found for $Name" | Out-File ($DirPath + "\" + "Log.txt") -Append
}
}
#Get password last set
$passwordSetDate = (Get-AAUser $user -properties * | ForEach-Object { $_.PasswordLastSet})
#Get the count on how many days until the password expires and stores it in the $daystoexpire VAR
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
if (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays)) {
"$Date - INFO: Sending expiry notice email to $Name" | Out-File ($DirPath + "\" + "Log.txt")
Write-Host "Sending Password expiry email to $Name" -ForegroundColor Yellow
$SmtpClient = New-Object system.net.mail.smtpclient
$MailMessage = New-Object system.net.mail.mailmessage
#Email Sender
$MailMessage.From = $FromEmail
#SMTP Server
$SmtpClient.Host = $SMTPHost
#SMTP SSL
$SmtpClient.EnableSsl = $true
#SMTP Credentials
$SmtpClient.Credentials = $Cred
#Email Recipients
$MailMessage.To.add($emailaddress)
#Subject
$MailMessage.Subject = "Your password will expire $daystoexpire days"
#Delivery Success
$MailMessage.DeliveryNotificationOptions = ("onSuccess", "onFailure")
#Set Priority
$MailMessage.Priority = "High"
#Body
$MailMessage.Body = "Password will expire, better change it!"
Write-Host "Sending email to $emailaddress..." -ForegroundColor Green
try {
$SmtpClient.Send($MailMessage)
}
catch {
$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
}
else {
"$Date- INFO: Password for $Name not expiring for another $daystoexpire days" | Out-File ($DirPath + "\" + "Log.txt") -Append
Write-Host "Password for $Name does not expire for $daystoexpire days" -ForegroundColor White
}
}
}
Output:
I noticed you did not set the $Expireson variable anywhere, so you would not get a correct value for $daystoexpire aswell.
As a matter of fact, I made a script to do the same some time ago. I have edited it a bit for you to try out.
This uses the Send-Mailmessage instead of the System.Net.Mail.SmtpClient to make things easier. This way, we can also use Splatting to make the code more readable.
Import-Module ActiveDirectory
$smtpServer = "smtp.office365.com"
$expireInDays = 3 # 3 is a bit close... better do something like 7
$from = "YOUR EMAILADDRESS"
$logPath = "C:\TEMP"
$logFile = Join-Path -Path $logPath -ChildPath 'PasswordExpiryLog.txt'
$logDate = '{0:dd-MM-yyyy}' -f (Get-Date)
$credPath = Join-Path -Path $logPath -ChildPath 'EmailExpiry.cred'
# create the output path if it does not exist
if (!(Test-Path -Path $logPath -PathType Container)) {
New-Item -Path $logPath -ItemType Directory | Out-Null
}
# Credentials
If (!(Test-Path -Path $credPath -PathType Leaf)) {
# write to the log and screen
$msg = "Creating credentials object"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# If not present get O365 cred and store
$cred = Get-Credential -Message "Please enter your Office 365 credentials."
# Export CredObj
$cred | Export-Clixml -Path $credPath
}
else {
# write to the log and screen
$msg = "Importing credentials Object"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
$cred = Import-Clixml -Path $credPath
}
# create a template for the emails
$emailTemplate = #"
<html>
<head>
<title>Password Expire Notification</title>
<meta name="generator" content="PowerShell" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 12px;
}
</style>
</head>
<body>
Dear _NAME_,
<p>Your password will expire in _DAYS_ days.<br /><br />
To change your password on a Windows pc in the office press CTRL-ALT-Delete and choose <strong>Change a password...</strong><br />
</p>
Regards
</body>
</html>
"#
# get all users that are enabled and that have a password expiry date
# test it out on dummy user(s) first of course !
$users = Get-ADUser -Filter * -Properties GivenName, Name, SamAccountName, PasswordNeverExpires, PasswordExpired,
PasswordLastSet, EmailAddress, AccountExpirationDate, accountExpires |
Where-Object { $_.Enabled -eq $true -and $_.PasswordNeverExpires -eq $false}
# get the domains default max password age
$defaultMaxPasswordAge = (Get-ADDefaultDomainpasswordPolicy).MaxPasswordAge
$mailCount = 0
foreach ($user in $users) {
if ([string]::IsNullOrWhiteSpace($emailAddress)) {
# write to the log and screen
$msg = "$userName has no email address to send an e-mail to!"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# skip this user because we cannot send mail..
continue
}
# just for convenience, store some properties in variables
$firstName = $user.GivenName
$userName = $user.Name
$accountName = $user.SamAccountName
$emailAddress = $user.EmailAddress
$passwordSetDate = $user.PasswordLastSet
$passwordPolicy = (Get-AduserResultantpasswordPolicy $user)
# check if there is a 'Fine Grained Password' policy for this user
if ($null -ne $passwordPolicy) {
$maxPasswordAge = ($passwordPolicy).MaxPasswordAge
}
else {
# no 'Fine Grained Password' policy, so use the default domain password age
$maxPasswordAge = $defaultMaxPasswordAge
}
# prevent errors when the 'User must change password at next logon' checkmark is set
if (!$passwordSetDate -or !$maxPasswordAge) {
# write to the log and screen
$msg = "Please check if the 'User must change password at next logon' checkmark is off for user '$userName'"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
}
# calculate the expiry date for the password
$passwordExpiresAt = $passwordSetDate + $maxPasswordAge
# check if the account does not expire before the password does using the accountExpires property.
# 0 means the expiration date has been removed. 9223372036854775807 means the account never had an expiration date
if ($user.accountExpires -ne 0 -and $user.accountExpires -ne 9223372036854775807 -and $user.AccountExpirationDate -ne $null) {
if ($user.AccountExpirationDate -le $passwordExpiresAt) {
# skip this user if the account expires before the password needs changing
$msg = "The account for user '$userName' expires before the password needs changing."
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
continue
}
}
# calculate how many days are left
$daysToExpire = [int](New-TimeSpan -Start (Get-Date) -End $passwordExpiresAt).Days
if (($daysToExpire -ge 0) -and ($daysToExpire -lt $expireInDays)) {
# if there are still days left to change the password, send an email
# using Send-MailMessage rather than System.Net.Mail.SmtpClient
$msg = "Sending expiry notice email to '$userName'"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# use splatting for cmdlets that take a lot of parameters
$params = #{
SmtpServer = $smtpServer
From = $from
To = $emailAddress
Subject = "Your password will expire in $daysToExpire days."
Body = $emailTemplate -replace "_NAME_", $firstName -replace "_DAYS_", $daysToExpire
BodyAsHtml = $true
Encoding = [System.Text.Encoding]::UTF8
Credential = $cred
UseSsl = $true
Priority = 'High'
DeliveryNotificationOption = 'OnSuccess', 'OnFailure'
# Port = 587
}
Send-Mailmessage #params
# update the counter for the users that were sent an email
$mailCount++
}
elseif ($daysToExpire -le 0) {
$msg = "Password for user '$userName' is already expired!"
Add-Content -Path $logFile -Value "$logDate - WARNING: $msg"
Write-Host $msg -ForegroundColor Red
}
}
$msg = "Password expiry notifications have been sent to $mailCount users"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Green
Note: As always, create a couple of testusers to try this out first. You can use the -Filter parameter on the Get-ADUser cmdlet to only get the testuser or use the -SearchBase parameter and put your test accounts in a special OU.

Nested If Statement first -notlike condition

I am trying to use nested IF statements to check a AD-Computer Attribute and if it is not either VM or VeraCrypt, use Manage-BDE to check the Bitlocker status.
When I use just Get-Adcomputer <name> -Properties extensionAttribute1 | select extensionAttribute1 it returns the expected result VM.
When I do
$Attribute = Get-Adcomputer <name> -Properties extensionAttribute1 | select extensionAttribute1
Write-Host $Attribute
I get #{extensionAttribute1=VM}
I have tried many using -Notlike "*VM* but this did not work.
Here is my code.
# -----------------------
# Define global variables
# -----------------------
$ScanCount = 0
$UnprotectedCount = 0
$Date = Get-Date -Format yyyyMMdd
$StartDate = Get-Date -Format HH:mm:ss
$ReportFile = "C:\BitLocker_Status\BitLocker_Status.csv"
$BackupFile = "C:\BitLocker_Status\BitLocker_Status_Backup$BackupCopy'_$Date.csv"
$OutputArray = #()
$BackupCopy = 0
$SearchBase = "DC=Merallis,DC=net"
# ----------------------------------------
# Checking backing up output file
# ----------------------------------------
if (Test-Path $ReportFile) {
Rename-Item -Path $ReportFile -newname $BackupFile
$BackupCopy = $BackupCopy + 1
}
Else {
$BackupCopy = 0
}
# ----------------------------------------
# Build array from list of computers in AD
# ----------------------------------------
Write-Host -NoNewline "- Gathering a list of Computers from Active Directory..."
Try
{
$Computers = Get-ADComputer -SearchBase $SearchBase -Filter * -Properties Name,Description | Sort-Object
Write-Host -ForegroundColor Green "Success"
}
Catch
{
Write-Host -ForegroundColor Red "Failed ($_)"
}
# -------------------------------------------------
# Use the Manage-BDE command to query each computer
# -------------------------------------------------
Write-Host "- Querying BitLocker status..."
ForEach ($Computer in $Computers)
{
$Name = $Computer.Name
$Description = $Computer.Description
$BDE = Manage-BDE -ComputerName $Computer.Name -Status C:
# -------------------------------------------------
# Use the Get-ADComputer command to query the current attribute for each computer
# -------------------------------------------------
$Attribute = Get-ADComputer $Name -Properties extensionAttribute1 | select extensionAttribute1
Write-Host -nonewline " - $Name ..."
If ($Attribute -notlike "*VM*" -or $Attribute -notlike "*VeraCrypt*") {
If ($BDE -Like "*An error occurred while connecting*") {Write-Host -ForegroundColor Yellow "Unable to connect"; $Status = "Unable to connect"; Set-ADComputer -identity $Name -Replace #{"ExtensionAttribute1"=$Status}}
ElseIf ($BDE -Like "*Protection On*") {Write-Host -ForegroundColor Green "Protected"; $Status = "Protected"; Set-ADComputer -identity $Name -Replace #{"ExtensionAttribute1"=$Status}}
ElseIf ($BDE -Like "*Protection Off*") {Write-Host -ForegroundColor Red $Status; $Status = "Not protected"; $UnprotectedCount = $UnprotectedCount + 1 ; Set-ADComputer -identity $Name -Replace #{"ExtensionAttribute1"=$Status}}
ElseIf ($BDE -Like "*The term 'manage-bde'*") {Write-Host -ForegroundColor Red "error manage-bd!"; $Status = "Not protected"; $UnprotectedCount = $UnprotectedCount + 1}
Else {Set-ADComputer -identity $Name -Replace #{"ExtensionAttribute1"="Unknown"}}
}
$ScanCount = $ScanCount +1
$OutputArray += New-Object PsObject -Property #{
'Computer name' = $Computer.Name
'Description' = $Computer.Description
'BitLocker status' = $Status
}
}
# -----------------
# Generate a report
# -----------------
Write-Host -NoNewline "- Saving report..."
Try
{
$OutputArray | Export-CSV -NoTypeInformation $ReportFile
Write-Host -ForegroundColor Green "Success"
}
Catch
{
Write-Host -ForegroundColor Red "Failed ($_)"
}
# -----------------------------------------
# Display completion message and statistics
# -----------------------------------------
$EndDate = Get-Date -Format HH:mm:ss
$Duration = New-TimeSpan $StartDate $EndDate
Write-Host ""
Write-Host "-------------------------------------------------------------"
Write-Host "Script complete. Start time: $StartDate, End time: $EndDate"
Write-Host "Scanned $ScanCount computers. $UnprotectedCount are unprotected!"
Write-Host "-------------------------------------------------------------"man
Write-Host ""
If you want to filter objects from list based on some property value then you can use Where-Object
i.e. Website list ( without "default" website Name )
$YOURLIST = Get-Website
$YOURLIST | Where-Object { $_.Name -notlike "*Default*" }