Hi i am new to powershell and i have a scenario where i have a script to read all the CREATE TABLES from a sql file. Before these CREATE TABLES statement i have to print a IF EXIST statement which include the table name of the CREATE TABLE statement
Just uses a regex replace, something like this:
$x = Get-Content my_file.sql -raw
$r = #'
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'$1')
DROP TABLE [dbo].[$1]
--GO
CREATE TABLE [dbo].[$1]
'#
$x -replace 'CREATE TABLE \[dbo\]\.\[([^\]]+)\]', $r
If $SqlStatements is a variable holding the content then this works.
$ifExists = #'
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'{0}')
DROP TABLE {1}
--GO
'#
[Regex]::Matches($SqlStatements, '\s*CREATE TABLE (\S+\.\[(\S+)\])') | Sort-Object Index -Descending | ForEach-Object {
$SqlStatements = $SqlStatements.Insert(
$_.Index,
"`r`n" + ($ifExists -f $_.Groups[2].Value, $_.Groups[1].Value) + "`r`n"
)
}
$SqlStatements
Replacements are done from the end tracking backwards. Attempting to go forwards will invalidate the Index value after the first insert.
Related
I have two csv files. Acts.csv contains the values I want to change:
Activities,personId
132137,35030;20001
132138,17776
132139,13780
132140,37209
132141,30067;5124;35030;17776;13780;20001;15545;37209;17190
132142,30067;5124;35030;17776;
132187,17776
132188,5124
132189,30067;5124;35030;17776;13780;20001
I want to change the personId to the corresponding value in the rand column of the file rands.csv below:
rand,personId
24830,30067
4557,5124
30795,35030
19711,17776
15481,13780
42181,20001
17331,15545
32468,37209
39411,17190
So, the output (first four lines anyway) should look like this:
Activities,personId
132137,30795;42181
132138,19711
132139,15481
132140,32468
This answer looks like a good start, but do I need to put some kind of loop in the find string?
[regex]::Replace($appConfigFile, "{{(\w*)}}",{param($match) $dictionaryObject[$($match.Groups[1].Value)]})
Yes, you need a loop for first result and some kind of search to look for replacements.
$acts = convertfrom-csv "Activities,personId
132137,35030;20001
132138,17776
132139,13780
132140,37209
132141,30067;5124;35030;17776;13780;20001;15545;37209;17190
132142,30067;5124;35030;17776;
132187,17776
132188,5124
132189,30067;5124;35030;17776;13780;20001" -Delimiter ','
$rand = convertfrom-csv "rand,personId
24830,30067
4557,5124
30795,35030
19711,17776
15481,13780
42181,20001
17331,15545
32468,37209
39411,17190" -Delimiter ','
$acts | select -PipelineVariable act | foreach {
# split personids in each input object
$act.personid -split ';' | foreach {
$rand | where personid -eq $_ # find object in rand by personid
} | Join-String -Property rand -Separator ';' # join replacements back to a string
} | select #{n='Activities';e={$act.Activities}}, #{n='NewPerson';e={$_}}, #{n='OldPerson';e={$act.PersonId}}
Please note that order of values in new string is not guaranteed, and errors are not raised if there is no matching value.
Is there a way to link a PS variable as a table within the Invoke-Sqlcmd?
I've tried LEFT JOIN $psvar as p on T1.ID=P.ID
I updated the script by making a DataTable from the advice of #Cpt.Whale.
# Define DataTable Columns
$tbl = New-Object system.Data.DataTable 'tbl_New'
$newcol = New-Object system.Data.DataColumn emplID,([string]); $tbl.columns.add($newcol)
$newcol = New-Object system.Data.DataColumn adGrp,([string]); $tbl.columns.add($newcol)
# Add data from Excel
$exelWkbk = '.\table.xlsx'
$excelQuery = '
SELECT F1 as emplID
,F2 as pcType
FROM [Sheet1$]
'
$queryOutput = Invoke-ExcelQuery $exelWkbk $excelQuery | Select-Object -Skip 1
$queryOutput | ForEach-Object {
$row = $tbl.NewRow()
$row.tmplID = ($_.emplID)
$row.adGrp = ($_.pcType)
$tbl.Rows.Add($row)
}
# Query SQL Data source joining Excel data
$sqlQuery = "
USE SQLDATABASE;
DECLARE #today as date = GETDATE();
SELECT emp.USER_ID
,wt.HOST
,a.pcType as DevicModel
FROM workstationTable as wt
JOIN employeeTable as emp on wt.USER_ID = emp.USER_ID
JOIN $tbl as a on emp.USER_ID = a.emplID
WHERE emp.NAME is not NULL
"
Invoke-Sqlcmd -Query $sqlQuery -ServerInstance 'dbName' |
Out-GridView
Powershell doesn't have a built-in function for doing SQL-style joins of different datasets. You can use Select-Object calculated properties for simple lookup-table type things, but I prefer using the Join-Object module built on LINQ:
# Gather both data sources into separate list variables:
$sqlData = Invoke-Sqlcmd -ServerInstance 'dbName' -Query '
USE SQLDATABASE;
DECLARE #today as date = GETDATE();
SELECT emp.USER_ID,wt.HOST
FROM workstationTable as wt
JOIN employeeTable as emp on wt.USER_ID = emp.USER_ID
WHERE emp.NAME is not NULL'
$excelData = Invoke-ExcelQuery $exelWkbk $excelQuery | Select-Object -Skip 1
# join the lists on a specific property
$joined = Join-Object -Type AllInLeft `
-Left $sqlData -LeftJoinProperty USER_ID `
-Right $excelData -RightJoinProperty EmplID
$joined | Out-GridView
Or since you're already using Excel, an SQL data connection in the file may be an option.
I have a CSV File and in Column 1 are words.
I want to modify the words, for example I want to add the String "cat" at the end and write it down in Column 2.
I've posted a Question days ago where #Theo archived this:
$CSV = Import-CSV -Path 'C:\path.csv' -Header Column1
$newCsv = foreach ($row in $CSV) {
# output an Object that gets collected in variable $newCsv
# Select-Object * takes everything already in $row,
# #{Name = 'Column2'; Expression = {$row.Column1 + 'cat'}} adds the extra column to it.
$row | Select-Object *, #{Name = 'Column2'; Expression = {$row.Column1 + '-cat'}}
}
# output on screen:
$newCsv
# output to new CSV file
$newCsv | Export-Csv -Path 'C:\path.csv' -NoTypeInformation
Output (on screen):
Column1 Column2
------- -------
Wild Wildcat
Copy Copycat
Hell Hellcat
Tom Tomcat
Snow Snowcat
As far as good, now I want to create and write down a Password in Column 3.
So I would create a variable with a randomized Password with some of the many PS generators already posted online.
And I also would like to declare Column1 and Column2 as a variable because I need those 3 Column entries further down the road to create a .txt File that include those.
Just if you curious why the hell do I create a .txt File AND a CSV:
Column1 is basicly a Systemname, Column2 Username and Column3 a Password.
I document access data in the CSV and create a Script in the .txt, so I can create the User in the Exchange by Script (for about 1000+ Systems).
I appreciate any hint!
I have a query which looks like this:
FROM TableA
INNER JOIN TableB
ON TableA.xx = TableB.xx
INNER JOIN TableC
ON TableA.yy = TableC.yy
I am trying to write a script which selects the tables which come after the word "JOIN".
The script that I wrote now is:
$data = Get-Content -Path query1.txt
$dataconv = "$data".ToLower() -replace '\s+', ' '
$join = 0
$overigetabellen = ($dataconv) | foreach {
if ($_ -match "join (.*)") {
$join++
$join = $matches[1].Split(" ")[0]
#Write-Host "Table(s) on which is joined:" $join"."
$join
}
}
$overigetabellen
This gives me only the first table, so TableB.
Can anyone help me how I get the second table also as output?
Process your data with Select-String:
$data | Select-String -AllMatches -Pattern '(?<=join\s+)\S+' |
Select-Object -Expand Matches |
Select-Object -Expand Groups |
Select-Object -Expand Value
(?<=...) is a so-called positive lookbehind assertion that is used for matching the pattern without being included in the returned string (meaning the returned matches are just the table names without the JOIN before them).
This is my naive attempt to find the desired table names.
Split the data input on whitespace into an array, find the indices of the word "JOIN", and then access the following indices after the word "JOIN."
$data = Get-Content -Path query1.txt
$indices = #()
$output = #()
$dataarray = $data -split '\s+'
$singleIndex = -1
Do{
$singleIndex = [array]::IndexOf($dataarray,"JOIN",$singleIndex + 1)
If($singleIndex -ge 0){$indices += $singleIndex}
}While($singleIndex -ge 0)
foreach ($index in $indices) {
$output += $dataarray[$index + 1]
}
Outputs:
TableB
TableC
You can adjust for capitalization (saw you set your input to all lowercase), etc as needed if you expect varying input files.
I want to retrieve all users from our HP ALM QC installation and have a Powershell script that does this. The problem is that it pads the output with spaces to, I assume, make it more readable.
This is the script
$ServerInstance = "qc-server "
$Database = "qcsiteadmin_db "
$ConnectionTimeout = 30
$Query = "select USER_NAME, FULL_NAME, EMAIL from [td].USERS"
$QueryTimeout = 120
$conn=new-object System.Data.SqlClient.SQLConnection
$ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerInstance,$Database,$ConnectionTimeout
$conn.ConnectionString=$ConnectionString
$conn.Open()
$cmd=new-object system.Data.SqlClient.SqlCommand($Query,$conn)
$cmd.CommandTimeout=$QueryTimeout
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
[void]$da.fill($ds)
$conn.Close()
$ds.Tables
This script gives me the following output:
USER_NAME FULL_NAME EMAIL
--------- --------- -----
user01 First Last user01#foo.com
user02 First Last user02#foo.com
user03 First Last user03#foo.com
Nicely tabulated data with lots of spaces, which makes import into Excel rather daunting...
I then tried to change my SQL-query into something that would be better suited, i.e., I tried to create a semicolon separated output since that lends itself to import rather splendidly.
$Query = "select USER_NAME + ';' + FULL_NAME + ';' + EMAIL from [td].USERS"
This did almost work, in that I got the following output:
Column1
-------
user01;First Last;user01#foo.com
user02;First Last;user02#foo.com
user03;First Last;user03#foo.com
What doesn't show is that all lines are padded at the end with spaces all the way up to position 119 - that is a lot of spaces...
So, my question at last: how can I get rid of all the spaces? Can I do it in the script above or do I need another script to use on the output of the first?
Try exporting directly to a csv file:
$ds.Tables | Export-Csv file.csv
Tell the database to trim off the extra space (sounds like the fields are char(120) instead of varchar).
$Query = "select rtrim(USER_NAME) as USER_NAME, rtrim(FULL_NAME) as FULL_NAME, rtrim(EMAIL) as FULL_NAME from [td].USERS"
Then to export to CSV cleanly for Excel:
$ds.Tables | export-csv FILENAME -notypeinformation