Powershell to SQL database - sql-server

My initial post was how to pass data directly from the pipeline to a (remote) SQL database. Writing to a CSV then a database did not work for the amount of data I am working with - over 2 million files I am querying.
Below is the final script I came up with. It scans a file server, filters in the pipeline, creates a PSObject with the file attributes and then stores the attributes of the Object to variables. Those variables are then passed to the SQL query string. It's a bit cumbersome, but I could not see another way to get the file attributes read directly into the query string.
I also needed a way to run this remotely.

With the help of Invoke-SQLCmd2 you can write and read data from an SQL server database. More info here.
I'm not sure but I think this CmdLet does not accept pipeline input. So your best bet would be to transform your code to a Foreach structure and invoke the Cmdlet Invoke-SQLcmd2 every time you want to do an INSERT or something else.
Something like this:
$CSV = Get-Content -Path "D:\FS01-USER-Files\$name.csv"
Foreach ($Line in $CSV) {
Invoke-Sqlcmd2 #SQLParams -Query "
INSERT INTO $SQLTable
(FileName, Data)
VALUES('$Line.FileName', '$($Line.Data)')"
}
How can this be run with another account that has domain privileges?
You can set up a Scheduled Task that runs as another user with the password stored. This task can then be triggered by other users who have RDP access to the server where the Scheduled Task has been created.

$ErrorActionPreference = "SilentlyContinue"
$cutOffDate = (Get-Date).addYears(-1)
$exclusions = #(".lnk",".url",".ini",".odc",".ctx",".upd",".ica")
$connectionString = "Server=db01;Database=Files;Integrated Security=True;"
$count = 0
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
gci "D:\USERS" -Recurse | ? {
$_.PSIsContainer -eq $False -and
$_.LastAccessTime -le $cutOffDate -and
$exclusions -notcontains $_.Extension -and
$_.length -gt "0" -and
$_.Directory -notmatch ".*USERS\\.*\\Personal\\sysdata\\cookies"
} | % {
$obj = New-Object PSObject
$obj | Add-Member NoteProperty Directory $_.DirectoryName
$obj | Add-Member NoteProperty Name $_.Name
$obj | Add-Member NoteProperty MB ("{0:N3}" -f ($_.Length/1MB))
$obj | Add-Member NoteProperty LastAccessed $_.LastAccessTime
$obj | Add-Member NoteProperty LastMofified $_.LastWriteTime
$obj | Add-Member NoteProperty Created $_.creationtime
$obj | Add-Member NoteProperty Extension $_.Extension
$v1 = $obj.Directory
$v2 = $obj.Name
$v3 = $obj.MB
$v4 = $obj.LastAccessed
$v5 = $obj.LastMofified
$v6 = $obj.Created
$v7 = $obj.Extension
$query = "INSERT INTO dbo.fs01 (directoryPath,fName,fileSize,lastAccessed,lastModified,createdDate,extension) VALUES ('$v1','$v2','$v3','$v4','$v5','$v6','$v7');"
$command = $connection.CreateCommand()
$command.CommandText = $query
$command.ExecuteNonQuery()
}
$connection.close()

Related

Export Multi column Excel spreadsheet from Powershell script

I have been working at this for what seems like way too long now. I am pulling all of the ADgroups names and descriptions in my domain. At this point it doesn't necessarily matter but its eating at me.
$exportList = #()
$ADgroups = Get-ADGroup -Filter * -Properties Description
Foreach ($group in $adgroups){
$GroupObj = New-Object System.Object
$GroupObj | Add-Member -Type NoteProperty -Name Name -Value $group.Name
$GroupObj | Add-Member -Type NoteProperty -Name Description -Value $group.Description
$exportList += $GroupObj
}
$exportList | Out-File C:\test\ADGroups.csv
And the file comes out like this where all of the data is within column A
but I would like for the name to show in column A and the Description to show in column B I have tried making different Arrays and tried calling the properties in different ways but nothing I have tried yet has worked and I am sure that I am missing something very simple.
You're using Out-File Instead of Export-CSV which export a text file instead of a comma separated file
Replace the:
$exportList | Out-File C:\test\ADGroups.csv
To:
$exportList | Export-CSV C:\test\ADGroups.csv
Also, You can cut some lines and simply do:
Get-ADGroup -Filter * -Properties Description |
Select Name,Description | Export-CSV C:\test\ADGroups.csv

How may I export the output of SQL query in Excel fetched through PowerShell?

I am using this power-shell script to fetch the versions of all SQL Servers in a list.
How may I export the result columns (only query output not error messages) into excel and send to email after the script is run?
Can someone help me add the required script please?
Import-Module SQLPS -DisableNameChecking
$ServerInstences = Get-Content "D:\DBA\All_Server_monitoring\ServerList.txt"
$SQLQuery = #"
Select ##Servername 'Server Name' ,##version 'Version'
"#
$DBName = "master"
$ServerInstences |
ForEach-Object {
$ServerObject = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $_
Invoke-Sqlcmd -ServerInstance $_ -Database $DBName -Query $SQLQuery
}
The easiest way to export data to a csv file is by using Export-CSV which takes an input object (or object array) and a path and can fill out the csv file from that object/array. For you, it would look like this:
$results = Invoke-Sqlcmd -ServerInstance $_ -Database $DBName -Query $SQLQuery
New-Item -Path "MYPATH.csv"
Export-CSV -Path "MYPATH.csv" -InputObject $results -Append
CSV files are versatile and can be opened with the most lightweight text editors. They also can be easily emailed and opened with Excel.

Grabbing a list of MemberOf based off a list of users

I'm currently running into a problem where I am failing to get a list of security groups based off a list of users. The trouble is mainly within grabbing their "MemberOf"; since that is an array within itself. Any suggestions would be helpful!
Code below:
$companycount = Get-ADUser -Properties * -Filter{(company -Like "companyname.")}
$users=#()
foreach($user in $companycount)
{
if($user.Enabled)
{
$ScriptObject = New-Object PSOBJECT
Add-Member -InputObject $ScriptObject -MemberType NoteProperty -Name Sam -Value ""
Add-Member -InputObject $ScriptObject -MemberType NoteProperty -Name Description -Value ""
Add-Member -InputObject $ScriptObject -MemberType NoteProperty -Name MemberOf -Value ""
$ScriptObject.Sam = $user.SamAccountName
$ScriptObject.Description =$user.Description
$ScriptObject.MemberOf = $user.MemberOf
$users+=$ScriptObject
}
}
$users|export-csv
You'll have to treat it like an array, much like you're looping through $companycount.
Keep in mind that MemberOf is an array of the distinguisedName attributes of each group. But the name of the group is part of the distinguisedName (the CN portion), so you can just use Substring() to extract that.
You could use something like this:
$ScriptObject.MemberOf = ($u.MemberOf | ForEach { $_.Substring(3, $_.IndexOf(",") - 3) }) -Join ", "
That will give you a comma-delimited list of names of the groups.
Keep in mind that the name of the group (the cn attribute) can be different than the displayName (for distribution lists, it's the displayName that is shown in Outlook), which may or may not be relevant to you. Also, my code there will cause problems if any of your group names have commas in them.

How to load specific packages from a server with Powershell

I have a PowerShell script that I am writing to extract all the jobs of a specific server like
$sqlserver = "Servername"
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Smo') | Out-Null
$srv = New-Object ('Microsoft.SqlServer.Management.Smo.Server') $sqlserver
$jobs = $srv.JobServer.Jobs
ForEach ($job in $jobs)
{
$jobname =$Servernaam.replace("\","_") + '_'+ $job.Name.replace(" ","_").replace("\","_").replace("[","_").replace("]","_").replace(".","_").replace(":","_") + ".sql"
$job.Script() | Out-File C:\Users\Desktop\Jobs_from_Server\Orgineel\$jobname
if ($jobs -like '*.dtsx*')
}
The code I got now gets all the jobs from the server and store them in separate files.
The problem is that I only want to get the jobs of the Micrososft SQL Server that contains .dtsx in the string of #command
I tried for example
ForEach ($job in $jobs)
{
$jobname =$Servernaam.replace("\","_") + '_'+ $job.Name.replace(" ","_").replace("\","_").replace("[","_").replace("]","_").replace(".","_").replace(":","_") + ".sql"
$job.Script() | Out-File C:\Users\Desktop\Jobs_from_Server\Orgineel\$jobname
if ($jobs -like '*.dtsx*')
I also have tried - Contain and set the code in the foreachloop like
ForEach ($job in $jobs |if ($jobs -like '*.dtsx*'))
Your code has a number of typos and other errors in which objects you're using where. Try this as a starter. It assumes that the first step in a job that uses SSIS is an SSIS step. Modify as needed.
The key here is checking the subsystem of the job step(s) to detect if the step is run with the SSIS subsystem.
$sqlserver = "servername"
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Smo') | Out-Null
$srv = New-Object ('Microsoft.SqlServer.Management.Smo.Server') $sqlserver
$jobs = $srv.JobServer.Jobs
ForEach ($job in $jobs)
{
if ($Job.JobSteps[0].Subsystem -eq "ssis") {
# Do SSIS stuff
write-output "Found an SSIS job $($job.name)"
}
}

Join SQL query Results and Get-ChildItem Results

Background: I have a directory with a number of files that are imported to SQL server.
Task: Creating a PowerShell script which will pick up files within this directory and use the filenames as in the SQL query.
Ultimate objective: To display SQL results besides the filenames but the resultset being displayed should also show files having no entries in SQL server. Something like RIGHT JOIN in SQL server queries.
Powershell Code
$files = Get-ChildItem -Recurse -Force $filePath -ErrorAction SilentlyContinue | Where-Object { ($_.PSIsContainer -eq $false) } | Select-Object Name
$Server = "Loadv1"
$DB = "LoadDB"
$dbResults = #()
ForEach ($file in $files)
{
$fileName = $file.name
write-host $fileName
if($fileName.Length -gt 1)
{
$Query = "
SELECT FileName,CurrentStatus
FROM LogStatus
WHERE FileName LIKE '$fileName%'
"
# Write-host $Query
}
$dbResults += Invoke-Sqlcmd -ServerInstance $Server -Database $DB -Query $Query
}
$dispResults = $dbResults,$file
$dispResults | Format-Table -autosize
Work done so far: I have been able to fetch the file names using Get-ChildItem and loop them to get the query results. However, the result I am currently getting does not show the files that don't have corresponding entry in SQL server table
Current Result
OperationalLanding20150622061502.dat
OperationalLandingAudit20150622061502.dat
OperativeThird_Party_System20150616090701.dat
FileName CurrentStatus
OperationalLandingAudit20150622061502.dat SSIS Package Complete
OperativeThird_Party_System20150616090701.dat SSIS Package Complete
Expected Result
OperationalLanding20150622061502.dat
OperationalLandingAudit20150622061502.dat
OperativeThird_Party_System20150616090701.dat
FileName CurrentStatus
OperationalLanding20150622061502.dat NULL
OperationalLandingAudit20150622061502.dat SSIS Package Complete
OperativeThird_Party_System20150616090701.dat SSIS Package Complete
Hoping I was able to explain my requirement above.
OK so if the SQL query does not have results then NULL is returned and, in essence, nothing is added to the $dbResults array. Instead lets append the results to a custom object. I don't know what PowerShell version you have so I needed to do something that I know should work. I also don't use the SQL cmdlets much so I had to guess for some of this.
$files = Get-ChildItem -Recurse -Force $filePath -ErrorAction SilentlyContinue |
Where-Object {$_.PSIsContainer -eq $false -and $_.Length -gt 1} |
Select-Object -ExpandProperty Name
$Server = "Loadv1"
$DB = "LoadDB"
$files | ForEach-Object{
write-host $_
$Query = "
SELECT FileName,CurrentStatus
FROM LogStatus
WHERE FileName LIKE '$_%'
"
$Results = Invoke-Sqlcmd -ServerInstance $Server -Database $DB -Query $Query
$props = #{Name = $_}
If($Results){
$props.CurrentStatus = $Results.CurrentStatus
} Else {
$props.CurrentStatus = "Null"
}
New-Object -TypeName PSCustomObject -Property $props
} | Format-Table -autosize
What this does is create a custom object that contains the results of the sql query (Which I did not change for reasons stated above). If there are no results returned we use the string "null" as a filler.
I cleaned up how you generated the $files variable by making is a simple string array with -Expand and moved the length condition there as well.
You should now have all the expected results. I say should since I am assuming what the return object looks like.
$Query = "
SELECT isNull(A.FileName, b.FileName) FileName,ISNULL(A.CurrentStatus,B.CurrentStatus) CurrentStatus
FROM LogStatus A
Right JOIN (SELECT '$filename' FileName,NULL CurrentStatus) B
ON a.Filename like '$filename%'
"
This should pad out the filenames for you. A little tough to prototype since it's in powershell but I might be able to come up with a sql fiddle to prove it.
EDIT
Answer edited, with sql fiddle:
http://sqlfiddle.com/#!3/12b43/9
Obviously, since you're in a cursor, we can only prove one query at a time.

Resources