How to use result output columns as objects in MSSQL - sql-server

What I'm trying to achieve is finding out how long retention a database backup has by using DATEDIFF function.
But in order to use DATEDIFF I would need something to compare, the data from the result, because I don't know it being anywhere else.
Why from a result ?
I found out that this command gives me all the info I need to accomplish my task (BackupFinishDate, ExpirationDate):
RESTORE HEADERONLY FROM DISK = 'X:\Backups\Backuptest.bak'
I'm pretty sure I'm not allowed to create temp tables in production servers, so if this is one option, I'm afraid I can't use that.
PS! If there's a better way to find out retentiondays of a backup, I'd happily use that. If this would be possible in PowerShell, that would be even better.

Well, it seemed I answered my own question with the PowerShell hint.. I gave myself :P
Solution was:
$bkp_start = Invoke-Sqlcmd -ServerInstance myServer -Query "RESTORE HEADERONLY FROM DISK = 'X:\Backups\Backuptest.bak'" | Select-Object -ExpandProperty BackupFinishDate
$bkp_end = Invoke-Sqlcmd -ServerInstance myServer -Query "RESTORE HEADERONLY FROM DISK = 'X:\Backups\Backuptest.bak'" | Select-Object -ExpandProperty ExpirationDate
$RetentionInDays = New-TimeSpan -Start $bkp_start -End $bkp_end | Select-Object -ExpandProperty Days
Write-Output "Retention period : $RetentionInDays"
I love PowerShell.. looks a bit clunky, but it works and I don't know a better way at this time.

Related

Powershell - Export SQL to XML to file - no clean output

I am trying to export a sql query to an xml file with Powershell using the below script:
$SQLResult = Invoke-Sqlcmd -MaxCharLength ([int]::MaxValue) -AbortOnError -EncryptConnection -ConnectionTimeout $TIMEOUT -Database $Database -ServerInstance $SQL_SERVER_FULLNAME_SOURCE -Username $SQL_ACCOUNT_NAME_SOURCE -Password $SQL_ACCOUNT_PASSWORD_SOURCE -Query $QUERY
$PropertyName = ($SQLResult | Get-Member -MemberType Property | Where {$_.Name -like "XML*"}).Name
$SQLResult.$PropertyName | Out-File -FilePath $OutputFile -Force
It should generate a file like below:
<vendors>
<vendor>
<administration>YIT</administration>
<FISCALCODE>804658055B01</FISCALCODE>
<accountNumber>10001</accountNumber>
<Offset_LedgerAccount></Offset_LedgerAccount>
<name>Comp Europe B.V.</name>
<shortName>Comp Europe B.V.</shortName>
<TAXEXEMPTNUMBER>NL801238055B01</TAXEXEMPTNUMBER>
<DefaultDescription></DefaultDescription>
<invoiceType>Non-PO CEE-FN-ACQ</invoiceType>
<IBAN>NL57MHCB0212303590</IBAN>
<CUSTOMERACCOUNT></CUSTOMERACCOUNT>
<TAXITEMGROUP></TAXITEMGROUP>
<IncludeOrderReference>Unknown</IncludeOrderReference>
<lineText></lineText>
<lines>Unknown</lines>
</vendor>
<vendor>
<administration>YIT</administration>
<FISCALCODE>03840123961</FISCALCODE>
<accountNumber>20001</accountNumber>
<Offset_LedgerAccount></Offset_LedgerAccount>
<name>4ABCD - For Marketing s.r.l.</name>
<shortName>4ABCD-FOR MARKETING</shortName>
<TAXEXEMPTNUMBER>03840123961</TAXEXEMPTNUMBER>
<DefaultDescription></DefaultDescription>
<invoiceType>Purchase invoice</invoiceType>
<IBAN>IT93M0306912330615256048252</IBAN>
<CUSTOMERACCOUNT></CUSTOMERACCOUNT>
<TAXITEMGROUP></TAXITEMGROUP>
<IncludeOrderReference>Unknown</IncludeOrderReference>
<lineText></lineText>
<lines>Unknown</lines>
</vendor>
<vendors>
In real it can contain a few thousand records.
The problem with the various other options that I used is that the output file is either truncated, or it contains double quotes. With the above script suddenly extra spaces are added that are repeated every certain block of output. If I run the query in MSMS it generates a perfectly clean result that I can save as .xml file.
<vendor>
<administration>YIT</administration>
<FISCALCODE>0381230961</FISCALCODE>
<accountNumber>20001</accountNumber>
<Offset_LedgerAccount/>
<name>4ABCD - For Marketing s.r.l.</name>
<shortName>4ABCD-FOR MARKETING</shortName>
<TAXEXEMPTNUMBER>03840123961</TAXEXEMPTNUMBER>
<DefaultDescription/>
<invoiceType>Purchase invoice</invoiceType>
<IBAN>IT93M03069121238252</IBAN>
<CUST OMERACCOUNT>< CUSTOMERACCOUNT><TAXITEMGROUP>< TAXITEMGROUP><IncludeOrderReference>Unknown< IncludeOrderReference><lineText>< lineText>
As you can see above it starts okay but then suddenly it starts adding a single space to certain nodes, not to all. Then it continues okay for some records and then a gain a line with a single space in some of the nodes.
I tried various solutions but none of them seem to work for me. Can somebody explain what I am doing wrong? The actual query I use is below.
SELECT
v.[DATAAREAID] AS [administration]
,v.[FISCALCODE]
,v.[VENDORACCOUNTNUMBER] AS [accountNumber]
,v.[DEFAULTOFFSETLEDGERACCOUNTDISPLAYVALUE] AS [Offset_LedgerAccount]
,v.[VENDORORGANIZATIONNAME] AS [name]
,v.[VENDORSEARCHNAME] AS [shortName]
,CASE WHEN LEFT(v.[TAXEXEMPTNUMBER],2)='IT' THEN RIGHT(v.[TAXEXEMPTNUMBER],LEN(v.[TAXEXEMPTNUMBER])-2) ELSE v.[TAXEXEMPTNUMBER] END AS [TAXEXEMPTNUMBER]
,ISNULL(v.[NOTES],'') AS [DefaultDescription]
,ISNULL(ipvp.[INVOICETYPENAME],'') AS [invoiceType]
,ISNULL(vba.[IBAN],'') AS [IBAN]
,ISNULL(c.[CUSTOMERACCOUNT],'') AS [CUSTOMERACCOUNT]
,ISNULL(itc.[TAXITEMGROUP],'') AS [TAXITEMGROUP]
,'Unknown' AS [IncludeOrderReference]
,v.[DESTINATIONCODE] AS [lineText]
,'Unknown' AS [lines]
FROM [dbo].[RetailVendVendorV3Staging] v
LEFT OUTER JOIN [dbo].[AXTip_ParametersVendTableStaging] ipvp ON v.[VENDORACCOUNTNUMBER]=ipvp.[VENDORACCOUNT] AND v.[DATAAREAID]=ipvp.[DATAAREAID]
LEFT OUTER JOIN [dbo].[VendVendorBankAccountStaging] vba ON vba.[DATAAREAID]=v.[DATAAREAID] AND vba.[VENDORACCOUNTNUMBER]=v.[VENDORACCOUNTNUMBER] AND vba.[VENDORBANKACCOUNTID]=v.[BANKACCOUNTID]
LEFT OUTER JOIN [dbo].[CustCustomerV3Staging] c ON c.[VENDORACCOUNT]=v.[VENDORACCOUNTNUMBER] AND v.[DATAAREAID]=c.[DATAAREAID]
LEFT OUTER JOIN [dbo].[AXTip_ImportTaxcodeStaging] itc ON itc.[ACCOUNTRELATION]=v.[VENDORACCOUNTNUMBER] AND itc.[DATAAREAID]=v.[DATAAREAID] AND itc.[EXTERNALTAXCODE]='I'
WHERE v.[DATAAREAID] ='YIT' AND v.[FISCALCODE]!=''
FOR XML PATH('vendor'), root('vendors')
I read quite a lot of issues using the method that I used in the opening post. The method described in the link below seems a more "powershell" way to generate an xml file using sql-data. I copied this method and it works well.
stuartsplace.com: powershell-and-sql-server-exporting-data-xml

Capturing logs for .sql statements though powershell

I'm trying to figure out a good way to run insert/select/update statements into a MSSQL database through PowerShell scripting and log it thoroughly. I have managed to use Invoke-Sqlcmd which does the inserts and select statements pretty fine. But my concern is to capture the logs some where as an output file. That is when doing inserts the log should capture the no. of rows affected/inserted with the data that was inserted.
Invoke-Sqlcmd used:
PS C:\Users\moshink\Desktop\Powershell SQL> Invoke-Sqlcmd -Server $server -Database $db -Username $user -Password $pass -InputFile ".\test.sql" | Out-File -FilePath ".\test_$datetime.rpt" >> $LogFile
test.sql file query below:
use TCS_MIS
select * from tblMasterAccountType where acctType in ('0121') and intCat in ('0020')
--insert into tblMasterAccountType values ('DEP','0121','0020','PARENTHOOD ASSISTANCE ACCOUNT')
the test.sql file is called in the Invoke-Sqlcmd.
This file can be dynamic with any query going in there.
The Out-File ".\test_$datetime.rpt" does capture the select statement outputs if the data exits matching the criteria, but it will be blank if no data.
Is there something that can be ran to capture instantly when running a Insert .sql file/script? i.e. which will say 20 rows inserted and listing out the data inserted.
Basically what I'm after is a thorough logging when running any .sql scripts through PowerShell. It should capture no of rows affected with the data inserted/updated/deleted and the user who performed it.

How to load Powershell output into a SQL Table using SSIS?

I'm trying to get all users that had been disabled in my domain and put it into a SQL Table. I'm trying to use SSIS to do that. Now that I can grab the right output and put it into a CSV file using this code:
Search-ADAccount -AccountDisabled -UsersOnly |
Select Name |
Export-CSV -Path C:\Users\hou\Downloads\Test.csv
But since I'm going to run the package in different servers and I couldn't have a fixed location to store the file and load into SQL Table. So either I'm going to use a variable in the Execute Process Task (where I run the Powershell script) to store the CSV file, or use SSIS to store the output directly in SQL table.
But I don't know neither of those. How can I do that?
Location should be define in the script, i.e:
$Path = Get-Location
"$Path\Test.csv"
#Option 1 just a Name
$Path = Get-Location ; Get-ChildItem C:\temp | Select-Object Name | Export-CSV -Path "$Path\Test.csv"
## Option 2 Name, with other property
$Path = Get-Location ; Get-ChildItem C:\temp | Select-Object Name,mode | Export-CSV -Path "$Path\Test.csv"
For one liner script , use the ";" to separate the commands.
I would suggest loading the data into SQL using PowerShell. There is a free PowerShell module from Microsoft called "sqlserver" that allows PowerShell to talk directly to SQL. You may already have it installed.
## Check if installed:
Get-InstalledModule -Name SqlServer
## If installed you can Update (you may need to run as local admin):
Update-Module -Name SqlServer
## If not installed (only need admin if you want all users to have access to this module):
Install-Module SqlServer
Once the module is installed there is a cmdlet called "Write-SqlTableData" to bulk copy data into SQL. The assumption is (1) the table already exists in SQL. (2) All the columns in the PowerShell Select match the order and datatype as they exist in the SQL table. In this case, there would be a SQL table with a single [Name] column. (3) You are using your AD credentials to access SQL, if not you will have to add credentials to the cmdlet.
The actual PowerShell code, update the variables in the quotes:
## Input Variables
$SqlServerName = ""
$SqlDatabaseName = ""
$SqlTableSchemaName = ""
$SqlTableName = ""
## Insert into SQL
Search-ADAccount -AccountDisabled -UsersOnly | Select-Object Name | Write-SqlTableData -ServerInstance $SqlServerName -DatabaseName $SqlDatabaseName -SchemaName $SqlTableSchemaName -TableName $SqlTableName -Force
As a side note, if you plan on doing a lot of PowerShell/SQL work, you may want to also install the "WFTools" module as it also has many additional SQL cmdlets.
Hope this helps.

Powershell Invoke-Sqlcmd - return multiple datasets

I'm looking for suggestions on either returning multiple datasets, or keeping the session open, with Invoke-SqlCmd?
I have a series of SQL queries that use temporary tables to generate a few related views of the data that I am sending on (via Excel) to a manager. As we work on what is required from the datasets, I am getting a little tired of cutting and pasting samples into Excel.
I thought to use Powershell to simply send the results to HTML files as output for the manager, however I ran into a couple of problems
If I put the final extracts into one SQL file, Powershell appends all of the data into a single result set (sort of a union of the tables)
If I attempt to build the temporary tables and then extract each query individually, each Invoke-Sqlcmd is a seperate session, meaning my Temporary tables get dropped.
I'm looking for suggestions on either returning multiple datasets, or keeping the session open?
Invoke-Sqlcmd -InputFile .\GenerateTimecard.sql -Variable $params | Out-Null;
#{
'Summary' = 'select * from #WeeklyTimeSummary;'
'ByDay' = 'select * from #WeeklyTimeDaily order by postdate desc;'
'ByTask' = 'select * from #WeeklyTimeEvents order by HoursSpent desc;'
'Detail' = 'select * from #WeeklyTimeDetail order by postdate desc;'
}.GetEnumerator() | ForEach-Object {
Write-Output $_.Name;
$fname = $_.Name + '.html';
Invoke-Sqlcmd -Query $_.Value | ConvertTo-Html | Out-File -Encoding ascii $fname;
};
The Description section from Get-Help Invoke-Sqlcmd says it supports GO commands so you could try running everything at once. Personally I'd use the -InputFile parameter and pipe the results to Out-File.
You can specify the ApplicationName parameter for Invoke-SqlCmd, which results in a different SQL connection.
Omitting ApplicationName will result in the temp tables getting removed the second time you call Invoke-SqlCmd.
Something like:
Invoke-SqlCmd -ApplicationName CreateTable -Query 'CREATE TABLE ##FooTable (FooKey INT)
Invoke-SqlCmd -ApplicationName SelectTable -Query 'SELECT * FROM ##FooTable'

PowerShell script to list items in collection

I'm new to PowerShell and am trying to query against my SQL server. I get the idea of creating a new-psdrive and then navigating to databases etc and have a line of code as
$dbs = (get-childitem
sqlserver:\sql\SERVER\INSTANCE\databases)
when I pipe the $dbs to a foreach, how would I get results of a collection of the database object? I am trying to read the extendedproperties of my test database.
This single query gives the results I want repeated for each database.
set-location
DRIVENAME:\databases\beagle_test\extendedproperties
get-childitem | select displayname,
value
any help very much appreciated.
I dont have SQL server handy to try this. Let me know the result
Set-Location DRIVENAME:\Databases
Get-ChildItem | % { Get-ChildItem $("$_.Name\extendedproperties") | Select DisplayName, Value }
Try this
Set-Location DRIVENAME:\Databases
Get-ChildItem | foreach-object { if (Test-Path $("$.Name\extendedproperties")) { Get-ChildItem $("$.Name\extendedproperties") | Select DisplayName, Value } }
The second line here is a single statement. What I am doing is to check if Extendedproperties exist and then get child item.
How about:
dir sqlserver:\sql\ServerName\InstanceName\Databases\*\ExtendedProperties\* |
select #{Name="Database";Expression={$_.Parent.Name}}, Name, Value
How about just:
dir SQLSERVER:\SQL\Server\Instance\databases\*\extendedproperties\* | % {select $_.displayname, $_.value}
so, many years later I am looking into my SO stats and see this old question and figure that my powershell skills have grown a little since 2010.
The use-case has long gone but I think what I was trying to achieve is this:
foreach ($db in $SMOServer.databases | Where-Object status -eq 'normal') {
$db.ExtendedProperties | Select-Object #{name = "DBName"; expression = {$db.Name}}, name, value
}
which gives results like this:
DBName Name Value
------ ---- -----
AdventureWorks2014 MS_Description AdventureWorks 2014 Sample OLTP Database
AdventureWorks2016 MS_Description AdventureWorks 2016 Sample OLTP Database

Resources