Adding a datetime to a datatable with the current datetime? - powershell

I'm trying to add a field to a datatable with the current datetime. I want to add it here so that when I use another piece of code to create the table, it creates it as datetime (add-sqltable, for what it's worth).
#create the datatable
$quer = invoke-sqlcmd2 -serverinstance myservername -database "tempdb" -query "select ##servername as servername" -As 'DataTable'
#now add the datetime field
$quer.columns.add("InsDate",[DateTime])
At this point I get stuck. This doesn't work:
$quer | %{$_.InsDate = get-date}
I get this error message:
Exception setting "InsDate": "Unable to cast object of type
'System.Management.Automation.PSObject' to type 'System.IConvertible'.Could
n't store <2/26/2013 11:26:23 AM> in InsDate Column. Expected type is DateTime."
Changing the format doesn't work either. Is there some way to do this? Thanks.

Try this:
$quer | %{[datetime]$_.InsDate = get-date}
or this:
$quer | %{$_.InsDate = [datetime](Get-Date)}
I don't have the ability to test your specific case, but I believe one of them should work.
Edit: Changed closing ')' to '}' in second to fix answer.

Here's a workaround:
$date = get-date
$quer | %{$_.InsDate = [DateTime]$date}
Found here:
DateTime parsing in PowerShell

Hmm might be missing the obvious here, but can't you adjust your SQL query to just pull the datetime at the source?
Something like this:
select
##servername as [servername],
GETDATE() as [DateTime]
That is probably what I would do, rather than fudging it in later! :D

Related

PowerShell 5.1 handling sql server nvarchar datatype

I am loading a DataTable with data from SQL Server as such:
$queryStr = "SELECT TOP 10 ID, QueryText FROM dbo.DatabaseName";
$dataRows = Invoke-DbaQuery -SqlInstance instance.name -Database databasename -Query $queryStr -As DataSet;
In SQL Server the QueryText is nvarchar(max). In PowerShell, this becomes a string datatype, equal to varchar I think. I think this because when I try to calculate the hash in PowerShell with Get-FileHash, and in SQL Server I calculate the hash on the nvarchar column with SELECT (CONVERT([varchar](70),hashbytes('SHA2_256', QueryText),(1))), the hashes do not match.
They DO match however, if I convert the nvarchar to a varchar(max) in SQL Server.
So the question is, in PowerShell how can I convert the string datatype to match the nvarchar datatype in SQL Server? Because as far as I know, PowerShell does not have a nvarchar datatype, just the generic string datatype.
Added this part after reading comments.
In the DataTable that I retrieve from SQL Server as per the above code I add an extra column to hold the hash that I calculate in PowerShell.
Add extra column to DataTable:
$HashColumn = [System.Data.DataColumn]::new('QueryHashString', [string]);
$dataRows.Tables[0].Columns.Add($HashColumn);
Now I do a foreach to fill this column I just added:
foreach($row in $dataRows.Tables[0]) {
$stringAsStream = [System.IO.MemoryStream]::new()
$writer = [System.IO.StreamWriter]::new($stringAsStream)
$writer.write("$($row.QueryText)")
$writer.Flush()
$stringAsStream.Position = 0
$row.QueryHashString = (Get-FileHash -InputStream $stringAsStream | Select-Object -ExpandProperty Hash)
}
Your code uses StreamWriter that uses the default UTF-8 encoding, which matches what you get with hashing a VARCHAR -- if you stick to ASCII characters. To hash Unicode instead (and for variation, let's use SHA256 directly instead of going through Get-FileHash, and throw in an emoji so we have to deal with surrogates):
$s = "Hello, world! I 💖 you"
$sha256 = [System.Security.Cryptography.SHA256]::Create()
[BitConverter]::ToString(
$sha256.ComputeHash([System.Text.Encoding]::Unicode.GetBytes($s))
).Replace("-", "")
This yields the same result as
SELECT CONVERT(CHAR(64), HASHBYTES('SHA2_256', N'Hello, world! I 💖 you'), 2)

Modify a value returned from Invoke-sqlcmd

I've searched for a number of hours now and am unable to figure out how to do this.
I query an MSSQL database that returns 2 columns, one of these values is empty/null but does represent something in the SQL database(I've tested disabling it).
How would I check through what is returned from my query for the empty value and modify this to something else?
$TestQuery = Invoke-Sqlcmd -Database $DB -Query $qcd -ServerInstance "SomeInstance\Instance1" -Verbose
Result:
Activity Setting
-------- -------
All Operation Enabled
Backup Enabled
Restore Enabled
Prune Enabled
Aux Copy Enabled
Schedule Enabled
Archive Check Enabled
Tape Erase Enabled
Offline content Index Enabled
Online Content Index Enabled
Enabled
You can see the last item returned doesn't have a value but does reflect a setting in the application we use, I just want to modify that value to "Value1" for example.
Any help is greatly appreciated, I did try using hashtables but had no idea what I was doing despite several hours of googling.
Edit:
My Query:
SELECT JM.opName AS 'Activity',
CASE action
WHEN 1 THEN 'Disabled'
WHEN 2 THEN 'Enabled'
END AS 'Setting'
FROM JMJobAction AS J
LEFT JOIN JMJobOperationNames JM on JM.opType = J.opType
WHERE clientId = 1
AND appType = 0
AND J.opType != 8
AND appId = 1
You may do the following in PowerShell:
$TestQuery = Invoke-Sqlcmd -Database $DB -Query $qcd -ServerInstance "SomeInstance\Instance1"
$TestQuery |
Where { [string]::IsNullOrEmpty($_.Activity) } | Foreach-Object {
$_.Activity = 'Value1' # Update all empty or nulls with Value1
}
$TestQuery # Contains updated results
Note that this does not update the actual database. You will need a separate query that writes back to the database.
When a database table contains a NULL, it is interpreted as the System.DBNull data type in PowerShell. [System.DBNull]::Value is not the same as $null. So if you only wanted to query for NULL values, then your query could more appropriately be modified to the following:
$TestQuery | Where Activity -is [DBNUll]
I don't know if I understand your question correctly.
I understand that you want to have a default_value when there is no data in a column.
That can be solved in your SQL Query with case. Here an example
[Edit] Based on your added query
SELECT
CASE
WHEN JM.opName is null OR JM.opName = '' THEN "DefaultActivity"
ELSE JM.opName
END AS Activity,
CASE action
WHEN 1 THEN 'Disabled'
WHEN 2 THEN 'Enabled'
END AS 'Setting'
FROM JMJobAction AS J
LEFT JOIN JMJobOperationNames JM on JM.opType = J.opType
WHERE clientId = 1
AND appType = 0
AND J.opType != 8
AND appId = 1

Pass NULL from powershell to sql

I'm trying to pass a NULL from powershell to sql, without having to write NULL in the VALUES. For example below, i've tried so many things and can't get it to work, any ideas? Writing VALUES (NULL,'4') will be too much hassle.
$a = $null
$SqlQuery2 = #"
USE Testtable INSERT INTO dbo.Test2
(name,ID)
VALUES ('$a','4')
"#
$sqlcmd = New-Object System.Data.SqlClient.SqlCommand($SqlQuery2,$global:sqlconn)
$sqlcmd.ExecuteScalar()

powershell - get a keyword from query string

I'm learning PowerShell scripting & want to extract tableName from SQL Query String. For example, I've this query -
$q = "SELECT * FROM [TestDB].[dbo].Invoice_Details where Clientname='ABC'"
where I want to extract table name i.e. it should output this - Invoice_Details
Currently, I'm doing this with following working code -
$q1 = $q -split '\[dbo\]\.'
$q2 = $q1[1] -split ' where '
write-host $q2[0] #here I get it right (Invoice_Details)
But, sometimes the query may/ may not have bracketed names like - [TestDB].[dbo].
So, I want to optimize this code so that it will work even if query containing any combination of bracketed/ bracketless tableNames
Try something like this:
$res = ([regex]'(?is)\b(?:from|into|update)\s+(\[?.+\]?\.)?\[?(\[?\w+)\]?').Matches($q)
write-host $res[0].Groups[2].Value

Using "Select" in SharePoint list query

I have a list with a large number of datapoints. (130 columns, 31000 items). I run certain scripts to data-mine and/or update that info. One trick I use to speed up processing time is to pull the whole list into an array at the beginning. This allows powershell to query the array instead of going back to the list each time.
In these scripts I'm usually only searching a few of the fields, making it inefficient to pull all 130+ columns I'm hoping looking for a way to limit what fields are being pulled in.
In the below script, everything works fine until I add the "Select" part of the query. I then get an error of "Unable to index into an object of type System.Management.Automation.PSObject".
Any pointers are greatly appreciated!
$oList = $Web2.Lists["Forecasting data source"]
$aList = $Web.Lists["ArrayTest"]
filter MyFilter {if ($_["CHGTaskRegion"] -eq "Syracuse") {$_}}
$list = $oList.Items | MyFilter | Select ["CHGTaskFacility"],["CHGTicketNumber"]
$list | ForEach-Object {
$ListItem = $aList.Items.Add()
$ListItem["Title"] = [string]$_["CHGTaskFacility"]
$ListItem["Number"] = [string]$_["CHGTicketNumber"]
$ListItem.Update()
}
EDIT:
This is way after the fact but I saw this old post of mine and figured it was worth coming back to. The proper method isn't actually to pull in the whole list and then search it. The right way is to simply get just the items you wanted in the first place using a CAML query. Like so:
$spqQuery = New-Object Microsoft.SharePoint.SPQuery
$spqQuery.Query =
" <Where>
<Eq>
<FieldRef Name='CHGTaskRegion' />
<Value Type='File'>Syracuse</Value>
</Eq>
</Where>"
$spqQuery.ViewFields = "<FieldRef Name='CHGTaskFacility' /><FieldRef Name='CHGTicketNumber' />"
$spqQuery.ViewFieldsOnly = $true
$splListItems = $splList.GetItems($spqQuery)
Have you tried:
$list = $oList.Items | MyFilter | Select {$["CHGTaskFacility"]}, {$["CHGTicketNumber"]}
Add underscore after dollar signs. For some reason _ is not showing up in the code above.
/Pawel
I think the code should be :
$list = $oList.Items | MyFilter | Select CHGTaskFacility,CHGTicketNumber
The way you wrote it, means that you tried to type cast, anything between [ ] being the type.
And so it got confused.
CHGTaskFacility and CHGTicketNumber are properties of the $list of objects, and so Select CHGTaskFacility,CHGTicketNumber is sufficient for Powershell to select them.
UPDATE:
I think the filter code may be incorrect:
filter MyFilter {if ($_."CHGTaskRegion" -eq "Syracuse") {$_}}