PowerShell - next day - sql

I am trying to look into some past days to see if they are weekend or bank holiday. If they are failling into weekend, I am trying to run the query with the subsequent Monday of if bank holiday, trying to run it with next day.
The code is below.
function Check-BankHoliday
{
param
(
[Parameter(Position=1, Mandatory=$true)]
$DayChk
)
$JAMSHost="ukjam01apwpd"
if(!(test-path "JD:\")){$null=New-PSDrive JD JAMS $JAMSHost}
$CalendarName = "Default"
$DateTypeName = "BankHoliday"
$BHDates = Get-ChildItem JD:\Calendars\$CalendarName\$DateTypeName | Select-Object StartDate
$BHDayChk=$false
ForEach ($Date in $BHDates)
{
$BHDayDate=$Date.StartDate.ToString("dd/MM/yyyy")
if($BHDayDate -contains $ImpDateChk)
{
$BHDayChk=$true
}
}
Pop-Location
Return $BHDayChk
}
$lastquarter="select convert (char,(SELECT DATEADD(dd, -1, DATEADD(qq, DATEDIFF(qq, 0, GETDATE()), 0))), 23) as lastquarter"
$lastquarter_day=Invoke-Sqlcmd -Query $lastquarter -ServerInstance "UKWAR01APWPD\WHERESCAPE" -Database RJISDWH
$lastquarter_day= $lastquarter_day.lastquarter
$lastquarter_day = $lastquarter_day.trim(' ')
$lastquarter_day=(Get-Date $lastquarter_day).DayOfWeek
write-host $lastquarter_day
$BHDayChk_lastquarter=Check-BankHoliday $lastquarter_day
if ($BHDayChk_lastquarter -OR $lastquarter_day -eq "Sunday" -OR $lastquarter_day -eq "Saturday")
{
Write-Output "$lastquarter_day had been set as BankHoliday or weekend JAMS Calendars and Changing this to LastWorkDay"
#$lastquarter_day= ConvertTo-Date "today -1 workday" -server $JAMSHost
$lastworkday= ConvertTo-Date "today -1 workday" -server $JAMSHost
$lastquarter=$lastworkday.AddDays(1)
}
else
{
Write-Output "$lastquarter_day is not a BankHoliday or weekend in JAMS Calendars"
}
$SQLquery = "
declare #lastquarter varchar = '$lastquarter_day_date'
declare #sql nvarchar(1000)
set #sql = 'select bp1.sedol, b.benchmark_name, b.description,
bp1.price as '' ' +convert(char,#lastquarter,23) + ' ''
FROM
dbo.ds_benchmark_prices bp1
left join [RJISDWH].dbo.ds_benchmark b on b.sedol=bp1.sedol
where convert(char,bp1.price_date,23) = ''$lastquarter_day'' -- last quarter end
order by b.sedol'
exec (#sql)
"
$lastquarter is returning 2022-12-31 which is a weekend ( Saturday) and if condition below is capturing that being Saturday successfully too.
if ($BHDayChk_lastquarter -OR $lastquarter_day -eq "Sunday" -OR $lastquarter_day -eq "Saturday")
Howevever, how would I add day to Saturday so it runs on the following Monday . I have tried
$lastworkday= ConvertTo-Date "today -1 workday" -server $JAMSHost
$lastquarter=$lastworkday.AddDays(1)
write-host $lastquarter
and that would return 20/01/2023 00:00:00
Below would not work
$lastquarter=$lastquarter.AddDays(1) or $lastquarter=$lastquarter_day .AddDays(1)
I get following error
Method invocation failed because [System.String] does not contain a method named 'AddDays'.
At line:47 char:3
$lastquarter=$lastquarter.AddDays(1)
+ CategoryInfo : InvalidOperation: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MethodNotFound

Related

Powershell outputs mixed between loops - SQL datasets [duplicate]

This question already has an answer here:
PowerShell output is crossing between functions
(1 answer)
Closed 2 years ago.
I have a PowerShell script that loops through list of 3 servers. A SQL script is run with Invoke-Sqlcmd and the result set is stored to variable $DS. At the end of the loop I return the records with with $DS.Tables.Rows.
But the results sets are getting mixed together. I tried using a Write-Host message to breakup the results. But they are still getting mixed together.
Why are the result getting mixed together in the output?
How can I separate the outputs between each loop?
Thanks
Object type
$DS | gm ............... TypeName: System.Data.DataSet
$DS.Tables | gm ........ TypeName: System.Data.DataTable
$DS.Tables.Rows | gm ... TypeName: System.Data.DataRow
Script
#########################>
# SQL servers
$PCList= #("GCOD139","GCOD039","GCOP039")
Write-Host ($PCList -join ", ")
# Query multiple servers
foreach ($PC in $PCList) {
Write-Host ($PC + "...") -ForegroundColor Yellow
# SQL parameters
$Params = #{
'ServerInstance' = $PC;
'Database' = 'master';
# 'Username' = 'svcBIPOC';
# 'Password' = 'bipoc2020*';
# 'InputFile' = "C:\ScriptFolder\TestSqlCmd.sql"
'Query' = '
SELECT
[Server]= ##SERVERNAME
--MB to GB
, REPLACE(name, ''MB'', ''GB'')
,[value]= CAST(value as int)/1000
, [value_in_use]= CAST(value_in_use as int)/1000
--, value, value_in_use, [description]
FROM sys.configurations
WHERE name like ''%server memory%''
ORDER BY name desc
OPTION (RECOMPILE);
'
}
# Capture SQL Dataset
# (Get-Date).ToSTring('s') + " SQL query start..."
$DS = Invoke-Sqlcmd #Params -As DataSet
#(Get-Date).ToSTring('s') + " SQL query end..."
Write-host "-----"
Write-host "SQL"
sleep -Seconds 5
$DS.Tables.Rows
sleep -Seconds 5
}
#########################
Stop using Write-Host to convey progress information - use Write-Progress for that instead!
$PCList= #("GCOD139","GCOD039","GCOP039")
Write-Progress -Activity "Query servers" -Status "About to query: $($PCList -join ", ")"
# Query multiple servers
foreach ($PC in $PCList) {
Write-Progress -Activity "Query servers" -Status "Querying: $PC"
# SQL parameters
$Params = #{
'ServerInstance' = $PC;
'Database' = 'master';
# 'Username' = 'svcBIPOC';
# 'Password' = 'bipoc2020*';
# 'InputFile' = "C:\ScriptFolder\TestSqlCmd.sql"
'Query' = '
SELECT
[Server]= ##SERVERNAME
--MB to GB
, REPLACE(name, ''MB'', ''GB'')
,[value]= CAST(value as int)/1000
, [value_in_use]= CAST(value_in_use as int)/1000
--, value, value_in_use, [description]
FROM sys.configurations
WHERE name like ''%server memory%''
ORDER BY name desc
OPTION (RECOMPILE);
'
}
# Capture SQL Dataset
$DS = Invoke-Sqlcmd #Params -As DataSet
$DS.Tables.Rows
}
Write-Progress -Activity "Query servers" -Completed
Now the progress messages won't interfere with the actual output from the function

Whats the appropriate Filter syntax for Powershell?

What is wrong in my filter?
Get-Mailbox -Filter { ( ArchiveStatus -eq 0 ) -AND ( RecipientTypeDetails -eq UserMailbox ) }
Cannot bind parameter 'Filter' to the target. Exception setting "Filter": "Invalid filter syntax. For a
description of
the filter parameter syntax see the command help.
" ( ArchiveStatus -eq 0 ) -AND ( RecipientTypeDetails -eq UserMailbox ) " at position 58."
At C:\Users\username\AppData\Local\Temp\tmp_1retngr4.15m\tmp_1retngr4.15m.psm1:19986 char:9
$steppablePipeline.End()
~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : WriteError: (:) [Get-Mailbox], ParameterBindingException
FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.Exchange.Management.RecipientTasks.GetMailbox
You should use this format:
Get-Mailbox | Where-Object {$_.ArchiveStatus -eq "0" -and $_.RecipientTypeDetails -eq "UserMailbox"}
See reference here.
Put 0 and UserMailbox in quotes.

How to use For each loop in SQL server

I want to loop through a result set in SQL. So far I only know how to do this in powershell. See below:
foreach ($TestName in $DSFailures | % {$_.TestName}) {
$Query= "USE TestDS
insert into #temptable
SELECT space(iteration * 4) + TheFullEntityName + ' (' + rtrim(TheType) + ')' as EntityName, *
FROM dbo.fn_DependantObjects('$TestName', 1, 0)
ORDER BY ThePath"
Invoke-Sqlcmd -ServerInstance "SQL2016" -Database "db" -Query $Query
How can I achieve this in SQL?
Here is the answer:
Function Get-FunctionDependencies{
$FPM_Functions = "select replace (name, '_CLR','') AS FPM_FunctionName
into #temptable1
from sys.objects
where name like 'fn_clr%'
select * from #temptable1"
$GetCLRCallingFunctions = Invoke-Sqlcmd -ServerInstance "sql" -Database "DB" -Query $FPM_Functions
foreach ($FPM_FunctionName in $GetCLRCallingFunctions | % {$_.FPM_FunctionName}) {
Write-Output "--These are the dependencies for $FPM_FunctionName"
$query1 = " SELECT referencing_entity_name as [FPM Function Dependencies] FROM sys.dm_sql_referencing_entities ('dbo.$FPM_FunctionName', 'OBJECT');"

SQL Server backup status Report with PowerShell

I got a PowerShell script for reporting SQL backup status on multiple servers, it works fine but it had no function to send mail. I added that part and now I am able to get the mail with the attachment.
The only concern is, I want the report to show "NA" and not a default date where the satabase is in Simple Recovery Model or if backup has not happened. Can someone please advise?
Here is the code, just in case someone needs it unlike my requirement:
$ServerList = Get-Content "Serverlist location"
$OutputFile = "to save the report location"
$titleDate = Get-Date -UFormat "%m-%d-%Y - %A"
$HTML = '<style type="text/css">
#Header{font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;width:100%;border-collapse:collapse;}
#Header td, #Header th {font-size:14px;border:1px solid #98bf21;padding:3px 7px 2px 7px;}
#Header th {font-size:14px;text-align:left;padding-top:5px;padding-bottom:4px;background-color:#A7C942;color:#fff;}
#Header tr.alt td {color:#000;background-color:#EAF2D3;}
</Style>'
$HTML += "<HTML><BODY><Table border=1 cellpadding=0 cellspacing=0 width=100% id=Header>
<TR>
<TH><B>Database Name</B></TH>
<TH><B>RecoveryModel</B></TD>
<TH><B>Last Full Backup Date</B></TH>
<TH><B>Last Differential Backup Date</B></TH>
<TH><B>Last Log Backup Date</B></TH>
</TR>"
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null
foreach ($ServerName in $ServerList)
{
$HTML += "<TR bgColor='#ccff66'><TD colspan=5 align=center><B>$ServerName</B></TD></TR>"
$SQLServer = New-Object ('Microsoft.SqlServer.Management.Smo.Server') $ServerName
foreach ($Database in $SQLServer.Databases)
{
$HTML += "<TR>
<TD>$($Database.Name)</TD>
<TD>$($Database.RecoveryModel)</TD>
<TD>$($Database.LastBackupDate)</TD>
<TD>$($Database.LastDifferentialBackupDate)</TD>
<TD>$($Database.LastLogBackupDate)</TD>
</TR>"
}
}
$HTML += "</Table></BODY></HTML>"
$HTML | Out-File $OutputFile
$emailFrom = "send email address"
$emailTo = "recipient email address"
$subject = "Xyz Report"
$body = "your words "
$smtpServer = "Smptp server"
$filePath = "location of the file you want to attach"
function sendEmail([string]$emailFrom, [string]$emailTo, [string]$subject,[string]$body,[string]$smtpServer,[string]$filePath)
{
$email = New-Object System.Net.Mail.MailMessage
$email.From = $emailFrom
$email.To.Add($emailTo)
$email.Subject = $subject
$email.Body = $body
$emailAttach = New-Object System.Net.Mail.Attachment $filePath
$email.Attachments.Add($emailAttach)
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($email)
}
sendEmail $emailFrom $emailTo $subject $body $smtpServer $filePath
Replace
<TD>$($Database.LastBackupDate)</TD>
with something like
<TD>$(if ($Database.RecoveryModel -eq 'Simple' -or $Database.LastBackupDate -eq '01/01/0001 00:00:00') {'NA'} else {$Database.LastBackupDate})</TD>
Do the same for LastDifferentialBackupDate and LastLogBackupDate.
With that said, I strongly recommend looking into calculated properties, ConvertTo-Html, and Send-MailMessage, which would allow you to greatly simplify your code:
[Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null
$emailFrom = 'sender#example.com'
$emailTo = 'recipient#example.com'
$subject = 'Xyz Report'
$smtpServer = 'mail.example.com'
$style = #'
<style type="text/css">
...
</style>
'#
$msg = Get-Content 'C:\path\to\serverlist.txt' |
ForEach-Object {New-Object 'Microsoft.SqlServer.Management.Smo.Server' $_} |
Select-Object -Expand Databases |
Select-Object Name, RecoveryModel,
#{n='LastBackupDate';e={if ($_.RecoveryModel -eq 'Simple' -or $_.LastBackupDate -eq '01/01/0001 00:00:00') {'NA'} else {$_.LastBackupDate}}},
#{n='LastDifferentialBackupDate';e={if ($_.RecoveryModel -eq 'Simple' -or $_.LastDifferentialBackupDate -eq '01/01/0001 00:00:00') {'NA'} else {$_.LastDifferentialBackupDate}}},
#{n='LastLogBackupDate';e={if ($_.RecoveryModel -eq 'Simple' -or $_.LastLogBackupDate -eq '01/01/0001 00:00:00') {'NA'} else {$_.LastLogBackupDate}}} |
ConvertTo-Html -Head $style | Out-String
Send-MailMessage -From $emailFrom -To $emailTo -Subject $subject -Body $msg -BodyAsHtml -SmtpServer $smtpServer
See also.

update sql table for Active Directory createdon and disabled on information

I have a user table in the database that i am trying to update with Createdon date and disabled on date with the data from Active Directory. So far this is what I have:
$SearchRoot = "OU=NonAIQ,OU=FrontOffice,DC=dev,DC=local"
$serverName = "localhost"
#$SearchRoot = "OU=NonAIQ,OU=FrontOffice,DC=dmz,DC=local"
#$serverName = "spoproddb3.dmz.local"
try {
Import-Module "sqlps" -DisableNameChecking
if ((Get-PSSnapin -Name "Quest.ActiveRoles.ADManagement" -ErrorAction SilentlyContinue) -eq $null ) {
Add-PsSnapin "Quest.ActiveRoles.ADManagement"
}
$externalUsers = Get-QADUser -SizeLimit 0 -SearchRoot $SearchRoot | Select-Object whencreated, whenchanged
$externalUsers | % {
$query = #"
Update tbl_EdgeUsers Set CompanyName = '$_.CreationDate'
Where UserUPN = $_.UserPrincipalName;
"#
Write-Host "The query is $query"
Invoke-SqlCmd -ServerInstance $serverName -Query $query -Database "EdgeDW"
}
} finally {
Remove-Module "sqlps" -ErrorAction SilentlyContinue
Remove-PsSnapin "Quest.ActiveRoles.ADManagement"
}
Now for when created, we just grab all the values.
But since AD does not track the Disabled in date, I am using the when changed date since we dont make changes to an account once it is changed.
The part that I am stuck on is about the logic for when changed date. For this I have to check if an account is disabled. If it is the update the table with that date. If an account is not disabled, then ignore that value and set the value in the sql table as '1/1/9999'.
can you guys please help with this logic?
Thank you in advance for any help.
of top of my head maybe something such as this, although thinking about it now, its a nasty way having the invoke-sql inside the foreach loop if the dataset is large, probably better to output the results of the if statement to csv or somewhere then run the invoke-sql against that.
$users = Get-ADUser -Filter * -Properties whenchanged | Select-Object -Property UserPrincipalName, whenchanged, enabled
$disabledsql = #"
update tbl_EdgeUsers Set date = '$user.whenchanged'
Where UserUPN = '$user.UserPrincipalName';
"#
$activesql = #"
update tbl_EdgeUsers Set date = '1/1/9999
Where UserUPN = '$user.UserPrincipalName';
"#
foreach ($user in $users)
{
if ($user.enabled -eq 'False')
{
Invoke-Sqlcmd -ServerInstance $serverName -Query $disabledsql -Database 'EdgeDW'
}
else
{
Invoke-Sqlcmd -ServerInstance $serverName -Query $activesql -Database 'EdgeDW'
}
}