I have a Powershell script based on this example that I've been using to automate my database restores, which has worked without a problem for a while now.
Recently it started failing and throwing timeout errors.
To highlight the code block from that example:
############################################################################
# Restore db Script block
############################################################################
[ScriptBlock] $global:RestoreDBSMO = {
param([string] $newDBName, [string] $backupFilePath, [bool] $isNetworkPath = $true, [string] $newDataPath, [string] $newLogPath)
# http://www.codeproject.com/Articles/110908/SQL-DB-Restore-using-PowerShell
try
{
# Load assemblies
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
# Create sql server object
$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") "(local)"
# Copy database locally if backup file is on a network share
if($isNetworkPath)
{
$fileName = [IO.Path]::GetFileName($backupFilePath)
$localPath = Join-Path -Path $server.DefaultFile -ChildPath $fileName
Copy-Item $backupFilePath $localPath
$backupFilePath = $localPath
}
# Create restore object and specify its settings
$smoRestore = new-object("Microsoft.SqlServer.Management.Smo.Restore")
$smoRestore.Database = $newDBName
$smoRestore.NoRecovery = $false;
$smoRestore.ReplaceDatabase = $true;
$smoRestore.Action = "Database"
# Create location to restore from
$backupDevice = New-Object("Microsoft.SqlServer.Management.Smo.BackupDeviceItem") ($backupFilePath, "File")
$smoRestore.Devices.Add($backupDevice)
# Give empty string a nice name
$empty = ""
# Specify new data file (mdf)
$smoRestoreDataFile = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
if (($newDataPath -eq $null) -or ($newDataPath -eq $empty)) { #use exixting path
$defaultData = $server.DefaultFile
if (($defaultData -eq $null) -or ($defaultData -eq $empty))
{
$defaultData = $server.MasterDBPath
}
} Else {$defaultData = $newDataPath}
$fullPath = Join-Path -Path $defaultData -ChildPath ($newDBName + "_Data.mdf")
$smoRestoreDataFile.PhysicalFileName = $fullPath
# Specify new log file (ldf)
$smoRestoreLogFile = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
if (($newLogPath -eq $null) -or ($newLogPath -eq $empty)) { #use exixting path
$defaultLog = $server.DefaultLog
if (($defaultLog -eq $null) -or ($defaultLog -eq $empty))
{
$defaultLog = $server.MasterDBLogPath
}
} Else {$defaultLog = $newLogPath}
$fullPath = Join-Path -Path $defaultLog -ChildPath ($newDBName + "_Log.ldf")
$smoRestoreLogFile.PhysicalFileName = $fullPath
# Get the file list from backup file
$dbFileList = $smoRestore.ReadFileList($server)
# The logical file names should be the logical filename stored in the backup media
$smoRestoreDataFile.LogicalFileName = $dbFileList.Select("Type = 'D'")[0].LogicalName
$smoRestoreLogFile.LogicalFileName = $dbFileList.Select("Type = 'L'")[0].LogicalName
# Add the new data and log files to relocate to
$smoRestore.RelocateFiles.Add($smoRestoreDataFile)
$smoRestore.RelocateFiles.Add($smoRestoreLogFile)
# Restore the database
$smoRestore.SqlRestore($server)
"Database restore completed successfully"
}
catch [Exception]
{
"Database restore failed:`n`n " + $_.Exception
}
finally
{
# Clean up copied backup file after restore completes successfully
if($isNetworkPath)
{
Remove-Item $backupFilePath
}
}
}
When doing the actual restore, it throws the following error:
Restoring DB...
0
1
Database restore failed:
Microsoft.SqlServer.Management.Smo.FailedOperationException: Restore failed for Server 'SRV_MIC_DEV'. ---> Microsoft.SqlServer.Management.Common.ExecutionFailureException: An exception occurred while executing a Transact-SQL statement or batch. ---> System.
Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
The backup or restore was aborted.
10 percent processed.
20 percent processed.
30 percent processed.
40 percent processed.
50 percent processed.
60 percent processed.
at Microsoft.SqlServer.Management.Common.ConnectionManager.ExecuteTSql(ExecuteTSqlAction action, Object execObject, DataSet fillDataSet, Boolean catchException)
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(String sqlCommand, ExecutionTypes executionType)
--- End of inner exception stack trace ---
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(String sqlCommand, ExecutionTypes executionType)
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(StringCollection sqlCommands, ExecutionTypes executionType)
at Microsoft.SqlServer.Management.Smo.ExecutionManager.ExecuteNonQuery(StringCollection queries)
at Microsoft.SqlServer.Management.Smo.BackupRestoreBase.ExecuteSql(Server server, StringCollection queries)
at Microsoft.SqlServer.Management.Smo.Restore.SqlRestore(Server srv)
--- End of inner exception stack trace ---
at Microsoft.SqlServer.Management.Smo.Restore.SqlRestore(Server srv)
at SqlRestore(Object , Object[] )
at System.Management.Automation.DotNetAdapter.AuxiliaryMethodInvoke(Object target, Object[] arguments, MethodInformation methodInformation, Object[] originalArguments)
I've tried having a look over the Powershell documentation and other links and noticed that some websites mentioned that Powershell cmdlets have a 600 second default timeout.
I'm trying to find either a solution to increase this timeout from Powershell or from SQL Server, but I'm not really having any luck with documentation or regular web-searches.
Is there any quick fix for my script to increase the timeout or a simple alternative?
Any help is much appreciated.
Related
on a local Server I've got a bunch of sub-folders containing PowerShell-scripts, one of those is "sqlserver" folder contains Microsoft sqlserver module. I've got a daily task-scheduler job connecting a sql-server, there is a zip-file having the same sub-folder structure (with a folder: sqlserver) as on the local server.
The idea is to overwrite the local folder structure with the new structure from the zip-file.
The problem is the module "sqlserver" which I need to connect to sql server and get the zip file etc. Trying to overwrite it I get an error. I've tried to remove-module but it doesn't work as well.
The code:
try
{
[decimal]$lokaleVersion = 3.01 #
$deploymentVersion = 0
[string]$filetype = 'PS'
if($zipObject = Get-ZIPFile -lokaleAdminDBVersion $lokaleVersion -filetype $filetype -build 0)
{
$deploymentVersion = $zipObject.aktScriptVersion
if($deploymentVersion -gt $lokaleVersion)
{
Remove-Module -name sqlserver -Force
Unzip-File -zipObject $zipObject -zipname $filetype -modulePath $modulePath #error Access denied
$SubFolders = dir ($modulePath) | Where-Object {($_.PSIsContainer) -and ($_.Name -ne "sqlserver")} | ForEach-Object -Process {$_.FullName} -ErrorAction Stop
Import-Module -Name sqlserver -DisableNameChecking -Force
ForEach ($Folder in $SubFolders)
{
try
{
$a = (join-path -Path $modulePath -ChildPath ($folder.Split("\")[-1]) -Resolve) + "\" + "installer.ps1"
if(Test-Path ($a))
{
& $a
}
}
catch
{
Write-LogFile -Message $($Error[0].exception.message) -severity Fehler -modul $module
}
}
}
}
}
catch
{
if ($error[0].exception.message) {$message = $error[0].exception.message}
Write-LogFile -Message $message -severity Fehler -modul $module
}
It's important to overwrite the sub-folders (I'm updating the scripts) and the sqlserver-module should be updated regularly.
Thanks for your help.
I have put together a nice PowerShell script to script out the objects (tables, functions, sprocs etc) from a database, limiting it to the ones in a list.
But I am stuck trying to find a way to script the database itself. Each time I do that, it seems to try to script out the whole database (it is way to large for that to go well).
Assuming I have a $db variable that is a reference to my database, how can I use SMO to script out that database, creating it with the same Properties and DatabaseScopedConfigurations, but none of the actual objects in it?
Update:
For reference here is my current script. It takes a server and database name and will script out all the objects found in a file called DbObjectsList.txt (assuming they are in the database). But this does not actually make the database. The database I am running this on is a legacy one, and it has a bunch of odd options set. I would like to preserve those.
$serverName = "MyServerName"
$databaseName = "MyDbName"
$date_ = (date -f yyyyMMdd)
$path = ".\"+"$date_"
# Load the Sql Server Management Objects (SMO) and output to null so we don't show the dll details.
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') > $null
# Setup the scripting options
$scriptOptions = new-object ('Microsoft.SqlServer.Management.Smo.ScriptingOptions')
$scriptOptions.ExtendedProperties = $true
$scriptOptions.AnsiPadding = $true
$scriptOptions.ClusteredIndexes = $true
# Dri = Declarative Referential Integrity
$scriptOptions.DriAll = $true
$scriptOptions.Triggers = $true
$scriptOptions.NoCollation = $false
$scriptOptions.SchemaQualify = $true
$scriptOptions.ScriptSchema = $true
$scriptOptions.EnforceScriptingOptions = $true
$scriptOptions.SchemaQualifyForeignKeysReferences = $true
$scriptOptions.NonClusteredIndexes = $true
$scriptOptions.Statistics = $true
$scriptOptions.Permissions = $true
$scriptOptions.OptimizerData = $true
# get a reference to the database we are going to be scripting from
$serverInstance = New-Object ('Microsoft.SqlServer.Management.Smo.Server') $serverName
$db=$serverInstance.Databases | Where-Object {$_.Name -eq $databaseName}
$dbname = "$db".replace("[","").replace("]","")
$dbpath = "$path"+ "\"+"$dbname" + "\"
if ( !(Test-Path $dbpath))
{
$null=new-item -type directory -name "$dbname"-path "$path"
}
# Load the list of db objects we want to script.
$listPath = ".\DbObjectList.txt"
if ((Test-Path $listPath))
{
$dbListItems = Get-Content -Path $listPath
}
else
{
throw "Could not find DbObjectst.txt file (it should have a list of what to script)."
}
# Setup the output file, removing any existing one
$outFile = "$dbpath" + "FullScript.sql"
if ((Test-Path $outFile)){Remove-Item $outFile }
$typeDelimiter = "=========="
foreach ($dbListItem in $dbListItems)
{
# Let the caller know which one we are working on.
echo $dbListItem
if ($dbListItem.StartsWith($typeDelimiter))
{
# Pull the type out of the header
$startIndex = $typeDelimiter.Length;
$stopIndex = $dbListItem.LastIndexOf($typeDelimiter)
$type = $dbListItem.Substring($startIndex, $stopIndex - $startIndex).Trim()
continue;
}
if ($type -eq $null)
{
throw "Types not included DbObjectsList.txt. Add types before groups of objects, surrounded by " + $typeDelimiter
}
foreach ($dbObjectToScript in $db.$type)
{
$objName = "$dbObjectToScript".replace("[","").replace("]","")
$compareDbListItem = "$dbListItem".replace("[","").replace("]","")
if ($compareDbListItem -eq $objName)
{
"-- " + $dbListItem | out-File -Append $outFile
$dbObjectToScript.Script($scriptOptions)+"GO" | out-File -Append $outFile
}
}
}
I have created a PowerShell script that takes the back up of entire structure of database. When it comes to jobs backup, I cannot find a possible solution to that.
$v = [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO')
if ((($v.FullName.Split(','))[1].Split('='))[1].Split('.')[0] -ne '9')
{
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMOExtended') | out-null
}
[System.Reflection.Assembly]:: LoadWithPartialName('Microsoft.SqlServer.SmoEnum') | out-null
set-psdebug -strict # catch a few extra bugs
$ErrorActionPreference = "stop"
$My = 'Microsoft.SqlServer.Management.Smo'
$srv = new-object ("$My.Server") $ServerName # attach to the server
foreach($sqlDatabase in $srv.databases)
{
$databaseName=$sqlDatabase.name
if ($databaseName.count)
{
$scripter = new-object ("$My.Scripter") $srv # create the scripter
$scripter.Options.ToFileOnly = $true
# we now get all the object types except extended stored procedures
# first we get the bitmap of all the object types we want
$all =[long]
[Microsoft.SqlServer.Management.Smo.DatabaseObjectTypes]:: all -bxor
[Microsoft.SqlServer.Management.Smo.DatabaseObjectTypes]:: ExtendedStoredProcedure
# and we store them in a datatable
$d = new-object System.Data.Datatable
# get everything except the servicebroker object, the information schema and system views
$d = $srv.databases[$databaseName].EnumObjects([long]0x1FFFFFFF -band $all) | Where-Object {$_.Schema -ne 'sys'-and $_.Schema "information_schema"
#Saving it in a directory
}
}
This scripts takes the back up of the db but take the structural back up of msdb. I studied Microsoft.SqlServer.SMO that says it has a job server agent and job collection function but it doesn't seem to work.
For jobs, use the JobServer.Jobs collection. You can similarly script other server-level objects.
Below is an example.
$jobsCollection = $srv.JobServer.Jobs
$scriptingOptions = New-Object Microsoft.SqlServer.Management.Smo.ScriptingOptions
$scriptingOptions.IncludeIfNotExists = $true
$scriptingOptions.AppendToFile = $false
$scriptingOptions.ToFileOnly = $true
foreach ($job in $jobsCollection) {
Write-Host "Scripting $($job.Name)"
$scriptingOptions.FileName = "C:\ScriptFolder\Jobs.sql"
$job.Script($scriptingOptions)
$scriptingOptions.AppendToFile = $true
}
Although the answer given by Dan helped me but it wasn't creating a script in the folders. It was just creating folders with the jobs names. So, I did something like this :
foreach($sqlDatabase in $srv.JobServer.Jobs)
{ $databaseName=$sqlDatabase.name
write-host("I am her '$databaseName' ");
$scripter = new-object ("$My.Scripter") $srv # create the scripter
$scripter.Options.ToFileOnly = $true
$d = new-object System.Data.Datatable
$d=$srv.JobServer.Jobs[$databaseName]
$d| FOREACH-OBJECT {
trap [System.Management.Automation.MethodInvocationException]{
write-host ("ERROR: " + $_) -Foregroundcolor Red; Continue
}
# for every object we have in the datatable.
$SavePath="$($DirectoryToSaveTo)\$($ServerName)\$($databaseName)\$($_.DatabaseObjectTypes)"
# create the directory if necessary (SMO doesn't).
if (!( Test-Path -path $SavePath )) # create it if not existing
{Try { New-Item $SavePath -type directory | out-null }
Catch [system.exception]{
Write-Error "error while creating '$SavePath' $_"
return
}
}
# tell the scripter object where to write it
$scripter.Options.Filename = "$SavePath\$($_.name -replace '[\\\/\:\.]','-').sql";
# Create a single element URN array
$UrnCollection = new-object ('Microsoft.SqlServer.Management.Smo.urnCollection')
$URNCollection.add($_.urn)
# and write out the object to the specified file
$scripter.script($URNCollection)
}
}
I've been working on a little project in Powershell.
My task was to create a script that will collect all files from mail attachments, merge all .pdf files into one and send the generated file to my email.
The script works completely fine in Powershell ISE, but when I try to run it from task scheduler, the merged .pdf file is corrupted without any data in it.
Keep in mind I am new to this stuff.
This is my main code that does all the heavy work:
function getAttachments
{
#########################################################
##-----------------------------------------------------##
## GET ATTACHMENTS ##
##-----------------------------------------------------##
#########################################################
##PATH TO CREDENTIAL
$credpath = "C:\Users\" + $env:UserName + "\Documents\myCred_${env:USERNAME}_${env:COMPUTERNAME}.xml"
#test variable
$test = Test-Path $credpath
##TEST IF CREDENTIAL EXISTS
if(!$test){
## USER PROMPT PSW CREDENTIAL ##
$cred = Get-Credential
#save credential in documents
$cred | Export-CliXml -Path $credpath
}else{
##READ USER CREDENTIAL FROM FILE
$cred = Import-CliXml -Path $credpath
}
##url and date variables
$url = "https://outlook.office365.com/api/v1.0/me/messages"
$d = [DateTime]::Today.AddDays(-1)
$global:date = $d.ToString("yyyy-MM-dd")
## Get all messages that have attachments where received date is greater than $date
$messageQuery = "" + $url + "?`$select=Id&`$filter=HasAttachments eq true and DateTimeReceived ge " + $date
$messages = Invoke-RestMethod $messageQuery -Credential $cred
## Loop through each results
foreach ($message in $messages.value)
{
# get attachments and save to file system
$query = $url + "/" + $message.Id + "/attachments"
$attachments = Invoke-RestMethod $query -Credential $cred
# in case of multiple attachments in email
foreach ($attachment in $attachments.value)
{
Write-Host “Found File :- ” $attachment.Name
$path = "c:\Attachments\" + $attachment.Name
$Content = [System.Convert]::FromBase64String($attachment.ContentBytes)
Set-Content -Path $path -Value $Content -Encoding Byte
}
}
}
function sendAttachments
{
#############################################################
##---------------------------------------------------------##
## SEND ATTACHMENTS AND DELETE FILES ##
##---------------------------------------------------------##
#############################################################
#Connection Details
#PATH TO CREDENTIAL
$credpath = "C:\Users\" + $env:UserName + "\Documents\myCred_${env:USERNAME}_${env:COMPUTERNAME}.xml"
$cred = Import-CliXml -Path $credpath
$smtpServer = “ smtp.office365.com”
$msg = new-object Net.Mail.MailMessage
#Change port number for SSL to 587
$smtp = New-Object Net.Mail.SmtpClient($SmtpServer, 25)
#Uncomment Next line for SSL
$smtp.EnableSsl = $true
$smtp.Credentials = $cred
$msg.IsBodyHtml = $true
#From Address
$msg.From = $cred.UserName
#To Address, Copy the below line for multiple recipients
$msg.To.Add(“email#gmail.com”)
#Message Body
$msg.Body=”<h2>Alle attachments samen bevinden zich in de bijlage van did email</h2> <br/><br/>”
#Message Subject
$msg.Subject = “no-reply: Email met alle attachments”
#your file location
$files=Get-ChildItem “C:\Attachments\”
#attach the right file
$file = $global:pname
Write-Host “Attaching File :- ” $file
$attachment = New-Object System.Net.Mail.Attachment –ArgumentList C:\Attachments\$file
$msg.Attachments.Add($attachment)
#send email
$smtp.Send($msg)
$attachment.Dispose();
$msg.Dispose();
#delete the files from the folder
Get-ChildItem -Path C:\Attachments -Include * -File -Recurse | foreach { $_.Delete()}
}
function mergePDF
{
#############################################################
##---------------------------------------------------------##
## MERGE ALL PDF FILES ##
##---------------------------------------------------------##
#############################################################
$workingDirectory = "C:\Attachments"
$itspath = $PSScriptRoot
$global:pname = $global:date + "_pdfAttachments.pdf"
$pdfs = ls $workingDirectory -recurse | where {-not $_.PSIsContainer -and $_.Extension -imatch "^\.pdf$"};
[void] [System.Reflection.Assembly]::LoadFrom([System.IO.Path]::Combine($itspath, 'itextsharp.dll'));
$output = [System.IO.Path]::Combine($workingDirectory, $pname);
$fileStream = New-Object System.IO.FileStream($output, [System.IO.FileMode]::OpenOrCreate);
$document = New-Object iTextSharp.text.Document;
$pdfCopy = New-Object iTextSharp.text.pdf.PdfCopy($document, $fileStream);
$document.Open();
foreach ($pdf in $pdfs) {
$reader = New-Object iTextSharp.text.pdf.PdfReader($pdf.FullName);
[iTextSharp.text.pdf.PdfReader]::unethicalreading = $true
$pdfCopy.AddDocument($reader);
$reader.Dispose();
}
$document.Close()
$pdfCopy.Dispose();
$document.Dispose();
$fileStream.Dispose();
}
getAttachments
Start-Sleep -s 10
mergePDF
Start-Sleep -s 10
sendAttachments
In this piece of code that I run in another script file, I create a new task:
#############################################################
##---------------------------------------------------------##
## SCHEDULE SCRIPTS IN WINDOWS TASKS ##
##---------------------------------------------------------##
#############################################################
##PATH TO CREDENTIAL
$credpath = "C:\Users\" + $env:UserName + "\Documents\myCred_${env:USERNAME}_${env:COMPUTERNAME}.xml"
#test variable
$test = Test-Path $credpath
##TEST IF CREDENTIAL EXISTS
if(!$test){
## USER PROMPT PSW CREDENTIAL ##
$cred = Get-Credential
#save credential in documents
$cred | Export-CliXml -Path $credpath
}
$taskName = "ManageEmailAttachments"
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
if($taskExists)
{
Get-ScheduledJob ManageEmailAttachments
Unregister-ScheduledJob ManageEmailAttachments
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("Task successfully deleted, run the script again to schedule the task",0,"Done",0x0)
}
else
{
$tt = Get-Date
$tt = $tt.AddMinutes(1)
$testtime = $tt.ToString("HH:mm:ss")
#set trigger
$trigger = New-JobTrigger -Daily -At "1:00"
$testtrigger = New-JobTrigger -Daily -At $testtime
#path to the scripts
$scriptPath = $PSScriptRoot + "\wps_manage_pdf_attachments.ps1"
#options(optional)
$option = New-ScheduledJobOption -WakeToRun: $true
#create a new task
Register-ScheduledJob -Name ManageEmailAttachments -FilePath $scriptPath -Trigger $testtrigger -ScheduledJobOption $option
}
The script when run in Powershell works great, it gets all the attachments from mailbox, merges them into 1 .pdf file and sends them to the requested email address. But when scheduled in windows task scheduler it does the first step fine, but when merged, the .pdf file is corrupted without any content.
I couldn't figure out how to make it work so I posted a question on the forum.
Hope you guys find a way to figure it out.
Thanks in advance
Use below function to get script root directory.
Function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -scope 1).Value
Split-path $Invocation.MyCommand.Path
}
$scriptPath=Join-Path(Get-ScriptDirectory) 'wps_manage_pdf_attachments.ps1'
Apparently the problem nested itself in the main code. I used:
Try{...}
Catch{$_ | Out-File C:\errors.txt}
In mergePDF function to find out what the error was. Seems like the path to my ITextSharp.dll was incorrect. $PSScriptRoot that I used showed "C:\windows\windows32" instead of where the script actually is.
So what I did instead was add a line in my batch file to copy the itextsharp.dll to %Temp%:
xcopy Scripts\itextsharp.dll %Temp% /D >NUL 2>NUL
and then read the file from there with:
$itsPath = [System.IO.Path]::GetTempPath()
And everything works as it should be. I know this isn't the best way to do it but I had this batch file before to make the script run by just dubbleclicking it.
So adding a little line won't hurt.
I hope this helps anyone with the same problem.
Wrote a script to create incidents (objects) in bulk in SCSM (Microsoft System Center Service Manager) using PowerShell. The script pulls the data required from a CSV file. I am running into the following error:
New-SCSMIncident : Index was outside the bounds of the array.
At C:\Users\portalservice\Desktop\scripts\Incidents\BULK_Create_Incidents.ps1:83 char:5 + New-SCSMIncident -Title $Title -Description $Description -AffectedUser $Affe ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Interface Packets Dropped :String) [New-SCSMIncident], IndexOutOfRangeException
+ FullyQualifiedErrorId : NewIncident,SMLets.SCSMIncidentNew
When I echo the contents of the array I see normal data... it all looks correct. Here is my script:
# Script designed to create tickets in bulk, reading the information needed from a CSVfile
# Tailored for incidents, can be modified to work with any work item
# SirLearnAlot 2015
# NOTES: Modify the $path variable to match the path of the data file being imported
# Import the smlets module
ipmo SMLets
Write-Host ""
Write-Host "Importing Smlets..."
# ---------------------------------------- Variable Decleration ----------------------------------------
Write-Host "Getting the classes needed..."
# Get the incident class
$IncidentClass = Get-SCSMClass -Name System.WorkItem.Incident$
# Get the CI Class
$CIClass = Get-SCSMClass -Name COMPANY.CI.Class$
# Get the Relationship we want to add (Affected Items)
$RelWIaboutCI = Get-SCSMRelationshipClass -Name System.WorkItemAboutConfigItem$
# Clear the error variable incase it contains anything already
$error.clear()
# --------------------------------------------- Data Import --------------------------------------------
# Import the CSV Data file containing list of incidents to create and their information
Write-Host "Importing CSV Data File..."
$path = "C:\Users\portalservice\Desktop\Script Data\Work Item Creation\Incidents\11.12.15\data.csv"
$data = ipcsv $path
if ($error -like "Could not find file *")
{
Write-Host "Encountered an error while importing the data file from '$path'. Please verify the path directories and file exist and run the script again."
exit
}
else
{
Write-Host "Successfully imported data file!"
Write-Host "Beginning ticket creation..."
#pause
}
# ---------------------------------------------- Execution ---------------------------------------------
# Begin going through file line by line
foreach ($case in $data)
{
# Clear the error variable
$error.clear()
# Visual Formatting
Write-Host ""
Write-Host "----------------------------------------------------------------------------------------"
Write-Host ""
# GETTING THE INFORMATION FROM DATA FILE AND STORING IN VARIABLES
# Get the Info for the Incident to create
$Title = $case.Title
Write-Host "Got case title: $Title"
$Description = $case.Description
Write-Host "Got case description: $Description"
$AffectedUser = $case.AffectedUser
Write-Host "Got case affected user: $AffectedUser"
$Classification = $case.Classification
Write-Host "Got case classification: $Classification"
$Impact = $case.Impact
Write-Host "Got case impact: $Impact"
$Urgency = $case.Urgency
Write-Host "Got case urgency: $Urgency"
$SupportGroup = $case.SupportGroup
Write-Host "Got case support group: $SupportGroup"
$PrimaryOwner = $case.PrimaryOwner
Write-Host "Got case owner: $PrimaryOwner"
$Vendor = $case.Vendor
Write-Host "Got case vendor: $Vendor"
$Customer = $case.Customer
Write-Host "Got case customer: $Customer"
$ReportedOn = $case.ReportedOn
Write-Host "Got date reported on: $ReportedOn"
# Get the name of the correct CI to add
$CIToAddNum = $case.CI
Write-Host "Got case CI: $CIToAddNum"
# Apply the non-OOB Values to the property hash table
$PropertyHashTable = #{"Vendor" = $Vendor; "Customer" = $Customer; "Reported_On" = $ReportedOn}
# INCIDENT CREATION
Write-Host "Attemping to create Incident from case data..."
New-SCSMIncident -Title $Title -Description $Description -AffectedUser $AffectedUser -Classification $Classification -Impact $Impact -Urgency $Urgency -SupportGroup $SupportGroup -Bulk
# Checks to see if the there is an error, if so displays a warning message and exits
if (!$error)
{
Write-Host "Incident creation successful."
}
else
{
Write-Host "$error"
Write-Host "Error creating the incident. Check the incident creation code and run this script again."
exit
}
# INCIDENT RETRIEVAL (POST-CREATION)
Write-Host "Attempting to retrieve incident for modification (Adding Customer, Vendor, and Reported On date to ticket)"
$Incident = Get-SCSMObject -Class $IncidentClass -Filter "Description -like '%$Description%'"
# Checks to see if the retrieval failed, if so displays error message and exits script
if ($Incident = $null)
{
Write-Host "Incident retrieval failed. Check the incident retrieval code and run the script again."
exit
}
# Apply the property hash table to the retrieved incident
$Incident | Set-SCSMObject -PropertyHashtable $PropertyHashTable
# ADDING THE CI TO THE INCIDENT
# Get the CI from the CMDB
$CIToAdd = Get-SCSMObject -Class $CIClass -Filter "DisplayName -eq '$CIToAddNum'"
if ($CIToAdd = $null)
{
Write-Host "Cannot find $CIToAddNum in the database, this CI does not seem to exist or the code to retrieve the CI failed. Please import the CI into the SMDB or fix the retrieval code and run this script again"
exit
}
# Attempt to add the CI to the Incident (Create a new relationship)
# Note: Due to a bug the -bulk paramater is required
Write-Host "Attempting to add $CIToAddNum to Incident..."
New-SCSMRelationshipObject -Relationship $RelWIaboutCI -Source $Incident -Target $CIToAdd -bulk
# Check if script throws error (cannot find the CI from the data file in our SMDB)
# If so provides error message and exits, otherwise provides success message
if ($error -like "Cannot bind argument to parameter 'Target' because it is null.")
{
Write-Host "Encountered an error while trying to add $CIToAddNum to $IncidentNum, this CI is not in the Service Manager Database or there was a problem retrieving it. Please import the CI into the SMDB or check the retrieval code and run this script again"
exit
}
else
{
Write-Host "Successfully Added!"
}
}
Write-Host ""
Write-Host "Success! All Incidents Corrected :)"
Not sure what the problem is here, any ideas?
Hit this same problem, my solution was to instead use New-SCSMObject.
Here is a simple example:
$irprops = #{Title = 'test'
Description = 'test descripton'
Impact = (get-scsmenumeration -name 'System.WorkItem.TroubleTicket.ImpactEnum.Low')
Urgency = (get-scsmenumeration -name 'System.WorkItem.TroubleTicket.UrgencyEnum.Medium')
ID = "IR{0}"
Status = (get-scsmenumeration -name 'System.WorkItem.TroubleTicket.ImpactEnum.Low')
Priority = 2
}
$ir=new-scsmobject -Class (get-scsmclass -name 'System.WorkItem.Incident$') -PropertyHashtable $irprops -PassThru