I am trying to install SqlServer via DSC, but I keep hitting this error
Exception calling "NewScriptBlock" with "1" argument(s): "At line:10 char:5
+ Import-DscResource -ModuleName 'SqlServerDsc'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Could not find the module 'SqlServerDsc'.
At line:438 char:9
+ SqlSetup 'InstallDefaultInstance'
+ ~~~~~~~~
My DSC configuration snippet looks like this
Configuration InstallSoftware
{
param
(
$ComputerNames
)
Import-DSCResource -ModuleName PSDesiredStateConfiguration
Import-DSCResource -Module SqlServerDsc
Node $ComputerNames
{
WindowsFeature 'NetFramework45'
{
Name = 'NET-Framework-45-Core'
Ensure = 'Present'
}
SqlSetup 'SqlInstall'
{
InstanceName = 'localhost\mssql2019'
Features = 'SQLENGINE'
Action = 'Install';
SourcePath = 'C:\SQL2019'
SQLSysAdminAccounts = #('Administrators')
DependsOn = '[WindowsFeature]NetFramework45'
}
}
InstallSoftware
I am quite positive that the SqlServer has been installed in the remote server.
Get-DscResource -Module SqlServerDsc returned the list of resources
And the folder exists in C:\Program Files\WindowsPowerShell\Modules\SqlServerDsc
Any feedback/advice is highly appreciated.
Thank you so much for your time.
Looks like this was already answered, and I'm not sure I'm following everything, but I'll typically create a wrapper function for copying resources around. Something like below with flags for specifying path, server, credential, then helper stuff like changing max envelop size (if you haven't hit this, you will) and copying out my cert. Below isn't the whole thing, but it'd at least make sure your module would copy.
{
Param (
[Parameter(Mandatory=$true)]
[string]$localpath,
[Parameter(Mandatory=$true)]
[string]$ServerName,
[Parameter(Mandatory=$true)]
[PsCredential]$PsAdmin,
[Parameter(Mandatory=$true)]
[boolean]$MaxEnvelope,
[boolean]$CopyDscResources,
[boolean]$RunDscTest,
[boolean]$AddEncryptionCert
)
#Create Path if it doesnt exist
if (!(test-path -path $localpath)) {
New-Item -ItemType directory -Path $localpath
}
if ($MaxEnvelope -eq $true)
{
$so = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$session = New-PSSession -ComputerName $ServerName -Credential $PsAdmin -SessionOption $so
Invoke-Command -Session $session -ScriptBlock {
Set-Item -Path WSMan:\localhost\MaxEnvelopeSizeKb -Value 3072
}
}
if ($CopyDscResources -eq $true)
{
$so = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$session = New-PSSession -ComputerName $ServerName -Credential $PsAdmin -SessionOption $so
$paramsDefender = #{
Path = 'C:\Program Files\WindowsPowerShell\Modules\SqlServerDsc'
Destination = 'C:\Program Files\WindowsPowerShell\Modules'
ToSession = $session
}
Copy-Item #paramsDefender -Recurse -Force
}
$Session2 = New-CimSession -ComputerName $ServerName.ToString() -Credential $PsAdmin
Set-DscLocalConfigurationManager -Path $localpath -CimSession $Session2 -Force
Start-DSCConfiguration -Path $localpath -Cimsession $Session2 -Wait -Force -ErrorAction Stop -Verbose
if ($RunDscTest)
{
Test-DSCConfiguration -Path $localpath -Cimsession $Session2 -Verbose | Format-Table -AutoSize
}
}
#Example run
RunRemoteDsc $localpath 'Some-Server' $PsLocalAdmin $false $true $false
Related
I would like to perform a bunch of invoke-sqlcmd in one sql transaction. Here's what I'm doing:
try{
$scope = New-Object -TypeName System.Transactions.TransactionScope
GetFiles $SqlFilesDirectory
$scope.Complete()
}
catch{
$_.exception.message
}
finally{
$scope.Dispose()
}
Here's how GetFiles is defined:
#
# Get SQL Files recursively
#
function GetFiles($path = $pwd)
{
$subFolders = Get-ChildItem -Path $path -Directory | Select-Object FullName,Name | Sort-Object -Property Name
$sqlFiles = Get-ChildItem -Path $path -Filter *.sql | Select-Object FullName,Name | Sort-Object -Property Name
foreach ($file in $sqlFiles)
{
Write-Host "file: " $file.Name
Invoke-Sqlcmd -ServerInstance $ServerInstance -Database $DBName -Username $SvcAdminAccount -Password $SvcAdminPassword -InputFile $file.FullName -QueryTimeout 65535
}
foreach ($folder in $subFolders)
{
Write-Host "`nGetting files for subfolder: " $folder.Name
GetFiles $folder.FullName
}
}
How do we perform a series of invoke-sqlcmd in one transaction?
Here's the output:
The behavior that I want is that ALL
changes are rolled back if a single sql script fails.
I have the following contents in PowerShell script (Process.ps1) that reads from SQL tables and appends results to the variables listed:
function Query($Query) {
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$Server;Initial Catalog=$Database;Integrated Security=SSPI"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandText = $Query
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$a=$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSet.Tables[0]
}
$Result = Query "SELECT * from [$cubeTable]" | Out-GridView -Wait;
$CUBE = Query "SELECT [cube_name] FROM [$cubeTable] WHERE [cube_name] = '$CUBE_input'" | Select -ExpandProperty cube_name;
$Destination_Server = Query "SELECT [destination_server] FROM [$cubeTable] WHERE [cube_name] = '$CUBE'" | Select -ExpandProperty destination_server;
$BasePath = Query "SELECT [variable_value] FROM [$pathTable] WHERE [variable_name] = 'base_path'" | Select -ExpandProperty variable_value;
$jsonPath = Join-Path -Path $BasePath -ChildPath $jsonDirectory
New-Item -ItemType Directory -Force -Path $jsonPath
$JSON_file = Join-Path $jsonPath $CUBE |
%{ ($_ + ".json") }
$processPATH = Join-Path -Path $BasePath -ChildPath $process_output_Directory
New-Item -ItemType Directory -Force -Path $processPATH
$process_output = Join-Path $processPATH $CUBE |
%{ ($_ + ".txt") }
$autosysPATH = Join-Path -Path $BasePath -ChildPath $AUTOSYS_output_Directory
New-Item -ItemType Directory -Force -Path $autosysPATH
$process_AUTOSYS_output = Join-Path $autosysPATH $CUBE |
%{ ($_ + "_process.txt") }
When I run the script in CMD through a batch file, it runs great as it should, however, it's outputting these directory information somewhere from the following variables:
json_file, process_output, and autosys_output
I have an output image here:
Where exactly is the writing to console happening? I don't have any echo OR a Write-Host! let alone a function to output the directories...
and its definitely not this part: $Result = Query "SELECT * from [$cubeTable]" | Out-GridView -Wait; because I commented it out and it still outputted the directories info as the screenshot shows.
New-Item returns the created FileInfo or DirectoryInfo object. That's what you're seeing in your output. PowerShell default output formating just merges similar consecutive objects to provide more compact output, so you're getting a single table instead of three separate tables with one object each.
You can suppress the output by adding | Out-Null to the New-Item statements:
New-Item -ItemType Directory -Force -Path $jsonPath | Out-Null
Other options would be capturing the output in a variable or using redirection (> $null).
Hi i am quite frustrated with powershell. i want to use my powershell script to call another powershell script inside it.
My powershell only do the first part which is download files and does not invoke the following powershell script...
Can not think the reason behind it.. Could anyone help me with that? Thanks!
The Program looks like :
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
Set-Location $directorypath
if ($StepNumber -ne 2) {
$MyName = $MyInvocation.InvocationName
$LogFileName = ".\Logs\" + [System.IO.Path]::GetFileNameWithoutExtension($MyName) + [String]::Format("_{0:yyyy-MM-dd_HH-mm-ss}.Log", (Get-Date))
if (!(Test-Path ".\Logs")) {
$X = New-Item -path . -name Logs -ItemType directory
}
&PowerShell.exe -noProfile -File NSCCMPIDDownload.ps1 2 *>`&1 | Tee $LogFileName
exit
}
## ## ---- STEP2 ------------DownLoad the file from Website
$ErrorActionPreference = "Continue"
Write-Host Running NSCC-MPID-Download at $(Get-Date)
Write-Host ""
## Download the NSCC-MPID-Directory.xls from website
$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)
Write-Host Running NSCCMPIDInsertion.ps1
$cmd = "$directorypath\NSCCMPIDInsertion.ps1"
Invoke-Expression "$cmd"
Write-Host Running NSCCMPIDAfterParse.ps1
$cmd = "$directorypath\NSCCMPIDAfterParse.ps1"
Invoke-Expression "$cmd"
Write-Host --------------------------------------------------------------------------
Write-Host Process ended at $(Get-Date)
I am working on a disk space script for our clients in my off time. I just tested it using the ISE, and it looks like it was working until I checked the transcript.
There are sections during the first removal cycle around line 32 where it is removing files in C:\Windows\System32\, which of course I didn't want it to. I am sure I did something wrong, but I have checked for typos, and I do not understand how it can get %system32% from a users directory.
If (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator))
{
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + ' (Elevated)'
$Host.UI.RawUI.BackgroundColor = 'DarkBlue'
Clear-Host
}
Else
{
$newProcess = New-Object Diagnostics.ProcessStartInfo 'PowerShell'
$newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"
$newProcess.Verb = 'runas'
[Diagnostics.Process]::Start($newProcess) | Out-Null
exit
}
If ((Test-Path "C:\DiskSpaceCleanupLog\") -eq $False)
{
New-Item -ItemType Directory -Path "C:\DiskSpaceCleanupLog\"
}
$Date = [string]::Format( "{0:dd-MM-yyyy}", [datetime]::Now.Date )
$LogName = "C:\DiskSpaceCleanupLog\" + $Date + "Log.txt"
Start-Transcript $LogName
$Path = #()
$Array = #(Get-ChildItem C:\Users | Select-Object Name)
Read-Host -Verbose "Removing User Account temp files..."
Foreach ($Name IN $Array)
{
$Path = ("C:\Users\" + $Name.Name + "\AppData\Local\Temp\")
}
Foreach ($Path IN $Array)
{
Get-ChildItem | Remove-Item -Recurse -WhatIf
}
Remove-Variable Path
Read-Host -Verbose "Removing User Account crash dumps..."
Foreach ($Name IN $Array)
{
$Path = ("C:\Users\" + $Name.Name + "\AppData\Local\CrashDumps\")
}
Foreach ($Path IN $Array)
{
Get-ChildItem | Remove-Item -Recurse -WhatIf
}
Remove-Variable Path
Read-Host -Verbose "Removing User Account reporting files..."
Foreach ($Name IN $Array)
{
$Path = ("C:\Users\" + $Name.Name + "\AppData\Local\Microsoft\Windows\WER\ReportArchive\")
}
Foreach ($Temp IN $Path)
{
Get-ChildItem | Remove-Item -Recurse -WhatIf
}
Remove-Variable Path
Read-Host -Verbose "Removing User Account temp files from Internet Explorer..."
Foreach ($Name IN $Array)
{
$Path = ("C:\Users\" + $Name.Name + "\AppData\Local\Microsoft\Windows\Temporary Internet Files\")
}
Foreach ($Temp IN $Path)
{
Get-ChildItem | Remove-Item -Recurse -WhatIf
}
Read-Host -Verbose "Removing Recycle Bin files..."
Remove-Item -LiteralPath 'C:\$Recycle.Bin\' -Recurse -WhatIf
Read-Host -Verbose "Removing global crash dumps..."
Remove-Item "C:\ProgramData\Microsoft\Windows\WER\ReportQueue" -Recurse -WhatIf
Remove-Item "C:\ProgramData\Microsoft\Windows\WER\ReportArchive" -Recurse -WhatIf
Read-Host -Verbose "Removing Windows Update cached files..."
Stop-Service -DisplayName 'Windows Update'
Remove-Item "C:\Windows\SoftwareDistribution\Download\*" -Recurse -WhatIf
Start-Service -DisplayName 'Windows Update'
Remove-Variable Array, Path
Read-Host -Verbose "Cleaning base image of update cache..."
DISM.exe /Online /Cleanup-Image /SPSuperseded
Read-Host -Verbose "Running Windows Clean Manager..."
$OSVersion = Get-WMIObject -Class Win32_OperatingSystem | Format-Table Version
If ($OSVersion -le 6.1)
{
cleanmgr.exe /verylowdisk
}
Read-Host -Verbose "Removal is complete. Sending logs..."
Stop-Transcript
$SecurePassword = ConvertTo-SecureString "InsertPasswordHere" -AsPlainText -Force
$emailcredential = New-Object System.Management.Automation.PSCredential ("email#domain.com", $SecurePassword)
Send-MailMessage -To "Name Here <email#domain.com>" -From "Name Here <email#domain.com>" -Subject ("Disk Space Cleanup Log - " + $Date) -Body "Attached is the log from the script." -Attachments $LogName -SmtpServer "smtp.office365.com" -Credential $emailcredential -UseSSL -Port "587" -DeliveryNotificationOption OnFailure
Line 32 is Get-ChildItem | Remove-Item -Recurse -WhatIf
The are several things that should be adjusted in your code but the issue that is befalling you now is that you have not specified a -Path. Therefore Get-ChildItem will be returning items from the working directory!
Get-ChildItem | Remove-Item -Recurse -WhatIf
Should be instead
Get-ChildItem $path | Remove-Item -Recurse -WhatIf
Like I said though there are several potential pitfalls and areas of improvement there to be addressed. You use the same loop 5 times. A couple are exactly the same.
I believe the issue is on line 23, where the code is not populating the array with full pathnames. See Get full path of the files in PowerShell for some advice on how to get the full pathnames instead.
I get this error message when I run the Powershell script at the bottom:
Exception calling "EnumScript" with "1" argument(s): "Script failed for Table 'dbo.Product'. "
At :line:48 char:35
+ foreach ($s in $scripter.EnumScript <<<< ($tbl)) { write-host $s }
However, when I comment out the output_file line
#$output_file="C:\Product.sql"
(which won't set the Scripter options to write to file), it works fine and outputs the INSERT statments to the console.
Here's the failing script, is there something I'm missing?
# Script INSERTs for given table
param
(
[string] $server,
[string] $database,
[string] $schema,
[string] $table,
[string] $output_file
)
$server="devdidb02"
$database="EPCTrunk_EPC"
$schema="dbo"
$table="Product"
$output_file="C:\Product.sql"
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
$srv = New-Object "Microsoft.SqlServer.Management.SMO.Server" $server
$db = New-Object ("Microsoft.SqlServer.Management.SMO.Database")
$tbl = New-Object ("Microsoft.SqlServer.Management.SMO.Table")
$scripter = New-Object ("Microsoft.SqlServer.Management.SMO.Scripter") ($server)
# Get the database and table objects
$db = $srv.Databases[$database]
$tbl = $db.tables | Where-object {$_.schema -eq $schema-and$_.name -eq $table}
# Set scripter options to ensure only data is scripted
$scripter.Options.ScriptSchema = $false;
$scripter.Options.ScriptData = $true;
#Exclude GOs after every line
$scripter.Options.NoCommandTerminator = $true;
if ($output_file -gt "")
{
$scripter.Options.FileName = $output_file
$scripter.Options.ToFileOnly = $true
}
# Output the script
foreach ($s in $scripter.EnumScript($tbl)) { write-host $s }
I ran both yours and Keith's and it looks like the issue is in the path you are setting for the file. I was able to reproduce your error. You were using $output_file="C:\Product.sql". Then I changed the path to: $output_file="$home\Product.sql" it ran just fine and gave me the file.
I am guessing that the reason for this is that I don't have permission to write to c:\ which may be the problem you are having.
BTW - my home dir in this case for me is my user folder for my login so I was able to find it there.
FWIW I'm not able to repro the error you see using the AdventureWorks DB. The following generates the foo.sql file without any errors:
Add-Type -AssemblyName ('Microsoft.SqlServer.Smo, Version=10.0.0.0, ' + `
'Culture=neutral, PublicKeyToken=89845dcd8080cc91')
$serverName = '.\SQLEXPRESS'
$smo = new-object Microsoft.SqlServer.Management.Smo.Server $serverName
$db = $smo.Databases['AdventureWorks']
$tbl = $db.Tables | Where {$_.Schema -eq 'Production' -and `
$_.Name -eq 'Product'}
$output_file = "$home\foo.sql"
$scripter = new-object Microsoft.SqlServer.Management.Smo.Scripter $serverName
$scripter.Options.ScriptSchema = $false;
$scripter.Options.ScriptData = $true;
$scripter.Options.NoCommandTerminator = $true;
if ($output_file -gt "")
{
$scripter.Options.FileName = $output_file
$scripter.Options.ToFileOnly = $true
}
# Output the script
foreach ($s in $scripter.EnumScript($tbl)) { write-host $s }