Powershell Script execution using Schdule tasks - powershell

I need to go over a list of web services and query them individually and pull the details and store it into the database, I designed the code in the following way
Script 1 connects to the SNOW and pulls in the list of web servcies that i need to connect and loops them through the list and triggers a "Start-ThreadJob" with the service name as an argument
Scipt 2 connects to that specific web service (received as an argument) and connects to it and pull in the data and reports it to the database.
When i run the script 1 manually The script 1 is successfully calling all the required web services and the data is being reported to the database, however when i try to call the script 1 using the windows schdule task, The script 1 executes but the script 2 is not being triggered.
do i need to set
Any specific excution policies
Scope
Any inputs is appreciated, Here is an example for how the script 1 and 2 looks
Script 1
#Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
##############################################################################################################
#Function Name: ErrorHandler
#Inputs: Error Type(Info, Warning or Error), Error String
#Output: None
#Description: If the error type is 'Error' then captures the last known exceptions reported and appends to the file.
# If the error type is something else then the error message is appended to the log file.
##############################################################################################################
Function ErrorHandler ($errType, $ErrorString)
{
$timestamp = Get-Date -Format o
if ($errType -eq 'Error')
{
$errorstr = $timestamp + ' : ' + $errType + ' - ' + $ErrorString + $Error[0].Exception
}
else
{
$errorstr = $timestamp + ' : ' + $errType + ' - ' + $ErrorString
}
$errcounter = 0
$maxerrcounter = 5
do
{
try
{
$errorstr | Out-File $ErrFile -Append
break
}
catch
{
Start-Sleep 10
$errcounter++
}
}while ($errcounter -le $maxerrcounter)
}
##############################################################################################################
#Initialize Variable
##############################################################################################################
#Key file path
$CredFilePath = "E:\WIS\MonitorConfiguration\Schduled\Stage\creds\"
#Error file name
$ErrFile = 'C:\MonitorReportLogs\Sitescope_Config_Pull.log'
$authorization = $null
#SNOW API server fqdn
$SnowFQDNhost = "<Server Name>"
###################################
#Build Snow API authorization header
###################################
$user= Get-Content $CredFilePath'SNOW_User.txt'
$KeyFile = $CredFilePath+'AES.key'
$key = Get-Content $KeyFile
$EncryptedPW = Get-Content $CredFilePath'SNOW_Pass.txt' | ConvertTo-SecureString -Key $key
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($EncryptedPW)
$pass = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$pair = "$($user):$($pass)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$authorization = "Basic $encodedCreds"
#SNOW API authorization Header assignment
$Headers = #{
Authorization = $authorization
}
###################################
#Query SNOW for the list of sitescope instances
###################################
$snowsysurl="https://" + $SnowFQDNhost + "/api/now/table/u_cmdb_relationship_report?sysparm_query=u_service.name=BSM SiteScope - Production&sysparm_fields=u_hardware.fqdn"
try
{
$info=Invoke-WebRequest -Uri $snowsysurl -Headers $Headers
}
catch
{
$errStr = "SNOW Sitescope server list API request for the URL: "+ $snowsysurl +" failed - "
ErrorHandler 'Error' $errStr
}
###################################
#Process each sitescope instance monitor data
###################################
If($info -eq $null){
$errStr = "Unhandled Exception parsing data for " + $SnowFQDNhost + " exiting Script."
ErrorHandler 'Error' $errStr
Exit
}
else
{
#convert the JSON response to PS Custom data object dictionary
$snowContent = $info | ConvertFrom-Json
#Query each sitescope on the list and process the configuration data
$jobCounter = 0
if (($snowContent.result.'u_hardware.fqdn' -ne $null) -and ($snowContent.result.'u_hardware.fqdn' -ne ''))
{
foreach($obj in $snowContent.result.'u_hardware.fqdn')
{
if (($obj -ne $null) -and ($obj -ne ''))
{
Start-ThreadJob -ScriptBlock {param($hostname) E:\WIS\MonitorConfiguration\Schduled\Stage\SIS_Config_DB_Push.ps1 $hostname}`
-ArgumentList ($obj) -ThrottleLimit 10 -Name $obj
$errStr = "Triggered the script for server : "+ $obj
ErrorHandler 'Info' $errStr
}
}
}
else
{
$errStr = "SNOW Sitescope server list API request for the URL: "+ $snowsysurl +" returned 0 records."
ErrorHandler 'Error' $errStr
}
}
###################################
#Garbage Collection
###################################
$info = $null
$snowContent = $null
Script 2: (Limited Version)
#Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
##############################################################################################################
#Function Name: ErrorHandler
#Inputs: Error Type(Info, Warning or Error), Error String
#Output: None
#Description: If the error type is 'Error' then captures the last known exceptions reported and appends to the file.
# If the error type is something else then the error message is appended to the log file.
##############################################################################################################
Function ErrorHandler ($errType, $ErrorString)
{
$timestamp = Get-Date -Format o
if ($errType -eq 'Error')
{
$errorstr = $timestamp + ' : ' + $errType + ' - Server Name: ' + $SiSServerName + ' - ' + $ErrorString + $Error[0].Exception
}
else
{
$errorstr = $timestamp + ' : ' + $errType + ' - Server Name: ' + $SiSServerName + ' - ' + $ErrorString
}
$errcounter = 0
$maxerrcounter = 5
do
{
try
{
$errorstr | Out-File $ErrFile -Append
break
}
catch
{
Start-Sleep 10
$errcounter++
}
}while ($errcounter -le $maxerrcounter)
}
$obj = $args[0]
#Error file name
$ErrFile = 'C:\MonitorReportLogs\Sitescope_Config_Pull.log'
$errStr = "Start processing data for " + $obj
ErrorHandler 'Info' $errStr

Related

Cannot convert the "System.Security.SecureString" value of type "System.String" to type "System.Security.SecureString"

I have a problem with an app that I am creating: this app can configure from a remote device a server/PC through IP, Username, Password. There is a script I made in PowerShell that can add User with password in server (New-LocalUser), but when I'll execute it, it gives me this error
Cannot bind parameter 'Password'. Cannot convert the "System.Security.SecureString" value of type "System.String" to
type "System.Security.SecureString".
The password is saved in a temporary file and convert into secure string in PS script, so I don't understand why it doesn't work
Here the script
$path = (Get-Location).ToString() + "\..\..\script\PS\lib.ps1"
Import-Module -Name $path
$json = (Get-Location).ToString() + "\..\..\misc\json\user.json"
$userinfo = Get-Content $json | ConvertFrom-Json
$uj = (Get-Location).ToString() + "\..\..\misc\json\userToAdd.json"
$commands = Get-Content $uj | ConvertFrom-Json
$passtype = $commands.passwordType
$pass = $commands.password
if($commands.isEnable -eq "False"){
$arg = '-Disabled '
}
if($commands.password -eq "")
{
$arg = $arg + $commands.passwordType + '-NoPassword '
}else{
$npass = $pass | ConvertTo-SecureString -AsPlainText -Force
$arg = $arg + $commands.passwordType + '-Password '
}
if($commands.Description -eq ""){
$desc = " "
}else{
$desc = " -Description " + $commands.Description + " "
}
$cmd = "New-LocalUser -Name " + $commands.Name + $desc + $arg + $npass
$cmd
$ScriptBlock = [scriptblock]::Create($cmd)
ExcuteRemoteCommand -serverAddress $userinfo.ip -ServerUsername $userinfo.user -ServerPassword $userinfo.password -code $ScriptBlock
if($commands.logon -eq "True"){
$cmd = "net user " + ($commands.Name).ToString() + " /logonpasswordchg:yes"
$cmd
$ScriptBlock = [scriptblock]::Create($cmd)
ExcuteRemoteCommand -serverAddress $userinfo.ip -ServerUsername $userinfo.user -ServerPassword $userinfo.password -code $ScriptBlock
}else{
$cmd = "net user " + ($commands.Name).ToString() + " /logonpasswordchg:no"
$cmd
$ScriptBlock = [scriptblock]::Create($cmd)
ExcuteRemoteCommand -serverAddress $userinfo.ip -ServerUsername $userinfo.user -ServerPassword $userinfo.password -code $ScriptBlock
}
Read-Host
Exit
I finally find a solution for my problem. I used the command NET, so here the che command line that I used
NET USER $user $pass /ADD
For the other parameters, I'll pass after it creates the user
$pass is NOT a secure string!

Deploying an SSIS package with dtutil

I am trying to deploy a package with dtutil, however I am getting an error that reads:
Option "-xxxx" is not valid.
This correlates to the SOURCESERVER pararmeter I am providing, which has a hypen in it.
$conString = "xxx-xxxx";
$dtUtilQueryToExecute = '/SOURCESERVER "' + $conString + '" /sql "my path" /exists';
$result = dtutil $dtUtilQueryToExecute
I think that dtutil is expecting a new parameter when it reaches the hyphen and cannot escape the hyphen even though it is in double/single quotation marks.
The reason why I am using dtutil is that I need to be able to deploy the same package to many other servers from one location.
So either I need to figure out how to escape the hyphen in the server name, or I need to use an alternative deployment method.
How do I escape the hyphen, or what alternative deployment method can I use?
I believe PowerShell is interpreting the hyphen in the variable. It looks like the wisdom of the internet suggests permutations like
$conString = 'xxx-xxxx'
$conString = "xxx`-xxxx"
Also, no trailing semicolon is required in PowerShell
As an alternative method why not use SMO with Powershell. That wayyou can create a script to deploy your package and also create foders, projects, environments and SQL Agent tasks.
Here is an example of something I would use:
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$target_server_name = 'target_server_name'
$source_server_name = 'source_server_name'
$target_database_name = 'target_database_name'
$source_database_name = 'source_database_name'
$environment_name = 'enviornment_name'
$folder_name = 'folder_name'
$project_name = 'project_name'
$ispac_name = 'ispac_name'
$variables = #{
email_alert = 'xx#xx.com'
email_error = 'xx#xx.com'
email_reply = 'noreply#xx.com'
smtp_server = 'outlook.xx.local'
tax_rate = '20'
}
function Write-Message ($msg) {
Write-Host ' [+] ' -ForegroundColor Yellow -NoNewline
Write-Host $msg
}
Write-Host 'Starting deployment' -ForegroundColor DarkGray
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Management.IntegrationServices") | Out-Null
Write-Message ("Connecting to integration services on '$source_server_name'")
$conn_str = "Data Source={0};Initial Catalog=master;Integrated Security=SSPI;" -f $source_server_name
$conn = New-Object System.Data.SqlClient.SqlConnection $conn_str
$namespace = 'Microsoft.SqlServer.Management.IntegrationServices'
$intg_serv = New-Object "$namespace.IntegrationServices" $conn
$catalog = $intg_serv.Catalogs['SSISDB']
$folder = $catalog.Folders[$folder_name]
if(!$folder) {
Write-Message 'Creating folder ...'
$folder = New-Object "$($namespace).CatalogFolder" ($catalog, $Folder_name, $Folder_name)
$folder.Create()
} else {
Write-Message 'Folder found ...'
}
Write-Message 'Deploying project file ...'
$path = "$here\..\path_to_your_project\bin\Development\$($ispac_name).ispac"
if(Test-Path $path) {Copy-Item (Resolve-Path $path) $here}
[byte[]]$project_file = [System.IO.File]::ReadAllBytes("$here\crm_imports.ispac")
$dummy = $folder.DeployProject($project_name, $project_file)
$project = $folder.Projects[$project_name]
Write-Message 'Removing old environment ...'
$old = $folder.Environments | Select -ExpandProperty name
$old | % {$folder.Environments[$_].Drop()}
Write-Message "Creating environment '$envionment_name'"
$environment = New-Object "$namespace.EnvironmentInfo" ($folder, $environment_name, $environment_name)
$environment.Create()
$variables.GetEnumerator() | % {
$n = $_.Name
$v = $_.Value
Write-Message " -> adding environment variable $($n): $v"
$environment.Variables.Add($n,[System.TypeCode]::String, $v, $false, $n)
$environment.Alter()
$project.Packages | % {
if($_.Parameters[$n] -ne $null)
{
$_.Parameters[$n].Set([Microsoft.SqlServer.Management.IntegrationServices.ParameterInfo+ParameterValueType]::Referenced, $n)
$_.Alter()
}
}
}
$reference = $project.References[$environment.name, $folder.Name]
if(!$reference) {
$project.References.Add($environment.name, $folder.Name)
$project.Alter()
}
$environment_ref_id = $project.References[0].ReferenceId
$job_name = 'job_name'
$server = New-Object microsoft.sqlserver.management.smo.server $source_server_name
$Job_server = $server.JobServer
$job = $job_server.Jobs[$job_name]
if($job) {$job.Drop()}
Write-Message "Creating SQL agent job '$job_name'"
$job = New-Object Microsoft.SqlServer.Management.SMO.Agent.Job -ArgumentList $Job_server, $job_name
$job.Create()
$job.OwnerLoginName = 'sa'
$job.ApplyToTargetServer($source_server_name)
$job.Alter()
$job_step = New-Object Microsoft.SqlServer.Management.SMO.Agent.JobStep -ArgumentList $job, 'Run SSIS import_donations package'
$job_step.SubSystem = 'Ssis'
$job_step.command = ('/ISSERVER "\"\SSISDB\{3}\{4}\{5}.dtsx\"" ' +
'/SERVER {0} /ENVREFERENCE {1} ' +
'/Par "\"CM.source.ConnectionString\"";' +
'"\"Data Source={0};Initial Catalog={6};Integrated Security=SSPI;Application Name=my_app;\"" ' +
'/Par "\"CM.source.InitialCatalog\"";"\"{6}\"" ' +
'/Par "\"CM.source.ServerName\"";{0} ' +
'/Par "\"CM.target.ConnectionString\"";' +
'"\"Data Source={2};Initial Catalog={7};Integrated Security=SSPI;Application Name=my_app;\"" ' +
'/Par "\"CM.target.InitialCatalog\"";"\"{7}\"" ' +
'/Par "\"CM.target.ServerName\"";{2} ' +
'/Par "\"$ServerOption::LOGGING_LEVEL(Int16)\"";3 ' +
'/Par "\"$ServerOption::SYNCHRONIZED(Boolean)\"";True /CALLERINFO SQLAGENT /REPORTING E') -f $source_server_name, $reference.ReferenceId, $target_server_name, $folder_name, $project_name, $ispac_name, $source_database_name, $target_database_name
$job_step.Create()
$conn.Close()

access $args/params from inside method

I am working on an error handling method for my PowerShell scripts. I pass it the error via try/catch on the catch, but I want to iterate through the original params from the command line that called it in order to create an error log and error email.
Here's what I have so far:
# --params--
param(
[string]$Directory,
[string]$ArchiveDirectory,
[string]$ErrorDirectory,
[string]$ErrorEmailFrom,
[string]$ErrorEmailTo,
[string]$ErrorEmailSubject,
[string]$ErrorSMTP,
[string]$FTPSite,
[string]$FTPUser,
[string]$FTPPass,
[string]$FTPRemoteDir
)
# list of arguments for debug
$paramList = $args
# --functions--
function Handle-MyError
{
Write-Host "handle-error"
Write-Host $args[0]; # this is the exception passed in
# -Email alert-
$subject = $ErrorEmailSubject + $FTPSite
# build message
$message = Get-Date -Format "yyyy-mm-dd hh:mm:ss"
$message += "`r`nError: " + $FTPSite + " : " + $args[0]
$message += "`r`nParameters:`r`n"
# Grab each parameter value, using Get-Variable
for ($i=0;$i -lt $paramList.Length; $i++)
{
$message += $paramList[$i]
}
# send email
$smtp = New-Object Net.Mail.SmtpClient($ErrorSMTP)
$smtp.Send($ErrorEmailFrom, $ErrorEmailTo, $subject, $message)
# drop error file
$theDate = Get-Date -Format "yyyymmdd"
$errorFile = $ErrorDirectory + "\" + $theDate + "_ERROR.txt"
Write-Host $errorFile
$message | Out-File $errorFile -Append
}
and in my try/catch:
catch [Exception]
{
Write-Host "SPOT 1"
Handle-MyError $_.
}
At the top, I try to save the original $args as $paramList to loop through later, but it's not working. Inside the Handle-MyError method, $args becomes the error that is passed so I thought if I save the original $argsas $paramList I could access it later, but it's wonky... Ideas?
There are several ways, in order of worst to best:
Use Get-Variable with Scope parameter. Scope number can differ, but it should be at least 2 (Script->Catch->Handle-MyError)
function Handle-MyError
{
Write-Host (Get-Variable -Name ErrorEmailFrom -ValueOnly -Scope 2)
}
Using $Script: prefix
function Handle-MyError
{
Write-Host $Script:ErrorEmailFrom
}
Using $PSBoundParameters
# list of arguments for debug
$paramList = $PsBoundParameters
function Handle-MyError
{
Param
(
$Exception,
$Cfg
)
Write-Host $Cfg.ErrorEmailFrom
}
catch [Exception]
{
Write-host "SPOT 1"
Handle-MyError -Exception $_ -Cfg $paramList
}
Using splatting:
$paramList = $PsBoundParameters
function Handle-MyError
{
Param
(
$Exception,
$ErrorDirectory,
$ErrorEmailFrom,
$ErrorEmailTo,
$ErrorEmailSubject,
$ErrorSMTP
)
Write-Host $ErrorEmailFrom
}
catch [Exception]
{
Write-host "SPOT 1"
Handle-MyError #paramList -Exception $_
}
Here's my final code after some help from #beatcracker.
I combined two pieces of the puzzle.
I need to save the initial params in a local var and Two, ($paramList = $PsBoundParameters)
Access this var/list using .GetEnumerator()
# --params--
param(
[string]$Directory,
[string]$ArchiveDirectory,
[string]$ErrorDirectory,
[string]$ErrorEmailFrom,
[string]$ErrorEmailTo,
[string]$ErrorEmailSubject,
[string]$ErrorSMTP,
[string]$FTPSite,
[string]$FTPUser,
[string]$FTPPass,
[string]$FTPRemoteDir
)
# set params as var for debug later
$paramList = $PsBoundParameters
# --functions--
function Handle-MyError
{
Write-Host "handle-error"
#write-host "Exception:" $args[0]; # this is the exception passed in
# -Email alert-
# build subject
$subject = $ErrorEmailSubject + " " + $FTPSite
# build message
$message = Get-Date -format s
$message += "`r`nError Message: " + $args[0]
$message += "`r`nParameters:`r`n"
$paramList.GetEnumerator() | ForEach-Object `
{
#Write-Host $_.Key "=" $_.Value
if ($_.Key -ne "FTPPass"){
$message += "`r`n" + $_
}
}
}

Why does PowerShell intermittently not find List[string].Add() method?

I've got a build script (PowerShell 4 on Windows 2012 R2) that runs NUnit in a background job and returns NUnit's output. This output is collected in a Collections.Generic.List[string].
$nunitJob = Start-Job -ScriptBlock {
param(
[string]
$BinRoot,
[string]
$NUnitConsolePath,
[string[]]
$NUnitParams,
[string]
$Verbose
)
Set-Location -Path $BinRoot
$VerbosePreference = $Verbose
Write-Verbose -Message ('{0} {1}' -f $NUnitConsolePath,($NUnitParams -join ' '))
& $NUnitConsolePath $NUnitParams 2>&1
$LASTEXITCODE
} -ArgumentList $binRoot,$nunitConsolePath,$nunitParams,$VerbosePreference
$nunitJob | Wait-Job -Timeout ($timeoutMinutes * 60) | Out-Null
$jobKilled = $false
if( $nunitJob.JobStateInfo.State -eq [Management.Automation.JobState]::Running )
{
$jobKilled = $true
$errMsg = 'Killing {0} tests: exceeded {1} minute timeout.' -f $assembly.Name,$timeoutMinutes
Write-Error -Message $errMsg
}
$output = New-Object 'Collections.Generic.List[string]'
$nunitJob |
Stop-Job -PassThru |
Receive-Job |
ForEach-Object {
if( -not $_ )
{
[void]$output.Add( '' )
return
}
switch -Regex ( $_ )
{
'^Tests run: (\d+), Errors: (\d+), Failures: (\d+), Inconclusive: (\d+), Time: ([\d\.]+) seconds$'
{
$testsRun = $Matches[1]
$errors = $Matches[2]
$failures = $Matches[3]
$inconclusive = $Matches[4]
$duration = New-Object 'TimeSpan' 0,0,$Matches[5]
break
}
'^ Not run: (\d+), Invalid: (\d+), Ignored: (\d+), Skipped: (\d+)$'
{
$notRun = $Matches[1]
$invalid = $Matches[2]
$ignored = $Matches[3]
$skipped = $Matches[4]
break
}
}
# Error happens here:
[void] $output.Add( $_ )
}
Intermittently, our build will fail with this error:
Cannot find an overload for "Add" and the argument count: "1".
At line:XXXXX char:XXXXX
+ [void] $output.Add( $_ )
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Any idea why PowerShell would not be able to find List[string]'s Add method?
I've opened a console Window and played around with passing different typed objects to Add without getting an error.
> $o = New-Object 'Collections.Generic.List[string]'
> $o.Add( '' )
> $o.Add( $null )
> $o.Add( 1 )
> $o
1
When you redirect stderr to stdout, you can get System.Management.Automation.ErrorRecords interspersed with strings. Stderr is automatically converted to ErrorRecords while stdout is strings.
So you'll probably want to look to see if the output contains ErrorRecords of interest and if not then filter them out.

sql failed jobs export to csv with powershell

I am battling with a PowerShell script that captures all SQL Failed jobs for the past day and exports it to .CSV
Please view code below.
param (
#[string]$serverInstance = '03RNB-VSQLPRD4\SQLPRD04
)
begin {
[void][reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
}
process {
try {
Write-Verbose "List failed SQL Server jobs using SMO..."
$serverInstance = Get-Content "C:\MountSpaceCollector\SQLJobFailures\servers2.txt";
$server = new-object Microsoft.SqlServer.Management.Smo.server $serverInstance
$results = #()
$reasons = #()
$jobs = $server.jobserver.jobs | where-object {$_.isenabled}
# Process all SQL Agent Jobs looking for failed jobs based on the last run outcome
foreach ($job in $jobs) {
[int]$outcome = 0
[string]$reason = ""
# Did the job fail completely?
if ($job.LastRunOutcome -eq "Failed") {
$outcome++
$reasons += "Job failed: " + $job.name + " Result: " + $job.LastRunOutcome
# Did any of the steps fail?
foreach ($jobStep in $job.jobsteps) {
if ($jobStep.LastRunOutcome -ne "Succeeded") {
$outcome++
$reasons += "Step failed: " + $jobStep.name + " Result: " + $jobStep.LastRunOutcome
}
}
}
if ($outcome -gt 0) {
$jobFailure = New-Object -TypeName PSObject -Property #{
Name = $job.name
LastRunDate = $job.lastrundate
LastRunOutcome = $reasons
}
$results += $jobFailure
}
}
Write-Output $results | Export-CSV -Path 'C:\MountSpaceCollector\SQLJobFailures\SQLJobFailures.csv' -Delimiter '|'
}
catch [Exception] {
Write-Error $Error[0]
$err = $_.Exception
while ( $err.InnerException ) {
$err = $err.InnerException
Write-Output $err.Message
Write-Output $results
}
}
}
But It Exports all except the last field (LastRunOutcome). It only displays "System.Object[]"?
Can anyone please assist with this as I do not know what I am doing wrong?
It's because $Reasons is an object, more specifically an array. You need to format the reasons differently, as a string for instance, to be able to have it appear in the CSV normally.
Perhaps you meant to use the string $Reason that you declare, but don't use?