How to add data from SQL server to hashtable using PowerShell? - sql

Basically, I want the data to show up in an excel file like it shows in the SQL database.
This is much more simplified version of the work that I need to do but in essence this what it is.
I retrieve the data from SQL and for each item retrieved(which is the primary key) I want the data corresponding to it to be added in the hashtable. I then export this hashtable as a CSV
The CSV file is generated but with some weird data
I am not sure what exactly is wrong because when I Write-host $hashObject I can see the data is in there.
Code
$server = "DESKTOP\SQLEXPRESS"
$database = "AdventureWorks2019"
$hashTable = #{}
$hashObject = #([PSCustomObject]$hashTable)
$query = "SELECT[DepartmentID] FROM [AdventureWorks2019].[HumanResources].[Department]"
$invokeSql = Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $query
$departmentResult = $invokeSql.DepartmentID
ForEach($department in $departmentResult){
$queryAll = "SELECT [Name],[GroupName],[ModifiedDate]FROM [AdventureWorks2019].[HumanResources].[Department] Where DepartmentID=$department"
$invokeSql = Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $queryAll
$name = $invokeSql.Name
$groupName = $invokeSql.GroupName
$modifiedDate = $invokeSql.ModifiedDate
$hashObject+=("Department",$department, "Name",$name,"GroupName",$groupName,"ModifiedDate",$modifiedDate)
}
ConvertTo-Csv $hashObject| Export-Csv -Path "C:\Users\Desktop\PowerShell\HashTable_OutputFiles\HashOutput.csv"

This is a simplified version of what you're attempting to do, in this case you should be able to use the SQL IN Operator in your second query instead of querying your Database on each loop iteration.
As aside, is unclear what you wanted to do when declaring a hash table to then convert it to a PSCustomObject instance and then wrap it in an array:
$hashTable = #{}
$hashObject = #([PSCustomObject] $hashTable)
It's also worth noting that ConvertTo-Csv and Import-Csv are coded in such a way that they are intended to receive objects from the pipeline. This answer might help clarifying the Why. It's also unclear why are you attempting to first convert the objects to Csv and then exporting them when Import-Csv can (and in this case, must) receive the objects, convert them to a Csv string and then export them to a file.
$server = "DESKTOP\SQLEXPRESS"
$database = "AdventureWorks2019"
$query = "SELECT [DepartmentID] FROM [AdventureWorks2019].[HumanResources].[Department]"
$invokeSql = Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $query
$department = "'{0}'" -f ($invokeSql.DepartmentID -join "','")
$query = #"
SELECT [Name],
[GroupName],
[ModifiedDate]
FROM [AdventureWorks2019].[HumanResources].[Department]
WHERE DepartmentID IN ($department);
"#
Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $query |
Export-Csv -Path "C:\Users\Desktop\PowerShell\HashTable_OutputFiles\HashOutput.csv"
If you want to query the database per ID from the first query, you could do it this way (note this is similar to what you where looking to accomplish, merge the ID with the second results from the second query):
$invokeSql = Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $query
$query = #"
SELECT [Name],
[GroupName],
[ModifiedDate]
FROM [AdventureWorks2019].[HumanResources].[Department]
WHERE DepartmentID = '{0}';
"#
& {
foreach($id in $invokeSql.DepartmentID) {
$queryID = $query -f $id
Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $queryID |
Select-Object #{ N='DepartmentID'; E={ $id }}, *
}
} | Export-Csv -Path "C:\Users\Desktop\PowerShell\HashTable_OutputFiles\HashOutput.csv"

Related

how to filter out items from FileInfo?

How do we filter out items from $filesSorted?
I am getting a list of files:
$files = Get-ChildItem -Path $SqlFilesDirectory -File -Filter *.sql
$filesSorted = $files |Sort-Object -Property Name
$filesSorted
20211026_111111.sql
20211026_222222.sql
20211026_333333.sql
I'm also getting back query results:
$filesAlreadyApplied = Invoke-Sqlcmd -ServerInstance $ServerInstance -Database $DBName -Username $SvcAdminAccount -Password $SvcAdminPassword -Query "SELECT PatchFileName FROM [dbo].[PatchLog]"
$filesAlreadyApplied
PatchFileName : 20211026_111111
PatchFileName : 20211026_222222
How do we remove items from $filesSorted that exist in $filesAlreadyApplied?

Powershell, invoke-sqlcmd, export-csv fails to show data if there is more than one result

I have the below code to get data from a SQL DB and export it into a CSV file:
#Server and Database names
$SQLServer = "Servername"
$DB = "DatabaseName"
#SQL Command
$FullScriptSQL="Select * from MyTable WHERE Column = 'TestData'"
#Invoke the command, rename the column headers and export to CSV file
$FullScriptCallLinked = Invoke-Sqlcmd -ServerInstance $SQLServer -Database $DB -Query $FullScriptSQL | select-object #{ expression={$_.Column1};label='Column1 Name'},#{ expression={$_.Column2};label='Column2 Name'},#{ expression={$_.Column3}; label='Column3 Name' },#{ expression={$_.Column4} ; label='Column4 Name' }
Export-CSV -Path ".\ResultFile\FullScript.csv" -inputobject $FullScriptCallLinked -Append -NoTypeInformation
This works perfectly if there is one result. But if there is more than one result, it will show the below in the csv file
I am at my wits end as to why it is doing this. It's obviously the DB parameter data or something to that effect. Been googling for a few days with no luck. Anyone smarter than I able to assist please?
Instead of using Select-Object to rename your columns, which is quite inefficient, you could give the alias to your columns on the query itself:
$SQLServer = "Servername"
$DB = "DatabaseName"
$query = #'
SELECT Column1 AS "Column1 Name",
Column2 AS "Column2 Name",
Column3 AS "Column3 Name",
Column4 AS "Column4 Name"
FROM MyTable
WHERE ColumnX = 'TestData'
'#
Invoke-Sqlcmd -ServerInstance $SQLServer -Database $DB -Query $query |
Export-CSV -Path ".\ResultFile\FullScript.csv" -NoTypeInformation
Also, as in my comment, the code you have on your question is fine and should work, the only problem was using -InputObject instead of piping the results to Export-Csv:
$FullScriptCallLinked | Export-Csv -Path ".\ResultFile\FullScript.csv" -NoTypeInformation
Figured it out. I knew I was close!
#Server and Database names
$SQLServer = "Servername"
$DB = "DatabaseName"
#SQL Command
$FullScriptSQL="Select * from MyTable WHERE Column = 'TestData'"
#Invoke the command, rename the column headers and export to CSV file
$FullScriptCallLinked = Invoke-Sqlcmd -ServerInstance $SQLServer -Database $DB -Query $FullScriptSQL
foreach($i in $FullScriptCallLinked){
select-object #{ expression={$_.Column1};label='Column1 Name'},#{ expression={$_.Column2};label='Column2 Name'},#{ expression={$_.Column3}; label='Column3 Name' },#{ expression={$_.Column4} ; label='Column4 Name' }
Export-CSV -Path ".\ResultFile\FullScript.csv" -inputobject $i -Append -NoTypeInformation
}

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');"

Get count of rows in a partition of an azure table using Azure PowerShell

I would like to get count of rows in a partition. I have the code for getting the total count of rows. How can I alter it to get count for a particular partition. Also I am getting warning for fetching count of all rows and not getting the count on powershell window. Is there any documentation on this?
function GetTable($connectionString, $tableName)
{
$context = New-AzureStorageContext -ConnectionString $connectionString
$azureStorageTable = Get-AzureStorageTable $tableName -Context $context
$azureStorageTable
}
function GetTableCount($table)
{
#Create a table query.
$query = New-Object Microsoft.WindowsAzure.Storage.Table.TableQuery
#Define columns to select.
$list = New-Object System.Collections.Generic.List[string]
$list.Add("PartitionKey")
#Set query details.
$query.SelectColumns = $list
#Execute the query.
$entities = $table.CloudTable.ExecuteQuery($query)
($entities | measure).Count
}
$connectionString = "xyz"
$table = GetTable $connectionString SystemAudit
GetTableCount $table
How can I alter it to get count for a particular partition
There is a function Get-AzureStorageTableRowByPartitionKey you could use, and the following is the sample code
function GetTable($connectionString, $tableName)
{
$context = New-AzureStorageContext -ConnectionString $connectionString
$azureStorageTable = Get-AzureStorageTable $tableName -Context $context
$azureStorageTable
}
function GetTableCount($table)
{
$list = Get-AzureStorageTableRowByPartitionKey -table $table –partitionKey “storage” | measure
$list.Count
}
Import-Module AzureRmStorageTable
$connectionString = xyz"
$table = GetTable $connectionString <yourTableName>
GetTableCount $table
You can know more information on this blog

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'
}
}