I would like to add a bunch of SQL (mixture of 2000-2005) server instances on different servers to my SSMS (SQL Managment Studio) Registered servers, I was following this tutorial here but this only adds one server at a time not all at the same time.
The list is currently in Excel but can be imported to notepad or any other document format as long as it can be recognized by the PowerShell command. Also, another thing to note is where can i change the login to use sql authentication? and specify username and password?
New-Item $(Encode-Sqlname "SERVERNAME\INSTANCENAME") -itemtype registration -Value “server=MyServer;integrated security=true”
tks
ERROR
New-Object : Cannot convert argument "1", with value: "", for "PSCredential" to
type "System.Security.SecureString": "Cannot convert the "" value of type "Sys
tem.String" to type "System.Security.SecureString"."
At line:4 char:32
+ -Credential (New-Object <<<< System.Management.Automation.PSCredenti
al("sa", "")) }
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodExcept
ion
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.Power
Shell.Commands.NewObjectCommand
If you save the Excel spreadsheet as a CSV file, you can easily import it in PowerShell using the Import-Csv cmdlet and automatically register the servers in the list by their names.
Assuming your CSV file looks like this:
|Name |
|Server1 |
|Server2 |
|Server3 |
The following command will import its content as a list of objects, one for each row in the CSV file, all having a Name property, which contains the actual value. Those names are then used within the string passed to the New-Item cmdlet to actually do the registration:
Import-Csv ServersToRegister.csv | ForEach-Object { `
New-Item $(Encode-Sqlname $_.Name) -ItemType Registration `
-Value ("server=$($_.Name);integrated security=true") }
You can specify the username and password to use to connect to the SQL Server instance by passing a PSCredential object to the New-Item cmdlet. So the complete command would be:
Import-Csv ServersToRegister.csv | ForEach-Object { `
New-Item $(Encode-Sqlname $_.Name) -ItemType Registration `
-Value ("server=$($_.Name);integrated security=true") `
-Credential (New-Object System.Management.Automation.PSCredential("username", "password")) }
Related
I want to import an Excel file into my SQL server DB. Here is my code below:
$dir = "\\server\files\"
$latest = Get-ChildItem -Path $dir |
Where-Object {$_.name -like "*Data Action source *"} |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
Write-Output "The latest file is: $latest"
Write-SqlTableData -ServerInstance "instance1" -DatabaseName "db1" -SchemaName dbo -TableName Table1 -InputData $latest -Force
Write-Output "The latest file is $latest. Let's start the import"
The code picks the latest file nicely but when it comes to inserting into a database its failing with the error below:
Write-SqlTableData : A mapping between .Net type 'System.IO.DirectoryInfo' and SQL type for column 'Directory' was not found. Consider removing the column with that type and repeat the operation
From the error: The variable $latest is of the type System.IO.DirectoryInfo, which is not expected by the Write-SqlTableData command's -InputData parameter.
Run this line in the console for the documentation:
Get-Help Write-SqlTableData -Full
There, you will see this entry for -InputData
-InputData <PSObject>
Specifies the data to write to the database.
Typical input data is a System.Data.DataTable, but you can specify System.Data.DataSet or
System.Data.DateRow objects.
Required? true
Position? named
Default value none
Accept pipeline input? true (ByValue)
Accept wildcard characters? false
So the solution is to convert the csv into a format that this command can understand. The first step is to actually import the data into PowerShell as the moment all you have is file information (path, size etc)
Below, I have cast the CSV as psobject data type. This may still give you an error. For converting to System.Data.Datable which will be accepted, check out this link
dir = "\\server\files\"
$latest = Get-ChildItem -Path $dir |
Where-Object {$_.name -like "*Data Action source *"} |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
Write-Output "The latest file is: $latest"
# Import CSV to get the data
$csvData = Import-csv $latest.FullName
# Convert to psobject. This may still be rejected; I can't test. If it is, convert to DataTable.
$thingToImport = [psobject]$csvData
Write-SqlTableData -ServerInstance "instance1" -DatabaseName "db1" -SchemaName dbo -TableName Table1 -InputData $thingToImport -Force
Write-Output "The latest file is $latest. Let's start the import"
I am trying to write the contents of an Excel file (on tab 5) to a database but it keeps failing.
Here is my code:
$dir = "\\server\files\"
$latest = Get-ChildItem -Path $dir | Where-Object {$_.name -like "*Data Notes*"} | Sort-Object LastWriteTime -Descending | Select-Object -First 1
Write-Output "The latest file is: $latest"
Write-SqlTableData -ServerInstance "sql server" -DatabaseName "sql5" -SchemaName dbo -TableName Temptable100 -InputData $latest.FullName -Force
The table gets created fine but its empty. Can anyone please help me??
I have attached the contents of the Excel file here:
Write-SQLTableData won't be able to read an Excel file so you will need to use something like OLEDB to first read the Excel table into a DataTable and then pass that DataTable to Write-SQLTableData.
All I needed was to store the information in a data variable and then use the Write-SQLTableData to store the information in a database. See below:
Write-SqlTableData -ServerInstance "instance" -DatabaseName "db1" -SchemaName dbo -TableName TableName -InputData $DataTable -Force
I'm working on a project to create some Excel reports with data from MSSQL databases and need some help with the end result.
Disclaimer - I'm not great with PowerShell and MSSQL).
So far, with the help of the internet, I've managed to create a .ps1 file that elevates itself, imports a PS module called PSExcel (https://github.com/RamblingCookieMonster/PSExcel), imports the SQLPS module and runs three separate queries to export to three separate .xlsx files.
My script for the last few parts is:
# Import PSExcel module
Import-Module C:\scripts-and-reports\Modules\PSExcel
# Import SQLPS module
Import-Module sqlps
# Import PSExcel module
Import-Module C:\scripts-and-reports\Modules\PSExcel
# Import SQLPS module
Import-Module sqlps
# Create individuals
invoke-sqlcmd -inputfile "C:\scripts-and-reports\individuals.sql" -serverinstance "SERVER\INSTANCE" -database "DATABASE" |
Export-XLSX -WorksheetName "Individuals" -Path "C:\scripts-and-reports\Individuals.xlsx" -Table -Force
# Create joint parties
invoke-sqlcmd -inputfile "C:\scripts-and-reports\joint-parties.sql" -serverinstance "SERVER\INSTANCE" -database "DATABASE" |
Export-XLSX -WorksheetName "Joint Parties" -Path "C:\scripts-and-reports\Joint Parties.xlsx" -Table -Force
# Create organisations
invoke-sqlcmd -inputfile "C:\scripts-and-reports\organisations.sql" -serverinstance "SERVER\INSTANCE" -database "DATABASE" |
Export-XLSX -WorksheetName "Organisations" -Path "C:\scripts-and-reports\Organisations.xlsx" -Table -Force
I've tried to no avail to combine the last two query exports into the first query's export as additional worksheets so that I only have a single Excel workbook to hand to my boss, but I think I must be approaching it incorrectly.
When I read the example on Line 94 of ../Export-XLSX.ps1 and try to implement it in my scenario by changing the file names to match each other, the last query replaces the first in the outputted .xlsx file. This must be because of the -Force. Changing that to -Append won't help because then it says the file already exists.
Can anyone help me by first showing me where I'm going wrong and then pointing me in the right direction (this may end up in a walkthrough).
Please and thanks!
---** UPDATE **---
With #gms0ulman's fix to Export-XLSX.ps1, it looks like it's going to work as I've tested it with different SQL queries to what I need and it adds the worksheets OK.
The queries I'm using for the test are
SELECT DISTINCT
case mt.[Status]
when 0 then 'In Progress'
When 1 then 'On Hold'
when 2 then 'Completed'
when 3 then 'Not Proceeding'
else 'Unknown' end as MatterStatus,
mt.LastUpdatedOn as LastModified
from matter mt
where mt.LastUpdatedOn >= '2016-07-01'
AND (mt.[status] = 0 or mt.[status] = 1)
While this (and the other two iterations of it in my PS script) works, my actual queries don't. The queries themselves work, and the first export too, but when -Append is used in PS with the invoke-sqlcmd and invoke-sqlcmd -inputfile "query2.sql" -serverinstance "" -database "" | Export-XLSX -WorksheetName "Joint Parties" -Path "C:\scripts-and-reports\Matter Details.xlsx" -Table -Append, the two appended worksheets get the error:
Exceptions calling "SaveAs" with "1" argument(s): "Error saving file C:\scripts-and-reports\Matter Details.xlsx"
At C:\scripts-and-reports\Modules\PSExcel\Export-XLSX.ps1:496 char:13
$Excel.SaveAs($Path)
~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : InvalidOperationException
The problem is with the module you're using. -Append should work. In the Export-XLSX.ps1 file, look at lines 351 and 371.
As you are providing an existing path, 351 evaluates to true and 371 never gets executed.
Line 371 is where the module creates a new worksheet for you.
if (($Append -or $ClearSheet) -and ($PSBoundParameters.ContainsKey('Excel') -or (Test-Path $Path)) ) # line 351
{
$WorkSheet=$Excel.Workbook.Worksheets | Where-Object {$_.Name -like $WorkSheetName}
if($ClearSheet)
{
$WorkSheet.Cells[$WorkSheet.Dimension.Start.Row, $WorkSheet.Dimension.Start.Column, $WorkSheet.Dimension.End.Row, $WorkSheet.Dimension.End.Column].Clear()
}
if($Append)
{
$RealHeaderCount = $WorkSheet.Dimension.Columns
if($Header.count -ne $RealHeaderCount)
{
$Excel.Dispose()
Throw "Found $RealHeaderCount existing headers, provided data has $($Header.count)."
}
$RowIndex = 1 + $Worksheet.Dimension.Rows
}
}
else
{
$WorkSheet = $Workbook.Worksheets.Add($WorkSheetName) #line 371
}
To get around this, I've added a couple of lines to the Export-XLSX.ps1 file.
Now, even if the path exists, it will:
check if a $WorksheetName is provided
check this worksheet does not already exist
create new worksheet if both are true.
Note you will have to Remove-Module and Import-Module for changes to be recognised. You will need to use -Append. I used -Force on first worksheet, not the second one. Also, you may find -Verbose helpful as it provides you with more information as the script runs - good for debugging.
if (($Append -or $ClearSheet) -and ($PSBoundParameters.ContainsKey('Excel') -or (Test-Path $Path)) )
{
# New line: even if path exists, check for $WorkSheetName and that this worksheet doesn't exist
if($WorkSheetName -and $Excel.Workbook.Worksheets | Where-Object {$_.Name -like $WorkSheetName} -eq $null)
{
# if you have $WorksheetName and it doesn't exist, create worksheet.
$WorkSheet = $Workbook.Worksheets.Add($WorkSheetName)
}
else
{
$WorkSheet=$Excel.Workbook.Worksheets | Where-Object {$_.Name -like $WorkSheetName}
if($ClearSheet)
{
$WorkSheet.Cells[$WorkSheet.Dimension.Start.Row, $WorkSheet.Dimension.Start.Column, $WorkSheet.Dimension.End.Row, $WorkSheet.Dimension.End.Column].Clear()
}
if($Append)
{
$RealHeaderCount = $WorkSheet.Dimension.Columns
if($Header.count -ne $RealHeaderCount)
{
$Excel.Dispose()
Throw "Found $RealHeaderCount existing headers, provided data has $($Header.count)."
}
$RowIndex = 1 + $Worksheet.Dimension.Rows
}
} # this is also new.
}
else
{
$WorkSheet = $Workbook.Worksheets.Add($WorkSheetName)
}
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.
Hi dear lord(s) of Powershell :)
I have 380 server to modify.
Some DNS server in forest and domain have changed and I need to change the Dns search order parameter.
If my server have following DNSsearchOrder : 172.xx.xx.1 I want to change to 172.xx.xx.2
If my server have following DNSsearchOrder : 172.xx.xx.1 AND 172.xx.xx.10 I want to change only the first IP to 172.xx.xx.2 and let the 2nd
etc etc (I Have 10dns server moving and they're used on different domain and server)
I retrieve all my server export to CSV file with the following command :
Import-csv "C:\Julien\Script\CheckNchangeRegKeyValue\listOfcomputerOS_OK.csv" -Delimiter ";" |
Foreach-object{
$ServerToAnalyse=$_.Server
Get-WmiObject Win32_NetworkAdapterConfiguration -Filter "ipenabled='true'" -ComputerName $ServerToAnalyse |Where-Object {$_.DNSServerSearchOrder -ne $null}| Where-Object {$_.DNSServerSearchOrder -ine "127.0.0.1"} |`
select DNSHostName,#{Name="DNSParam"; Expression={$(($_.DNSServerSearchOrder))}},MACAddress,description,caption,index
} | Export-csv "C:\Julien\Script\CheckNchangeRegKeyValue\ListOfDNSSettingsAndHostName.csv" -notypeinformation -delimiter ";"
first file is a csv contain data like that :
"Caption";"Server"
"Microsoft(R) Windows(R) Server 2003, Standard Edition";"d0001doi.Mydomain.com"
"Microsoft(R) Windows(R) Server 2003, Standard Edition";"d0001ira.Mydomain.com"
"Microsoft Windows Server 2008 R2 Standard ";"D0005DLF.Mydomain.com"
"Microsoft(R) Windows(R) Server 2003, Standard Edition";"d0001ath.Mydomain.com"
"Microsoft Windows Server 2008 R2 Enterprise ";"D0002TEH.Mydomain.com"
"Microsoft Windows Server 2008 R2 Standard ";"D0003MAD.Mydomain.com"
The output CSV is like that :
"DNSHostName";"DNSParam";"MACAddress";"description";"caption";"index"
"v1068bel";"172.19.1.3";"xx:xx:xx:xx:xx";"VMware Accelerated AMD PCNet Adapter";"[00000010] VMware Accelerated AMD PCNet Adapter";"10"
The output file contain the actual settings and my idea is to modify this file with the following command to use this output file to modify the settings of my server :
[io.file]::readalltext("C:\Julien\Script\CheckNchangeRegKeyValue\ListOfDNSSettingsAndHostName.csv").replace("172.19.1.1","172.19.16.211").replace("172.18.37.8","172.19.17.52").replace("172.19.1.5","172.19.16.211").replace("172.19.1.3","172.19.16.28").replace("172.18.37.4","172.19.16.28").replace("172.19.1.6","172.19.16.27").replace(" ",",") | Out-File "C:\Julien\Script\CheckNchangeRegKeyValue\ListOfDNSSettingsAndHostName.csv" -Encoding ascii –Force
After this modification I try to use the following command :
Import-Csv "C:\Julien\Script\CheckNchangeRegKeyValue\ListOfDNSSettingsAndHostName.csv" -Delimiter ";" |
ForEach-Object{
$Server=$_.DNSHostName
$DNS=$_.DNSParam
$DNS=$DNS -replace "$DNS","`"$DNS`""
$DNS=($DNS -replace ",","`",`"")#.tostring()
$DNSIP=#("$DNS")
#$DNS=#($DNS)
#$DNS.GetType().fullname
#= New-Object System.Object
Write-Host "settings to put : $DNS"
(Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $server).SetDNSServerSearchOrder(("$DNSIP"))#|Out-Null
$ActualDNS = (Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $server)|Where-Object {$_.DNSServerSearchOrder -ne $null}| Where-Object {$_.DNSServerSearchOrder -ine "127.0.0.1"} |select #{Name="actualSettings"; Expression={$(($_.DNSServerSearchOrder))}}
Write-Host "actual settings $ACtualDNS"
}
If I put manually SetDNSServerSearchOrder((“198.102.234.125",”198.102.234.126")) instead of .SetDNSServerSearchOrder(("$DNSIP"))
it's working
but with $dnsip variable the result is 70 (bad IP address)
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 70
PSComputerName :
actual settings #{actualSettings=172.19.1.1}
anyone can help me ?
Thanks a lot
Regards
Julien
According to this article you really need a string array so you should replace $DNSIP=#("$DNS") by $DNSIP.split(',').
Explanation : when you write “198.102.234.125",”198.102.234.126" you create an array, because in PowerShell , is the array operator. $DNSIP=#("$DNS") just create an array of one string which is not an IP address.