I have a script that checks on disk size and percentage used for my servers. When everything is correct, it works. However, it seems like the Try-catch fails to catch any errors. The script merely writes a message to the console, then quits the script. Here is some sample code:
$Error.Clear()
try
{
$wkDisk = Get-WmiObject Win32_LogicalDisk `
-ComputerName "Apathy.computrolllc.com" `
-filter "DeviceID = 'C:'" `
-Credential $wkLogCreds
}
catch
{
$Msg = "Error retrieving disk info`n"
$Msg += $_.Exception.Message
Write-Host $Msg
$Error.Clear()
$wkDisk = $Null
}
if ($Null -ne $wkDisk)
{
$wkSizeGB = $wkDisk.Size / 1GB
$wkFreeGB = $wkDisk.FreeSpace / 1GB
$wkFreePct = $wkDisk.FreeSpace / $wkDisk.size
$wkFreePct *= 100
$wkFreePct = [math]::Round($wkFreePct)
$wkResults = " Size: " + $wkSizeGB.ToString("0.00") + " Free: " + $wkFreeGB.ToString("0.00")
$wkResults += " (" + $wkFreePct + "%)"
Write-Host $wkResults
}
else {
Write-host "Catch failed"
}
The host "Apathy.computrollls.com" does not exist. I get other errors in my production script, but I used this to test the error handling. It does not execute the statements in the Catch. Here is the output:
PS C:\Batch Jobs> . "c:\Batch Jobs\Test Disk Space.ps1"
[DBG]: PS C:\Batch Jobs>
Get-WmiObject: The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
[DBG]: PS C:\Batch Jobs>
[DBG]: PS C:\Batch Jobs>
Catch failed
PS C:\Batch Jobs>
Related
I'm trying to make a script that checks how long the computers on a network are on, and if they are on for more then 10 days they need to restart. I'm planning to run the script automatically with task manager every Sunday.
Thanks to #vonPryz I've got something like this now:
$clients = get-content "C:\Documents\lijstcomputers.txt"
foreach ($client in $clients) {
if (test-connection -computername $client -BufferSize 16 -Count 1 -Quiet) {
write-Host $client is online
$uptime = (get-date) - (gcim Win32_OperatingSystem -computer $client).LastBootUpTime
$startTime = [Management.ManagementDateTimeConverter]::ToDateTime((gwmi Win32_OperatingSystem -computer $client).lastbootuptime)
if( $uptime.days -ge 10) {
restart-computer -computername $client
add-content -path "c:\path\to\log.txt" -value "$client, $startTime, $uptime"
}
}
else {
write-Host $client is offline
}
}
But now I'm getting this error:
gcim : WinRM cannot complete the operation. Verify that the specified computer name is valid, that the computer is accessible over the network, and
that a firewall exception for the WinRM service is enabled and allows access from this computer. By default, the WinRM firewall exception for publ
ic profiles limits access to remote computers within the same local subnet.
At line:1 char:25
+ $uptime = (get-date) - (gcim Win32_OperatingSystem -computer $client).LastBootUp ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ConnectionError: (root\cimv2:Win32_OperatingSystem:String) [Get-CimInstance], CimException
+ FullyQualifiedErrorId : HRESULT 0x80338126,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
+ PSComputerName : ASND0042
Cannot find an overload for "op_Subtraction" and the argument count: "2".
At line:1 char:1
+ $uptime = (get-date) - (gcim Win32_OperatingSystem -computer $client).LastBootUp ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Since you already got some parts covered, this isn't just a plz give me teh codez and thus warrants help. So let's outline how the whole script should look.
# Write computer names into a file, one per row for easier management
$clients = get-content "c:\ListOfComputers.txt"
foreach ($client in $clients) {
# If computer's not up, there's no need to check uptime
if (test-connection -computername $client -BufferSize 16 -Count 1 -Quiet) {
write-Host $client is online
# Get uptime
$uptime = (get-date) - (gcim Win32_OperatingSystem -computer $client).LastBootUpTime
# Get start time
$startTime = [Management.ManagementDateTimeConverter]::ToDateTime((gwmi Win32_OperatingSystem -computer $client).lastbootuptime)
# Restart the client if uptime's at least 10 days.
if( $uptime.days -ge 10) {
restart-computer -computername $client
# Add client name, start date and uptime into a log file
add-content -path "c:\path\to\log.txt" -value "$client, $startTime, $uptime"
}
}
else {
write-Host $client is offline
}
}
This skeleton can be further improved by adding some error handling and, say, proper CSV export.
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.
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
I've done varied amounts of research into how to run a parameterised PS script from SSIS. I am having issues getting a parameterised script running. PS script is as follows, if I hard code the parameters into the script it behaves as expected:
Param ([string]$filepath,[string]$filename)
$Path = $filepath
$InputFile = (Join-Path $Path $filename)
$Reader = New-Object System.IO.StreamReader($InputFile)
While (($Line = $Reader.ReadLine()) -ne $null) {
If ($Line -match 'FILE\|([^\|]+)') {
$OutputFile = "$($matches[1]).txt"
}
Add-Content (Join-Path $Path $OutputFile) $Line
}
Running in SSIS execute process task, I am trying to build the Arguments command via an expression as follows:
"-ExecutionPolicy ByPass -File " + #[User::vPSScriptLocation] + " " + #[User::vFilePath]+ " "+ #[User::vFileName]
Evaluating the expression gives the following:
-ExecutionPolicy ByPass -File \\WorkDirectory\Script.ps1 \\transfer datafile.data
Upon execution, the task fails. The .ps1 is deleted from the work directory and SSIS gives the following error code:
Error: 0xC0029151 at Execute powershell script, Execute Process Task: In Executing "C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe" "-ExecutionPolicy ByPass -File \\WorkDirectory\Script.ps1 \\transfer datafile.data" at "", The process exit code was "-196608" while the expected was "0".
Looks like it's getting an empty string where it shouldn't? Any pointers appreciated.
OK so as it appears I could not call a UNC path to execute this using an Execute Process Task, I decided to execute this within a Script Task with a reference added to System.Management.Automation which allowed me to create a PowerShell instance. This is far from my ideal solution as I really wanted to call a .ps1 file, but looks like this is my only solution given I need to use a UNC path.
I build the PS script with my Dts variables and then executed it within the instance, which achieved the desired result:
public void Main()
{
string filepath = Dts.Variables["User::vUNCPath"].Value.ToString();
string filename = Dts.Variables["User::vFileName"].Value.ToString();
string searchterm = Dts.Variables["User::vSearchTerm"].Value.ToString();
bool fireAgain = true;
// Build powershell script
string script = "$Path = \""+filepath+"\";"+
"$InputFile = (Join-Path $Path \""+ filename+"\");" +
"$Reader = New-Object System.IO.StreamReader($InputFile);" +
"While (($Line = $Reader.ReadLine()) -ne $null) {" +
"If ($Line -match '"+searchterm+"') { "+
"$OutputFile = \"$($matches[1]).txt\"};" +
"Add-Content (Join-Path $Path $OutputFile) $Line}";
Dts.Events.FireInformation(0, "Info", "Powershell script built: " + script, String.Empty, 0, ref fireAgain);
try
{
// Create instance to run script
using (PowerShell psinstance = PowerShell.Create())
{
//Assign built script to this instance
psinstance.AddScript(script);
//Run powershell script
psinstance.Invoke();
}
Dts.TaskResult = (int)ScriptResults.Success;
}
catch (Exception ex)
{
Dts.Events.FireError(0, "Error", ex.Message, String.Empty, 0);
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
If you're running your script as a ps1-File with a param-block like this, your execution-call should name the parameters by their name:
"-ExecutionPolicy ByPass -File " + #[User::vPSScriptLocation] + " -filepath " + #[User::vFilePath]+ " -filename "+ #[User::vFileName]
This should do it, if you use a valid filepath and filename.
If it doesn't work, please try to write your script as a function and try it in a powershell-console. Your script as a function looks like this:
function SearchLines
{
Param (
[string]$filepath,
[string]$filename
)
$Path = $filepath
$InputFile = (Join-Path $Path $filename)
$Reader = New-Object System.IO.StreamReader($InputFile)
While (($Line = $Reader.ReadLine()) -ne $null) {
If ($Line -match 'FILE\|([^\|]+)') {
$OutputFile = "$($matches[1]).txt"
}
Add-Content (Join-Path $Path $OutputFile) $Line
}
}
Usage:
SearchLines -filepath "\\your\unc\path\here" -filename "filename.txt"
If this don't work for you, please let us know which error you got.
Thx.
UPDATE:
Based on your comments, i wrote your function new in the hope, it meets your requirements as close as possible. The function now looks like this:
function SearchLines
{
Param (
[string]$InputFile
)
$FileContent = Get-Content $InputFile
foreach($Line in $FileContent)
{
If ($Line -match 'FILE\|([^\|]+)')
{
$OutputFile = "$($matches[1]).txt"
}
Add-Content -Path $OutputFile -Value $Line
}
}
Usage:
SearchLines -InputFile c:\your\path\to\your\file.log
This function creates for every line in your given file a new file in the actual folder named what is written in the line. The Cmdlet Join-Path simply adds the two strings together, without any check for plausibility. That's why you can simply commit the full path to your file instead of the path and the file in separate parameters.
If you need the path of the inputfile to set it for your outputfiles, you can get it with these lines:
$tmpPath = Get-Childitem $InputFullPath
$Path = $tmpPath.Directory.FullName
Because you didn't explained what exactly this script should do, i hope you can use this to get what you wanted.
Greetings
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