Not able to access shared path in powershell - sql-server

I want to take a SQL DB backup to a shared path and perform restoration through PS. Below is the code to perform the op
function restore-TemporaryInLocal($dbName,$backupPath,$sqlServer,$isOverWrite,$DecDBObj,$sqlInstanceName)
{
$percentEventHandler = [Microsoft.SqlServer.Management.Smo.PercentCompleteEventHandler] { Write-Host "Restoration progress : " $_.Percent "%" }
$completedEventHandler = [Microsoft.SqlServer.Management.Common.ServerMessageEventHandler] { Write-Host $_.Error.Message}
# Get the default file and log locations
# (If DefaultFile and DefaultLog are empty, use the MasterDBPath and MasterDBLogPath values)
$DataFileLoc = $sqlServer.Settings.DefaultFile
$LogFileLoc = $sqlServer.Settings.DefaultLog
if ($DataFileLoc.Length -eq 0) {
$DataFileLoc = $sqlServer.Information.MasterDBPath
}
if ($LogFileLoc.Length -eq 0) {
$LogFileLoc = $sqlServer.Information.MasterDBLogPath
}
# Identify the backup file to use, and the name of the database copy to create
#$BackupFile= 'D:\SQLJobs\Errdb2.bak'
#$RestoredDBName = 'ErrDB2_20101016'
# Build the physical file names for the database copy
$DBFile = $DataFileLoc + $dbname + '_Data.mdf'
$LogFile = $LogFileLoc + $dbname + '_Log.ldf'
# Use the backup file name to create the backup device
$bdi = new-object ('Microsoft.SqlServer.Management.Smo.BackupDeviceItem') ($backupPath, 'File')
# Create the new restore object, set the database name and add the backup device
$restoreObj = new-object('Microsoft.SqlServer.Management.Smo.Restore')
$restoreObj.Database = $dbName
$restoreObj.Devices.Add($bdi)
# Get the file list info from the backup file
$FileList = $restoreObj.ReadFileList($sqlServer)
foreach ($file in $FileList) {
$rsfile = new-object('Microsoft.SqlServer.Management.Smo.RelocateFile')
$rsfile.LogicalFileName = $file.LogicalName
if ($file.Type -eq 'D'){
$rsfile.PhysicalFileName = $DBFile
}
else {
$rsfile.PhysicalFileName = $LogFile
}
$restoreObj.RelocateFiles.Add($rsfile)
}
# Restore the database
$restoreObj.ReplaceDatabase=$isOverWrite;
#Write-Host "Replace DB :"$restoreObj.ReplaceDatabase
$restoreObj.add_PercentComplete($percentEventHandler)
$restoreObj.add_Complete($completedEventHandler)
if($isOverWrite -eq $true)
{
Write-Host "Taking DB Offline";
$script="ALTER DATABASE $dbname SET OFFLINE WITH ROLLBACK IMMEDIATE";
#Write-Host $script $dbname $sqlInstanceName
Invoke-SQLcmd -Server $sqlInstanceName -Database $dbName $script
Write-Host "Getting DB Online";
$DecDBObj.SetOnline();
}
Write-Host "Initiating DB restore..."
$restoreObj.SqlRestore($sqlServer)
}
function take-BackupToLocal($backupDirectory,$serverName,$backupDB,$isCopyOnly,$serverRef)
{
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
$percentEventHandler = [Microsoft.SqlServer.Management.Smo.PercentCompleteEventHandler] { Write-Host "Database backed up" $_.Percent "%" }
$completedEventHandler = [Microsoft.SqlServer.Management.Common.ServerMessageEventHandler] { Write-Host $_.Error.Message
Write-Host "Backup Path:"$targetPath
}
$dbList = $serverRef.Databases
$BackupDB =$BackupDB.Trim();
$DBexists=$false;
if(test-path $backupDirectory)
{
$timestamp = Get-Date -format yyyy-MM-dd-HHmmss
$targetPath = $backupDirectory + "\" + $backupDB + "_" + $timestamp + ".bak"
foreach ($database in $dbList | where { $_.IsSystemObject -eq $False })
{
$dbName = $database.Name
if($database.Name -eq $BackupDB -and $database.Status -ieq "normal"){
$DBexists=$true;
$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$smoBackup.Action = "Database"
$smoBackup.BackupSetDescription = "Full Backup of " + $dbName
$smoBackup.BackupSetName = $dbName + " Backup"
$smoBackup.Database = $dbName
$smoBackup.MediaDescription = "Disk"
$smoBackup.CopyOnly=$isCopyOnly
$smoBackup.Devices.AddDevice($targetPath, "File")
$smoBackup.PercentCompleteNotification=5
$smoBackup.add_PercentComplete($percentEventHandler)
$smoBackup.add_Complete($completedEventHandler)
$smoBackup.SqlBackup($serverRef)
return $targetPath;
}else{
Write-Host "Cannot perform a backup as the DB is in:" $database.Status " mode";
}
}
if($DBexists -eq $false)
{
Write-Host "$BackupDB DB not found in $serverName.Please check the DB & Server details"
}
}
else
{
Write-Host "Cannot find the path specified. Contact admin"
Write-Host "backup path:"$backupDirectory
}
}
$sqlName= "*************"
$serverName="******";
# Set new or existing databse name to restote backup
$backupDB= "AdventureWorksDW2012"
# Set the existing backup file path
#$backupPath= "D:\Automation\Ps-scripts\Backups\tempdb1_2017-05-25-222232.bak"
#Load the required assemlies SMO and SmoExtended.
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
$percentEventHandler = [Microsoft.SqlServer.Management.Smo.PercentCompleteEventHandler] { Write-Host "Restoration progress : " $_.Percent "%" }
$completedEventHandler = [Microsoft.SqlServer.Management.Common.ServerMessageEventHandler] { Write-Host $_.Error.Message}
try{
# Connect SQL Server.
$sqlServer = New-Object ('Microsoft.SqlServer.Management.Smo.Server') $sqlName
$ExistingDB=$sqlServer.Databases.Item($backupDB)
$backupDirectory="\\***********\ps_jobs_backup_shared";
$isCopyOnly=$true;
if($ExistingDB.EncryptionEnabled -eq $true)
{
$needToDecrypt = Read-Host -Prompt 'Specify if backup needs to be decrypted (Y/N)'
}
if($needToDecrypt -ieq "y")
{
#Write-Host "decryption code...."
$decServerSqlName="***************"
Write-Host "Initiating Backup..."
$DecryptDB="tempDB1"
$decSqlServer = New-Object ('Microsoft.SqlServer.Management.Smo.Server') $decServerSqlName
$decServerSqlName="****************"
$isOverWrite=$true;
$DecDBObj=$decSqlServer.Databases.Item($DecryptDB)
$backupPath=take-BackupToLocal -backupDirectory $backupDirectory -serverName $sqlName -backupDB $backupDB -isCopyOnly $isCopyOnly -serverRef $sqlServer
restore-TemporaryInLocal -dbName $DecryptDB -backupPath $backupPath -sqlServer $decSqlServer -isOverWrite $isOverWrite -DecDBObj $DecDBObj -sqlInstanceName $decServerSqlName
}elseif($needToDecrypt -ieq "n")
{
Write-Host "Initiating a encrypted backup...";
take-BackupToLocal -backupDirectory $backupDirectory -serverName $sqlName -backupDB $backupDB -isCopyOnly $isCopyOnly -serverRef $sqlServer
}
}
catch
{
$_.Exception.GetBaseException().Message
}
Now the above code works fine. However when I execute the same code once again the TEST-PATH conditions fails[work-around: Need to re-open the PS IDE again after every run]
Below is the log for first 2 runs.
Specify if backup needs to be decrypted (Y/N): y
Initiating Backup...
Database backed up 5 %
Database backed up 10 %
Database backed up 100 %
BACKUP DATABASE successfully processed 25625 pages in 8.435 seconds (23.733 MB/sec).
Taking DB Offline
Getting DB Online
Initiating DB restore...
Restoration progress : 10 %
Restoration progress : 20 %
Restoration progress : 100 %
RESTORE DATABASE successfully processed 25625 pages in 7.429 seconds (26.946 MB/sec).
2nd Run:
Specify if backup needs to be decrypted (Y/N): y
Initiating Backup...
Cannot find the path specified. Contact admin
backup path: \\sanky555\ps_jobs_backup_shared

Related

How do you script out SQL Server agent jobs to single or individual files

I've tried various Powershell scripts but they fail with:
The following exception occurred while trying to enumerate the collection: "An exception occurred while executing a Transact-SQL statement or batch.".
At H:\Create_SQLAgentJobSripts2.ps1:89 char:22
foreach ($job in $s.JobServer.Jobs)
~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
FullyQualifiedErrorId : ExceptionInGetEnumerator
What has gone wrong or how can I get better debugging on this error?
I executed this script:
.\Create_SQLAgentJobSripts2.ps1 .\ServerNameList.txt
Here's the script
param([String]$ServerListPath)
#write-host "Parameter: $ServerListPath"
#Load the input file into an Object array
$ServerNameList = get-content -path $ServerListPath
#Load the SQL Server SMO Assemly
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
#Create a new SqlConnection object
$objSQLConnection = New-Object System.Data.SqlClient.SqlConnection
#For each server in the array do the following.
foreach($ServerName in $ServerNameList)
{
Write-Host "Beginning with Server: $ServerName"
Try
{
$objSQLConnection.ConnectionString = "Server=$ServerName;Initial Catalog=CED_NCT_RESOURCE_TRACK;Persist Security Info=True;User ID=CEDNCTAdmin;Password=CEDNCTAdmin;"
Write-Host "Trying to connect to SQL Server instance on $ServerName..." -NoNewline
$objSQLConnection.Open() | Out-Null
Write-Host "Success."
$objSQLConnection.Close()
}
Catch
{
Write-Host -BackgroundColor Red -ForegroundColor White "Fail"
$errText = $Error[0].ToString()
if ($errText.Contains("network-related"))
{Write-Host "Connection Error. Check server name, port, firewall."}
Write-Host $errText
continue
}
# Won't be using this object again
Remove-Variable -Name objSQLConnection
#If the output folder does not exist then create it
$OutputFolder = ".\$ServerName"
if (!(Test-Path $OutputFolder))
{
write-host ("Creating directory: " + $OutputFolder)
New-Item -ItemType directory -Path $OutputFolder
}
else
{
write-host ("Directory already exists: " + $OutputFolder)
}
write-host "File: $(".\$OutputFolder\" + $($_.Name -replace '\\', '') + ".job.sql")"
# Connect to the instance using SMO
$s = new-object ('Microsoft.SqlServer.Management.Smo.Server') $ServerName
write-host ("SQL Server Edition: " + $s.Edition)
write-host ("SQL Agent ErrorLogFile: " + $s.JobServer.ErrorLogFile)
# Instantiate the Scripter object and set the base properties
$scrp = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($ServerName)
write-host ("SCRP ToString():" + $scrp.ToString())
write-host ("Test scrp - Server: " + $scrp.Server)
#The next step is to set the properties for the script files:
$scrp.Options.ScriptDrops = $False
$scrp.Options.WithDependencies = $False
$scrp.Options.IncludeHeaders = $True
$scrp.Options.AppendToFile = $False
$scrp.Options.ToFileOnly = $True
$scrp.Options.ClusteredIndexes = $True
$scrp.Options.DriAll = $True
$scrp.Options.Indexes = $False
$scrp.Options.Triggers = $False
$scrp.Options.IncludeIfNotExists = $True
#Now, we can cycle through the jobs and create scripts for each job on the server.
# Create the script file for each job
foreach ($job in $s.JobServer.Jobs)
{
$jobname = $job.Name
write-host ("Job: " + $jobname)
$jobfilename = ($OutputFolder + "\" + $jobname + ".job.sql")
$scrp.Options.FileName = $jobfilename
write-host "Filename: $jobfilename"
#This line blows up
$scrp.Script($job)
}
}
Possibly you're not instantiating the Server object correctly. Try the following instead...
# Alternative 1: With servername and port, using Trusted Connection...
$ServerName = 'YourServerName,1433'
$ServerConnection = New-Object Microsoft.SqlServer.Management.Common.ServerConnection -ArgumentList #( $ServerName )
# Alternative 2: With an SqlConnection object
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$ServerName;Initial Catalog=CED_NCT_RESOURCE_TRACK;Persist Security Info=True;User ID=CEDNCTAdmin;Password=CEDNCTAdmin;"
$SqlConnection.Open() | Out-Null
$ServerConnection = New-Object Microsoft.SqlServer.Management.Common.ServerConnection -ArgumentList #( $SqlConnection )
# Then...
$Server = New-Object Microsoft.SqlServer.Management.Smo.Server -ArgumentList #( $ServerConnection )
$Server.JobServer.Jobs | ForEach-Object {
Write-Host "Job: $($_.Name)"
}

Powershell "The Microsoft.ACE.OLEDB.12.0 Provider is not registered on the local machine

i am running a powershell program to insert the data from Excel to database:
param([int]$StepNumber=1)
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
$datestr=$(Get-Date).ToString("yyyy-MM-dd")
$url="http://www.dtcc.com/~/media/Files/Downloads/client-center/NSCC/NSCC-MPID-Directory.xls"
$destination = $directorypath +"/NSCC-MPID-Directory"+"_"+$datestr+".xls"
## if destination does not exsist, creat a new one.
if (!(Test-Path $destination) ) {
New-Item $destination -type file -force
}
$client = new-object System.Net.WebClient
$client.DownloadFile( $url, $destination)
$filepath = $destination
$excelConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$filepath;Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'"
$sqlConnection = 'Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=SIAC;Data Source=database1;'
$excelQuery = 'select * from [OTC$]'
$tablename = 'NSCC_MPID_OTC'
Try {
$conn = New-Object System.Data.OleDb.OleDbConnection($excelConnection)
$conn.open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = $excelQuery
$rdr = $cmd.ExecuteReader()
$sqlbc = New-Object System.Data.SqlClient.SqlBulkCopy($sqlConnection, [System.Data.SqlClient.SqlBulkCopyOptions]::TableLock)
$sqlbc.DestinationTableName = $tableName
#$sqlbc.Batchsize = 1000
#$sqlbc.BulkCopyTimeout = 60
#$sqlbc.EnableStreaming=$true
# add all columns - you can add as few as you like.
for ($i = 0; $i -lt $rdr.FieldCount; $i++) {
$fname = $rdr.GetName($i)
Write-Host $fname -ForegroundColor green
[void]$sqlbc.ColumnMappings.Add($fname, $fname)
}
# write all of the data to the table
Try {
$sqlbc.WriteToServer($rdr)
} Catch {
Write-Host "$_" -Fore red -back white
} Finally {
$rdr.Close()
}
} Catch {
Write-Host "$_" -ForegroundColor red
}
When I run the program which needs to use the OLE DB Provider, it gives the error: "The Microsoft.ACE.OLEDB.12.0 Provider is not registered on the local machine. Can someone tell me why it can not find the provider when it is already there.
I tried dowloading Microsoft Database Access Engine 2017 and Microsoft Database Access Engine 2010 Redistributible and still have the same error. I also restart my computer and try run as administrator.... No thing worked for me.
Could anyone help me with this? Thanks.
The OLEDB provider are 32-bit and 64-bit aware.
If only 32-bit provider is installed (when installed Office is 32-bit),
The script must be run using powershell (x86).
To do that, run this command:
& "$Env:WINDIR\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -File <script_file_path>
To list installed OLEDB, see List all Ole DB Providers in Powershell.
The output may be different when run in Powershell (x64) and Powershell (x86).
function Get-OledbRegistered
{
[CmdletBinding()]
[OutputType([System.Collections.Generic.List[PSObject]])]
param ()
Process
{
$list = New-Object ([System.Collections.Generic.List[PSObject]])
foreach ($provider in [System.Data.OleDb.OleDbEnumerator]::GetRootEnumerator())
{
$v = New-Object PSObject
for ($i = 0; $i -lt $provider.FieldCount; $i++)
{
Add-Member -in $v NoteProperty $provider.GetName($i) $provider.GetValue($i)
}
$list.Add($v)
}
return $list
}
}
Get-OledbRegistered

SQL Server backup script (PowerShell) works on 2016 server but not 2012

I have the following script:
$serverName = "."
$backupDirectory = "\\backup\server1"
$daysToStoreDailyBackups = 7
$daysToStoreWeeklyBackups = 28
$monthsToStoreMonthlyBackups = 3
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
$mySrvConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$mySrvConn.ServerInstance=$serverName
$mySrvConn.LoginSecure = $false
$mySrvConn.Login = "sa"
$mySrvConn.Password = "myPass"
$server = new-object Microsoft.SqlServer.Management.SMO.Server($mySrvConn)
$dbs = $server.Databases
$startDate = (Get-Date)
"$startDate"
Get-ChildItem "$backupDirectory\*_daily.bak" |? { $_.lastwritetime -le (Get-Date).AddDays(-$daysToStoreDailyBackups)} |% {Remove-Item $_ -force }
"removed all previous daily backups older than $daysToStoreDailyBackups days"
foreach ($database in $dbs | where {$_.IsSystemObject -eq $False})
{
$dbName = $database.Name
if ($dbName -ne "ReportServer" -and $dbName -ne "ReportServerTempDB")
{
$timestamp = Get-Date -format yyyy-MM-dd-HHmmss
$targetPath = $backupDirectory + "\" + $dbName + "_" + $timestamp + "_daily.bak"
$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$smoBackup.Action = "Database"
$smoBackup.BackupSetDescription = "Full Backup of " + $dbName
$smoBackup.BackupSetName = $dbName + " Backup"
$smoBackup.Database = $dbName
$smoBackup.MediaDescription = "Disk"
$smoBackup.Devices.AddDevice($targetPath, "File")
$smoBackup.SqlBackup($server)
"backed up $dbName ($serverName) to $targetPath"
}
else
{
"$dbName backup skipped"
}
}
if([Int] (Get-Date).DayOfWeek -eq 0)
{
Get-ChildItem "$backupDirectory\*_weekly.bak" |? { $_.lastwritetime -le (Get-Date).AddDays(-$daysToStoreWeeklyBackups)} |% {Remove-Item $_ -force }
"removed all previous daily backups older than $daysToStoreWeeklyBackups days"
foreach ($database in $dbs | where { $_.IsSystemObject -eq $False})
{
$dbName = $database.Name
if ($dbName -ne "ReportServer" -and $dbName -ne "ReportServerTempDB")
{
$timestamp = Get-Date -format yyyy-MM-dd-HHmmss
$targetPath = $backupDirectory + "\" + $dbName + "_" + $timestamp + "_weekly.bak"
$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$smoBackup.Action = "Database"
$smoBackup.BackupSetDescription = "Full Backup of " + $dbName
$smoBackup.BackupSetName = $dbName + " Backup"
$smoBackup.Database = $dbName
$smoBackup.MediaDescription = "Disk"
$smoBackup.Devices.AddDevice($targetPath, "File")
$smoBackup.SqlBackup($server)
"backed up $dbName ($serverName) to $targetPath"
}
else
{
"$dbName backup skipped"
}
}
}
if([Int] (Get-Date).Day -eq 1)
{
Get-ChildItem "$backupDirectory\*_monthly.bak" |? { $_.lastwritetime -le (Get-Date).AddMonths(-$monthsToStoreMonthlyBackups)} |% {Remove-Item $_ -force }
"removed all previous monthly backups older than $monthsToStoreMonthlyBackups days"
foreach ($database in $dbs | where { $_.IsSystemObject -eq $False})
{
$dbName = $database.Name
if ($dbName -ne "ReportServer" -and $dbName -ne "ReportServerTempDB")
{
$timestamp = Get-Date -format yyyy-MM-dd-HHmmss
$targetPath = $backupDirectory + "\" + $dbName + "_" + $timestamp + "_monthly.bak"
$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$smoBackup.Action = "Database"
$smoBackup.BackupSetDescription = "Full Backup of " + $dbName
$smoBackup.BackupSetName = $dbName + " Backup"
$smoBackup.Database = $dbName
$smoBackup.MediaDescription = "Disk"
$smoBackup.Devices.AddDevice($targetPath, "File")
$smoBackup.SqlBackup($server)
"backed up $dbName ($serverName) to $targetPath"
}
else
{
"$dbName backup skipped"
}
}
}
This works perfectly on one of my servers (running server 2016), the other (running server 2012) it does not, it gives me the following error:
Exception calling "SqlBackup" with "1" argument(s): "Backup failed for Server 'Server1'. "
At C:\Users\Administrator\Documents\Scripts\sqlFullBackup.ps1:43 char:9
+ $smoBackup.SqlBackup($server)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FailedOperationException
Any ideas how to get around this?
thanks in advance
--- EDIT -----------------------------
When running
$error[0] | fl -force
I get the following:
System.Data.SqlClient.SqlException: Cannot open backup device '\\ServerAddress\Folder\file_2017-06-17-110451_daily.bak'. Operating system error 5(Access is denied.).
I tested your script on sql server 2012 and success backup to local folder.
Your script is working fine.
Try (for test) to backup to local folder on the server.
Be sure:
You installed Microsoft Windows PowerShell Extensions for Microsoft SQL Server 2012 (with SMO).
For details, read my answer: What do I need to execute a SQL Server PowerShell module
Your server has access permission to the shared folder "\\backup\server1".
In server 2012, Set MSSQLSERVER account a permission R/W on the shared folder "\\backup\server1"
Edit:
From your comment, the script is working fine by using local folder.
So, the problem is the setting of the shared folder.
In Workgroup Environment
If you sql server 2012 is working in WORKGROUP environment:
Create the same window user account with the same password (e.g 'sql2012') on both sql server 2012 and the backup server (using Computer manager).
Set this account (sql2012/password) as the account running sql service (using the Sql Server Configuration Manager tool).
in backup server set the permission in the shared folder Full R/W to the account sql2012
In domain environment
Use a domain account as the account running sql service (using the Sql Server Configuration Manager tool)
in backup server set the permission in the shared folder Full R/W to the that domain account.

Powershell Job Step in SQL Error

I'm new to PowerShell and still early in SQL Server, but I'm trying to write a PowerShell step for a SQL Agent job that looks at a CSV file that contains names of .sql files.
It should then look at a different directory and if the names from the CSV file exist in that directory it should open the .sql file and execute the function inside.
I'm getting an error:
Unable to cast object of type 'System.String to type System.Type
Any help would be greatly appreciated.
$excelFile = "C:/ExcelTest/Test.csv"
$functionDirectory = "some directory"
$excel_Array = (Get-Content $excelFile)[0].split(",")
foreach ($sqlName in $excel_Array)
{
if($sqlName::exists($functionDirectory + "/" + $sqlName) -ne $true)
{
invoke-sqlcmd -inputfile $functionDirectory + "/" + $sqlName -serverinstance "serverinstance" -database "database"
}
}
If understand the question correctly, you need to use Test-Path not ::exists
$excelFile = "C:/ExcelTest/Test.csv"
$functionDirectory = "some directory"
Import-Csv $excelFile |
Foreach-Object {
$filename = $functionDirectory + '\' + $_[0]
if (Test-Path $filename) {
invoke-sqlcmd -inputfile $filename -serverinstance "serverinstance" -database "database"
}
}
I would adjust a few things in your script to properly handle a CSV and then utilize built-in cmdlet for testing the path of a given file.
[cmdletbinding()]
param()
Import-Module SQLPS -DisableNameChecking
$functionDirectory = "C:\temp\PowerShell_Testing2"
$excelFile = Import-Csv "C:\temp\PowerShell_Testing\SQLFileList.csv"
foreach ($e in $excelFile) {
$fileonly = Split-Path $e.SQLFile -Leaf
$fdFile = $functionDirectory + "\" + $fileonly
if (Test-Path $fdFile) {
Write-Host "Found File $fdFile"
Invoke-Sqlcmd -ServerInstance "MANATARMS\SQL12" -InputFile $fdFile -Database master
}
}
In my setup there is only one file that just runs:
SELECT TOP 1 name FROM sys.databases
If your CSV contains say a ServerName, and then SQLFile you can adjust your script to also pull the ServerInstance value like this:
[cmdletbinding()]
param()
Import-Module SQLPS -DisableNameChecking
$functionDirectory = "C:\temp\PowerShell_Testing2"
$excelFile = Import-Csv "C:\temp\PowerShell_Testing\SQLFileList.csv"
foreach ($e in $excelFile) {
$fileonly = Split-Path $e.SQLFile -Leaf
$fdFile = $functionDirectory + "\" + $fileonly
if (Test-Path $fdFile) {
Write-Host "Found File $fdFile"
Invoke-Sqlcmd -ServerInstance $e.ServerName -InputFile $fdFile -Database master
}
}

Looking to speed up this PowerShell Function

I'm running the following code to pull data from SCOM 2012 and using an exported spreadsheet from SCCM 2012, output servers which are pending reboot along with their SCCM maintenance window for automated scheduled reboots.
The code takes around 5-8 minutes to run and I was wondering if there was any way to speed up the process. The code running under Begin Loop is the bottle neck.
Function Generate-RebootData{
IF(Get-Command Get-SCOMAlert -ErrorAction SilentlyContinue){}ELSE{Import-Module OperationsManager}
"Get Pend reboot servers from prod"
New-SCOMManagementGroupConnection -ComputerName ProdSrv
$AlertData = get-SCOMAlert -Criteria `
"Severity = 1 AND ResolutionState < 254 AND Name = 'Pending Reboot'" |
Select NetbiosComputerName
"Get Pend reboot servers from cert"
#For cert information
New-SCOMManagementGroupConnection -ComputerName CertSrv
$AlertData += Get-SCOMAlert -Criteria `
"Severity = 1 AND ResolutionState < 254 AND Name = 'Pending Reboot'" |
Select NetbiosComputerName
"Remove duplicates"
$AlertDataNoDupe = $AlertData | Sort NetbiosComputerName -Unique
"Create hash table"
$table = #{}
"Populate hash table"
Import-Csv D:\Scripts\servers2.csv | ForEach-Object {
$table[$_.Computername] = $_.'Collection Name'}
"Create final object"
$result = #{}
"Begin Loop"
$result = $AlertDataNoDupe | ForEach-Object { [PSCustomObject] #{
Server=$_.NetbiosComputerName
MaintenanceWindow=IF($table[$_.NetbiosComputerName]){$table[$_.NetbiosComputerName]}
ELSE{"Not found!"}
PingCheck=IF(Test-Connection -Count 1 $_.NetbiosComputerName -Quiet -EA SilentlyContinue)
{"Alive"}
ELSE{"Dead"}
LastReboot=Try{
$operatingSystem = Get-WmiObject Win32_OperatingSystem -ComputerName `
$_.NetbiosComputerName -ErrorAction Stop
[Management.ManagementDateTimeConverter]::ToDateTime(`
$operatingSystem.LastBootUpTime)}
Catch{"Access Denied!"}
} }
}
You should perform the PingCheck first, and only if that succeeds move on with the Get-WmiObject call - there's no need to contact a machine if you've just determined that it's "dead".
...
$result = $AlertDataNoDupe | ForEach-Object {
# Create hashtable
$Properties = #{
Server = $_.NetbiosComputerName
MaintenanceWindow = if($table[$_.NetbiosComputerName]){
= $_.NetbiosComputerName
} else {
'Not found!'
}
}
# Perform ping check, keep as boolean
$Properties['PingCheck'] = Test-Connection -Count 1 $_.NetbiosComputerName -Quiet -EA SilentlyContinue
$Properties['LastReboot'] = if($Properties['PingCheck'])
{
try
{
# Server seems to be online
$operatingSystem = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $_.NetbiosComputerName -ErrorAction Stop
[Management.ManagementDateTimeConverter]::ToDateTime($operatingSystem.LastBootUpTime)
}
catch
{
'Access Denied!'
}
}
else
{
# If server doesn't respond, declare it offline
'Computer offline!'
}
# create the object
New-Object -TypeName psobject -Property $Properties
}

Resources