Continue script, once search will be done - powershell

I have command in the script to do compliance search(Microsoft Exchange) and it takes ~20 minutes and I need to wait until it will be done to use powershell. I need to continue script automatically, once search will be done. Here is example:
ShowSearchResults
Write-Host "You can find search results under the following path: C:\ExportResults" -ForegroundColor Green
Write-Host "Do you want to delete found mails? (y/n)" -ForegroundColor Green
New-ComplianceSearchAction -SearchName $FinalSearchName -PurgeType softdelete -Purge
And when I start "ShowSearchResults" I need to wait once it will be done. I need to show "Write-Host..." once search will be done, until it, I need my session.
I tried with Start-Job, but I didn't find the solution with this way

Your code seems good to me except for 1 misrepresented statement.
PowerShell, like most scripting languages, will execute the commands/statements in your script from top to bottom by default.
So your Write-Host will be executed only after the previous command is completed.
As for the "misrepresented" statement, you might've wanted to use Read-Host to get a user choice to soft delete your last search. So after small corrections, your code looks like the below,
#1
$ComplianceSearchJob = Start-Job -ScriptBlock {
ShowSearchResults
Write-Host "You can find search results under the following path: C:\ExportResults" -ForegroundColor Green
# Invoke-Item "C:\ExportResults\SearchResults.csv"
}
#2
Receive-Job $ComplianceSearchJob -Keep
#3
$DeleteChoice = Read-Host "Do you want to delete found mails? (y/n): " -ForegroundColor Green
if($DeleteChoice -eq "Y"){ # case insensitive
New-ComplianceSearchAction -SearchName $FinalSearchName -PurgeType softdelete -Purge
}
EDIT 1: Added Invoke-Item to open the C:\ExportResults\SearchResults.csv file in a comment.
EDIT 2: Used Start-Job to allow running as a background process.

Related

if then else not seeing else argument

I'm trying to learn myself some PowerShell scripting to automate some tasks at work.
The latest task I tried to automate was to create a copy of user files to a network-folder, so that users can easily relocate their files when swapping computers.
Problem is that my script automatically grabs the first option in the whole shebang, it never picks the "else"-option.
I'll walk you through part of the script. (I translated some words to make it easier to read)
#the script asks whether you want to create a copy, or put a copy back
$question1 = Read-Host "What would you like to do with your backup? make/put back"
if ($question1 -match 'put back')
{Write-Host ''
Write-Host 'Checking for backup'
Write-Host ''
#check for existing backup
if (-Not(Test-Path -Literalpath "G:\backupfolder"))
{Write-Host "no backup has been found"}
Elseif (Test-Path -LiteralPath "G:\backupfolder")
{Write-Host "a backup has been found."
Copy-Item -Path "G:\backupfolder\pictures\" -Destination "C:\Users\$env:USERNAME\ ....}}
Above you see the part where a user would want the user to put a "backup" back.
It checks if a "backup" exists on the G-drive. If the script doesn't see a backup-folder it says so. If the script DOES see the backup it should copy the content from the folders on the G-drive to the similarly named folder you'd find on the user-profile-folder. Problem is: So far it only acts as if there is never a G:\backupfolder to be found. It seems that I'm doing something wrong with if/then/else.
I tried with if-->Else, and with if-->Elseif, but neither works.
I also thought that it could be the Test-Path, so I tried adding -LiteralPath, but to no avail.
There is more to the script but it's just more if/then/else. If I can get it to work on this part I should be able to get the rest working. What am I not seeing/doing wrong?

Making a PowerShell more efficient other than if statements

I have a script here that does its job for the most part. I am new to PowerShell scripting, so I am trying to get an outside view of what I should change.
The first part of the script asks the user if they would like to install the program or not.
$<application> = Read-Host -Prompt 'Would you like to install <>? Please type Yes or No'
This then leads to an if else statement
if ( $<application> -eq 'Yes' )
{
start-process <application.exe>
Start-Sleep -s 30
}
else
{
Write-Host "Installation of <Application> was skipped"
}
The reason I have start sleep is because it opens up an application one at a time. You have 30 seconds to setup the application which doesn't seem efficient
My questions are
Is there any way to do this without a sea of if statements? I know there is a way with a csv file but I am looking for alternatives. I like how the script asks if you should install a program or not
Is there anyway to stop the Start- Sleep process when the application is done? So the user doesn't feel rushed on one application?
Thank you.
Is there any way to do this without a sea of if statements?
Sure - organize your applications into an ordered dictionary and loop through the entries:
$applications = [ordered]#{
"App One" = "path\to\application1.exe"
"App Two" = "path\to\application2.exe"
# ...
}
foreach($appName in $applications.Keys){
$response = Read-Host -Prompt "Would you like to install '${appName}'? Please type Yes or No"
if($response -eq 'yes'){
Start-Process -Path $applications[$appName]
Start-Sleep -Seconds 30
} else {
Write-Host "Installation of '${appName}' was skipped"
}
}
Is there anyway to stop the Start- Sleep process when the application is done?
Yes, use Start-Process -Wait instead of sleeping for a set duration:
Start-Process -Path $applications[$appName] -Wait

Remove Directory path from Powershell [duplicate]

Using Windows PowerShell, how do I change the command prompt?
For example, the default prompt says
PS C:\Documents and Settings\govendes\My Documents>
I want to customize that string.
Just put the function prompt in your PowerShell profile (notepad $PROFILE), e.g.:
function prompt {"PS: $(get-date)>"}
or colored:
function prompt
{
Write-Host ("PS " + $(get-date) +">") -nonewline -foregroundcolor White
return " "
}
Related to a comment to Ocaso Protal's answer, the following is needed for Windows Server 2012 as well as Windows 7 (in a PowerShell window):
new-item -itemtype file -path $profile -force
notepad $PROFILE
I would suggest the following as a prompt if you run with multiple user names (e.g. yourself + a production login):
function Global:prompt {"PS [$Env:username]$PWD`n>"}
(Credit goes to David I. McIntosh for this one.)
At the prompt, I like a current timestamp and resolved drive letters for network drives. To make it more readable, I put it in two lines, and played a bit with colors.
With CMD, I ended up with
PROMPT=$E[33m$D$T$H$H$H$S$E[37m$M$_$E[1m$P$G
For PowerShell, I got the same result with:
function prompt {
$dateTime = get-date -Format "dd.MM.yyyy HH:mm:ss"
$currentDirectory = $(Get-Location)
$UncRoot = $currentDirectory.Drive.DisplayRoot
write-host "$dateTime" -NoNewline -ForegroundColor White
write-host " $UncRoot" -ForegroundColor Gray
# Convert-Path needed for pure UNC-locations
write-host "PS $(Convert-Path $currentDirectory)>" -NoNewline -ForegroundColor Yellow
return " "
}
Which is a little more readable :-)
BTW:
I prefer powershell_ise.exe $PROFILE instead of (dumb) Notepad.
If you like to debug your prompt() with breakpoints, you should rename the prompt-function to anything else (or try it in another file). Otherwise you might end up in a loop: When you stop debugging, prompt() is called again and you stop at the breakpoint, again. Quite irritating, at first...
If you want to do it yourself, then Ocaso Protal's answer is the way to go. But if you're lazy like me and just want something to do it for you, then I highly recommend Luke Sampson's Pshazz package.
Just to show you how lazy you can be, I'll provide a quick tutorial.
Install Pshazz with Scoop (scoop install pshazz)
Use a nice predefined theme (pshazz use msys)
Drink (root) beer
Pshazz also allows you to create your own themes, which is as simple as configuring a JSON file. Check out mine to see how easy it is!
To just show the drive letter I use:
function prompt {(get-location).drive.name+"\...>"}
Then to revert to the path I use:
function prompt {"$pwd>"}
This version of Warren Stevens' answer avoids the noisy "Microsoft.PowerShell.Core\FileSystem" in the path if you Set-Location to network shares.
function prompt {"PS [$Env:username#$Env:computername]$($PWD.ProviderPath)`n> "}
PROMPT in PowerShell
A better way to track the path, while keeping the hostname and logging time/date in every line run:
function prompt {
$dateTime = get-date -Format "dd.MM.yyyy HH:mm:ss"
$currentDirectory = $(Get-Location)
$UncRoot = $currentDirectory.Drive.DisplayRoot
write-host "$dateTime" -NoNewline -ForegroundColor YELLOW
write-host " $UncRoot" -ForegroundColor White
# Convert-Path needed for pure UNC-locations
write-host "$ENV:COMPUTERNAME-PS:$(Convert-Path $currentDirectory)>" -NoNewline -ForegroundColor GREEN
return " "
}
...and you get:
myservername-C:\Users\myusername\Documents\WindowsPowerShell\scripts>
Finally! :)

Moving content from one external storage location to a network with email confirmation

This is my first non-very-basic attempt at PowerShell scripting, so please excuse any poor etiquette.
I have an need to transfer approximately 30GB of video data from USB attached storage to a local network share. As I started this little project, I quickly identified that the processes I do naturally when performing this task need to be accounted for during the scripting, so my question is, how do I lay this all out and achieve my end goal of a simple copy and allow for this.
This is what I have thus far;
### (The purpose of this script is to automate the offloading of the Driver Cameras during FP1 and FP2 on a Friday.
### Please remember that the cameras still need to be cleared after fireups on a Thursday"
Write-Host -NoNewLine "This script will move the footage captured on the SD cards of the FWD and RWD cameras and copy them to a defined network share" -ForegroundColor Green `n
Start-Sleep -Seconds 10
# Execute the copy from the foward facing camera to the network and remove the local files once complete
Write-Host "FWD Camera copy in progress" -ForegroundColor White -BackgroundColor Magenta `n
Start-Sleep -Seconds 5
Get-ChildItem -Path "SourcePath" -Recurse |
Move-Item -destination "DestinationPath" -Verbose
# Execute the copy from the rearward facing camera to the network and remove the local files once complete
Write-Host "RWD Camera copy in progress" -ForegroundColor White -BackgroundColor Magenta `n
Start-Sleep -Seconds 5
Get-ChildItem -Path "SourcePath" -Recurse |
Move-Item -destination "DestinationPath" -Verbose
Write-Host "Sending email confirmation" -ForegroundColor Green `n
Send-MailMessage -smtpserver ServerIP -To "EmailAddress" -From "EmailAddress" -Subject "Camera offload" -body BodyHere -bodyasHTML
Write-Host "All tasks have completed" -ForegroundColor Green `n
Read-Host "Press any key to exit..."
exit
What I'd like to add is fault tolerance and allow for this to be communicated via email dynamically. find these criteria below;
There's a chance the cable connecting the storage to the machine running the script could become disconnected and only have moved a number of items, can I add something to aid this?
If a file transfer fails how do i restart and track this? Can I add a loop to confirm all the items have been moved?
How do I reference a fault code to dynamically update the content of the email sent to the end user?
Finally, are there any other common practice references I've missed and that need to be included?
Many thanks in advance for any help.
This topic is a bit broad but let me try to address your question to help you to start. Of course I won't give you the whole code, just explanation what to use and why.
There's a chance the cable connecting the storage to the machine running the script could become disconnected and only have moved a number of items, can I add something to aid this?
First of all, as vonPryz said in comments, use robocopy!
It should survive network interruptions (e.g. check this post). As a general approach, I'd first make sure that the content is successfully copied before deleting it. For example you could use something like this:
(Get-ChildItem -Recurse).FullName.Replace("C:\old\path","D:\new\path") | Test-Path
Of course the above will only check if file exists, not if the file has the same content. To compare if the files are the same you could use Get-FileHash.
If a file transfer fails how do i restart and track this? Can I add a loop to confirm all the items have been moved?
Partially answered above. Robocopy has this feature built-in. And yes, you can add a loop to check.
How do I reference a fault code to dynamically update the content of the email sent to the end user?
Check the example from here:
robocopy b:\destinationdoesnotexist C:\documents /MIR
if ($lastexitcode -eq 0)
{
write-host "Success"
}
else
{
write-host "Failure with exit code:" $lastexitcode
}
Also, there's article on MS side listing all exit codes which might be helpful to handle the exceptions. All you have to do is to add $LASTEXITCODE to email body.

Get batch file return code in powershell

I'm trying to write a PowerShell script as a "Framework". Basically what it does is calls batch files that installs msi files locally.
There are few things I am trying to get done.
PowerShell should get all exit codes whatever the batch files return.
Need a timer and check if the batch file is stuck.If it's stuck kill it, return an error and continue
Need a progress bar for each batch file installation.
I'm not sure if I can do all or any. Since every package(the batch files) comes from different groups, I can't use PowerShell to do everything and have to use the batch files other groups sent me.
I was able to get the packages install with a simple script but couldn't get to do any of the above things I was trying to do. I keep getting last exit code as 0. I assume it's because the batch file ran successfully.
$APP1 = "Microsoft_RDP_8.1_L_EN_01"
Stop-Process -Name reg* -Force
Write-Host "=== $Time -- Starting $APP1 Installation"
TRY
{
$Install = "$pwd\cmd\$App1\Install.cmd"
cmd /c $Install /b 1
$App1ErrorCode = $LastExitCode
Write-Host "Final Return Code Of $APP1 Is = $APP1ErrorCode"
}
CATCH
{
Write-Host "-----------------------------------------------------------" -ForegroundColor Green
Write-Host "Caught an exception:" -ForegroundColor Red
Write-Host "Exception Type: $($_.Exception.GetType().FullName)" -ForegroundColor Red
Write-Host "Exception Message: $($_.Exception.Message)" -ForegroundColor Red
Write-Host "-----------------------------------------------------------" -ForegroundColor Green
}
$LastExitCode = $null
$Value = $null