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

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.

Related

A positional parameter cannot be found that accepts argument "from" when doing db2 query to get all schemas

I am getting an error when trying to run a db2 select query to get all the schemas listed in a db2 database.
Here is the error:
Select-Object : A positional parameter cannot be found that accepts
argument 'from' .At line:5 char:1...
I don't see the issue here since this appears to be the correct format. My code is below:
$conn = New-Object System.Data.OleDb.OleDbConnection("Provider=IBMDADB2;Database=TESTDATABASE;HostName=DB2HOST.db2domain.net;Protocol=TCPIP;Port=50002;Uid=adminID;Pwd=aPassWord;")
$ds = New-Object System.Data.DataSet
$conn.Open();
set-item -path env:DB2CLP -value "**$$**"
Select schemaname from syscat.schemata;
Your Select is a bare-line command in PowerShell. Select is aliased to Select-Object and that's why you get the error. You need to issue your Select to the database.
See examples like:
How To Execute MS Access Query with OLEDB.12
https://technet.microsoft.com/en-us/library/hh855069.aspx
Note that this one incorrectly marks the PowerShell examples as C#.

How to make a PowerShell PSObject from the output of a batch file?

I'm trying to make a PowerShell PSObject out of the output of a batch file.
I am calling the batch file like this, which gives me an object containing the output of the batch file:
function browseGateway {
& $migrationUtilityScript "browse" "-z" "$sourceGateway" "-showIds" "--hideProgress" |
select -Skip 1 |
Tee-Object -Variable gatewayItems |
Out-Null |
Sort-Object
Clear-Host
return $gatewayItems
}
The output looks like this:
folder 27fa3a0eb01caf5f1e31b6aeadd68d35 _Management and internal
folder 2ab9e48a1b83968c3844d93bc0919919 Mediclinic
folder 2c0a788b7f39a0415b423f14c0aa9e9c OAuth
folder a49ab6404138110fbd6c993cc9b87e46 customers
folder b015056834707a42a07bcbfbbeb0a6dd Users
folder b015056834707a42a07bcbfbbeb2ca34 Product Offerings
folder e001cfd0c1c1ffaa18e187b5e72fc718 OTK-3.2.00
policy 20a437bb3db29c1700a4f074773ffa41 DemoLogo
service 2ab9e48a1b83968c3844d93bc08ba780 kevinGMU
service 2ab9e48a1b83968c3844d93bc09596e9 testJJ
service 3afaef13bd772e8e25acfe85c4d101a7 Error
service 88f089fba30183fc4f18b7b7d05f5889 test
I want to put them into PowerShell Objects for further processing:
Column 1: Types
Column 2: IDs
Column 3: Names
I'm pretty sure you need to use New-Object for this, but I'm not entirely sure how to sort the information. Do I need to use a regex for each word and split it up further?
As you are effectively reading in a tab delimited file you don't need to use a RegEx, although you certainly could approach it that way. Once you have your raw input in a $items object you can use the following statements to convert it into an array of PSObject:
$items| ForEach-Object {
$properties = $_ -Split "`t"
New-Object PSObject -Property #{
Type = $properties[0].Trim();
ID = $properties[1].Trim();
Name = $properties[2].Trim();
}
}
Results in:
Name ID Type
---- -- ----
_Management and internal 27fa3a0eb01caf5f1e31b6aeadd68d35 folder
Mediclinic 2ab9e48a1b83968c3844d93bc0919919 folder
OAuth 2c0a788b7f39a0415b423f14c0aa9e9c folder
customers a49ab6404138110fbd6c993cc9b87e46 folder
Users b015056834707a42a07bcbfbbeb0a6dd folder
Product Offerings b015056834707a42a07bcbfbbeb2ca34 folder
OTK-3.2.00 e001cfd0c1c1ffaa18e187b5e72fc718 folder
DemoLogo 20a437bb3db29c1700a4f074773ffa41 policy
kevinGMU 2ab9e48a1b83968c3844d93bc08ba780 service
testJJ 2ab9e48a1b83968c3844d93bc09596e9 service
Error 3afaef13bd772e8e25acfe85c4d101a7 service
test 88f089fba30183fc4f18b7b7d05f5889 service
If you wanted to use a RegEx simply swap out the $_.Split for an equivalent $_ -Match <RegEx> and instead of referencing the $properties array you would be referencing the $matches variable. There is an exceptionally good run down of RegEx in PowerShell on Jouni Heikniemi's Blog.
You can do this quite easily with some -splits - regex is a tad bit overkill for something as simple as this.
$Content = (Invoke-WebRequest "http://pastebin.com/raw/591dk6Gj").Content
$FinalObj = $Content -split "`r`n" | % {
$Delimited = $_ -split "`t"
[PSCustomObject]#{
Col1 = $Delimited[0]
Col2 = $Delimited[1]
Col3 = $Delimited[2]
}
}
return $FinalObj
You end up with $FinalObj containing this:
Col1 Col2 Col3
---- ---- ----
folder 27fa3a0eb01caf5f1e31b6aeadd68d35 _Management and internal
folder 2ab9e48a1b83968c3844d93bc0919919 Mediclinic
folder 2c0a788b7f39a0415b423f14c0aa9e9c OAuth
folder a49ab6404138110fbd6c993cc9b87e46 customers
folder b015056834707a42a07bcbfbbeb0a6dd Users
folder b015056834707a42a07bcbfbbeb2ca34 Product Offerings
folder e001cfd0c1c1ffaa18e187b5e72fc718 OTK-3.2.00
policy 20a437bb3db29c1700a4f074773ffa41 DemoLogo
service 2ab9e48a1b83968c3844d93bc08ba780 kevinGMU
service 2ab9e48a1b83968c3844d93bc09596e9 testJJ
service 3afaef13bd772e8e25acfe85c4d101a7 Error
service 88f089fba30183fc4f18b7b7d05f5889 test

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 logging results to DB

How can I save the results from a Powershell command to a MS SQL DB?
For example:
I run this at a Powershell prompt: get-psdrive and it returns some results in a column view.
How can I take each element of the result and log it into a separate DB row/column?
I recommend saving the results of your command to a variable. Such as:
$drives = Get-PSDrive
The variable can be indexed like this:
First Element:
$drives[0]
Last Element:
$drives[-1]
You can iterate through each element with foreach:
foreach ($drive in $drives) {
# current drive is $drive
}
Or the ForEach-Object cmdlet:
$drives | ForEach-Object {
# current drive is $_
}
Now that you have the data to populate your table with you are ready to connect to the database and perform the database record inserts.
You can make use of the Powershell SQL server cmdlets or you can connect using .NET objects. Depending on what version of SQL server you have will drive your choice on which to use. SQL Server 2008 has Powershell cmdlets, 2005 does not. There is a wealth of information about the SQL server 2008 Powershell integration here. For SQL Server 2005 you have some different options. This question answer here provides a list of Powershell options to use with SQL Server 2005.
More Info:
When Powershell displays object information it uses a type system to selectively determine what properties of the object to display on the screen. Not all of the object's are displayed. Powershell uses XML files to determine what properties to display which are stored in the Powershell directory:
dir $PSHOME/*format* | select Name
The objects returned from Get-PsDrive are of type System.Management.Automation.PSDriveInfo. The file PowerShellCore.format.ps1xml tells the formatting engine what properties to display in the Powershell window. It just might be that these are the exact properties you are looking for however many objects have additional properties that are not displayed. For example an object of type System.IO.DirectoryInfo will not have all it's properties displayed by default. You can view the rest of the objects properties using the Get-Member cmdlet, for example:
Get-Item $env:windir | Get-Member
This will show all of the object's methods and properties. You can also view all of the object's properties using the Select-Object cmdlet using a wildcard for the property parameter:
Get-Item $env:windir | Select-Object -Property *
To access an objects properties values use the following syntax:
$objectVariable.ObjectProperty
Now that you know how to view an objects properties and access their values you'll need to use this to construct an Insert SQL statement. Here is an example using the Invoke-SqlCmd cmdlet provided with SQL Server 2008.
Invoke-Sqlcmd -ServerInstance $env:COMPUTERNAME -Database Test -Query "Insert MyTable values ('a', 'b')"
Here's an example looping through objects returned from Get-PsDrive assuming you have a table called MyTable and it has at least two columns which accept textual data:
Get-PsDrive | ForEach-Object {
$providerName = $_.Name
$providerRoot = $_.Root
Invoke-Sqlcmd -ServerInstance $env:COMPUTERNAME -Database Test -Query "Insert MyTable values ('$providerName', '$providerRoot')"
}

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