Return SQL Query as Array in Powershell
I have a SQL 2008 Ent server with the databases "DBOne", "DBTwo", "DBThree" on the server DEVSQLSRV.
Here is my Powershell script:
$DBNameList = (Invoke-SQLCmd -query "select Name from sysdatabases" -Server DEVSQLSRV)
This produces my desired list of database names as:
Name
-----
DBOne
DBTwo
DBThree
I has been my assumption that anything that is returned as a list is an Array in Powershell. However, when I then try this in Powershell:
$DBNameList -contains 'DBTwo'
It comes back has "False" instead of "True" which is leadi开发者_开发问答ng me to believe that my list is not an actual array.
Any idea what I'm missing here?
Thanks so much!
Emo
I'd do this:
$DBNameList = @(Invoke-SQLCmd -query "select Name from sysdatabases" -Server DEVSQLSRV) | select-object -expand Name
That will give you an array of names.The option -contains
should work fine.
What's missing from the original post is some type of conversion, from an object to an array.
Powershell outputs the result of $DBNameList because it kinda interprets the object. But if you need to manipulate this object and identify a specific item from it, this is the method I use:
$Itm = "DBTwo"
$DBNameList = @(Invoke-SQLCmd -query "select Name from sysdatabases" -Server DEVSQLSRV)
$NameList = @($DBNameList | select-object -ExpandProperty Name)
$Name = ($NameList.Split()).Contains($Itm)
Write-Output $Name
True
I have been looking for this myself for a while and finally worked it out, so I hope it helps someone else!
The Name header suggests it's a single object with a Name property which is an array.
I reckon initialize an empty PS array :
$DBNameList = (Invoke-SQLCmd -query "select Name from sysdatabases" -Server DEVSQLSRV)
[Array]$DbNames = @()
$DBNameList.Name | ForEach-Object {$DbNames += $_}
$DbNames -contains "DBTwo"
Any luck?
Your code...
$DBNameList = (Invoke-SQLCmd -query "select Name from sysdatabases" -Server DEVSQLSRV)
...gives you Datarows back..
You can check this with
$DBNameList | Get-Member
You can also see that there is a property wit the name "Name".
If you want to check if one of the datarows in your $DBNameList contains the Name of 'DBTwo' you would need to write it the following:
$DBNameList.Name -contains 'DBTwo'
In case anybody else ended up here because they were terrified they were going to have to hand-type the name of every property in the DataRow object response in order to get several columns into an array, have no fear, there is a handy property called "ItemArray" that provides what you need.
(Invoke-SQLCmd -query "select Name from sysdatabases").ItemArray -contains 'DBTwo'
True
There are plenty of great answers here that solve this particular OP's quandry, but when the column list get's long, this makes things a lot simpler.
(Invoke-SQLCmd -query "select DBID,Name,Version from sysdatabases")[0].ItemArray -join ','
1,master,852
Reading all these complicated answers and I realized there is a simple one:
$DBNameList.Name -contains 'DBTwo'
This should return true. Your initial pull of the data (the database names) returns an array of objects. Each object has many properties. But in your logic test, you are trying to compare the entire object to a single string. You need to compare a single property of the object (.Name) to the string.
Still very new to Powershell (less than two weeks): I suggest that you try this, if your query contains multiple columns and rows... Multi-Dimensional Arrays. This was my first attempt at this, and after checking the web, given that I could not find a simple straight forward solution, I ended up writing my own solution. Here's the full set of sample code for you to experiment with and use.
Full set of sample code below....
#############################################################################################
# RDSago
# RDSago@gmail.com
# 09/20/2014
#############################################################################################
#
# Capturing database size information from a collection of servers
# and returning that back to an array that can be used to populate
# a SQL table that can be used for monitoring database growth remotely.
# RDSago, RDSago@gmail.com
#
# Note, SQL data retrieved in this manner, does not have to be parsed
# before it is consumed and used elsewhere, just like any array you have defined.
# The data only needs to be addressed by its ".identityname" captured in the
# array $queryResults (shown below).
#
############################################################################################
#############################################################################################
# T-SQL for creating table to hold data returned
#
# CREATE TABLE [dba].[tbl_dbfilesize](
# [ServerNameInstance] [varchar](20) NULL,
# [DatabaseName] [varchar](30) NULL,
# [DataFileSizeMB] [numeric](20, 0) NULL,
# [LogFileSizeMB] [numeric](20, 0) NULL,
# [TotalDatabaseSizeMB] [numeric](20, 0) NULL,
# [CollectionDate] [date] NULL
# ) ON [PRIMARY]
#############################################################################################
Try
{
#define your connection points
# first create an array that will hold the server/instance name of the servers you wish to audit
# the first sever assumes a named instance, the second a default instance name.
$SourceServerName = @("ServerName01/InstanceName", "ServerName02", "ServerName03") # Server you will retrieve data from
#next define the server connection for where you will write your data back to
$TargetServerInstance = "TaretServerName"
# define your sql query that will be used to pull data from SQL on the Source Server
$qryDatabaseInfo = "
SELECT @@ServerName as ServerNameInstance,
DB.name as DatabaseName,
SUM(CASE WHEN type = 0 THEN MF.size * 8 / 1024 ELSE 0 END) AS DataFileSizeMB,
SUM(CASE WHEN type = 1 THEN MF.size * 8 / 1024 ELSE 0 END) AS LogFileSizeMB,
SUM(CASE WHEN type = 1 THEN MF.size * 8 / 1024 ELSE 0 END) + SUM(CASE WHEN type = 0 THEN MF.size * 8 / 1024 ELSE 0 END) AS TotalDatabaseSizeMB
FROM sys.master_files MF
JOIN sys.databases DB ON DB.database_id = MF.database_id
GROUP BY DB.name
ORDER BY DB.NAME ASC
"
#Loop through all the servers you wish to audit
ForEach ($SourceServerName in $SourceServerNames)
{
#execute query to pull data from server into an array
$queryResults = @(Invoke-SQLCmd -query $qryDatabaseInfo -Server $SourceServerInstance)
# Next, construct your insert statement from data in your $queryresults array.
Foreach ($queryResult in $queryResults)
{
$query = "
Insert Into [DBS_AUDIT_SERVERS].[dba].[tbl_dbfilesize]
([ServerNameInstance],
[DatabaseName],
[DataFileSizeMB],
[LogFileSizeMB],
[TotalDatabaseSizeMB],
[CollectionDate])
Values
(" +
"'" + $SourceServerInstance + "'," +
"'" + $queryResult.DatabaseName + "'," +
"'" + $queryResult.DataFileSizeMB + "'," +
"'" + $queryResult.LogFileSizeMB + "'," +
"'" + $queryResult.TotalDatabaseSizeMB + "'," +
"'" + $Date + "'" +
")"
""
#execute insert statement for sql
Invoke-Sqlcmd -Query $query -ServerInstance $TargetServerInstance
}
}
}
Catch [Exception]
{
$ErrorMessage = $_.Exception.Message
Write-Host $ErrorMessage
}
Finally
{
Write-Host "Completed Successfully"
}
Return 0;
精彩评论