I am trying to perform a scheduled operation where I create a file share in Azure and copy some files in it. Before I begin doing so, I would like to cleanup the previous job if it did not cleanup on the prior run. To do so, I found the handy-dandy Remove-AzureStorageShare method. My problem is that after I call this method, it takes Azure sometimes up to 2 minutes to complete the task. I have a wait in PowerShell, but I'm unable to check Azure for the share without throwing an exception and then continue. So basically, I want the following operations to happen:
1] Check for Share in Azure, delete if it exists
2] Once Azure is done deleting, re-create it
3] Copy my files into the new Share
Here is what I have and it doesn't work:
Write-Host "STEP 6 : Removing existing Azure Share...";
# THIS NEXT LINE THROWS AN ERROR IF THE SHARE DOESN'T EXIST
If ((Get-AzureStorageShare -Name $azureShareName -Context $context) {
Remove-AzureStorageShare
-Context $context
-Name $azureShareName
-Force
-ErrorAction SilentlyContinue | Out-Null
}
$removed = $false;
While(!$removed) {
Try {
# THIS LINE SHOULD THROW AN EXCEPTION SINCE IT'S BEING DELETED
If ((Get-AzureStorageShare -Name $azureShareName -Context $context) -eq $null) {
$removed = $true;
}
}
Catch
{
# SINCE THE EXCEPTION IS THROWN, WE WILL SLEEP FOR A FEW...
Write-Host "STEP 6a : Waiting...still removing.";
Start-Sleep -s 10;
}
}
When I attempt to create the share again, I get the following error:
New-AzureStorageShare : The remote server returned an error: (409) Conflict. HTTP Status Code: 409 - HTTP Error Message: The specified share is being deleted. Try operation later.
Thank you for your question.
I think we can use this PowerShell to check for share in Azure:
Write-Host "STEP 6 : Removing existing Azure Share...";
# THIS NEXT LINE THROWS AN ERROR IF THE SHARE DOESN'T EXIST
If ((Get-AzureStorageShare -Name $azureShareName -Context $ctx)) {
Remove-AzureStorageShare `
-Context $ctx `
-Name $azureShareName `
-Force `
-ErrorAction SilentlyContinue | Out-Null
}
$removed = $false;
While(!$removed) {
Try {
# THIS LINE SHOULD THROW AN EXCEPTION SINCE IT'S BEING DELETED
If ((Get-AzureStorageShare -Name $azureShareName -Context $ctx) -eq $null) {
$removed = $true;
}
else {
Write-Host "STEP 6a : Waiting...still removing.";
Start-Sleep -s 5;
}
}
Catch
{
# SINCE THE EXCEPTION IS THROWN, WE WILL SLEEP FOR A FEW...
Write-Host "STEP 6b : Waiting...still removing.";
Start-Sleep -s 5;
}
}
If the Share existing the PowerShell will show: waiting…still removing, else the PowerShell will show error 404:
If you still have questions, welcome to post back here. Thanks.
Related
I'm new to powershell and while practicing the examples for loops, I came across a problem that I couldn't solve.
I want to call a notification about the status of a process running in the system through a loop
However, in the code, only the alarm of the process executed first among Taskmgr or Calculator is called by Wait-Process.
I mean, Wait-Process by Sequential Execution makes notification invocation by loop no longer possible
below is my code
do{
Start-Sleep -s 3
$Calculator = Get-Process -Name 'Calculator'
$Taskmgr = Get-Process -Name 'Taskmgr'
if ($Calculator)
{
Show-Notification -ToastTitle 'Calculator is open.'
Wait-Process -name 'Calculator'
Show-Notification -ToastTitle 'Calculator is closed.'
}
if ($Taskmgr)
{
Show-Notification -ToastTitle 'Taskmgr is open.'
Wait-Process -name 'Taskmgr'
Show-Notification -ToastTitle 'Taskmgr is closed.'
}
} while (1 -eq 1)
Since I am Japanese, I am not familiar with English, so I am using a translator. thank you.
I'm still not good enough skill to recreate the code. sorry
Wait-Process blocks the thread indefinitely without the -Timeout parameter but also, while using this parameter if it times out you would get an error and the cmdlet is not particularly useful for this use case.
You could achieve this by using only Get-Process with -ErrorAction SilentlyContinue to avoid errors when the processes are not running and adding else conditions:
while ($true) {
Start-Sleep -s 3
$calc = Get-Process -Name CalculatorApp -ErrorAction SilentlyContinue
$taskmgr = Get-Process -Name Taskmgr -ErrorAction SilentlyContinue
# if calc is running
if ($calc) {
# and there was no notification before
if (-not $calcOpen) {
# display notification
'Calculator is opened.'
# and set a reminder to not display more popups
$calcOpen = $true
}
}
# if calc was not running
else {
# and was running before
if ($calcOpen) {
# display notification
'Calculator is closed.'
# and set a reminder that calc has been closed
$calcOpen = $false
}
}
# same logic applies here
if ($taskmgr) {
if (-not $taskmgrOpen) {
'Taskmgr is opened.'
$taskmgrOpen = $true
}
}
else {
if ($taskmgrOpen) {
'Taskmgr is closed.'
$taskmgrOpen = $false
}
}
}
I am limited to only using native windows tools, and I need to automate opening a browser, going to a website, and then closing the browser. I'm going to use task scheduler to run the script.
I created this PowerShell script which successfully opens a browser, and closes it.
How would I go about having this open a specific webpage? Start Arguments or something else?
$browser = [Diagnostics.Process]::Start("chrome.exe")
$id = $browser.Id
Start-Sleep -Seconds 5
try {
Stop-Process -Id $id -ErrorAction stop
} catch {
Write-Host "Failed to kill"
}
You can start the process with the appropriate Chromium command line argument(s):
$browser = [Diagnostics.Process]::Start("chrome.exe", "https://stackoverflow.com/ --new-window")
$id = $browser.Id
Start-Sleep -Seconds 5
try {
Stop-Process -Id $id -ErrorAction stop
}
catch {
Write-Host "Failed to kill"
}
Process.Start Method
Run Chromium with flags
List of Chromium Command Line Switches
I have two processes that reads from the same file. I want to make sure that those two processes doesn't run at the same. My approach is that , when a process starts, it should look for a file(process.txt). If the file doesn't exist, it creates the file and continue execution, reading from the shared file(sharedfile.txt) between the two processes. It then deletes the process.txt file after executing.
Since both process deletes process.txt file after execution, if the file exists,it should go into a start sleep until the other process finishes and deletes the file.
The problem here is when one process finishes and deletes the file(process.txt), the other still stay in the loop without executing even if no file exists. I am not sure of the right loop to use. I tried a couple of them and couldn't achieve my goal.
Clear Host
$sleeptime = 15
$lockfile = "C:\Users\processid.txt"
$file = test-path -Path $lockfile
Try
{
if($file -eq 'True')
{
echo “Lock file found!”
echo "This means file is being used by another process"
echo "Wait for file to be deleted/released"
echo “Sleeping for $sleeptime seconds”
Start-Sleep $sleeptime -Verbose
}
else
{
New-item -Path $lockfile
#Executing a code here
}
Remove-Item $lockfile –Force
}
}
Catch
{
Write-Host $_.Exception.Message`n
}
Consider this one, it creates a lock file and opens it for exclusive access. Let's you run your script, then cleans up afterwards. If access cannot be gained it waits 5 seconds before trying again.
Using this for both scripts should make them play nice and wait for their turn. If for some reason a lock file gets left behind (unplanned reboot that aborts script or similar) this one will still work fine as well.
$LockFile = 'C:\temp\test.lock'
# Loop that runs until we have exclusive write access to $LockFile
while ($FileStream.CanWrite -eq $false) {
if (-not (Test-Path -Path $LockFile)) {
Set-Content -Path $LockFile -Value 'Lockfile'
}
try {
$FileStream = [System.IO.File]::Open("C:\temp\test.lock",'Open','Write')
}
catch {
'Waiting 5 seconds'
Start-Sleep -Seconds 5
}
}
# ---
# Your actual script here
# ---
# Cleanup
$FileStream.Close()
$FileStream.Dispose()
Remove-Item -Path $LockFile -Force
You could also go one step further and instead lock the file you're actually using, but then you'll need to read it from the file stream since it will be locked for any cmdlets.
You could use a while loop like this
Clear Host
$sleeptime = 15
$lockfile = "C:\Users\processid.txt"
While(Test-Path -Path $lockfile){
Write-Host "Lock file found!"
Write-Host "This means file is being used by another process"
Write-Host "Wait for file to be deleted/released"
Write-Host "Sleeping for $sleeptime seconds"
Start-Sleep $sleeptime -Verbose
}
try{
New-item -Path $lockfile
#Executing a code here
}
catch{
Write-Host $_.Exception.Message`n
}
finally{
Remove-Item $lockfile –Force -ErrorAction SilentlyContinue
}
Have a command that (on 2008 boxes) throws an exception due to the buffer limit.
Essentially, the script stops WAUA, blows out SoftwareDistribution, then reaches out to rebuild SD and check for updates against WSUS then checks back in so the alerts in WSUS stop.
I want a specific line to retry if an exception is thrown until it finishes without an exception, then we can tell it to report back in to WSUS to clear it out.
Stop-Service WUAUSERV
Remove-Item -Path C:\WINDOWS\SoftwareDistribution -recurse
Start-Service WUAUSERV
GPUpdate /force
WUAUCLT /detectnow
sleep 5
## This is the command I'd like to loop, if possible, when an exception is thrown ##
$updateSession = new-object -com "Microsoft.Update.Session"; $updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates
WUAUCLT /reportnow
Any kind of help would be appreciated. Everything I've been able to find has been how to create my own exception but not how to handle it when an exception is thrown and retry until it finishes without an error.
Edit:
Then based on the below Answer, is this how I would want it to be written so it will continue to check until it runs successfully and then it'll report back in?
Stop-Service WUAUSERV
Remove-Item -Path C:\WINDOWS\SoftwareDistribution -recurse
Start-Service WUAUSERV
GPUpdate /force
WUAUCLT /detectnow
sleep 5
while(-not $?) {$updateSession = new-object -com "Microsoft.Update.Session"; $updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates}
WUAUCLT /reportnow
You can use the special character $? This will return false if the last command returned with error, so your while loop would just look like:
while(-not $?)
See what is $? in powershell.
Alternatively, $error[0] gives the last thrown error message so you could build a while loop around that, similar to:
while($error[0] -ne "error message")
Set a value to false and only flip it if you get total success. Loop until you succeed or your timeout exceeds your defined value -- if you don't include a timeout, you have created an infinite loop condition where if the host never succeeds, it'll run until reboot.
$sts = $false
$count = 0
do {
try {
$updateSession = new-object -com "Microsoft.Update.Session"
$updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates
$sts = $true
} catch {
## an exception was thrown before we got to $true
}
$Count++
Start-Sleep -Seconds 1
} Until ($sts -eq $true -or $Count -eq 100)
I'm working on a large script where I run a Foreach loop, define variables in that loop and afterwards check if the $Server variable is pingable and if it is remotely accessible.
For this I use the following functions coming from the PowerShell help:
# Function to check if $Server is online
Function CanPing ($Server) {
$error.clear()
$tmp = Test-Connection $Server -ErrorAction SilentlyContinue
if ($?) {
Write-Host "Ping succeeded: $Server"; Return $true
}
else {
Write-Host "Ping failed: $Server."; Return $false
}
}
# Function to check if $Server is remotely accessible
Function CanRemote ($Server) {
$s = New-PSSession $Server -Authentication Credssp -Credential $Credentials -Name "Test" -ErrorAction SilentlyContinue
if ($s -is [System.Management.Automation.Runspaces.PSSession]) {
Enter-PSSession -Session $s
Exit-PSSession
Write-Host "Remote test succeeded: $Server."; Return $true
}
else {
Write-Host "Remote test failed: $Server."; Return $false
}
}
# Execute functions to check $Server
if ($Server -ne "UNC") {
if (CanPing $Server) {
if (-Not (CanRemote $Server)) {
Write-Host "Exit loop REMOTE" -ForegroundColor Yellow
continue
}
}
else {
Write-Host "Exit loop PING" -ForegroundColor Yellow
continue # 'continue' to the next object and don't execute the rest of the code, 'break' exits the foreach loop completely
}
}
Every time when I run this code, there is a process created on the remote server called wsmprovhost.exe. This process represents the PowerShell session, if the info I found on the web is correct. However, when doing Get-PSSession $Server there are no open sessions displayed in the PowerShell ISE, even though the processes are visible on the remote server and can only be killed with the Task Manager.
When I run this code often the limit of open sessions is reached because every time a new process wsmprovhost.exe is added to the $Server and the command errors out. I've tried to solve this by adding Exit-PSSessionto the code, but it doesn't close the session.
Any help or ideas are more than welcome.
The problem is that Enter-PSSession. Enter-PSSession can only be used interactively, you can't use it in a script. I'd suggest something more like this:
# Function to check if $Server is remotely accessible
Function CanRemote ($Server) {
Try {
$s = New-PSSession $Server -Authentication Credssp -Credential $Credentials -Name "Test" -ErrorAction Stop
Write-Host "Remote test succeeded: $Server."
$true
Remove-PSSession $s
}
Catch {
"Remote test failed: $Server."
$false
}
}
If I have understood correctly, Your remote ps-session are not getting closed.
To my understaning, Get-PSSession will show the session till your local session
is alive (I mean the session you created the remote ps-session) but once your local session
ends Get-PSSession will not show them cause they are no more live on your computer
rather on the remote system (or) they are no more in local session scope.
You can get the session using the command
Get-PSSession -ComputerName server_name
If you want to remove them you can do like
Get-PSSession -ComputerName server_name | Remove-PSSession
Even After executing the below command also, if you are not able to create session
Get-PSSession -ComputerName server_name | Remove-PSSession
Please, Restart the service Windows Remote Management (WS-Management) in the target machine.