Log each Powershell process to text file through - powershell

Firstly, I'm by no means a PS expert, total newbie - admission done. I have scoured the internet for what I need in order to get the script to do what I want, but I've reached a point where I'm struggling and in need of help.
Basically, I've created a script using ISE that grabs the users in an AD OU, processes them by disabling the accounts, renaming them, stripping out the groups and moving them to another folder. In order to automate the deactivation process for users. But I now need to create a log file every time this runs, to show a) if it found any Users in the original OU (ToBeProcessed) and b) what processes were run and if they were successful. Here is the code.
$OUToBeProcessed = "OU=ToBeProcessed,OU=Users,OU=World,DC=local"
$OURetired = "OU=RetiredUsers,OU=Users,OU=World,DC=local"
$Users = Get-ADUser -SearchBase $OUToBeProcessed -Filter 'name -Like "*"' -Properties MemberOf
ForEach($User in $Users){
$SAN = $User.SamAccountName
#Disable user account
Disable-ADAccount -Identity $SAN
#Remove membership from groups for user
$User.Memberof | Remove-ADGroupMember -Member $User -Confirm:$False
$NewDN = "zzz_" + $User.Name
#Change display name
set-aduser $User -Displayname $newDN -ErrorAction SilentlyContinue
#Change distinguished name
Get-ADUser $SAN | Rename-ADObject -Newname $NewDN
Write-Host "$SAN may already exist."
#Move account to RetiredUsers
Get-Aduser $SAN | Move-ADObject -TargetPath $OURetired
}
I'm assuming I'll need to either use a Write-Output or Log-File cmdlet, though someone had also suggested Transcript, but I don't think that's what I need.
I've tried a number of ways to incorporate the Write-Output into the script, it runs without errors, but no text file is produced. But I'm placing it within the loop which may be the issue. I've placed it outside the loop but I think because it's not being passed anything it's creating the file with nothing in it. Would really appreciate some help as to where the Write-Output might need to go if that is the right cmdlet.

Personally I tend to add a Log function to my scripts. Something like this (where I output to the host and file):
Function Log {
Param (
[Parameter(Mandatory=$true)] [string] $String,
[Parameter(Mandatory=$true)] [string] $LogFilePath,
[Parameter(Mandatory=$false)][ValidateSet("ERROR","WARN","INFO","DEBUG")] [string] $Level = "INFO"
)
$LogString = ((Get-Date -Format "s") +" $Level $env:USERNAME $String")
Write-Host $LogString
Out-File -Append -FilePath $LogFilePath -InputObject $LogString
}
Then you could do logging:
Log "Something wrong!" "c:\mylog.log" "WARN"
Log "Updated stuff" "c:\mylog.log"
Or search the http://www.powershellgallery.com/ for logging modules.
Example (haven't tried this one myself):
https://www.powershellgallery.com/packages/PSLogging/2.5.2

Related

Enabling Exchange Online SMTP Client Authentication with Powershell

I'm trying to enable Authenticated SMTP in Exchange Online via PowerShell.
I was semi successful with my attempts.
$Users = Get-CASMailbox -ResultSize unlimited
$Users | where {$_.SmtpClientAuthenticationDisabled -eq $true} | Set-CASMailbox -SmtpClientAuthenticationDisabled $False
This resulted in about 75% of the users having SMTP Authentication activated. But weirdly not all of them.
$Users = Get-CASMailbox -ResultSize unlimited
$Users | where {$_.SmtpClientAuthenticationDisabled -eq $true -or $null -or ""} | Set-CASMailbox -SmtpClientAuthenticationDisabled $False
Showed the same results.
As did:
$Users = Get-CASMailbox -ResultSize unlimited
$Users | where {$_.ImapEnabled -eq $true} | Set-CASMailbox -SmtpClientAuthenticationDisabled $False
So apparently this has nothing to do with the state of SmtpClientAuthenticationDisabled since I tried all possible states and used ImapEnabled -eq $true as a condition which is $true for every user.
I just started working with PowerShell and only have some basic programming knowledge. This setting has to be changed for about 80 accounts right now, but in a week or two about 4000 accounts will be synchronized with AzureAD and therefore Exchange Online. So far I haven't received an answer from the company which synchronizes the accounts on wether or not it's possible to set the state of SmtpClientAuthenticationDisabled when the synchronization happens. I expect that I will have to do it myself.
All users have an active Office 365 Licence and an active Exchange Online Plan.
Does anyone have some insight as to why only most but no all of the users accept this setting?
Edit:
When trying to execute your suggested script or when trying to execute my own commands I run into the issue that '$user' returns '$null' which I don't understand.
Setting SmtpClientAuthenticationDisabled for failed, error: Cannot bind argument to parameter 'Identity' because it is null.
This also happens when im only executing this:
$Users = Get-CASMailbox -ResultSize Unlimited
foreach($user in $users) {Write-Host "$($user.DisplayName)"}
It just returns nothing.
I think there is something fundamental that I don't understand.
If I just list the contents of '$users' PowerShell returns a list of all the users with the related settings like 'SmtpClientAuthenticationDisabled'.
If you want your complete organization to use the same setting, you should leave the values of the users $null. Instead set the TransportConfig.
Get-TransportConfig
Then check the value. If it is set to 'False', all users with a $null-value for SmtpClientAuthenticationDisabled will have the default setting of 'False'.
If set to 'True', change to 'False' instead:
Set-TransportConfig -SmtpClientAuthenticationDisabled $false
To answer your original question, of why the users are not updated properly. I think it has something to do with the fact that 'SmtpClientAuthenticationDisabled' is not a filterable attribute in the first place. So you will always have to query your complete dataset, which is not very elegant.
You could do something like the following to check and see what happens exactly:
$Users = Get-CASMailbox -ResultSize Unlimited
foreach($user in $Users){
if($user.SmtpClientAuthenticationDisabled -eq $null -or $user.SmtpClientAuthenticationDisabled -eq $true){
try{
Set-CASMailbox -Identity $user.ExchangeObjectId.guid -SmtpClientAuthenticationDisabled $false -ErrorAction Stop
Write-Host "$($user.DisplayName) succesfully set to correct state" -ForegroundColor Green
}catch{
Write-Host "Setting SmtpClientAuthenticationDisabled for $($user.DisplayName) failed, error: $_" -ForegroundColor Red
}
}else{
Write-Host "$($user.DisplayName) already has the correct state: $($user.SmtpClientAuthenticationDisabled)" -ForegroundColor Green
}
}
But personally I would change the above script to use it to set all values to $null:
Set-CASMailbox -Identity $user.ExchangeObjectId.guid -SmtpClientAuthenticationDisabled $null -ErrorAction Stop

Powershell Deployed via SCCM Issue

I am writing a powershell script to be deployed by SCCM via a package. The aim of this is to remove an account with a specific name then write to a file stating if the account exists or not. The code is below:
$Computer = hostname
foreach ($C in $Computer) {
if (Test-Connection $C -Quiet) {
Write-Verbose "$C > Online"
$Users = Get-WMIObject Win32_UserAccount -Filter "LocalAccount=True" -ComputerName $C
if ($Users.Name -contains 'test') {
Add-Content \\SERVERNAME\SHARENAME.$\$computer-found_$(get-date -Format yyyymmdd_hhmmtt).txt "User 'test' found, Disable 'test' found"
net user test /active:no }
else {
Add-Content \\SERVERNAME\SHARENAME.$\$computer-notfound_$(get-date -Format yyyymmdd_hhmmtt).txt "User 'test' not found"
}
}
else {
Write-Verbose "$C > Offline"
}
}
I have also tried replace Write-Verbose with Write-Host and Add-Content with Out-File but the problem I having is that no content / file is created when I use the full network path or share e.g. \\SERVERNAME\SHARENAME.$ the path identified has all the correct permissions and is being ran locally using the System account.
I wanted to see if the issue occured when writing the file locatlly consequently this does not happen when written to C:\Temp\
Does anyone have any ideas on to solve this.
I don't think that local system account has access to a network resource. I'm not sure if you have ever configured it or not. And what the command you used to run the command
Here I post a working way of doing this using Configuration Manager deployment after testing in my lab.
Basically I created a package with source files
and created a task sequence with single "Run Command Line" step.
The reason I use a task sequence is because I want to use an account to access the txt file on the network, which I can configure within a task sequence. I don't think Local System Account have such permission.
The script (DeactivateTest.ps1) I use as below just like what you provided and changed a little on the logic:
$Computer = hostname
foreach ($C in $Computer) {
if (Test-Connection $C -Quiet) {
Write-host "$C > Online"
$Users = Get-WMIObject Win32_UserAccount -Filter "LocalAccount=True" -ComputerName $C
$result=0
Foreach($user in $Users){
if ($User.Name -like '*test*') {
$username = $user.Name
"`n$(get-date -Format yyyymmdd_hhmmtt) User $username found ON $C, Disable 'test'" | Add-Content \\cas\resource\Result.txt
net user $username /active:no
$result+=1
}}
if($result =0){
"`n$(get-date -Format yyyymmdd_hhmmtt) User 'test' not found ON $C" | Add-Content \\cas\resource\Result.txt}
}
else {
"`n$C is Offline" | Add-Content \\cas\resource\Result.txt
}
}
The script query local account and disable accounts which have words "Test" in the name. If you don't like this logic, you can change :).
\\cas\resource\Result.txt is a txt file on the network share. Clients will write result to this txt file.
The command in the task sequence is (it's a x64 machine):
PowerShell.exe -ExecutionPolicy Bypass -File ".\DeactiveTest.ps1"
The output is like:
I may get downvoted for this as my answer isn't technically directly answering your question, it is, however, intended to try and point you in what may be a more logical direction. All apologies if I offend anyone, but here it is:
Why not just disable the user using Group Policy? If you really want to know where the user is/isn't disabled then you could just use hardware inventory for that, but GP really is the best way to enforce this kind of setting.

user to see Terms and conditions screen at password change

The company I am working for would like a splash screen that I did to pop up when ever a user changes password (90 day rule at present), this is mainly due to a external requirement.
One of the snags I have is that the system has no email to show me that a user is expiring, I am looking at a couple of things
A log output of expired accounts and locked accounts, ignoring accounts not logged on disabled accounts system etc.
On the 90 day policy a splash screen pops up with the t$c with an accept or decline window (they see this when they first turn the PC and pops up just before the logon box on basically saying by accepting you agree to have read blah and blah)
I do not know how to get either this to run as one script or have two separate scripts,
Any input greatly appreciated
Import-Module ActiveDirectory # Required for PowerShell 2.0 only
$a = (Get-Date).Date.AddDays(-89)
# The following line will build the variable based upon the noted criteria
$b = Get-ADUser `
-Property Name, SamAccountName, PasswordLastSet, CannotChangePassword, PasswordNeverExpires `
-Filter { (PasswordLastSet -lt $a) -and (PasswordNeverExpires -eq $false) } |
Where-Object { $_.CannotChangePassword -eq $false }
# The following line will display/export the data logging the accounts to be changed
# please note the Out-File path and change to suit your needs.
$b | Format-Table Name, PasswordLastSet, CannotChangePassword, PasswordNeverExpires -AutoSize |
Out-File -FilePath "C:\passwordchanges.txt"
# The following line will actually flag the accounts to require a password change
# (after -WhatIf is removed)
$b.SamAccountName | ForEach-Object {
Set-ADUser -Identity $_ -ChangePasswordAtLogon $true -WhatIf
}

PowerShell: Get membership info for a computer account (not a user account)

Getting an ambiguous identity error. I can search successfully to return the group that a user account is a member of, but when I try to search for the groups that a computer account is a member of there is the ambiguous identity error. I tried to use a -type or -identity switch, but either I did not have the syntax correct or it was just not applicable.
Where my targeted computer account is called SNA00760856, I have been working on using...
Get-QADGroup -Containsindirectmember SNA00760856
Any massaging that I can do to the command to get the groups that the computer SNA00760856 is a member of? Dropping in a user account in place of the computer account works like a charm.
I have also tried to qualify the computer name with the domain info.
Ie SNA00760856.mydivision.mydomain.com or mydivision\SNA00760856
Also tried to collect the membership of the computer using which I know is wrong after a closer reading of the switch info....
Get-QADobject -IndirectMemberOf SNA00760856
Results in ambiguous identity as well.
You can get the group memberships of a computer in AD through the ActiveDirectory module with Get-ADPrincipalGroupMembership. You'll need to search via the computers DistinguishedName, which can be achieved by leveraging Get-ADComputer:
Get-ADPrincipalGroupMembership (Get-ADComputer SNA00760856).DistinguishedName
That'll return all of the group objects SNA00760856 is a member of.
If you want to clean up the output, use this
Get-ADPrincipalGroupMembership (Get-ADComputer ComputerName) | select-object name
If you export to a list use
Get-AdPrincipalGroupMembership ( Get-ADComputer XXXXXXX ) | Out-File C:\XXX\XXX
I used something to pull down the AD Computer information and the Computer membership into one Text file.
This is using $Env:computerName to get the name of computer script is run on. If you want to select a different computer, change out the variable $HostName = to a computer name of your choice. Example $HostName = "Janes-Laptop01" .
The computer you run this script on must have the Active Directory module installed for this to work.
Import-module -Name ActiveDirectory
$HostName = $Env:computerName
$path = "c:\temp\Computer_AD_Membership_Info_$($HostName)_$(get-date -f yyyyMMdd-hhmm).txt"
Echo "`r`n ******* Computer OU Information. ******* `r`n" | Out-File -FilePath $path -Encoding utf8 -Force ;
Get-AdComputer -Identity $($HostName) -Properties * | Out-File -FilePath $path -Encoding utf8 -Append -Force ;
Echo "`r`n ******* AD Groups Computer Member of. ******* `r`n" | Out-File -FilePath $path -Encoding utf8 -Append -Force ;
Get-ADPrincipalGroupMembership (Get-ADComputer $($HostName)).DistinguishedName | Out-File -FilePath $path -Encoding utf8 -Append -Force ;

How to create a loop to add info in the AD with powershell

I am a kind of a newbie in Powershell yet, can someone please tell me how i can create a loop (purpose is to add the info to all the people (usernames) in the .CSV list)
This is what i got now, tryed many things but still no good..
Import-Module ActiveDirectory
$username = Import-Csv c:\user.csv
Set-ADuser -Identity $Username -Company "Company name"
Try a foreach loop.
Example:
foreach($user in $username)
{
//some action for example
Set-ADuser -Identity $user -Company "A Company"
}
Reference:
http://www.powershellpro.com/powershell-tutorial-introduction/logic-using-loops/
I'd also recommend adding some sort of logging (using either add-content or write-host) to track the progress of the script, if the file has a lot of entries.
regards
Arcass