Powershell foreach Exchange Online InboxRule issue - powershell

I'm having an issue when trying to complete my script.
I'm trying to create a rule for couple of users:
(if message arrives from (x), move to Inbox).
This is the script I wrote:
$names = #{"name1#name.com","name2#name.com"}
Loop
foreach($name in $names){
Write-Host "Moving the message for $name"
new-inboxrule -Name "MoveFromMailchimp" -Mailbox $name -MoveToFolder
"$name:\Inbox" -From "senderEmailAddress" -StopProcessingRules: $false
}
However it throws an error upon $name:\Inbox, saying it does not want to take ":".
Does anyone have any ideas?

You need to escape your variable in the string.
Try:
"$($name):\Inbox"

Related

How to use SplitPipeline with o365 cmdlets

I have been trying to check the mailboxes for a specific list of users (about 14k users) because it is possible that a malicious rule has been created.
I created a very simple PowerShell script to achieve that but obviously it took more than 12 hours to finish. I have found a multi-threading option to process all this data: SplitPipeline, but I don't even know how to start.
After installing and importing the module and logging into O365, I'm trying this (please not that I'm just starting in this powershell world, I'm not an expert):
$file = Get-Content userlist.txt
$outputFile = "outputFile.txt"
$data = #{
Count = $file.Count
Done = 0
}
$file | Split-Pipeline -Count 10 -Variable data {process{
[System.Threading.Monitor]::Enter($data)
try
{
$done = ++$data.Done
}
finally
{
[System.Threading.Monitor]::Exit($data)
}
Write-Progress -Activity "Done $done" -Status Processing -PercentComplete (100*$done/$data.Count)
$User2Check = $_
Write-Host "Checking $User2Check"
get-mailbox $User2Check | Select identity
}} | Set-Content $outputFile
The result is the typical message: The term 'get-mailbox' is not recognized as the name of a cmdlet, it is like SplitPipeline is not aware I'm logged against O365.
Do you have any ideas?
You have to understand how Split-Pipeline works, it runs in its own workspace. Unfortunately one cannot call/use functions and variables specified outside split-pipeline run space. You can use the -Variable -Function switches provided by Split-pipeline, but keep in mind that in the case of functions, any global variable used by xyz function you are trying to call cannot see the global variable.
Indoor case, get-mailbox is null because Split-pipe does not know about it, you will have to include the model and create a new connection to office in order for the get-mailbox cmdlet to work.

Powershell: redirect output from "NET share" or "Remove-SmbShare"

I want to delete all shares and store the output of the command in a variable
Hopefully you can help me!
How do I delete a share?
Invoke-Expression "Remove-SmbShare -Force -Name $name"
or
NET SHARE $name /delete
Thanks!
edit:
I know that I can redirect the output to a File, but I do want it to redirect it directly into a variable.
NET SHARE i$ /delete *> "C:\workspace\output.txt"
Why do I want to delete shares via Powershell?
Forced shares via company rules and I want to get rid of them directly after the login
If you are asking in the powershell section if you should use a executable or a commandlet the answer is pretty obvious: the commandlet.
Remove-SmbShare does not generate output for successful execution so you will have to work around that.
What you could do is something like this:
$names = "TestShare","TestShare2"
$success = #()
foreach($name in $names){
try {
Remove-SmbShare $name -force -Erroraction Stop
$success += $true
} catch {
$success += $false
}
}
Afterwards you will have two arrays with corresponding indexes. Alternatively you could also add a string to the success array like so $success += "$name $true" but you will figure that out on your own.

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.

Looking for advice on how to proceed with working powershell script

So I posted for and got some help with this script:
#Command to get list of folders with logfiles where the logfile is at least 30 minutes old send results to variable.
$varlogfile = Get-ChildItem -Path "drive:\folder" -Recurse -Include "logfile" | Where-Object {$_.LastWriteTime -le ((Get-Date).AddMinutes(-30))}
#Add a carriage return to results contained in the variable so email is easier to read
$varlogfile = $varlogfile -join "`r`n"
#Email setup from this line down to next comment
$SMTPServer = "email.server"
$From = "Administrator <administrator#place.com>"
$To = "email","email2"
$Subject = "A Logfile older than 30 minutes has been detected"
$Body = "Logfile(s) older than 30 minutes have been detected in the following folder(s):
$varlogfile
Please login and attempt to process the files manually, if the manual process fails, open a ticket with someone.
From the Admin
"
#Email setup above this line
#If statement that looks for the text blah in the variable, if found email is sent.
if($varlogfile -match "blah")
{
#Command to send email
Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer
}
exit 0;
And all that is working perfectly.
Here's the thing though. Over the weekend sometimes we may get a stuck logfile that can't be resolved until Monday morning and it would be nice to be able to turn off alerts when this happens.
Now I'm very new to powershell and this script has been my learning experience. The way I see it is I have 3 choices:
Keep the get-childitem from returning a result if it sees logfile and logfile.stop.
After get-childitem has produced $varlogfile, search $varlogfile for logfile.stop and delete the lines logfile and logfile.stop from it.
Rewrite the whole thing from scratch and produce $varlogfile in a better way that makes it easier to work with the results.
Thoughts and opinions? I'm leaning toward method 2, as I think I can figure that out, but I'm curious if that is a way of pain. I'd really like your input on this.
Thanks people!
I think you're on the right path with your current plan, so I'll help you with approach #2, creating a .sent file when we send an email, to keep the emails from sending multiple times.
Our first step: When an e-mail is sent , we create a new file titles $logfile.MessageSent or something like that. Doing this allows an e-mail to be sent, and for us to also create a flag that we can search for later in the filesystem to determine whether or not we send another e-mail.
#If statement that looks for the text blah in the variable, if found email is sent.
if($varlogfile -match "blah")
{
#Command to send email
Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer
New-Item -path $varLogfile.Sent -itemType File
}
Our second step: Modify our Get-ChildItem query to search for the flag:
$varlogfile = Get-ChildItem -Path "drive:\folder" -Recurse -Include "logfile" |
Where-Object {$_.LastWriteTime -le ((Get-Date).AddMinutes(-30))} |
? "($_.BaseName).sent" -notin (Get-ChildItem -Recurse -Include "*.sent" -Path "drive:\folder" | Where-Object {$_.LastWriteTime -le ((Get-Date).AddMinutes(-30))})
This second modification to the $varlogfile step is hard to understand, admittedly. Here is how I've changed it:
Get a lit of files in the drive\folder path, recursively and include logfile
Where the LastWriteTime is older than 30 mins
Where filename.sent is not found in the same directory
The only other thing you'll need to do is add a cleanup task to regularly delete the .sent files, and you're good to go.
Please let me know if you have any questions about this approach, as I want to be sure you understand and to help you learn.

PowerShell send email to list of addresses within another script

I am trying to create a PowerShell script that will send an email to a list of people, but the email call is already embedded within a ping script. This is for a system that only has PowerShell v2.0.
Computers.txt contains a list of computers to be pinged and on failure will send an email.
This is my existing script I am trying to modify:
Get-Content -path "E:\Computers.txt" | ForEach-Object {
if (-not (Test-Connection -ComputerName $_ -Delay 2 -Quiet)) {
Send-MailMessage -To "email address" -Subject "$_ is Unreachable" -Body "$_ is unreachable by ping. Next check is in 5 minutes" -SmtpServer "server address" -From "another email address"
}
}
I know that I can use the Get-Content -path "E:\From_Email.txt" and Get-Content -path "E:\To_Email.txt" to call the list of email addresses, but I am not sure how to do this within the existing command. I have looked online, but I have not found how to nest calling additional text files within PowerShell for a script.
Do I need to call these files earlier and set them equal to a variable which gets called? Any help would be greatly appreciated. Thank you.
Assuming you have an email address on each line of "E:\To_Email.txt", the code below should work
$emails = (Get-Content "E:\To_Email.txt") -join ";"
Get-Content -path "E:\Computers.txt" | ForEach-Object {
if (-not (Test-Connection -ComputerName $_ -Delay 2 -Quiet)) {
Send-MailMessage -To $emails -Subject "$_ is Unreachable" -Body "$_ is unreachable by ping. Next check is in 5 minutes" -SmtpServer "server address" -From "another email address"
}
}
The extra first line reads in all lines of the email list file as an array, then joins it with semi-colons, which I think is how your email addresses should be separated. Worth checking though.
Example content of "E:\To_Email.txt"
person.one#yourdomain.whatever
person.two#yourdomain.whatever
person.three#yourdomain.whatever
person.four#yourdomain.whatever