Locking the select statement - sql-server

In my PowerShell script, I will query the database using the select statement and it will run every one hour. It will took a quite longer period for completing all the process each time the scheduler executed, so when the next scheduler executed, it might query the old data where its still processing by the previous scheduler. May I know whether any method to prevent this? From what I read (this link) there is a method to achieve it.
Even I changed my query+PowerShell into the following, I found it still not able to achieve the things that I want
$queryAuth2="select * from [StagingDB].[dbo].[UnixAccResetPassword] WITH (HOLDLOCK,READPAST)"
#write-host "The command is : "$queryAuth
$command2=$connection.CreateCommand()
$command2.CommandText=$queryAuth2
$reader2 = $command2.ExecuteReader()
#write-host "The reader is : "$reader
#start-sleep -seconds 180
while ($reader2.read())
{
# write-host "In reader 1"
for ($i = 0; $i -lt $reader2.FieldCount; $i++)
{
# write-host "In reader 2"
$pfno=$reader2.GetValue($i)
write-host "pfno :"$pfno
}
}
The thing I want to achieve is when the select statement query the 5 records(item1,item2,item3,item4,item5) from table, it will locked until those records finished processed and remove away from table.

Related

Loop and Array of Arrays in powershell

I was hoping someone could help me. I am new to powershell and struggling with trying to find the right way to approach something in my script. The script is to do a restore check on our backups using the veeam powershell commands. We have 7 backup jobs with various servers in each job and various drives being backed up in each job. Sometimes the servers are in multiple jobs as we have to split the drives across jobs as we copy the backup jobs to USB every day (so we have to balance out the amount of data we backup in each job so that we can copy the drives to the USB drives). I can write the entire script and get it to work but its around 800 lines long and is very inefficient although easy to understand for my team (and me later on!). My current approach pretty much revolves around performing certain actions for each backup job then each server within that job on each disk. I would like to cut it down using an array/loop. I have figured out how to use basic loops and arrays but I am struggling with being able to link the drives and servers in an array for example:
$Backupjob1 = "Backup Job 1E"
$Backupjob1Servers =#('Server1','Server2')
Somekind of array that allows different numbers of multiple drives for Server1 and Server 2.
$Backupjob1ServeDrives =#(Server1.Drive1 ='C', Server1.Drive2 ='F', Server2.Drive1 = 'C')
and then I need to loop through it so that on each loop, it performs an action on server1 and its first drive then does the next drive. Once server1 has finished, it performs the action on server2 on its first drive and then repeats on the second drive.
I understand the basics of looping through an array but I am struggling to understand how i would create an array of arrays that can deal with the above and then loop through it correctly.
I am stuck as not sure what array works and what options there are.
One way would be to externalise your config into a json file or similar and feed that to your script. Here is an example using a json string:
$serverConfig = #"
[{
"serverName": "server1",
"backupDrives": [
"D","F"
]
},
{
"serverName": "server2",
"backupDrives": [
"D","G","H"
]
}]
"#
$serverList = $serverConfig | ConvertFrom-Json
foreach($server in $serverList) {
Write-Host "Server: $($server.serverName)"
foreach($drive in $server.backupDrives) {
Write-Host "Backing up drive $drive..."
# Logic for the backup
}
}
This demonstrates handling the array of arrays you reference, you have an array of server objects and each server object has an array of drives, so on each iteration of the servers you iterate the server's drives too.
If you save the string into a config file your script could read that in, and then if you make any changes to the backup configuration you only need to change the config file and not the script.
It sounds like you want a dictionary type - thankfully PowerShell has a builtin unordered dictionary type called a hashtable that can be used.
In order to construct a hashtable literal, use #{...} instead of #(...):
$driveMapping = #{
Server1 = #{
Drive1 = 'C'
Drive2 = 'F'
}
Server2 = #{
Drive1 = 'C'
}
}
To traverse this data structure, use a simple nested loop:
foreach($server in $drivemapping.psbase.Keys){
Write-Host "About to backup the drives on server '$server'"
foreach($drive in $drivemapping[$server].psbase.Keys){
$driveLetter = $drivemapping[$server][$drive]
Write-Host "About to backup drive '$drive' with letter '$driveLetter' on server '$server'"
}
}

Convert a number entered by a user in PowerShell into an array by counting

I have a PowerShell script I am using to automate creating volumes on a SAN. The script prompts the user to enter the pertinent information: number of volumes, volume size and naming pattern. Next it should run a command on the array to create the volumes using the information provided. Here is where I am stuck. Right now the script asks the user to specify the number of volumes to create. For example let's say the user enters the number 4. I a stuck on how to take 4 and make it an array 1,2,3,4 or 7 to 1,2,3,4,5,6,7. Maybe there is an easier way to do this via counting or some other function. I am new to scripting, so any help is greatly appreciated.
# Define the number of volumes to create
$num_vols = read-host "Please enter the number of volumes"
# Define naming pattern
$vol_name = read-host "Please enter the volume naming pattern"
What I wanted to do was create a function that would basically run something like:
# Run command to create volumes on array
foreach ($i in $num_vols){
& "command to execute" $vol_name + $i
}
Thanks for the suggestions. I am now using:
# Run command to create volumes on array
foreach ($i in 1..$num_vols){
& "command to execute" $vol_name"."$i
}
Works perfectly! I can now create X volumes named VolName.1, VolName.2 and so on, where X is the number of volumes entered by the user.
You can use the range operator (..):
foreach ($i in 1..$num_vols) { ... }
Or the range operator like this:
1..$num_vols | ForEach-Object { ... }
Or you can use a traditional for loop:
for ($i = 0; $i -lt $num_vols; $i++) { ... }

Increment through array across daily scheduled jobs

Is it possible to have the arguments in a daily scheduled job increment each day? I have an array of values and I want to run one job per value, spread out so that the jobs occur once a day.
This is my code so far:
$dailyTrigger = New-JobTrigger -Daily -At "11:00 AM"
$option = New-ScheduledJobOption -StartIfOnBattery -StartIfIdle -WakeToRun -IdleTimeout "10:00:00"
Register-ScheduledJob -Name $JobName -FilePath $ScriptToRun -Trigger $dailyTrigger -ScheduledJobOption $option
I was planning on using Register-ScheduledJob's -ArgumentList parameter, but from what I've seen there would be no way to pass a different value to each daily instance of the job. Is there some way I could store which element of the array is next so that the jobs could reach it?
One possible way to persist a counter between job runs is to store the value in the registry:
Set-ItemProperty -Path 'HKCU:\foo' -Name 'Job1' -Value ($counter + 1)
and read it on the next run:
$counter = (Get-ItemProperty -Path 'HKCU:\foo').Job1

How to process SSAS cube structures concurrently from PowerShell script using Mircrosoft.AnalysisServices namespace

TL;DR: Is there a way for a PowerShell script calling Microsoft.AnalysisServices functions to process multiple cube structures concurrently?
I have a Microsoft SSAS cube that needs several measure groups processed before the rest of the cube is processed later in the job plan. I have created a PowerShell script that enumerates the measure groups to process and calls measureGroup.Process('ProcessFull') from the Microsoft.AnalysisServices namespace. This works to process the measure group, dimension, et.al.
However, processing the measure groups in this manner doesn't allows SQL Server 2014 to parallelize the processing. A cube that takes on average 2 hours to fully process was running for 7 hours before we killed it.
Is there a way in PowerShell to batch the processes so that they are sent at the same time to the cube? If this could be done, it would allow the server to do concurrent processing instead of one object at a time.
I have taken a look through the documentation on the MSDN as well as consulted Google, but was unable to find an answer. Thanks!
You should check this method in PowerShell: http://ssas-info.com/analysis-services-scripts/1238-powershell-script-to-process-all-dimensions-and-cubes-in-one-db-limiting-workload
Have a look at powershell jobs:
Background Jobs
Here's a quick example that you could adapt to run your measuregroup processing:
$cmd = {
param($a)
Write-Host $a
}
$list = #("a","b","c")
$list | ForEach-Object {
Start-Job -ScriptBlock $cmd -ArgumentList $_
}
It's quite simple, you define your script block in the $cmd variable, this is where you would put your logic around processing the measure group. The $list variable could contain a list of the measure groups to process.
You then start a job for each item in the list, which executes the code in the script block, passing through the item in the list as a parameter. In this example it simply prints out the parameter that you passed in. You can of course pass in as many parameters as you like.
To get the results, you can use the Get-Job cmdlet to check the status of the jobs and Receive-Job to get the output. Remove-Job can then be used to clear finished jobs from the queue.
The following command run after the code above will get the results of all the jobs (in this case just the a,b,c that we passed in and then will remove it from the queue:
Get-Job | ForEach-Object { Receive-Job $_.Id; Remove-Job $_.Id }

PowerShell: Write-Progress for Progress on Multiple Scripts

My Research:
Okay, I have looked at dozens upon dozens of examples for Write-Progress and observed the following. Most of the time used in conjuction with a loop, usually "for" or "foreach". Most examples don't do anything but count to 100. Other more useful examples will perform a certain command, such as copying files. No examples envelope entire scripts.
My Setup:
I have several scripts (thousands of lines of code) which call each other at certain times. One single script controls or calls all the other scripts. The script runs for about 15 minutes, during that time I would like to provide status using Write-Progress.
My Question:
How can I use Write-Progress to provide status while ALL my scripts are executing? Basically I want to "wrap" Write-Progress around all my scripts or whatever is the best method for providing status for multiple called scripts from a single script.
Best Example:
The best use of this I've seen thus far is when using the Update-Help CmdLet in PowerShell V3. But since I cannot see the source-code for the Update-Help CmdLet, this doesn't help me.
Try this out. First file is master.p1:
$parentId = 1
$childId = 2
Write-Progress -Id $parentId -Activity "Running master script" -Status "Step 1 of 3" -PercentComplete 0
.\slave.ps1 $parentId $childId
Write-Progress -Id $parentId -Activity "Running master script" -Status "Step 2 of 3" -PercentComplete 33.3
.\slave.ps1 $parentId $childId
Write-Progress -Id $parentId -Activity "Running master script" -Status "Step 3 of 3" -PercentComplete 66.3
.\slave.ps1 $parentId $childId
Second file is slave.ps1:
param([int32]$ProgressParentId, [int32]$progressId)
for($i = 0; $i -le 100; $i += 10)
{
Write-Progress -Id $progressId -ParentId $parentId `
-Activity "Running slave script" `
-Status "Processing $i" `
-CurrentOperation "CurrentOp $i" -PercentComplete $i
Start-Sleep -Milliseconds 500
}
Put those two files in the same dir and from PowerShell (or ISE) execute master.ps1. I have used this approach before to report progress of multiple phases across multiple scripts. The key is to pass the ParentId of the top level progress to the child scripts so they can report progress in that same context. If you provide a unique Id for each, they can get their own separate progress bar. Or just the same Id everywhere to update a single progress bar.

Resources